blob: b03e721270aa974198d5f99a1db3d9aea3f229da [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 Sharmaa18a2dd2014-04-20 15:51:17 +0530424static const struct hdmiphy_config hdmiphy_5420_configs[] = {
425 {
426 .pixel_clock = 25200000,
427 .conf = {
428 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
429 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
430 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
431 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
432 },
433 },
434 {
435 .pixel_clock = 27000000,
436 .conf = {
437 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
438 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
439 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
440 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
441 },
442 },
443 {
444 .pixel_clock = 27027000,
445 .conf = {
446 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
447 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
448 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
449 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
450 },
451 },
452 {
453 .pixel_clock = 36000000,
454 .conf = {
455 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
456 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
457 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
458 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
459 },
460 },
461 {
462 .pixel_clock = 40000000,
463 .conf = {
464 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
465 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
466 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
467 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
468 },
469 },
470 {
471 .pixel_clock = 65000000,
472 .conf = {
473 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
474 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
475 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
476 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
477 },
478 },
479 {
480 .pixel_clock = 71000000,
481 .conf = {
482 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
483 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
484 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
485 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
486 },
487 },
488 {
489 .pixel_clock = 73250000,
490 .conf = {
491 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
492 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
493 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
494 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
495 },
496 },
497 {
498 .pixel_clock = 74176000,
499 .conf = {
500 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
501 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
502 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
503 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
504 },
505 },
506 {
507 .pixel_clock = 74250000,
508 .conf = {
509 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
510 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
511 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
512 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
513 },
514 },
515 {
516 .pixel_clock = 83500000,
517 .conf = {
518 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
519 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
520 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
521 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
522 },
523 },
524 {
525 .pixel_clock = 88750000,
526 .conf = {
527 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
528 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
529 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
530 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
531 },
532 },
533 {
534 .pixel_clock = 106500000,
535 .conf = {
536 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
537 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
538 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
539 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
540 },
541 },
542 {
543 .pixel_clock = 108000000,
544 .conf = {
545 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
546 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
547 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
548 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
549 },
550 },
551 {
552 .pixel_clock = 115500000,
553 .conf = {
554 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
555 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
556 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
557 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
558 },
559 },
560 {
561 .pixel_clock = 146250000,
562 .conf = {
563 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
564 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
565 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
566 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
567 },
568 },
569 {
570 .pixel_clock = 148500000,
571 .conf = {
572 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
573 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
574 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
575 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
576 },
577 },
578};
579
580struct hdmi_driver_data exynos5420_hdmi_driver_data = {
581 .type = HDMI_TYPE14,
582 .phy_confs = hdmiphy_5420_configs,
583 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
584 .is_apb_phy = 1,
585};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900586
587struct hdmi_driver_data exynos4212_hdmi_driver_data = {
588 .type = HDMI_TYPE14,
589 .phy_confs = hdmiphy_v14_configs,
590 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
591 .is_apb_phy = 0,
592};
593
594struct hdmi_driver_data exynos5_hdmi_driver_data = {
595 .type = HDMI_TYPE14,
596 .phy_confs = hdmiphy_v13_configs,
597 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
598 .is_apb_phy = 0,
599};
600
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900601static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
602{
603 return readl(hdata->regs + reg_id);
604}
605
606static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
607 u32 reg_id, u8 value)
608{
609 writeb(value, hdata->regs + reg_id);
610}
611
612static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
613 u32 reg_id, u32 value, u32 mask)
614{
615 u32 old = readl(hdata->regs + reg_id);
616 value = (value & mask) | (old & ~mask);
617 writel(value, hdata->regs + reg_id);
618}
619
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900620static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
621 u32 reg_offset, u8 value)
622{
623 if (hdata->hdmiphy_port) {
624 u8 buffer[2];
625 int ret;
626
627 buffer[0] = reg_offset;
628 buffer[1] = value;
629
630 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
631 if (ret == 2)
632 return 0;
633 return ret;
634 } else {
635 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
636 return 0;
637 }
638}
639
640static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
641 u32 reg_offset, const u8 *buf, u32 len)
642{
643 if ((reg_offset + len) > 32)
644 return -EINVAL;
645
646 if (hdata->hdmiphy_port) {
647 int ret;
648
649 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
650 if (ret == len)
651 return 0;
652 return ret;
653 } else {
654 int i;
655 for (i = 0; i < len; i++)
656 writeb(buf[i], hdata->regs_hdmiphy +
657 ((reg_offset + i)<<2));
658 return 0;
659 }
660}
661
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900662static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900663{
664#define DUMPREG(reg_id) \
665 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
666 readl(hdata->regs + reg_id))
667 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
668 DUMPREG(HDMI_INTC_FLAG);
669 DUMPREG(HDMI_INTC_CON);
670 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900671 DUMPREG(HDMI_V13_PHY_RSTOUT);
672 DUMPREG(HDMI_V13_PHY_VPLL);
673 DUMPREG(HDMI_V13_PHY_CMU);
674 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900675
676 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
677 DUMPREG(HDMI_CON_0);
678 DUMPREG(HDMI_CON_1);
679 DUMPREG(HDMI_CON_2);
680 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900681 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900682 DUMPREG(HDMI_STATUS_EN);
683 DUMPREG(HDMI_HPD);
684 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900685 DUMPREG(HDMI_V13_HPD_GEN);
686 DUMPREG(HDMI_V13_DC_CONTROL);
687 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900688
689 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
690 DUMPREG(HDMI_H_BLANK_0);
691 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900692 DUMPREG(HDMI_V13_V_BLANK_0);
693 DUMPREG(HDMI_V13_V_BLANK_1);
694 DUMPREG(HDMI_V13_V_BLANK_2);
695 DUMPREG(HDMI_V13_H_V_LINE_0);
696 DUMPREG(HDMI_V13_H_V_LINE_1);
697 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900698 DUMPREG(HDMI_VSYNC_POL);
699 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900700 DUMPREG(HDMI_V13_V_BLANK_F_0);
701 DUMPREG(HDMI_V13_V_BLANK_F_1);
702 DUMPREG(HDMI_V13_V_BLANK_F_2);
703 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
704 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
705 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
706 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
707 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
708 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
709 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
710 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
711 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
712 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
713 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
714 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900715
716 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
717 DUMPREG(HDMI_TG_CMD);
718 DUMPREG(HDMI_TG_H_FSZ_L);
719 DUMPREG(HDMI_TG_H_FSZ_H);
720 DUMPREG(HDMI_TG_HACT_ST_L);
721 DUMPREG(HDMI_TG_HACT_ST_H);
722 DUMPREG(HDMI_TG_HACT_SZ_L);
723 DUMPREG(HDMI_TG_HACT_SZ_H);
724 DUMPREG(HDMI_TG_V_FSZ_L);
725 DUMPREG(HDMI_TG_V_FSZ_H);
726 DUMPREG(HDMI_TG_VSYNC_L);
727 DUMPREG(HDMI_TG_VSYNC_H);
728 DUMPREG(HDMI_TG_VSYNC2_L);
729 DUMPREG(HDMI_TG_VSYNC2_H);
730 DUMPREG(HDMI_TG_VACT_ST_L);
731 DUMPREG(HDMI_TG_VACT_ST_H);
732 DUMPREG(HDMI_TG_VACT_SZ_L);
733 DUMPREG(HDMI_TG_VACT_SZ_H);
734 DUMPREG(HDMI_TG_FIELD_CHG_L);
735 DUMPREG(HDMI_TG_FIELD_CHG_H);
736 DUMPREG(HDMI_TG_VACT_ST2_L);
737 DUMPREG(HDMI_TG_VACT_ST2_H);
738 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
739 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
740 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
741 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
742 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
743 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
744 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
745 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
746#undef DUMPREG
747}
748
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900749static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
750{
751 int i;
752
753#define DUMPREG(reg_id) \
754 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
755 readl(hdata->regs + reg_id))
756
757 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
758 DUMPREG(HDMI_INTC_CON);
759 DUMPREG(HDMI_INTC_FLAG);
760 DUMPREG(HDMI_HPD_STATUS);
761 DUMPREG(HDMI_INTC_CON_1);
762 DUMPREG(HDMI_INTC_FLAG_1);
763 DUMPREG(HDMI_PHY_STATUS_0);
764 DUMPREG(HDMI_PHY_STATUS_PLL);
765 DUMPREG(HDMI_PHY_CON_0);
766 DUMPREG(HDMI_PHY_RSTOUT);
767 DUMPREG(HDMI_PHY_VPLL);
768 DUMPREG(HDMI_PHY_CMU);
769 DUMPREG(HDMI_CORE_RSTOUT);
770
771 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
772 DUMPREG(HDMI_CON_0);
773 DUMPREG(HDMI_CON_1);
774 DUMPREG(HDMI_CON_2);
775 DUMPREG(HDMI_SYS_STATUS);
776 DUMPREG(HDMI_PHY_STATUS_0);
777 DUMPREG(HDMI_STATUS_EN);
778 DUMPREG(HDMI_HPD);
779 DUMPREG(HDMI_MODE_SEL);
780 DUMPREG(HDMI_ENC_EN);
781 DUMPREG(HDMI_DC_CONTROL);
782 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
783
784 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
785 DUMPREG(HDMI_H_BLANK_0);
786 DUMPREG(HDMI_H_BLANK_1);
787 DUMPREG(HDMI_V2_BLANK_0);
788 DUMPREG(HDMI_V2_BLANK_1);
789 DUMPREG(HDMI_V1_BLANK_0);
790 DUMPREG(HDMI_V1_BLANK_1);
791 DUMPREG(HDMI_V_LINE_0);
792 DUMPREG(HDMI_V_LINE_1);
793 DUMPREG(HDMI_H_LINE_0);
794 DUMPREG(HDMI_H_LINE_1);
795 DUMPREG(HDMI_HSYNC_POL);
796
797 DUMPREG(HDMI_VSYNC_POL);
798 DUMPREG(HDMI_INT_PRO_MODE);
799 DUMPREG(HDMI_V_BLANK_F0_0);
800 DUMPREG(HDMI_V_BLANK_F0_1);
801 DUMPREG(HDMI_V_BLANK_F1_0);
802 DUMPREG(HDMI_V_BLANK_F1_1);
803
804 DUMPREG(HDMI_H_SYNC_START_0);
805 DUMPREG(HDMI_H_SYNC_START_1);
806 DUMPREG(HDMI_H_SYNC_END_0);
807 DUMPREG(HDMI_H_SYNC_END_1);
808
809 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
810 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
811 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
812 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
813
814 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
815 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
816 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
817 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
818
819 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
820 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
821 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
822 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
823
824 DUMPREG(HDMI_V_BLANK_F2_0);
825 DUMPREG(HDMI_V_BLANK_F2_1);
826 DUMPREG(HDMI_V_BLANK_F3_0);
827 DUMPREG(HDMI_V_BLANK_F3_1);
828 DUMPREG(HDMI_V_BLANK_F4_0);
829 DUMPREG(HDMI_V_BLANK_F4_1);
830 DUMPREG(HDMI_V_BLANK_F5_0);
831 DUMPREG(HDMI_V_BLANK_F5_1);
832
833 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
834 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
836 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
837 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
838 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
839 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
840 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
841
842 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
843 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
844 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
845 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
846 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
850
851 DUMPREG(HDMI_VACT_SPACE_1_0);
852 DUMPREG(HDMI_VACT_SPACE_1_1);
853 DUMPREG(HDMI_VACT_SPACE_2_0);
854 DUMPREG(HDMI_VACT_SPACE_2_1);
855 DUMPREG(HDMI_VACT_SPACE_3_0);
856 DUMPREG(HDMI_VACT_SPACE_3_1);
857 DUMPREG(HDMI_VACT_SPACE_4_0);
858 DUMPREG(HDMI_VACT_SPACE_4_1);
859 DUMPREG(HDMI_VACT_SPACE_5_0);
860 DUMPREG(HDMI_VACT_SPACE_5_1);
861 DUMPREG(HDMI_VACT_SPACE_6_0);
862 DUMPREG(HDMI_VACT_SPACE_6_1);
863
864 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
865 DUMPREG(HDMI_TG_CMD);
866 DUMPREG(HDMI_TG_H_FSZ_L);
867 DUMPREG(HDMI_TG_H_FSZ_H);
868 DUMPREG(HDMI_TG_HACT_ST_L);
869 DUMPREG(HDMI_TG_HACT_ST_H);
870 DUMPREG(HDMI_TG_HACT_SZ_L);
871 DUMPREG(HDMI_TG_HACT_SZ_H);
872 DUMPREG(HDMI_TG_V_FSZ_L);
873 DUMPREG(HDMI_TG_V_FSZ_H);
874 DUMPREG(HDMI_TG_VSYNC_L);
875 DUMPREG(HDMI_TG_VSYNC_H);
876 DUMPREG(HDMI_TG_VSYNC2_L);
877 DUMPREG(HDMI_TG_VSYNC2_H);
878 DUMPREG(HDMI_TG_VACT_ST_L);
879 DUMPREG(HDMI_TG_VACT_ST_H);
880 DUMPREG(HDMI_TG_VACT_SZ_L);
881 DUMPREG(HDMI_TG_VACT_SZ_H);
882 DUMPREG(HDMI_TG_FIELD_CHG_L);
883 DUMPREG(HDMI_TG_FIELD_CHG_H);
884 DUMPREG(HDMI_TG_VACT_ST2_L);
885 DUMPREG(HDMI_TG_VACT_ST2_H);
886 DUMPREG(HDMI_TG_VACT_ST3_L);
887 DUMPREG(HDMI_TG_VACT_ST3_H);
888 DUMPREG(HDMI_TG_VACT_ST4_L);
889 DUMPREG(HDMI_TG_VACT_ST4_H);
890 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
891 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
892 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
893 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
894 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
895 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
896 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
897 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
898 DUMPREG(HDMI_TG_3D);
899
900 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
901 DUMPREG(HDMI_AVI_CON);
902 DUMPREG(HDMI_AVI_HEADER0);
903 DUMPREG(HDMI_AVI_HEADER1);
904 DUMPREG(HDMI_AVI_HEADER2);
905 DUMPREG(HDMI_AVI_CHECK_SUM);
906 DUMPREG(HDMI_VSI_CON);
907 DUMPREG(HDMI_VSI_HEADER0);
908 DUMPREG(HDMI_VSI_HEADER1);
909 DUMPREG(HDMI_VSI_HEADER2);
910 for (i = 0; i < 7; ++i)
911 DUMPREG(HDMI_VSI_DATA(i));
912
913#undef DUMPREG
914}
915
916static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
917{
Rahul Sharma5a325072012-10-04 20:48:54 +0530918 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900919 hdmi_v13_regs_dump(hdata, prefix);
920 else
921 hdmi_v14_regs_dump(hdata, prefix);
922}
923
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530924static u8 hdmi_chksum(struct hdmi_context *hdata,
925 u32 start, u8 len, u32 hdr_sum)
926{
927 int i;
928
929 /* hdr_sum : header0 + header1 + header2
930 * start : start address of packet byte1
931 * len : packet bytes - 1 */
932 for (i = 0; i < len; ++i)
933 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
934
935 /* return 2's complement of 8 bit hdr_sum */
936 return (u8)(~(hdr_sum & 0xff) + 1);
937}
938
939static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530940 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530941{
942 u32 hdr_sum;
943 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530944 u32 mod;
945 u32 vic;
946
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530947 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
948 if (hdata->dvi_mode) {
949 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
950 HDMI_VSI_CON_DO_NOT_TRANSMIT);
951 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
952 HDMI_AVI_CON_DO_NOT_TRANSMIT);
953 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
954 return;
955 }
956
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530957 switch (infoframe->any.type) {
958 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530959 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530960 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
961 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
962 infoframe->any.version);
963 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
964 hdr_sum = infoframe->any.type + infoframe->any.version +
965 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530966
967 /* Output format zero hardcoded ,RGB YBCR selection */
968 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
969 AVI_ACTIVE_FORMAT_VALID |
970 AVI_UNDERSCANNED_DISPLAY_VALID);
971
Shirish S46154152014-03-13 10:58:28 +0530972 /*
973 * Set the aspect ratio as per the mode, mentioned in
974 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
975 */
976 switch (hdata->mode_conf.aspect_ratio) {
977 case HDMI_PICTURE_ASPECT_4_3:
978 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
979 hdata->mode_conf.aspect_ratio |
980 AVI_4_3_CENTER_RATIO);
981 break;
982 case HDMI_PICTURE_ASPECT_16_9:
983 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
984 hdata->mode_conf.aspect_ratio |
985 AVI_16_9_CENTER_RATIO);
986 break;
987 case HDMI_PICTURE_ASPECT_NONE:
988 default:
989 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
990 hdata->mode_conf.aspect_ratio |
991 AVI_SAME_AS_PIC_ASPECT_RATIO);
992 break;
993 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530994
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900995 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530996 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
997
998 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530999 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301000 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1001 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1002 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301003 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301004 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301005 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1006 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1007 infoframe->any.version);
1008 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1009 hdr_sum = infoframe->any.type + infoframe->any.version +
1010 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301011 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301012 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301013 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1014 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1015 break;
1016 default:
1017 break;
1018 }
1019}
1020
Sean Pauld9716ee2014-01-30 16:19:29 -05001021static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1022 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001023{
Sean Pauld9716ee2014-01-30 16:19:29 -05001024 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001025
Sean Paul5137c8c2014-04-03 20:41:03 +05301026 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1027
Sean Pauld9716ee2014-01-30 16:19:29 -05001028 return hdata->hpd ? connector_status_connected :
1029 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001030}
1031
Sean Pauld9716ee2014-01-30 16:19:29 -05001032static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001033{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001034}
1035
Sean Pauld9716ee2014-01-30 16:19:29 -05001036static struct drm_connector_funcs hdmi_connector_funcs = {
1037 .dpms = drm_helper_connector_dpms,
1038 .fill_modes = drm_helper_probe_single_connector_modes,
1039 .detect = hdmi_detect,
1040 .destroy = hdmi_connector_destroy,
1041};
1042
1043static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001044{
Sean Pauld9716ee2014-01-30 16:19:29 -05001045 struct hdmi_context *hdata = ctx_from_connector(connector);
1046 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001047
Inki Dae8fa04aa2014-03-13 16:38:31 +09001048 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001049 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001050
Inki Dae8fa04aa2014-03-13 16:38:31 +09001051 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001052 if (!edid)
1053 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001054
Sean Pauld9716ee2014-01-30 16:19:29 -05001055 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001056 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1057 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001058 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001059
Sean Pauld9716ee2014-01-30 16:19:29 -05001060 drm_mode_connector_update_edid_property(connector, edid);
1061
1062 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001063}
1064
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001065static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001066{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001067 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001068
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001069 for (i = 0; i < hdata->phy_conf_count; i++)
1070 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001071 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001072
1073 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1074 return -EINVAL;
1075}
1076
Sean Pauld9716ee2014-01-30 16:19:29 -05001077static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001078 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001079{
Sean Pauld9716ee2014-01-30 16:19:29 -05001080 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001081 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001082
Rahul Sharma16844fb2013-06-10 14:50:00 +05301083 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1084 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1085 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1086 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001087
Sean Paulf041b252014-01-30 16:19:15 -05001088 ret = mixer_check_mode(mode);
1089 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001090 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001091
Rahul Sharma16844fb2013-06-10 14:50:00 +05301092 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001093 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001094 return MODE_BAD;
1095
1096 return MODE_OK;
1097}
1098
1099static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1100{
1101 struct hdmi_context *hdata = ctx_from_connector(connector);
1102
1103 return hdata->encoder;
1104}
1105
1106static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1107 .get_modes = hdmi_get_modes,
1108 .mode_valid = hdmi_mode_valid,
1109 .best_encoder = hdmi_best_encoder,
1110};
1111
1112static int hdmi_create_connector(struct exynos_drm_display *display,
1113 struct drm_encoder *encoder)
1114{
1115 struct hdmi_context *hdata = display->ctx;
1116 struct drm_connector *connector = &hdata->connector;
1117 int ret;
1118
1119 hdata->encoder = encoder;
1120 connector->interlace_allowed = true;
1121 connector->polled = DRM_CONNECTOR_POLL_HPD;
1122
1123 ret = drm_connector_init(hdata->drm_dev, connector,
1124 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1125 if (ret) {
1126 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001127 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001128 }
1129
1130 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
1131 drm_sysfs_connector_add(connector);
1132 drm_mode_connector_attach_encoder(connector, encoder);
1133
1134 return 0;
1135}
1136
Sean Paulf041b252014-01-30 16:19:15 -05001137static void hdmi_mode_fixup(struct exynos_drm_display *display,
1138 struct drm_connector *connector,
1139 const struct drm_display_mode *mode,
1140 struct drm_display_mode *adjusted_mode)
1141{
1142 struct drm_display_mode *m;
1143 int mode_ok;
1144
1145 DRM_DEBUG_KMS("%s\n", __FILE__);
1146
1147 drm_mode_set_crtcinfo(adjusted_mode, 0);
1148
Sean Pauld9716ee2014-01-30 16:19:29 -05001149 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001150
1151 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001152 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001153 return;
1154
1155 /*
1156 * otherwise, find the most suitable mode among modes and change it
1157 * to adjusted_mode.
1158 */
1159 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001160 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001161
Sean Pauld9716ee2014-01-30 16:19:29 -05001162 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001163 DRM_INFO("desired mode doesn't exist so\n");
1164 DRM_INFO("use the most suitable mode among modes.\n");
1165
1166 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1167 m->hdisplay, m->vdisplay, m->vrefresh);
1168
Sean Paul75626852014-01-30 16:19:16 -05001169 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001170 break;
1171 }
1172 }
1173}
1174
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001175static void hdmi_set_acr(u32 freq, u8 *acr)
1176{
1177 u32 n, cts;
1178
1179 switch (freq) {
1180 case 32000:
1181 n = 4096;
1182 cts = 27000;
1183 break;
1184 case 44100:
1185 n = 6272;
1186 cts = 30000;
1187 break;
1188 case 88200:
1189 n = 12544;
1190 cts = 30000;
1191 break;
1192 case 176400:
1193 n = 25088;
1194 cts = 30000;
1195 break;
1196 case 48000:
1197 n = 6144;
1198 cts = 27000;
1199 break;
1200 case 96000:
1201 n = 12288;
1202 cts = 27000;
1203 break;
1204 case 192000:
1205 n = 24576;
1206 cts = 27000;
1207 break;
1208 default:
1209 n = 0;
1210 cts = 0;
1211 break;
1212 }
1213
1214 acr[1] = cts >> 16;
1215 acr[2] = cts >> 8 & 0xff;
1216 acr[3] = cts & 0xff;
1217
1218 acr[4] = n >> 16;
1219 acr[5] = n >> 8 & 0xff;
1220 acr[6] = n & 0xff;
1221}
1222
1223static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1224{
1225 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1226 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1227 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1228 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1229 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1230 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1231 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1232 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1233 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1234
Rahul Sharma5a325072012-10-04 20:48:54 +05301235 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001236 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1237 else
1238 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1239}
1240
1241static void hdmi_audio_init(struct hdmi_context *hdata)
1242{
1243 u32 sample_rate, bits_per_sample, frame_size_code;
1244 u32 data_num, bit_ch, sample_frq;
1245 u32 val;
1246 u8 acr[7];
1247
1248 sample_rate = 44100;
1249 bits_per_sample = 16;
1250 frame_size_code = 0;
1251
1252 switch (bits_per_sample) {
1253 case 20:
1254 data_num = 2;
1255 bit_ch = 1;
1256 break;
1257 case 24:
1258 data_num = 3;
1259 bit_ch = 1;
1260 break;
1261 default:
1262 data_num = 1;
1263 bit_ch = 0;
1264 break;
1265 }
1266
1267 hdmi_set_acr(sample_rate, acr);
1268 hdmi_reg_acr(hdata, acr);
1269
1270 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1271 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1272 | HDMI_I2S_MUX_ENABLE);
1273
1274 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1275 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1276
1277 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1278
1279 sample_frq = (sample_rate == 44100) ? 0 :
1280 (sample_rate == 48000) ? 2 :
1281 (sample_rate == 32000) ? 3 :
1282 (sample_rate == 96000) ? 0xa : 0x0;
1283
1284 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1285 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1286
1287 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1288 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1289
1290 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1291 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1292 | HDMI_I2S_SEL_LRCK(6));
1293 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1294 | HDMI_I2S_SEL_SDATA2(4));
1295 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1296 | HDMI_I2S_SEL_SDATA2(2));
1297 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1298
1299 /* I2S_CON_1 & 2 */
1300 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1301 | HDMI_I2S_L_CH_LOW_POL);
1302 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1303 | HDMI_I2S_SET_BIT_CH(bit_ch)
1304 | HDMI_I2S_SET_SDATA_BIT(data_num)
1305 | HDMI_I2S_BASIC_FORMAT);
1306
1307 /* Configure register related to CUV information */
1308 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1309 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1310 | HDMI_I2S_COPYRIGHT
1311 | HDMI_I2S_LINEAR_PCM
1312 | HDMI_I2S_CONSUMER_FORMAT);
1313 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1314 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1315 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1316 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1317 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1318 HDMI_I2S_ORG_SMP_FREQ_44_1
1319 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1320 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1321
1322 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1323}
1324
1325static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1326{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001327 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001328 return;
1329
1330 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1331 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1332 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1333}
1334
Rahul Sharmabfa48422014-04-03 20:41:04 +05301335static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001336{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301337 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001338
Rahul Sharmabfa48422014-04-03 20:41:04 +05301339 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1340 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001341
Rahul Sharmabfa48422014-04-03 20:41:04 +05301342 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1343 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001344}
1345
1346static void hdmi_conf_init(struct hdmi_context *hdata)
1347{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301348 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301349
Sean Paul77006a72013-01-16 10:17:20 -05001350 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001351 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1352 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001353
1354 /* choose HDMI mode */
1355 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1356 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301357 /* Apply Video preable and Guard band in HDMI mode only */
1358 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001359 /* disable bluescreen */
1360 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001361
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001362 if (hdata->dvi_mode) {
1363 /* choose DVI mode */
1364 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1365 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1366 hdmi_reg_writeb(hdata, HDMI_CON_2,
1367 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1368 }
1369
Rahul Sharma5a325072012-10-04 20:48:54 +05301370 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001371 /* choose bluescreen (fecal) color */
1372 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1373 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1374 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1375
1376 /* enable AVI packet every vsync, fixes purple line problem */
1377 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1378 /* force RGB, look to CEA-861-D, table 7 for more detail */
1379 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1380 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1381
1382 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1383 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1384 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1385 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301386 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1387 infoframe.any.version = HDMI_AVI_VERSION;
1388 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301389 hdmi_reg_infoframe(hdata, &infoframe);
1390
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301391 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1392 infoframe.any.version = HDMI_AUI_VERSION;
1393 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301394 hdmi_reg_infoframe(hdata, &infoframe);
1395
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001396 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001397 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1398 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001399}
1400
Rahul Sharma16844fb2013-06-10 14:50:00 +05301401static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001402{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001403 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1404 const struct hdmi_v13_core_regs *core =
1405 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001406 int tries;
1407
1408 /* setting core registers */
1409 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1410 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001411 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1412 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1413 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1414 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1415 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1416 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001417 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1418 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001419 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1420 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1421 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1422 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1423 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1424 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1425 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1426 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1427 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1428 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1429 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1430 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1431 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1432 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1433 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001434 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001435 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1436 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1437 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1438 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1439 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1440 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1441 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1442 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1443 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1444 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1445 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1446 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1447 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1448 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1449 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1450 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1451 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1452 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1453 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1454 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1455 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1456 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1457 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001463
1464 /* waiting for HDMIPHY's PLL to get to steady state */
1465 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001466 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001467 if (val & HDMI_PHY_STATUS_READY)
1468 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001469 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001470 }
1471 /* steady state not achieved */
1472 if (tries == 0) {
1473 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1474 hdmi_regs_dump(hdata, "timing apply");
1475 }
1476
Sean Paul0bfb1f82013-06-11 12:24:02 +05301477 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301478 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301479 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001480
1481 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301482 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001483}
1484
Rahul Sharma16844fb2013-06-10 14:50:00 +05301485static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001486{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001487 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1488 const struct hdmi_v14_core_regs *core =
1489 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001490 int tries;
1491
1492 /* setting core registers */
1493 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1494 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1495 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1496 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1497 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1498 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1499 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1500 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1501 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1502 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1503 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1504 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1505 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1506 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1507 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1508 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1509 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1510 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1511 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1512 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1513 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1514 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1515 core->v_sync_line_bef_2[0]);
1516 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1517 core->v_sync_line_bef_2[1]);
1518 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1519 core->v_sync_line_bef_1[0]);
1520 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1521 core->v_sync_line_bef_1[1]);
1522 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1523 core->v_sync_line_aft_2[0]);
1524 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1525 core->v_sync_line_aft_2[1]);
1526 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1527 core->v_sync_line_aft_1[0]);
1528 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1529 core->v_sync_line_aft_1[1]);
1530 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1531 core->v_sync_line_aft_pxl_2[0]);
1532 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1533 core->v_sync_line_aft_pxl_2[1]);
1534 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1535 core->v_sync_line_aft_pxl_1[0]);
1536 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1537 core->v_sync_line_aft_pxl_1[1]);
1538 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1539 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1540 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1541 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1542 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1543 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1544 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1545 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1546 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1547 core->v_sync_line_aft_3[0]);
1548 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1549 core->v_sync_line_aft_3[1]);
1550 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1551 core->v_sync_line_aft_4[0]);
1552 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1553 core->v_sync_line_aft_4[1]);
1554 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1555 core->v_sync_line_aft_5[0]);
1556 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1557 core->v_sync_line_aft_5[1]);
1558 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1559 core->v_sync_line_aft_6[0]);
1560 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1561 core->v_sync_line_aft_6[1]);
1562 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1563 core->v_sync_line_aft_pxl_3[0]);
1564 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1565 core->v_sync_line_aft_pxl_3[1]);
1566 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1567 core->v_sync_line_aft_pxl_4[0]);
1568 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1569 core->v_sync_line_aft_pxl_4[1]);
1570 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1571 core->v_sync_line_aft_pxl_5[0]);
1572 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1573 core->v_sync_line_aft_pxl_5[1]);
1574 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1575 core->v_sync_line_aft_pxl_6[0]);
1576 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1577 core->v_sync_line_aft_pxl_6[1]);
1578 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1579 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1580 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1581 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1582 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1583 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1584 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1585 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1586 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1587 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1588 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1589 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1590
1591 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001592 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1593 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1594 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1595 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1596 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1597 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1598 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1599 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1600 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1601 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1602 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1603 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1604 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1605 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1606 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1607 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1608 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1609 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1610 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1611 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1612 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1613 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1614 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1615 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001625
1626 /* waiting for HDMIPHY's PLL to get to steady state */
1627 for (tries = 100; tries; --tries) {
1628 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1629 if (val & HDMI_PHY_STATUS_READY)
1630 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001631 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001632 }
1633 /* steady state not achieved */
1634 if (tries == 0) {
1635 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1636 hdmi_regs_dump(hdata, "timing apply");
1637 }
1638
Sean Paul0bfb1f82013-06-11 12:24:02 +05301639 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301640 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301641 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001642
1643 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301644 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001645}
1646
Rahul Sharma16844fb2013-06-10 14:50:00 +05301647static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001648{
Rahul Sharma5a325072012-10-04 20:48:54 +05301649 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301650 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001651 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301652 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001653}
1654
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001655static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1656{
1657 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001658 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001659
Sean Paul0bfb1f82013-06-11 12:24:02 +05301660 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301661 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301662 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001663
1664 /* operation mode */
1665 buffer[0] = 0x1f;
1666 buffer[1] = 0x00;
1667
1668 if (hdata->hdmiphy_port)
1669 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1670
Rahul Sharma5a325072012-10-04 20:48:54 +05301671 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001672 reg = HDMI_V13_PHY_RSTOUT;
1673 else
1674 reg = HDMI_PHY_RSTOUT;
1675
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001676 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001677 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001678 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001679 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001680 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001681}
1682
Rahul Sharmaa5562252012-11-28 11:30:25 +05301683static void hdmiphy_poweron(struct hdmi_context *hdata)
1684{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301685 if (hdata->type == HDMI_TYPE14)
1686 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1687 HDMI_PHY_POWER_OFF_EN);
1688}
1689
1690static void hdmiphy_poweroff(struct hdmi_context *hdata)
1691{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301692 if (hdata->type == HDMI_TYPE14)
1693 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1694 HDMI_PHY_POWER_OFF_EN);
1695}
1696
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001697static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1698{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001699 int ret;
1700 int i;
1701
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001702 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001703 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1704 if (i < 0) {
1705 DRM_ERROR("failed to find hdmiphy conf\n");
1706 return;
1707 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001708
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001709 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1710 if (ret) {
1711 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001712 return;
1713 }
1714
Sean Paul09760ea2013-01-14 17:03:20 -05001715 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001716
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001717 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1718 HDMI_PHY_DISABLE_MODE_SET);
1719 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001720 DRM_ERROR("failed to enable hdmiphy\n");
1721 return;
1722 }
1723
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001724}
1725
1726static void hdmi_conf_apply(struct hdmi_context *hdata)
1727{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001728 hdmiphy_conf_reset(hdata);
1729 hdmiphy_conf_apply(hdata);
1730
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001731 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301732 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001733 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001734 mutex_unlock(&hdata->hdmi_mutex);
1735
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001736 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001737
1738 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301739 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001740 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001741
1742 hdmi_regs_dump(hdata, "start");
1743}
1744
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001745static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1746{
1747 int i;
1748 BUG_ON(num_bytes > 4);
1749 for (i = 0; i < num_bytes; i++)
1750 reg_pair[i] = (value >> (8 * i)) & 0xff;
1751}
1752
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001753static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1754 struct drm_display_mode *m)
1755{
1756 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1757 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1758 unsigned int val;
1759
1760 hdata->mode_conf.cea_video_id =
1761 drm_match_cea_mode((struct drm_display_mode *)m);
1762 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301763 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001764
1765 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1766 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1767
1768 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1769 hdmi_set_reg(core->vsync_pol, 1, val);
1770
1771 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1772 hdmi_set_reg(core->int_pro_mode, 1, val);
1773
1774 val = (m->hsync_start - m->hdisplay - 2);
1775 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1776 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1777 hdmi_set_reg(core->h_sync_gen, 3, val);
1778
1779 /*
1780 * Quirk requirement for exynos HDMI IP design,
1781 * 2 pixels less than the actual calculation for hsync_start
1782 * and end.
1783 */
1784
1785 /* Following values & calculations differ for different type of modes */
1786 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1787 /* Interlaced Mode */
1788 val = ((m->vsync_end - m->vdisplay) / 2);
1789 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1790 hdmi_set_reg(core->v_sync_gen1, 3, val);
1791
1792 val = m->vtotal / 2;
1793 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1794 hdmi_set_reg(core->v_blank, 3, val);
1795
1796 val = (m->vtotal +
1797 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1798 val |= m->vtotal << 11;
1799 hdmi_set_reg(core->v_blank_f, 3, val);
1800
1801 val = ((m->vtotal / 2) + 7);
1802 val |= ((m->vtotal / 2) + 2) << 12;
1803 hdmi_set_reg(core->v_sync_gen2, 3, val);
1804
1805 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1806 val |= ((m->htotal / 2) +
1807 (m->hsync_start - m->hdisplay)) << 12;
1808 hdmi_set_reg(core->v_sync_gen3, 3, val);
1809
1810 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1811 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1812
1813 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1814 } else {
1815 /* Progressive Mode */
1816
1817 val = m->vtotal;
1818 val |= (m->vtotal - m->vdisplay) << 11;
1819 hdmi_set_reg(core->v_blank, 3, val);
1820
1821 hdmi_set_reg(core->v_blank_f, 3, 0);
1822
1823 val = (m->vsync_end - m->vdisplay);
1824 val |= ((m->vsync_start - m->vdisplay) << 12);
1825 hdmi_set_reg(core->v_sync_gen1, 3, val);
1826
1827 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1828 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1829 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1830 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1831 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1832 }
1833
1834 /* Timing generator registers */
1835 hdmi_set_reg(tg->cmd, 1, 0x0);
1836 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1837 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1838 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1839 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1840 hdmi_set_reg(tg->vsync, 2, 0x1);
1841 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1842 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1843 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1844 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1845 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1846 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1847 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1848}
1849
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001850static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1851 struct drm_display_mode *m)
1852{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001853 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1854 struct hdmi_v14_core_regs *core =
1855 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001856
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001857 hdata->mode_conf.cea_video_id =
1858 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001859 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301860 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001861
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001862 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1863 hdmi_set_reg(core->v_line, 2, m->vtotal);
1864 hdmi_set_reg(core->h_line, 2, m->htotal);
1865 hdmi_set_reg(core->hsync_pol, 1,
1866 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1867 hdmi_set_reg(core->vsync_pol, 1,
1868 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1869 hdmi_set_reg(core->int_pro_mode, 1,
1870 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1871
1872 /*
1873 * Quirk requirement for exynos 5 HDMI IP design,
1874 * 2 pixels less than the actual calculation for hsync_start
1875 * and end.
1876 */
1877
1878 /* Following values & calculations differ for different type of modes */
1879 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1880 /* Interlaced Mode */
1881 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1882 (m->vsync_end - m->vdisplay) / 2);
1883 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1884 (m->vsync_start - m->vdisplay) / 2);
1885 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1886 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301887 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001888 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1889 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1890 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1891 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1892 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1893 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1894 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1895 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1896 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301897 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1898 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1899 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1900 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001901 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1902 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1903 } else {
1904 /* Progressive Mode */
1905 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1906 m->vsync_end - m->vdisplay);
1907 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1908 m->vsync_start - m->vdisplay);
1909 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1910 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1911 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1912 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1913 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1914 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1915 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1916 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1917 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1918 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1919 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1920 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1921 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301922 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1923 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1924 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001925 }
1926
1927 /* Following values & calculations are same irrespective of mode type */
1928 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1929 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1930 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1931 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1932 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1933 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1934 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1935 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1936 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1937 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1938 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1939 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1940 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1941 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1942 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1943 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1944 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1945 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1946 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1947 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1948
1949 /* Timing generator registers */
1950 hdmi_set_reg(tg->cmd, 1, 0x0);
1951 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1952 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1953 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1954 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1955 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001956 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1957 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001958 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001959 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001960}
1961
Sean Paulf041b252014-01-30 16:19:15 -05001962static void hdmi_mode_set(struct exynos_drm_display *display,
1963 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001964{
Sean Paulf041b252014-01-30 16:19:15 -05001965 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001966 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001967
YoungJun Chocbc4c332013-06-12 10:44:40 +09001968 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1969 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001970 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1971 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001972
Rahul Sharmabfa48422014-04-03 20:41:04 +05301973 /* preserve mode information for later use. */
1974 drm_mode_copy(&hdata->current_mode, mode);
1975
Sachin Kamat5f46c332013-04-26 11:29:00 +05301976 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001977 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301978 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001979 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001980}
1981
Sean Paulf041b252014-01-30 16:19:15 -05001982static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001983{
Sean Paulf041b252014-01-30 16:19:15 -05001984 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001985
Shirish Sdda90122013-01-23 22:03:18 -05001986 mutex_lock(&hdata->hdmi_mutex);
1987 if (!hdata->powered) {
1988 mutex_unlock(&hdata->hdmi_mutex);
1989 return;
1990 }
1991 mutex_unlock(&hdata->hdmi_mutex);
1992
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001993 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994}
1995
Sean Paulf041b252014-01-30 16:19:15 -05001996static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001997{
Sean Paulf041b252014-01-30 16:19:15 -05001998 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001999 struct hdmi_resources *res = &hdata->res;
2000
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002001 mutex_lock(&hdata->hdmi_mutex);
2002 if (hdata->powered) {
2003 mutex_unlock(&hdata->hdmi_mutex);
2004 return;
2005 }
2006
2007 hdata->powered = true;
2008
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002009 mutex_unlock(&hdata->hdmi_mutex);
2010
Sean Paulaf65c802014-01-30 16:19:27 -05002011 pm_runtime_get_sync(hdata->dev);
2012
Seung-Woo Kimad079452013-06-05 14:34:38 +09002013 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2014 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2015
Sean Paul0bfb1f82013-06-11 12:24:02 +05302016 clk_prepare_enable(res->hdmiphy);
2017 clk_prepare_enable(res->hdmi);
2018 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302019
2020 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05002021 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002022}
2023
Sean Paulf041b252014-01-30 16:19:15 -05002024static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002025{
Sean Paulf041b252014-01-30 16:19:15 -05002026 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002027 struct hdmi_resources *res = &hdata->res;
2028
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002029 mutex_lock(&hdata->hdmi_mutex);
2030 if (!hdata->powered)
2031 goto out;
2032 mutex_unlock(&hdata->hdmi_mutex);
2033
Rahul Sharmabfa48422014-04-03 20:41:04 +05302034 /* HDMI System Disable */
2035 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2036
Rahul Sharmaa5562252012-11-28 11:30:25 +05302037 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002038
Sean Paul724fd142014-05-09 15:05:10 +09002039 cancel_delayed_work(&hdata->hotplug_work);
2040
Sean Paul0bfb1f82013-06-11 12:24:02 +05302041 clk_disable_unprepare(res->sclk_hdmi);
2042 clk_disable_unprepare(res->hdmi);
2043 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002044 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2045
Sean Paulaf65c802014-01-30 16:19:27 -05002046 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002047
Sean Paulaf65c802014-01-30 16:19:27 -05002048 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002049 hdata->powered = false;
2050
2051out:
2052 mutex_unlock(&hdata->hdmi_mutex);
2053}
2054
Sean Paulf041b252014-01-30 16:19:15 -05002055static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002056{
YoungJun Chocbc4c332013-06-12 10:44:40 +09002057 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002058
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002059 switch (mode) {
2060 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05002061 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002062 break;
2063 case DRM_MODE_DPMS_STANDBY:
2064 case DRM_MODE_DPMS_SUSPEND:
2065 case DRM_MODE_DPMS_OFF:
Sean Paulaf65c802014-01-30 16:19:27 -05002066 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002067 break;
2068 default:
2069 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2070 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002071 }
2072}
2073
Sean Paulf041b252014-01-30 16:19:15 -05002074static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002075 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002076 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002077 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002078 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002079 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002080};
2081
Sean Paulf041b252014-01-30 16:19:15 -05002082static struct exynos_drm_display hdmi_display = {
2083 .type = EXYNOS_DISPLAY_TYPE_HDMI,
2084 .ops = &hdmi_display_ops,
2085};
2086
Sean Paul724fd142014-05-09 15:05:10 +09002087static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002088{
Sean Paul724fd142014-05-09 15:05:10 +09002089 struct hdmi_context *hdata;
2090
2091 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002092
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002093 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302094 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002095 mutex_unlock(&hdata->hdmi_mutex);
2096
Sean Paul45517892014-01-30 16:19:05 -05002097 if (hdata->drm_dev)
2098 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002099}
2100
2101static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2102{
2103 struct hdmi_context *hdata = arg;
2104
2105 mod_delayed_work(system_wq, &hdata->hotplug_work,
2106 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002107
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002108 return IRQ_HANDLED;
2109}
2110
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002111static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002112{
2113 struct device *dev = hdata->dev;
2114 struct hdmi_resources *res = &hdata->res;
2115 static char *supply[] = {
2116 "hdmi-en",
2117 "vdd",
2118 "vdd_osc",
2119 "vdd_pll",
2120 };
2121 int i, ret;
2122
2123 DRM_DEBUG_KMS("HDMI resource init\n");
2124
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002125 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302126 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302127 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002128 DRM_ERROR("failed to get clock 'hdmi'\n");
2129 goto fail;
2130 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302131 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302132 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
2134 goto fail;
2135 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302136 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302137 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002138 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
2139 goto fail;
2140 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302141 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302142 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002143 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
2144 goto fail;
2145 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302146 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302147 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002148 DRM_ERROR("failed to get clock 'hdmiphy'\n");
2149 goto fail;
2150 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302151 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2152 if (IS_ERR(res->mout_hdmi)) {
2153 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
2154 goto fail;
2155 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002156
Rahul Sharma59956d32013-06-11 12:24:03 +05302157 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002158
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302159 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302160 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002161 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002162 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002163 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2164 res->regul_bulk[i].supply = supply[i];
2165 res->regul_bulk[i].consumer = NULL;
2166 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302167 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002168 if (ret) {
2169 DRM_ERROR("failed to get regulators\n");
2170 goto fail;
2171 }
2172 res->regul_count = ARRAY_SIZE(supply);
2173
2174 return 0;
2175fail:
2176 DRM_ERROR("HDMI resource init - failed\n");
2177 return -ENODEV;
2178}
2179
Rahul Sharma22c4f422012-10-04 20:48:55 +05302180static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2181 (struct device *dev)
2182{
2183 struct device_node *np = dev->of_node;
2184 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302185 u32 value;
2186
2187 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002188 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302189 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302190
2191 if (!of_find_property(np, "hpd-gpio", &value)) {
2192 DRM_ERROR("no hpd gpio property found\n");
2193 goto err_data;
2194 }
2195
Rahul Sharma5f916e22013-06-11 19:41:29 +05302196 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302197
2198 return pd;
2199
2200err_data:
2201 return NULL;
2202}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302203
Rahul Sharma22c4f422012-10-04 20:48:55 +05302204static struct of_device_id hdmi_match_types[] = {
2205 {
2206 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002207 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302208 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302209 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002210 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302211 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302212 .compatible = "samsung,exynos5420-hdmi",
2213 .data = &exynos5420_hdmi_driver_data,
2214 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302215 /* end node */
2216 }
2217};
2218
Inki Daef37cd5e2014-05-09 14:25:20 +09002219static int hdmi_bind(struct device *dev, struct device *master, void *data)
2220{
2221 struct drm_device *drm_dev = data;
2222 struct hdmi_context *hdata;
2223
2224 hdata = hdmi_display.ctx;
2225 hdata->drm_dev = drm_dev;
2226
2227 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2228}
2229
2230static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2231{
2232 struct exynos_drm_display *display = get_hdmi_display(dev);
2233 struct drm_encoder *encoder = display->encoder;
2234 struct hdmi_context *hdata = display->ctx;
2235
2236 encoder->funcs->destroy(encoder);
2237 drm_connector_cleanup(&hdata->connector);
2238}
2239
2240static const struct component_ops hdmi_component_ops = {
2241 .bind = hdmi_bind,
2242 .unbind = hdmi_unbind,
2243};
2244
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002245static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002246{
Inki Daef37cd5e2014-05-09 14:25:20 +09002247 struct device_node *ddc_node, *phy_node;
2248 struct s5p_hdmi_platform_data *pdata;
2249 struct hdmi_driver_data *drv_data;
2250 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002251 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002252 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002253 struct resource *res;
2254 int ret;
2255
Inki Daef37cd5e2014-05-09 14:25:20 +09002256 if (!dev->of_node)
Sachin Kamat88c49812013-08-28 10:47:57 +05302257 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302258
Sachin Kamat88c49812013-08-28 10:47:57 +05302259 pdata = drm_hdmi_dt_parse_pdata(dev);
2260 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002261 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002262
Sachin Kamat88c49812013-08-28 10:47:57 +05302263 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002264 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002265 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002266
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002267 mutex_init(&hdata->hdmi_mutex);
2268
Sean Paulf041b252014-01-30 16:19:15 -05002269 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002270
Sachin Kamat88c49812013-08-28 10:47:57 +05302271 match = of_match_node(hdmi_match_types, dev->of_node);
2272 if (!match)
2273 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002274
2275 drv_data = (struct hdmi_driver_data *)match->data;
2276 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002277 hdata->phy_confs = drv_data->phy_confs;
2278 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302279
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302280 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002281 hdata->dev = dev;
2282
2283 ret = hdmi_resources_init(hdata);
2284 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302285 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302286 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002287 }
2288
2289 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002290 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01002291 if (IS_ERR(hdata->regs))
2292 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002293
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002294 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302295 if (ret) {
2296 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302297 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302298 }
2299
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002300 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002301 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2302 if (!ddc_node) {
2303 DRM_ERROR("Failed to find ddc node in device tree\n");
2304 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002305 }
Inki Dae8fa04aa2014-03-13 16:38:31 +09002306 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2307 if (!hdata->ddc_adpt) {
2308 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Daniel Kurtz2b768132014-02-24 18:52:51 +09002309 return -ENODEV;
2310 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002311
2312 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002313 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2314 if (!phy_node) {
2315 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2316 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002317 goto err_ddc;
2318 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002319
2320 if (drv_data->is_apb_phy) {
2321 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2322 if (!hdata->regs_hdmiphy) {
2323 DRM_ERROR("failed to ioremap hdmi phy\n");
2324 ret = -ENOMEM;
2325 goto err_ddc;
2326 }
2327 } else {
2328 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2329 if (!hdata->hdmiphy_port) {
2330 DRM_ERROR("Failed to get hdmi phy i2c client\n");
2331 ret = -ENODEV;
2332 goto err_ddc;
2333 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002334 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002335
Sean Paul77006a72013-01-16 10:17:20 -05002336 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2337 if (hdata->irq < 0) {
2338 DRM_ERROR("failed to get GPIO irq\n");
2339 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002340 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002341 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002342
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302343 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2344
Sean Paul724fd142014-05-09 15:05:10 +09002345 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2346
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002347 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002348 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002349 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002350 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002351 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002352 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002353 goto err_hdmiphy;
2354 }
2355
Sean Paulaf65c802014-01-30 16:19:27 -05002356 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002357 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002358
Inki Daef37cd5e2014-05-09 14:25:20 +09002359 return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002360
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002361err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002362 if (hdata->hdmiphy_port)
2363 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002364err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002365 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002366 return ret;
2367}
2368
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002369static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002370{
Inki Daef37cd5e2014-05-09 14:25:20 +09002371 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002372
Sean Paul724fd142014-05-09 15:05:10 +09002373 cancel_delayed_work_sync(&hdata->hotplug_work);
2374
Daniel Kurtz2b768132014-02-24 18:52:51 +09002375 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002376 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002377
Sean Paulaf65c802014-01-30 16:19:27 -05002378 pm_runtime_disable(&pdev->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002379
Inki Daef37cd5e2014-05-09 14:25:20 +09002380 exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002381 return 0;
2382}
2383
2384struct platform_driver hdmi_driver = {
2385 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002386 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002387 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302388 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002389 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302390 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002391 },
2392};