blob: 1d07bdf787762db8f6f4b9d52e28d422481eeba9 [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>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
25#include <linux/spinlock.h>
26#include <linux/wait.h>
27#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090028#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/irq.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/clk.h>
34#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053036#include <linux/of.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090037#include <linux/of_address.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>
Rahul Sharma049d34e2014-05-20 10:36:05 +053041#include <linux/mfd/syscon.h>
42#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090043
44#include <drm/exynos_drm.h>
45
46#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090047#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050048#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090049
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053050#include <linux/gpio.h>
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053051
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;
Rahul Sharma59956d32013-06-11 12:24:03 +053084 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090085 struct regulator_bulk_data *regul_bulk;
Marek Szyprowski05fdf982014-07-01 10:10:06 +020086 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +090087 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 {
Andrzej Hajda930865f2014-11-17 09:54:20 +0100184 struct exynos_drm_display display;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900185 struct device *dev;
186 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500187 struct drm_connector connector;
188 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900189 bool powered;
Seung-Woo Kim872d20d2012-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
Rahul Sharma049d34e2014-05-20 10:36:05 +0530211 struct regmap *pmureg;
Rahul Sharma5a325072012-10-04 20:48:54 +0530212 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900213};
214
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100215static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
216{
217 return container_of(d, struct hdmi_context, display);
218}
219
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500220struct hdmiphy_config {
221 int pixel_clock;
222 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900223};
224
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900225/* list of phy config settings */
226static const struct hdmiphy_config hdmiphy_v13_configs[] = {
227 {
228 .pixel_clock = 27000000,
229 .conf = {
230 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
231 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
232 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
233 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
234 },
235 },
236 {
237 .pixel_clock = 27027000,
238 .conf = {
239 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
240 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
241 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
242 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
243 },
244 },
245 {
246 .pixel_clock = 74176000,
247 .conf = {
248 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
249 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
250 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
251 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
252 },
253 },
254 {
255 .pixel_clock = 74250000,
256 .conf = {
257 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
258 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
259 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
260 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
261 },
262 },
263 {
264 .pixel_clock = 148500000,
265 .conf = {
266 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
267 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
268 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
269 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
270 },
271 },
272};
273
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500274static const struct hdmiphy_config hdmiphy_v14_configs[] = {
275 {
276 .pixel_clock = 25200000,
277 .conf = {
278 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
279 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
280 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
281 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
282 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900283 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500284 {
285 .pixel_clock = 27000000,
286 .conf = {
287 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
288 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
289 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
290 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
291 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900292 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500293 {
294 .pixel_clock = 27027000,
295 .conf = {
296 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
297 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
298 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
299 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
300 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900301 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500302 {
303 .pixel_clock = 36000000,
304 .conf = {
305 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
306 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
307 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
308 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
309 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900310 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500311 {
312 .pixel_clock = 40000000,
313 .conf = {
314 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
315 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
316 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
317 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
318 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900319 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500320 {
321 .pixel_clock = 65000000,
322 .conf = {
323 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
324 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
325 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
326 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
327 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900328 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500329 {
Shirish Se1d883c2014-03-13 14:28:27 +0900330 .pixel_clock = 71000000,
331 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530332 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
333 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
334 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900335 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
336 },
337 },
338 {
339 .pixel_clock = 73250000,
340 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530341 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
342 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
343 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900344 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
345 },
346 },
347 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500348 .pixel_clock = 74176000,
349 .conf = {
350 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
351 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
352 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
353 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
354 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900355 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500356 {
357 .pixel_clock = 74250000,
358 .conf = {
359 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
360 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
361 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
362 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
363 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900364 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500365 {
366 .pixel_clock = 83500000,
367 .conf = {
368 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
369 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
370 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
371 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
372 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900373 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500374 {
375 .pixel_clock = 106500000,
376 .conf = {
377 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
378 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
379 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
380 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
381 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900382 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500383 {
384 .pixel_clock = 108000000,
385 .conf = {
386 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
387 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
388 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
389 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
390 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900391 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500392 {
Shirish Se1d883c2014-03-13 14:28:27 +0900393 .pixel_clock = 115500000,
394 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530395 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
396 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
397 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900398 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
399 },
400 },
401 {
402 .pixel_clock = 119000000,
403 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530404 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
405 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
406 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900407 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
408 },
409 },
410 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500411 .pixel_clock = 146250000,
412 .conf = {
413 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
414 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
415 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
416 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
417 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900418 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500419 {
420 .pixel_clock = 148500000,
421 .conf = {
422 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
423 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
424 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
425 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
426 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900427 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900428};
429
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530430static const struct hdmiphy_config hdmiphy_5420_configs[] = {
431 {
432 .pixel_clock = 25200000,
433 .conf = {
434 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
435 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
436 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
437 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
438 },
439 },
440 {
441 .pixel_clock = 27000000,
442 .conf = {
443 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
444 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
445 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
446 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
447 },
448 },
449 {
450 .pixel_clock = 27027000,
451 .conf = {
452 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
453 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
454 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
455 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
456 },
457 },
458 {
459 .pixel_clock = 36000000,
460 .conf = {
461 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
462 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
463 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
464 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
465 },
466 },
467 {
468 .pixel_clock = 40000000,
469 .conf = {
470 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
471 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
472 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
473 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
474 },
475 },
476 {
477 .pixel_clock = 65000000,
478 .conf = {
479 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
480 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
481 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
482 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
483 },
484 },
485 {
486 .pixel_clock = 71000000,
487 .conf = {
488 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
489 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
490 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
491 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
492 },
493 },
494 {
495 .pixel_clock = 73250000,
496 .conf = {
497 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
498 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
499 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
500 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
501 },
502 },
503 {
504 .pixel_clock = 74176000,
505 .conf = {
506 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
507 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
508 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
509 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
510 },
511 },
512 {
513 .pixel_clock = 74250000,
514 .conf = {
515 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
516 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
517 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
518 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
519 },
520 },
521 {
522 .pixel_clock = 83500000,
523 .conf = {
524 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
525 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
526 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
527 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
528 },
529 },
530 {
531 .pixel_clock = 88750000,
532 .conf = {
533 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
534 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
535 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
536 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
537 },
538 },
539 {
540 .pixel_clock = 106500000,
541 .conf = {
542 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
543 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
544 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
545 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
546 },
547 },
548 {
549 .pixel_clock = 108000000,
550 .conf = {
551 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
552 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
553 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
554 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
555 },
556 },
557 {
558 .pixel_clock = 115500000,
559 .conf = {
560 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
561 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
562 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
563 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
564 },
565 },
566 {
567 .pixel_clock = 146250000,
568 .conf = {
569 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
570 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
571 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
572 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
573 },
574 },
575 {
576 .pixel_clock = 148500000,
577 .conf = {
578 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
579 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
580 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
581 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
582 },
583 },
584};
585
Sachin Kamat16337072014-05-22 10:32:56 +0530586static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530587 .type = HDMI_TYPE14,
588 .phy_confs = hdmiphy_5420_configs,
589 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
590 .is_apb_phy = 1,
591};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900592
Sachin Kamat16337072014-05-22 10:32:56 +0530593static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900594 .type = HDMI_TYPE14,
595 .phy_confs = hdmiphy_v14_configs,
596 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
597 .is_apb_phy = 0,
598};
599
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200600static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
601 .type = HDMI_TYPE13,
602 .phy_confs = hdmiphy_v13_configs,
603 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
604 .is_apb_phy = 0,
605};
606
Sachin Kamat16337072014-05-22 10:32:56 +0530607static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900608 .type = HDMI_TYPE14,
609 .phy_confs = hdmiphy_v13_configs,
610 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
611 .is_apb_phy = 0,
612};
613
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
615{
616 return readl(hdata->regs + reg_id);
617}
618
619static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
620 u32 reg_id, u8 value)
621{
622 writeb(value, hdata->regs + reg_id);
623}
624
625static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
626 u32 reg_id, u32 value, u32 mask)
627{
628 u32 old = readl(hdata->regs + reg_id);
629 value = (value & mask) | (old & ~mask);
630 writel(value, hdata->regs + reg_id);
631}
632
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900633static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
634 u32 reg_offset, u8 value)
635{
636 if (hdata->hdmiphy_port) {
637 u8 buffer[2];
638 int ret;
639
640 buffer[0] = reg_offset;
641 buffer[1] = value;
642
643 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
644 if (ret == 2)
645 return 0;
646 return ret;
647 } else {
648 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
649 return 0;
650 }
651}
652
653static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
654 u32 reg_offset, const u8 *buf, u32 len)
655{
656 if ((reg_offset + len) > 32)
657 return -EINVAL;
658
659 if (hdata->hdmiphy_port) {
660 int ret;
661
662 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
663 if (ret == len)
664 return 0;
665 return ret;
666 } else {
667 int i;
668 for (i = 0; i < len; i++)
669 writeb(buf[i], hdata->regs_hdmiphy +
670 ((reg_offset + i)<<2));
671 return 0;
672 }
673}
674
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900675static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900676{
677#define DUMPREG(reg_id) \
678 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
679 readl(hdata->regs + reg_id))
680 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
681 DUMPREG(HDMI_INTC_FLAG);
682 DUMPREG(HDMI_INTC_CON);
683 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900684 DUMPREG(HDMI_V13_PHY_RSTOUT);
685 DUMPREG(HDMI_V13_PHY_VPLL);
686 DUMPREG(HDMI_V13_PHY_CMU);
687 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900688
689 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
690 DUMPREG(HDMI_CON_0);
691 DUMPREG(HDMI_CON_1);
692 DUMPREG(HDMI_CON_2);
693 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900694 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900695 DUMPREG(HDMI_STATUS_EN);
696 DUMPREG(HDMI_HPD);
697 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900698 DUMPREG(HDMI_V13_HPD_GEN);
699 DUMPREG(HDMI_V13_DC_CONTROL);
700 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900701
702 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
703 DUMPREG(HDMI_H_BLANK_0);
704 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900705 DUMPREG(HDMI_V13_V_BLANK_0);
706 DUMPREG(HDMI_V13_V_BLANK_1);
707 DUMPREG(HDMI_V13_V_BLANK_2);
708 DUMPREG(HDMI_V13_H_V_LINE_0);
709 DUMPREG(HDMI_V13_H_V_LINE_1);
710 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900711 DUMPREG(HDMI_VSYNC_POL);
712 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900713 DUMPREG(HDMI_V13_V_BLANK_F_0);
714 DUMPREG(HDMI_V13_V_BLANK_F_1);
715 DUMPREG(HDMI_V13_V_BLANK_F_2);
716 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
717 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
718 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
719 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
720 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
721 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
722 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
723 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
724 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
725 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
726 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
727 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900728
729 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
730 DUMPREG(HDMI_TG_CMD);
731 DUMPREG(HDMI_TG_H_FSZ_L);
732 DUMPREG(HDMI_TG_H_FSZ_H);
733 DUMPREG(HDMI_TG_HACT_ST_L);
734 DUMPREG(HDMI_TG_HACT_ST_H);
735 DUMPREG(HDMI_TG_HACT_SZ_L);
736 DUMPREG(HDMI_TG_HACT_SZ_H);
737 DUMPREG(HDMI_TG_V_FSZ_L);
738 DUMPREG(HDMI_TG_V_FSZ_H);
739 DUMPREG(HDMI_TG_VSYNC_L);
740 DUMPREG(HDMI_TG_VSYNC_H);
741 DUMPREG(HDMI_TG_VSYNC2_L);
742 DUMPREG(HDMI_TG_VSYNC2_H);
743 DUMPREG(HDMI_TG_VACT_ST_L);
744 DUMPREG(HDMI_TG_VACT_ST_H);
745 DUMPREG(HDMI_TG_VACT_SZ_L);
746 DUMPREG(HDMI_TG_VACT_SZ_H);
747 DUMPREG(HDMI_TG_FIELD_CHG_L);
748 DUMPREG(HDMI_TG_FIELD_CHG_H);
749 DUMPREG(HDMI_TG_VACT_ST2_L);
750 DUMPREG(HDMI_TG_VACT_ST2_H);
751 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
752 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
753 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
754 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
755 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
756 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
757 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
758 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
759#undef DUMPREG
760}
761
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900762static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
763{
764 int i;
765
766#define DUMPREG(reg_id) \
767 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
768 readl(hdata->regs + reg_id))
769
770 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
771 DUMPREG(HDMI_INTC_CON);
772 DUMPREG(HDMI_INTC_FLAG);
773 DUMPREG(HDMI_HPD_STATUS);
774 DUMPREG(HDMI_INTC_CON_1);
775 DUMPREG(HDMI_INTC_FLAG_1);
776 DUMPREG(HDMI_PHY_STATUS_0);
777 DUMPREG(HDMI_PHY_STATUS_PLL);
778 DUMPREG(HDMI_PHY_CON_0);
779 DUMPREG(HDMI_PHY_RSTOUT);
780 DUMPREG(HDMI_PHY_VPLL);
781 DUMPREG(HDMI_PHY_CMU);
782 DUMPREG(HDMI_CORE_RSTOUT);
783
784 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
785 DUMPREG(HDMI_CON_0);
786 DUMPREG(HDMI_CON_1);
787 DUMPREG(HDMI_CON_2);
788 DUMPREG(HDMI_SYS_STATUS);
789 DUMPREG(HDMI_PHY_STATUS_0);
790 DUMPREG(HDMI_STATUS_EN);
791 DUMPREG(HDMI_HPD);
792 DUMPREG(HDMI_MODE_SEL);
793 DUMPREG(HDMI_ENC_EN);
794 DUMPREG(HDMI_DC_CONTROL);
795 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
796
797 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
798 DUMPREG(HDMI_H_BLANK_0);
799 DUMPREG(HDMI_H_BLANK_1);
800 DUMPREG(HDMI_V2_BLANK_0);
801 DUMPREG(HDMI_V2_BLANK_1);
802 DUMPREG(HDMI_V1_BLANK_0);
803 DUMPREG(HDMI_V1_BLANK_1);
804 DUMPREG(HDMI_V_LINE_0);
805 DUMPREG(HDMI_V_LINE_1);
806 DUMPREG(HDMI_H_LINE_0);
807 DUMPREG(HDMI_H_LINE_1);
808 DUMPREG(HDMI_HSYNC_POL);
809
810 DUMPREG(HDMI_VSYNC_POL);
811 DUMPREG(HDMI_INT_PRO_MODE);
812 DUMPREG(HDMI_V_BLANK_F0_0);
813 DUMPREG(HDMI_V_BLANK_F0_1);
814 DUMPREG(HDMI_V_BLANK_F1_0);
815 DUMPREG(HDMI_V_BLANK_F1_1);
816
817 DUMPREG(HDMI_H_SYNC_START_0);
818 DUMPREG(HDMI_H_SYNC_START_1);
819 DUMPREG(HDMI_H_SYNC_END_0);
820 DUMPREG(HDMI_H_SYNC_END_1);
821
822 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
823 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
824 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
825 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
826
827 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
828 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
829 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
830 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
831
832 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
833 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
834 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
836
837 DUMPREG(HDMI_V_BLANK_F2_0);
838 DUMPREG(HDMI_V_BLANK_F2_1);
839 DUMPREG(HDMI_V_BLANK_F3_0);
840 DUMPREG(HDMI_V_BLANK_F3_1);
841 DUMPREG(HDMI_V_BLANK_F4_0);
842 DUMPREG(HDMI_V_BLANK_F4_1);
843 DUMPREG(HDMI_V_BLANK_F5_0);
844 DUMPREG(HDMI_V_BLANK_F5_1);
845
846 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
850 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
851 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
852 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
853 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
854
855 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
856 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
857 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
858 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
859 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
860 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
861 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
862 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
863
864 DUMPREG(HDMI_VACT_SPACE_1_0);
865 DUMPREG(HDMI_VACT_SPACE_1_1);
866 DUMPREG(HDMI_VACT_SPACE_2_0);
867 DUMPREG(HDMI_VACT_SPACE_2_1);
868 DUMPREG(HDMI_VACT_SPACE_3_0);
869 DUMPREG(HDMI_VACT_SPACE_3_1);
870 DUMPREG(HDMI_VACT_SPACE_4_0);
871 DUMPREG(HDMI_VACT_SPACE_4_1);
872 DUMPREG(HDMI_VACT_SPACE_5_0);
873 DUMPREG(HDMI_VACT_SPACE_5_1);
874 DUMPREG(HDMI_VACT_SPACE_6_0);
875 DUMPREG(HDMI_VACT_SPACE_6_1);
876
877 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
878 DUMPREG(HDMI_TG_CMD);
879 DUMPREG(HDMI_TG_H_FSZ_L);
880 DUMPREG(HDMI_TG_H_FSZ_H);
881 DUMPREG(HDMI_TG_HACT_ST_L);
882 DUMPREG(HDMI_TG_HACT_ST_H);
883 DUMPREG(HDMI_TG_HACT_SZ_L);
884 DUMPREG(HDMI_TG_HACT_SZ_H);
885 DUMPREG(HDMI_TG_V_FSZ_L);
886 DUMPREG(HDMI_TG_V_FSZ_H);
887 DUMPREG(HDMI_TG_VSYNC_L);
888 DUMPREG(HDMI_TG_VSYNC_H);
889 DUMPREG(HDMI_TG_VSYNC2_L);
890 DUMPREG(HDMI_TG_VSYNC2_H);
891 DUMPREG(HDMI_TG_VACT_ST_L);
892 DUMPREG(HDMI_TG_VACT_ST_H);
893 DUMPREG(HDMI_TG_VACT_SZ_L);
894 DUMPREG(HDMI_TG_VACT_SZ_H);
895 DUMPREG(HDMI_TG_FIELD_CHG_L);
896 DUMPREG(HDMI_TG_FIELD_CHG_H);
897 DUMPREG(HDMI_TG_VACT_ST2_L);
898 DUMPREG(HDMI_TG_VACT_ST2_H);
899 DUMPREG(HDMI_TG_VACT_ST3_L);
900 DUMPREG(HDMI_TG_VACT_ST3_H);
901 DUMPREG(HDMI_TG_VACT_ST4_L);
902 DUMPREG(HDMI_TG_VACT_ST4_H);
903 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
904 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
905 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
906 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
907 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
908 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
909 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
910 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
911 DUMPREG(HDMI_TG_3D);
912
913 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
914 DUMPREG(HDMI_AVI_CON);
915 DUMPREG(HDMI_AVI_HEADER0);
916 DUMPREG(HDMI_AVI_HEADER1);
917 DUMPREG(HDMI_AVI_HEADER2);
918 DUMPREG(HDMI_AVI_CHECK_SUM);
919 DUMPREG(HDMI_VSI_CON);
920 DUMPREG(HDMI_VSI_HEADER0);
921 DUMPREG(HDMI_VSI_HEADER1);
922 DUMPREG(HDMI_VSI_HEADER2);
923 for (i = 0; i < 7; ++i)
924 DUMPREG(HDMI_VSI_DATA(i));
925
926#undef DUMPREG
927}
928
929static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
930{
Rahul Sharma5a325072012-10-04 20:48:54 +0530931 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900932 hdmi_v13_regs_dump(hdata, prefix);
933 else
934 hdmi_v14_regs_dump(hdata, prefix);
935}
936
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530937static u8 hdmi_chksum(struct hdmi_context *hdata,
938 u32 start, u8 len, u32 hdr_sum)
939{
940 int i;
941
942 /* hdr_sum : header0 + header1 + header2
943 * start : start address of packet byte1
944 * len : packet bytes - 1 */
945 for (i = 0; i < len; ++i)
946 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
947
948 /* return 2's complement of 8 bit hdr_sum */
949 return (u8)(~(hdr_sum & 0xff) + 1);
950}
951
952static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530953 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530954{
955 u32 hdr_sum;
956 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530957 u32 mod;
958 u32 vic;
959
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530960 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
961 if (hdata->dvi_mode) {
962 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
963 HDMI_VSI_CON_DO_NOT_TRANSMIT);
964 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
965 HDMI_AVI_CON_DO_NOT_TRANSMIT);
966 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
967 return;
968 }
969
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530970 switch (infoframe->any.type) {
971 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530972 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530973 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
974 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
975 infoframe->any.version);
976 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
977 hdr_sum = infoframe->any.type + infoframe->any.version +
978 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530979
980 /* Output format zero hardcoded ,RGB YBCR selection */
981 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
982 AVI_ACTIVE_FORMAT_VALID |
983 AVI_UNDERSCANNED_DISPLAY_VALID);
984
Shirish S46154152014-03-13 10:58:28 +0530985 /*
986 * Set the aspect ratio as per the mode, mentioned in
987 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
988 */
989 switch (hdata->mode_conf.aspect_ratio) {
990 case HDMI_PICTURE_ASPECT_4_3:
991 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
992 hdata->mode_conf.aspect_ratio |
993 AVI_4_3_CENTER_RATIO);
994 break;
995 case HDMI_PICTURE_ASPECT_16_9:
996 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
997 hdata->mode_conf.aspect_ratio |
998 AVI_16_9_CENTER_RATIO);
999 break;
1000 case HDMI_PICTURE_ASPECT_NONE:
1001 default:
1002 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
1003 hdata->mode_conf.aspect_ratio |
1004 AVI_SAME_AS_PIC_ASPECT_RATIO);
1005 break;
1006 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301007
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001008 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301009 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
1010
1011 chksum = hdmi_chksum(hdata, HDMI_AVI_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("AVI checksum = 0x%x\n", chksum);
1014 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1015 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301016 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301017 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301018 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1019 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1020 infoframe->any.version);
1021 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1022 hdr_sum = infoframe->any.type + infoframe->any.version +
1023 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301024 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301025 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301026 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1027 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1028 break;
1029 default:
1030 break;
1031 }
1032}
1033
Sean Pauld9716ee2014-01-30 16:19:29 -05001034static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1035 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001036{
Sean Pauld9716ee2014-01-30 16:19:29 -05001037 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001038
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001039 if (gpio_get_value(hdata->hpd_gpio))
1040 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301041
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001042 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001043}
1044
Sean Pauld9716ee2014-01-30 16:19:29 -05001045static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001046{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001047 drm_connector_unregister(connector);
1048 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001049}
1050
Sean Pauld9716ee2014-01-30 16:19:29 -05001051static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001052 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001053 .fill_modes = drm_helper_probe_single_connector_modes,
1054 .detect = hdmi_detect,
1055 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001056 .reset = drm_atomic_helper_connector_reset,
1057 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1058 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001059};
1060
1061static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001062{
Sean Pauld9716ee2014-01-30 16:19:29 -05001063 struct hdmi_context *hdata = ctx_from_connector(connector);
1064 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001065 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001066
Inki Dae8fa04aa2014-03-13 16:38:31 +09001067 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001068 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001069
Inki Dae8fa04aa2014-03-13 16:38:31 +09001070 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001071 if (!edid)
1072 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001073
Sean Pauld9716ee2014-01-30 16:19:29 -05001074 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001075 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1076 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001077 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001078
Sean Pauld9716ee2014-01-30 16:19:29 -05001079 drm_mode_connector_update_edid_property(connector, edid);
1080
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001081 ret = drm_add_edid_modes(connector, edid);
1082
1083 kfree(edid);
1084
1085 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001086}
1087
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001088static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001089{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001090 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001091
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001092 for (i = 0; i < hdata->phy_conf_count; i++)
1093 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001094 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001095
1096 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1097 return -EINVAL;
1098}
1099
Sean Pauld9716ee2014-01-30 16:19:29 -05001100static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001101 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001102{
Sean Pauld9716ee2014-01-30 16:19:29 -05001103 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001104 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001105
Rahul Sharma16844fb2013-06-10 14:50:00 +05301106 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1107 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1108 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1109 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001110
Sean Paulf041b252014-01-30 16:19:15 -05001111 ret = mixer_check_mode(mode);
1112 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001113 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001114
Rahul Sharma16844fb2013-06-10 14:50:00 +05301115 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001116 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001117 return MODE_BAD;
1118
1119 return MODE_OK;
1120}
1121
1122static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1123{
1124 struct hdmi_context *hdata = ctx_from_connector(connector);
1125
1126 return hdata->encoder;
1127}
1128
1129static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1130 .get_modes = hdmi_get_modes,
1131 .mode_valid = hdmi_mode_valid,
1132 .best_encoder = hdmi_best_encoder,
1133};
1134
1135static int hdmi_create_connector(struct exynos_drm_display *display,
1136 struct drm_encoder *encoder)
1137{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001138 struct hdmi_context *hdata = display_to_hdmi(display);
Sean Pauld9716ee2014-01-30 16:19:29 -05001139 struct drm_connector *connector = &hdata->connector;
1140 int ret;
1141
1142 hdata->encoder = encoder;
1143 connector->interlace_allowed = true;
1144 connector->polled = DRM_CONNECTOR_POLL_HPD;
1145
1146 ret = drm_connector_init(hdata->drm_dev, connector,
1147 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1148 if (ret) {
1149 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001150 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001151 }
1152
1153 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001154 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001155 drm_mode_connector_attach_encoder(connector, encoder);
1156
1157 return 0;
1158}
1159
Sean Paulf041b252014-01-30 16:19:15 -05001160static void hdmi_mode_fixup(struct exynos_drm_display *display,
1161 struct drm_connector *connector,
1162 const struct drm_display_mode *mode,
1163 struct drm_display_mode *adjusted_mode)
1164{
1165 struct drm_display_mode *m;
1166 int mode_ok;
1167
1168 DRM_DEBUG_KMS("%s\n", __FILE__);
1169
1170 drm_mode_set_crtcinfo(adjusted_mode, 0);
1171
Sean Pauld9716ee2014-01-30 16:19:29 -05001172 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001173
1174 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001175 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001176 return;
1177
1178 /*
1179 * otherwise, find the most suitable mode among modes and change it
1180 * to adjusted_mode.
1181 */
1182 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001183 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001184
Sean Pauld9716ee2014-01-30 16:19:29 -05001185 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001186 DRM_INFO("desired mode doesn't exist so\n");
1187 DRM_INFO("use the most suitable mode among modes.\n");
1188
1189 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1190 m->hdisplay, m->vdisplay, m->vrefresh);
1191
Sean Paul75626852014-01-30 16:19:16 -05001192 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001193 break;
1194 }
1195 }
1196}
1197
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001198static void hdmi_set_acr(u32 freq, u8 *acr)
1199{
1200 u32 n, cts;
1201
1202 switch (freq) {
1203 case 32000:
1204 n = 4096;
1205 cts = 27000;
1206 break;
1207 case 44100:
1208 n = 6272;
1209 cts = 30000;
1210 break;
1211 case 88200:
1212 n = 12544;
1213 cts = 30000;
1214 break;
1215 case 176400:
1216 n = 25088;
1217 cts = 30000;
1218 break;
1219 case 48000:
1220 n = 6144;
1221 cts = 27000;
1222 break;
1223 case 96000:
1224 n = 12288;
1225 cts = 27000;
1226 break;
1227 case 192000:
1228 n = 24576;
1229 cts = 27000;
1230 break;
1231 default:
1232 n = 0;
1233 cts = 0;
1234 break;
1235 }
1236
1237 acr[1] = cts >> 16;
1238 acr[2] = cts >> 8 & 0xff;
1239 acr[3] = cts & 0xff;
1240
1241 acr[4] = n >> 16;
1242 acr[5] = n >> 8 & 0xff;
1243 acr[6] = n & 0xff;
1244}
1245
1246static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1247{
1248 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1249 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1250 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1251 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1252 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1253 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1254 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1255 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1256 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1257
Rahul Sharma5a325072012-10-04 20:48:54 +05301258 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001259 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1260 else
1261 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1262}
1263
1264static void hdmi_audio_init(struct hdmi_context *hdata)
1265{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301266 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001267 u32 data_num, bit_ch, sample_frq;
1268 u32 val;
1269 u8 acr[7];
1270
1271 sample_rate = 44100;
1272 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001273
1274 switch (bits_per_sample) {
1275 case 20:
1276 data_num = 2;
1277 bit_ch = 1;
1278 break;
1279 case 24:
1280 data_num = 3;
1281 bit_ch = 1;
1282 break;
1283 default:
1284 data_num = 1;
1285 bit_ch = 0;
1286 break;
1287 }
1288
1289 hdmi_set_acr(sample_rate, acr);
1290 hdmi_reg_acr(hdata, acr);
1291
1292 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1293 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1294 | HDMI_I2S_MUX_ENABLE);
1295
1296 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1297 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1298
1299 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1300
1301 sample_frq = (sample_rate == 44100) ? 0 :
1302 (sample_rate == 48000) ? 2 :
1303 (sample_rate == 32000) ? 3 :
1304 (sample_rate == 96000) ? 0xa : 0x0;
1305
1306 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1307 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1308
1309 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1310 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1311
1312 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1313 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1314 | HDMI_I2S_SEL_LRCK(6));
1315 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1316 | HDMI_I2S_SEL_SDATA2(4));
1317 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1318 | HDMI_I2S_SEL_SDATA2(2));
1319 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1320
1321 /* I2S_CON_1 & 2 */
1322 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1323 | HDMI_I2S_L_CH_LOW_POL);
1324 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1325 | HDMI_I2S_SET_BIT_CH(bit_ch)
1326 | HDMI_I2S_SET_SDATA_BIT(data_num)
1327 | HDMI_I2S_BASIC_FORMAT);
1328
1329 /* Configure register related to CUV information */
1330 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1331 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1332 | HDMI_I2S_COPYRIGHT
1333 | HDMI_I2S_LINEAR_PCM
1334 | HDMI_I2S_CONSUMER_FORMAT);
1335 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1336 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1337 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1338 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1339 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1340 HDMI_I2S_ORG_SMP_FREQ_44_1
1341 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1342 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1343
1344 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1345}
1346
1347static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1348{
Seung-Woo Kim872d20d2012-04-24 17:39:15 +09001349 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001350 return;
1351
1352 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1353 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1354 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1355}
1356
Rahul Sharmabfa48422014-04-03 20:41:04 +05301357static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001358{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301359 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001360
Rahul Sharmabfa48422014-04-03 20:41:04 +05301361 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1362 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001363
Rahul Sharmabfa48422014-04-03 20:41:04 +05301364 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1365 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001366}
1367
1368static void hdmi_conf_init(struct hdmi_context *hdata)
1369{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301370 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301371
Sean Paul77006a72013-01-16 10:17:20 -05001372 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001373 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1374 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001375
1376 /* choose HDMI mode */
1377 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1378 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301379 /* Apply Video preable and Guard band in HDMI mode only */
1380 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001381 /* disable bluescreen */
1382 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001383
Seung-Woo Kim872d20d2012-04-24 17:39:15 +09001384 if (hdata->dvi_mode) {
1385 /* choose DVI mode */
1386 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1387 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1388 hdmi_reg_writeb(hdata, HDMI_CON_2,
1389 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1390 }
1391
Rahul Sharma5a325072012-10-04 20:48:54 +05301392 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001393 /* choose bluescreen (fecal) color */
1394 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1395 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1396 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1397
1398 /* enable AVI packet every vsync, fixes purple line problem */
1399 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1400 /* force RGB, look to CEA-861-D, table 7 for more detail */
1401 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1402 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1403
1404 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1405 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1406 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1407 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301408 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1409 infoframe.any.version = HDMI_AVI_VERSION;
1410 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301411 hdmi_reg_infoframe(hdata, &infoframe);
1412
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301413 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1414 infoframe.any.version = HDMI_AUI_VERSION;
1415 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301416 hdmi_reg_infoframe(hdata, &infoframe);
1417
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001418 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001419 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1420 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001421}
1422
Rahul Sharma16844fb2013-06-10 14:50:00 +05301423static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001424{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001425 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1426 const struct hdmi_v13_core_regs *core =
1427 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001428 int tries;
1429
1430 /* setting core registers */
1431 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1432 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001433 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1434 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1435 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1436 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1437 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1438 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001439 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1440 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001441 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1442 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1443 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1444 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1445 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1446 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1447 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1448 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1449 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1450 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1451 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1452 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1453 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1454 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1455 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001456 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001457 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1463 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1464 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1465 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1466 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1467 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1468 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1469 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1470 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1471 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1472 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1473 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1474 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1475 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1476 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1477 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1478 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1479 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1480 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1481 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1482 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1483 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1484 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001485
1486 /* waiting for HDMIPHY's PLL to get to steady state */
1487 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001488 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001489 if (val & HDMI_PHY_STATUS_READY)
1490 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001491 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001492 }
1493 /* steady state not achieved */
1494 if (tries == 0) {
1495 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1496 hdmi_regs_dump(hdata, "timing apply");
1497 }
1498
Sean Paul0bfb1f82013-06-11 12:24:02 +05301499 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301500 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301501 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001502
1503 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301504 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001505}
1506
Rahul Sharma16844fb2013-06-10 14:50:00 +05301507static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001508{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001509 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1510 const struct hdmi_v14_core_regs *core =
1511 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001512 int tries;
1513
1514 /* setting core registers */
1515 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1516 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1517 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1518 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1519 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1520 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1521 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1522 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1523 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1524 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1525 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1526 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1527 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1528 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1529 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1530 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1531 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1532 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1533 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1534 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1535 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1536 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1537 core->v_sync_line_bef_2[0]);
1538 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1539 core->v_sync_line_bef_2[1]);
1540 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1541 core->v_sync_line_bef_1[0]);
1542 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1543 core->v_sync_line_bef_1[1]);
1544 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1545 core->v_sync_line_aft_2[0]);
1546 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1547 core->v_sync_line_aft_2[1]);
1548 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1549 core->v_sync_line_aft_1[0]);
1550 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1551 core->v_sync_line_aft_1[1]);
1552 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1553 core->v_sync_line_aft_pxl_2[0]);
1554 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1555 core->v_sync_line_aft_pxl_2[1]);
1556 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1557 core->v_sync_line_aft_pxl_1[0]);
1558 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1559 core->v_sync_line_aft_pxl_1[1]);
1560 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1561 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1562 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1563 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1564 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1565 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1566 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1567 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1568 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1569 core->v_sync_line_aft_3[0]);
1570 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1571 core->v_sync_line_aft_3[1]);
1572 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1573 core->v_sync_line_aft_4[0]);
1574 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1575 core->v_sync_line_aft_4[1]);
1576 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1577 core->v_sync_line_aft_5[0]);
1578 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1579 core->v_sync_line_aft_5[1]);
1580 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1581 core->v_sync_line_aft_6[0]);
1582 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1583 core->v_sync_line_aft_6[1]);
1584 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1585 core->v_sync_line_aft_pxl_3[0]);
1586 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1587 core->v_sync_line_aft_pxl_3[1]);
1588 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1589 core->v_sync_line_aft_pxl_4[0]);
1590 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1591 core->v_sync_line_aft_pxl_4[1]);
1592 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1593 core->v_sync_line_aft_pxl_5[0]);
1594 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1595 core->v_sync_line_aft_pxl_5[1]);
1596 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1597 core->v_sync_line_aft_pxl_6[0]);
1598 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1599 core->v_sync_line_aft_pxl_6[1]);
1600 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1601 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1602 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1603 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1604 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1605 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1606 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1607 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1608 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1609 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1610 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1611 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1612
1613 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001614 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1615 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1626 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1627 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1628 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1629 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1630 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1631 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1632 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1633 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1634 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1635 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1636 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1637 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1638 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1639 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1640 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1641 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1642 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1643 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1644 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1645 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1646 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001647
1648 /* waiting for HDMIPHY's PLL to get to steady state */
1649 for (tries = 100; tries; --tries) {
1650 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1651 if (val & HDMI_PHY_STATUS_READY)
1652 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001653 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001654 }
1655 /* steady state not achieved */
1656 if (tries == 0) {
1657 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1658 hdmi_regs_dump(hdata, "timing apply");
1659 }
1660
Sean Paul0bfb1f82013-06-11 12:24:02 +05301661 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301662 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301663 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001664
1665 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301666 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001667}
1668
Rahul Sharma16844fb2013-06-10 14:50:00 +05301669static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001670{
Rahul Sharma5a325072012-10-04 20:48:54 +05301671 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301672 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001673 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301674 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001675}
1676
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001677static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1678{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001679 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001680
Sean Paul0bfb1f82013-06-11 12:24:02 +05301681 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301682 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301683 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001684
1685 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001686 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1687 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001688
Rahul Sharma5a325072012-10-04 20:48:54 +05301689 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001690 reg = HDMI_V13_PHY_RSTOUT;
1691 else
1692 reg = HDMI_PHY_RSTOUT;
1693
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001694 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001695 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001696 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001697 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001698 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001699}
1700
Rahul Sharmaa5562252012-11-28 11:30:25 +05301701static void hdmiphy_poweron(struct hdmi_context *hdata)
1702{
Shirish S6a296e22014-04-03 20:41:02 +05301703 if (hdata->type != HDMI_TYPE14)
1704 return;
1705
1706 DRM_DEBUG_KMS("\n");
1707
1708 /* For PHY Mode Setting */
1709 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1710 HDMI_PHY_ENABLE_MODE_SET);
1711 /* Phy Power On */
1712 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1713 HDMI_PHY_POWER_ON);
1714 /* For PHY Mode Setting */
1715 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1716 HDMI_PHY_DISABLE_MODE_SET);
1717 /* PHY SW Reset */
1718 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301719}
1720
1721static void hdmiphy_poweroff(struct hdmi_context *hdata)
1722{
Shirish S6a296e22014-04-03 20:41:02 +05301723 if (hdata->type != HDMI_TYPE14)
1724 return;
1725
1726 DRM_DEBUG_KMS("\n");
1727
1728 /* PHY SW Reset */
1729 hdmiphy_conf_reset(hdata);
1730 /* For PHY Mode Setting */
1731 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1732 HDMI_PHY_ENABLE_MODE_SET);
1733
1734 /* PHY Power Off */
1735 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1736 HDMI_PHY_POWER_OFF);
1737
1738 /* For PHY Mode Setting */
1739 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1740 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301741}
1742
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001743static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1744{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001745 int ret;
1746 int i;
1747
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001748 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001749 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1750 if (i < 0) {
1751 DRM_ERROR("failed to find hdmiphy conf\n");
1752 return;
1753 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001754
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001755 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1756 if (ret) {
1757 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001758 return;
1759 }
1760
Sean Paul09760ea2013-01-14 17:03:20 -05001761 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001762
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001763 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1764 HDMI_PHY_DISABLE_MODE_SET);
1765 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001766 DRM_ERROR("failed to enable hdmiphy\n");
1767 return;
1768 }
1769
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001770}
1771
1772static void hdmi_conf_apply(struct hdmi_context *hdata)
1773{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001774 hdmiphy_conf_reset(hdata);
1775 hdmiphy_conf_apply(hdata);
1776
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001777 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301778 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001779 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001780 mutex_unlock(&hdata->hdmi_mutex);
1781
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001782 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001783
1784 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301785 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001786 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001787
1788 hdmi_regs_dump(hdata, "start");
1789}
1790
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001791static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1792{
1793 int i;
1794 BUG_ON(num_bytes > 4);
1795 for (i = 0; i < num_bytes; i++)
1796 reg_pair[i] = (value >> (8 * i)) & 0xff;
1797}
1798
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001799static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1800 struct drm_display_mode *m)
1801{
1802 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1803 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1804 unsigned int val;
1805
1806 hdata->mode_conf.cea_video_id =
1807 drm_match_cea_mode((struct drm_display_mode *)m);
1808 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301809 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001810
1811 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1812 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1813
1814 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1815 hdmi_set_reg(core->vsync_pol, 1, val);
1816
1817 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1818 hdmi_set_reg(core->int_pro_mode, 1, val);
1819
1820 val = (m->hsync_start - m->hdisplay - 2);
1821 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1822 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1823 hdmi_set_reg(core->h_sync_gen, 3, val);
1824
1825 /*
1826 * Quirk requirement for exynos HDMI IP design,
1827 * 2 pixels less than the actual calculation for hsync_start
1828 * and end.
1829 */
1830
1831 /* Following values & calculations differ for different type of modes */
1832 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1833 /* Interlaced Mode */
1834 val = ((m->vsync_end - m->vdisplay) / 2);
1835 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1836 hdmi_set_reg(core->v_sync_gen1, 3, val);
1837
1838 val = m->vtotal / 2;
1839 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1840 hdmi_set_reg(core->v_blank, 3, val);
1841
1842 val = (m->vtotal +
1843 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1844 val |= m->vtotal << 11;
1845 hdmi_set_reg(core->v_blank_f, 3, val);
1846
1847 val = ((m->vtotal / 2) + 7);
1848 val |= ((m->vtotal / 2) + 2) << 12;
1849 hdmi_set_reg(core->v_sync_gen2, 3, val);
1850
1851 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1852 val |= ((m->htotal / 2) +
1853 (m->hsync_start - m->hdisplay)) << 12;
1854 hdmi_set_reg(core->v_sync_gen3, 3, val);
1855
1856 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1857 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1858
1859 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1860 } else {
1861 /* Progressive Mode */
1862
1863 val = m->vtotal;
1864 val |= (m->vtotal - m->vdisplay) << 11;
1865 hdmi_set_reg(core->v_blank, 3, val);
1866
1867 hdmi_set_reg(core->v_blank_f, 3, 0);
1868
1869 val = (m->vsync_end - m->vdisplay);
1870 val |= ((m->vsync_start - m->vdisplay) << 12);
1871 hdmi_set_reg(core->v_sync_gen1, 3, val);
1872
1873 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1874 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1875 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1876 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1877 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1878 }
1879
1880 /* Timing generator registers */
1881 hdmi_set_reg(tg->cmd, 1, 0x0);
1882 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1883 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1884 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1885 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1886 hdmi_set_reg(tg->vsync, 2, 0x1);
1887 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1888 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1889 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1890 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1891 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1892 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1893 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1894}
1895
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001896static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1897 struct drm_display_mode *m)
1898{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001899 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1900 struct hdmi_v14_core_regs *core =
1901 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001902
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001903 hdata->mode_conf.cea_video_id =
1904 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001905 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301906 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001907
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001908 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1909 hdmi_set_reg(core->v_line, 2, m->vtotal);
1910 hdmi_set_reg(core->h_line, 2, m->htotal);
1911 hdmi_set_reg(core->hsync_pol, 1,
1912 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1913 hdmi_set_reg(core->vsync_pol, 1,
1914 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1915 hdmi_set_reg(core->int_pro_mode, 1,
1916 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1917
1918 /*
1919 * Quirk requirement for exynos 5 HDMI IP design,
1920 * 2 pixels less than the actual calculation for hsync_start
1921 * and end.
1922 */
1923
1924 /* Following values & calculations differ for different type of modes */
1925 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1926 /* Interlaced Mode */
1927 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1928 (m->vsync_end - m->vdisplay) / 2);
1929 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1930 (m->vsync_start - m->vdisplay) / 2);
1931 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1932 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301933 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001934 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1935 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1936 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1937 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1938 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1939 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1940 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1941 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1942 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301943 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1944 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1945 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1946 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001947 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1948 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1949 } else {
1950 /* Progressive Mode */
1951 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1952 m->vsync_end - m->vdisplay);
1953 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1954 m->vsync_start - m->vdisplay);
1955 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1956 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1957 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1958 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1959 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1960 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1961 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1962 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1963 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1964 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1965 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1966 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1967 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301968 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1969 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1970 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001971 }
1972
1973 /* Following values & calculations are same irrespective of mode type */
1974 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1975 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1976 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1977 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1978 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1979 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1980 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1981 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1982 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1983 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1984 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1985 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1986 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1987 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1988 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1989 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1990 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1991 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1992 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1993 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1994
1995 /* Timing generator registers */
1996 hdmi_set_reg(tg->cmd, 1, 0x0);
1997 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1998 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1999 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
2000 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
2001 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002002 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
2003 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002004 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002005 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002006}
2007
Sean Paulf041b252014-01-30 16:19:15 -05002008static void hdmi_mode_set(struct exynos_drm_display *display,
2009 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002010{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002011 struct hdmi_context *hdata = display_to_hdmi(display);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002012 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002013
YoungJun Chocbc4c332013-06-12 10:44:40 +09002014 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
2015 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002016 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02002017 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002018
Rahul Sharmabfa48422014-04-03 20:41:04 +05302019 /* preserve mode information for later use. */
2020 drm_mode_copy(&hdata->current_mode, mode);
2021
Sachin Kamat5f46c332013-04-26 11:29:00 +05302022 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002023 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302024 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002025 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002026}
2027
Sean Paulf041b252014-01-30 16:19:15 -05002028static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002029{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002030 struct hdmi_context *hdata = display_to_hdmi(display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002031
Shirish Sdda90122013-01-23 22:03:18 -05002032 mutex_lock(&hdata->hdmi_mutex);
2033 if (!hdata->powered) {
2034 mutex_unlock(&hdata->hdmi_mutex);
2035 return;
2036 }
2037 mutex_unlock(&hdata->hdmi_mutex);
2038
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002039 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002040}
2041
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002042static void hdmi_poweron(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002043{
2044 struct hdmi_resources *res = &hdata->res;
2045
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002046 mutex_lock(&hdata->hdmi_mutex);
2047 if (hdata->powered) {
2048 mutex_unlock(&hdata->hdmi_mutex);
2049 return;
2050 }
2051
2052 hdata->powered = true;
2053
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002054 mutex_unlock(&hdata->hdmi_mutex);
2055
Sean Paulaf65c802014-01-30 16:19:27 -05002056 pm_runtime_get_sync(hdata->dev);
2057
Seung-Woo Kimad079452013-06-05 14:34:38 +09002058 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2059 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2060
Rahul Sharma049d34e2014-05-20 10:36:05 +05302061 /* set pmu hdmiphy control bit to enable hdmiphy */
2062 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2063 PMU_HDMI_PHY_ENABLE_BIT, 1);
2064
Sean Paul0bfb1f82013-06-11 12:24:02 +05302065 clk_prepare_enable(res->hdmi);
2066 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302067
2068 hdmiphy_poweron(hdata);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002069 hdmi_commit(&hdata->display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002070}
2071
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002072static void hdmi_poweroff(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002073{
2074 struct hdmi_resources *res = &hdata->res;
2075
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002076 mutex_lock(&hdata->hdmi_mutex);
2077 if (!hdata->powered)
2078 goto out;
2079 mutex_unlock(&hdata->hdmi_mutex);
2080
Rahul Sharmabfa48422014-04-03 20:41:04 +05302081 /* HDMI System Disable */
2082 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2083
Rahul Sharmaa5562252012-11-28 11:30:25 +05302084 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002085
Sean Paul724fd142014-05-09 15:05:10 +09002086 cancel_delayed_work(&hdata->hotplug_work);
2087
Sean Paul0bfb1f82013-06-11 12:24:02 +05302088 clk_disable_unprepare(res->sclk_hdmi);
2089 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302090
2091 /* reset pmu hdmiphy control bit to disable hdmiphy */
2092 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2093 PMU_HDMI_PHY_ENABLE_BIT, 0);
2094
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002095 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2096
Sean Paulaf65c802014-01-30 16:19:27 -05002097 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002098
Sean Paulaf65c802014-01-30 16:19:27 -05002099 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002100 hdata->powered = false;
2101
2102out:
2103 mutex_unlock(&hdata->hdmi_mutex);
2104}
2105
Sean Paulf041b252014-01-30 16:19:15 -05002106static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002107{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002108 struct hdmi_context *hdata = display_to_hdmi(display);
Inki Dae245f98f2014-06-13 17:44:40 +09002109 struct drm_encoder *encoder = hdata->encoder;
2110 struct drm_crtc *crtc = encoder->crtc;
Jani Nikulab0f87782015-03-11 11:50:59 +02002111 const struct drm_crtc_helper_funcs *funcs = NULL;
Inki Dae245f98f2014-06-13 17:44:40 +09002112
YoungJun Chocbc4c332013-06-12 10:44:40 +09002113 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002114
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002115 switch (mode) {
2116 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002117 hdmi_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002118 break;
2119 case DRM_MODE_DPMS_STANDBY:
2120 case DRM_MODE_DPMS_SUSPEND:
2121 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002122 /*
2123 * The SFRs of VP and Mixer are updated by Vertical Sync of
2124 * Timing generator which is a part of HDMI so the sequence
2125 * to disable TV Subsystem should be as following,
2126 * VP -> Mixer -> HDMI
2127 *
2128 * Below codes will try to disable Mixer and VP(if used)
2129 * prior to disabling HDMI.
2130 */
2131 if (crtc)
2132 funcs = crtc->helper_private;
Gustavo Padovan63498e32015-06-01 12:04:53 -03002133 if (funcs && funcs->disable)
2134 (*funcs->disable)(crtc);
Inki Dae245f98f2014-06-13 17:44:40 +09002135
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002136 hdmi_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002137 break;
2138 default:
2139 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2140 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002141 }
2142}
2143
Sean Paulf041b252014-01-30 16:19:15 -05002144static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002145 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002146 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002147 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002148 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002149 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002150};
2151
Sean Paul724fd142014-05-09 15:05:10 +09002152static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002153{
Sean Paul724fd142014-05-09 15:05:10 +09002154 struct hdmi_context *hdata;
2155
2156 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002157
Sean Paul45517892014-01-30 16:19:05 -05002158 if (hdata->drm_dev)
2159 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002160}
2161
2162static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2163{
2164 struct hdmi_context *hdata = arg;
2165
2166 mod_delayed_work(system_wq, &hdata->hotplug_work,
2167 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002168
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002169 return IRQ_HANDLED;
2170}
2171
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002172static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002173{
2174 struct device *dev = hdata->dev;
2175 struct hdmi_resources *res = &hdata->res;
2176 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002177 "vdd",
2178 "vdd_osc",
2179 "vdd_pll",
2180 };
2181 int i, ret;
2182
2183 DRM_DEBUG_KMS("HDMI resource init\n");
2184
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002185 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302186 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302187 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002188 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002189 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002190 goto fail;
2191 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302192 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302193 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002195 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196 goto fail;
2197 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302198 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302199 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002200 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002201 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002202 goto fail;
2203 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302204 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302205 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002206 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002207 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002208 goto fail;
2209 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302210 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2211 if (IS_ERR(res->mout_hdmi)) {
2212 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002213 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302214 goto fail;
2215 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002216
Rahul Sharma59956d32013-06-11 12:24:03 +05302217 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002218
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302219 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302220 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002221 if (!res->regul_bulk) {
2222 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002223 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002224 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002225 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2226 res->regul_bulk[i].supply = supply[i];
2227 res->regul_bulk[i].consumer = NULL;
2228 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302229 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002230 if (ret) {
2231 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002232 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002233 }
2234 res->regul_count = ARRAY_SIZE(supply);
2235
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002236 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2237 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2238 DRM_ERROR("failed to get hdmi-en regulator\n");
2239 return PTR_ERR(res->reg_hdmi_en);
2240 }
2241 if (!IS_ERR(res->reg_hdmi_en)) {
2242 ret = regulator_enable(res->reg_hdmi_en);
2243 if (ret) {
2244 DRM_ERROR("failed to enable hdmi-en regulator\n");
2245 return ret;
2246 }
2247 } else
2248 res->reg_hdmi_en = NULL;
2249
Inki Daedf5225b2014-05-29 18:28:02 +09002250 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002251fail:
2252 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002253 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002254}
2255
Rahul Sharma22c4f422012-10-04 20:48:55 +05302256static struct of_device_id hdmi_match_types[] = {
2257 {
2258 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002259 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302260 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02002261 .compatible = "samsung,exynos4210-hdmi",
2262 .data = &exynos4210_hdmi_driver_data,
2263 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302264 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002265 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302266 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302267 .compatible = "samsung,exynos5420-hdmi",
2268 .data = &exynos5420_hdmi_driver_data,
2269 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302270 /* end node */
2271 }
2272};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02002273MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302274
Inki Daef37cd5e2014-05-09 14:25:20 +09002275static int hdmi_bind(struct device *dev, struct device *master, void *data)
2276{
2277 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002278 struct hdmi_context *hdata = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002279
Inki Daef37cd5e2014-05-09 14:25:20 +09002280 hdata->drm_dev = drm_dev;
2281
Andrzej Hajda930865f2014-11-17 09:54:20 +01002282 return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
Inki Daef37cd5e2014-05-09 14:25:20 +09002283}
2284
2285static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2286{
Inki Daef37cd5e2014-05-09 14:25:20 +09002287}
2288
2289static const struct component_ops hdmi_component_ops = {
2290 .bind = hdmi_bind,
2291 .unbind = hdmi_unbind,
2292};
2293
Inki Daee2a562d2014-05-09 16:46:10 +09002294static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2295{
2296 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2297 struct device_node *np;
2298
2299 np = of_find_compatible_node(NULL, NULL, compatible_str);
2300 if (np)
2301 return of_get_next_parent(np);
2302
2303 return NULL;
2304}
2305
2306static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2307{
2308 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2309
2310 return of_find_compatible_node(NULL, NULL, compatible_str);
2311}
2312
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002313static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002314{
Inki Daef37cd5e2014-05-09 14:25:20 +09002315 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09002316 struct hdmi_driver_data *drv_data;
2317 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002318 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002319 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002320 struct resource *res;
2321 int ret;
2322
Andrzej Hajda930865f2014-11-17 09:54:20 +01002323 if (!dev->of_node)
2324 return -ENODEV;
2325
Andrzej Hajda930865f2014-11-17 09:54:20 +01002326 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2327 if (!hdata)
2328 return -ENOMEM;
2329
2330 hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
2331 hdata->display.ops = &hdmi_display_ops;
2332
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002333 mutex_init(&hdata->hdmi_mutex);
2334
Andrzej Hajda930865f2014-11-17 09:54:20 +01002335 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002336
Sachin Kamat88c49812013-08-28 10:47:57 +05302337 match = of_match_node(hdmi_match_types, dev->of_node);
Andrzej Hajda86650402015-06-11 23:23:37 +09002338 if (!match)
2339 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002340
2341 drv_data = (struct hdmi_driver_data *)match->data;
2342 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002343 hdata->phy_confs = drv_data->phy_confs;
2344 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302345
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002346 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002347 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2348 if (hdata->hpd_gpio < 0) {
2349 DRM_ERROR("cannot get hpd gpio property\n");
2350 return hdata->hpd_gpio;
2351 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002352
2353 ret = hdmi_resources_init(hdata);
2354 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302355 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002356 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002357 }
2358
2359 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002360 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002361 if (IS_ERR(hdata->regs)) {
2362 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002363 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002364 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002365
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002366 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302367 if (ret) {
2368 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002369 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302370 }
2371
Inki Daee2a562d2014-05-09 16:46:10 +09002372 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2373 if (ddc_node)
2374 goto out_get_ddc_adpt;
2375
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002376 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002377 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2378 if (!ddc_node) {
2379 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002380 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002381 }
Inki Daee2a562d2014-05-09 16:46:10 +09002382
2383out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002384 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2385 if (!hdata->ddc_adpt) {
2386 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002387 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002388 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002389
Inki Daee2a562d2014-05-09 16:46:10 +09002390 phy_node = hdmi_legacy_phy_dt_binding(dev);
2391 if (phy_node)
2392 goto out_get_phy_port;
2393
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002394 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002395 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2396 if (!phy_node) {
2397 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2398 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002399 goto err_ddc;
2400 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002401
Inki Daee2a562d2014-05-09 16:46:10 +09002402out_get_phy_port:
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002403 if (drv_data->is_apb_phy) {
2404 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2405 if (!hdata->regs_hdmiphy) {
2406 DRM_ERROR("failed to ioremap hdmi phy\n");
2407 ret = -ENOMEM;
2408 goto err_ddc;
2409 }
2410 } else {
2411 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2412 if (!hdata->hdmiphy_port) {
2413 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002414 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002415 goto err_ddc;
2416 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002417 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002418
Sean Paul77006a72013-01-16 10:17:20 -05002419 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2420 if (hdata->irq < 0) {
2421 DRM_ERROR("failed to get GPIO irq\n");
2422 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002423 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002424 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002425
Sean Paul724fd142014-05-09 15:05:10 +09002426 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2427
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002428 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002429 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002430 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002431 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002432 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002433 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002434 goto err_hdmiphy;
2435 }
2436
Rahul Sharma049d34e2014-05-20 10:36:05 +05302437 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2438 "samsung,syscon-phandle");
2439 if (IS_ERR(hdata->pmureg)) {
2440 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002441 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302442 goto err_hdmiphy;
2443 }
2444
Sean Paulaf65c802014-01-30 16:19:27 -05002445 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002446
Inki Daedf5225b2014-05-29 18:28:02 +09002447 ret = component_add(&pdev->dev, &hdmi_component_ops);
2448 if (ret)
2449 goto err_disable_pm_runtime;
2450
2451 return ret;
2452
2453err_disable_pm_runtime:
2454 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002455
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002456err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002457 if (hdata->hdmiphy_port)
2458 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002459err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002460 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002461
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002462 return ret;
2463}
2464
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002465static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002466{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002467 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002468
Sean Paul724fd142014-05-09 15:05:10 +09002469 cancel_delayed_work_sync(&hdata->hotplug_work);
2470
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002471 if (hdata->res.reg_hdmi_en)
2472 regulator_disable(hdata->res.reg_hdmi_en);
2473
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002474 if (hdata->hdmiphy_port)
2475 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002476 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002477
Sean Paulaf65c802014-01-30 16:19:27 -05002478 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002479 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002480
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002481 return 0;
2482}
2483
2484struct platform_driver hdmi_driver = {
2485 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002486 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002487 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302488 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002489 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302490 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002491 },
2492};