blob: f9c4de16d91ac8073e6e8cf59fc72fc27f466302 [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>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053034#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090035#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020036#include <linux/of_device.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053037#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053049#include <linux/gpio.h>
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053050
Sean Pauld9716ee2014-01-30 16:19:29 -050051#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090052
Sean Paul724fd142014-05-09 15:05:10 +090053#define HOTPLUG_DEBOUNCE_MS 1100
54
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053055/* AVI header and aspect ratio */
56#define HDMI_AVI_VERSION 0x02
57#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053058
59/* AUI header info */
60#define HDMI_AUI_VERSION 0x01
61#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053062#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
63#define AVI_4_3_CENTER_RATIO 0x9
64#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053065
Rahul Sharma5a325072012-10-04 20:48:54 +053066enum hdmi_type {
67 HDMI_TYPE13,
68 HDMI_TYPE14,
69};
70
Inki Daebfe4e842014-03-06 14:18:17 +090071struct hdmi_driver_data {
72 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090073 const struct hdmiphy_config *phy_confs;
74 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090075 unsigned int is_apb_phy:1;
76};
77
Joonyoung Shim590f4182012-03-16 18:47:14 +090078struct hdmi_resources {
79 struct clk *hdmi;
80 struct clk *sclk_hdmi;
81 struct clk *sclk_pixel;
82 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053083 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090084 struct regulator_bulk_data *regul_bulk;
Marek Szyprowski05fdf982014-07-01 10:10:06 +020085 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +090086 int regul_count;
87};
88
Sean Paul2f7e2ed2013-01-15 08:11:08 -050089struct hdmi_tg_regs {
90 u8 cmd[1];
91 u8 h_fsz[2];
92 u8 hact_st[2];
93 u8 hact_sz[2];
94 u8 v_fsz[2];
95 u8 vsync[2];
96 u8 vsync2[2];
97 u8 vact_st[2];
98 u8 vact_sz[2];
99 u8 field_chg[2];
100 u8 vact_st2[2];
101 u8 vact_st3[2];
102 u8 vact_st4[2];
103 u8 vsync_top_hdmi[2];
104 u8 vsync_bot_hdmi[2];
105 u8 field_top_hdmi[2];
106 u8 field_bot_hdmi[2];
107 u8 tg_3d[1];
108};
109
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900110struct hdmi_v13_core_regs {
111 u8 h_blank[2];
112 u8 v_blank[3];
113 u8 h_v_line[3];
114 u8 vsync_pol[1];
115 u8 int_pro_mode[1];
116 u8 v_blank_f[3];
117 u8 h_sync_gen[3];
118 u8 v_sync_gen1[3];
119 u8 v_sync_gen2[3];
120 u8 v_sync_gen3[3];
121};
122
123struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500124 u8 h_blank[2];
125 u8 v2_blank[2];
126 u8 v1_blank[2];
127 u8 v_line[2];
128 u8 h_line[2];
129 u8 hsync_pol[1];
130 u8 vsync_pol[1];
131 u8 int_pro_mode[1];
132 u8 v_blank_f0[2];
133 u8 v_blank_f1[2];
134 u8 h_sync_start[2];
135 u8 h_sync_end[2];
136 u8 v_sync_line_bef_2[2];
137 u8 v_sync_line_bef_1[2];
138 u8 v_sync_line_aft_2[2];
139 u8 v_sync_line_aft_1[2];
140 u8 v_sync_line_aft_pxl_2[2];
141 u8 v_sync_line_aft_pxl_1[2];
142 u8 v_blank_f2[2]; /* for 3D mode */
143 u8 v_blank_f3[2]; /* for 3D mode */
144 u8 v_blank_f4[2]; /* for 3D mode */
145 u8 v_blank_f5[2]; /* for 3D mode */
146 u8 v_sync_line_aft_3[2];
147 u8 v_sync_line_aft_4[2];
148 u8 v_sync_line_aft_5[2];
149 u8 v_sync_line_aft_6[2];
150 u8 v_sync_line_aft_pxl_3[2];
151 u8 v_sync_line_aft_pxl_4[2];
152 u8 v_sync_line_aft_pxl_5[2];
153 u8 v_sync_line_aft_pxl_6[2];
154 u8 vact_space_1[2];
155 u8 vact_space_2[2];
156 u8 vact_space_3[2];
157 u8 vact_space_4[2];
158 u8 vact_space_5[2];
159 u8 vact_space_6[2];
160};
161
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900162struct hdmi_v13_conf {
163 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500164 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900165};
166
167struct hdmi_v14_conf {
168 struct hdmi_v14_core_regs core;
169 struct hdmi_tg_regs tg;
170};
171
172struct hdmi_conf_regs {
173 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500174 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530175 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900176 union {
177 struct hdmi_v13_conf v13_conf;
178 struct hdmi_v14_conf v14_conf;
179 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500180};
181
Joonyoung Shim590f4182012-03-16 18:47:14 +0900182struct hdmi_context {
Andrzej Hajda930865f2014-11-17 09:54:20 +0100183 struct exynos_drm_display display;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900184 struct device *dev;
185 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500186 struct drm_connector connector;
187 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900188 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900189 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900190
Joonyoung Shim590f4182012-03-16 18:47:14 +0900191 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500192 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900193 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900194
Inki Dae8fa04aa2014-03-13 16:38:31 +0900195 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900196 struct i2c_client *hdmiphy_port;
197
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900198 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530199 struct drm_display_mode current_mode;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900200 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900201
202 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200203 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900204
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530205 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900206 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530207
Rahul Sharma049d34e2014-05-20 10:36:05 +0530208 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900209};
210
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100211static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
212{
213 return container_of(d, struct hdmi_context, display);
214}
215
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500216struct hdmiphy_config {
217 int pixel_clock;
218 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900219};
220
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900221/* list of phy config settings */
222static const struct hdmiphy_config hdmiphy_v13_configs[] = {
223 {
224 .pixel_clock = 27000000,
225 .conf = {
226 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
227 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
228 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
229 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
230 },
231 },
232 {
233 .pixel_clock = 27027000,
234 .conf = {
235 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
236 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
237 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
238 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
239 },
240 },
241 {
242 .pixel_clock = 74176000,
243 .conf = {
244 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
245 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
246 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
247 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
248 },
249 },
250 {
251 .pixel_clock = 74250000,
252 .conf = {
253 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
254 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
255 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
256 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
257 },
258 },
259 {
260 .pixel_clock = 148500000,
261 .conf = {
262 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
263 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
264 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
265 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
266 },
267 },
268};
269
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500270static const struct hdmiphy_config hdmiphy_v14_configs[] = {
271 {
272 .pixel_clock = 25200000,
273 .conf = {
274 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
275 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
276 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
277 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
278 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900279 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500280 {
281 .pixel_clock = 27000000,
282 .conf = {
283 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
284 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
285 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
286 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
287 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900288 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500289 {
290 .pixel_clock = 27027000,
291 .conf = {
292 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
293 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
294 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
295 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
296 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900297 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 {
299 .pixel_clock = 36000000,
300 .conf = {
301 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
302 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
303 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
304 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
305 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900306 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500307 {
308 .pixel_clock = 40000000,
309 .conf = {
310 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
311 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
312 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
313 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
314 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900315 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500316 {
317 .pixel_clock = 65000000,
318 .conf = {
319 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
320 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
321 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
322 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
323 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900324 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 {
Shirish Se1d883c2014-03-13 14:28:27 +0900326 .pixel_clock = 71000000,
327 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530328 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
329 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
330 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900331 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
332 },
333 },
334 {
335 .pixel_clock = 73250000,
336 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530337 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
338 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
339 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900340 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
341 },
342 },
343 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500344 .pixel_clock = 74176000,
345 .conf = {
346 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
347 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
348 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
349 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
350 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900351 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500352 {
353 .pixel_clock = 74250000,
354 .conf = {
355 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
356 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
357 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
358 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
359 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900360 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500361 {
362 .pixel_clock = 83500000,
363 .conf = {
364 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
365 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
366 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
367 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
368 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900369 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500370 {
371 .pixel_clock = 106500000,
372 .conf = {
373 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
374 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
375 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
376 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
377 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900378 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500379 {
380 .pixel_clock = 108000000,
381 .conf = {
382 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
383 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
384 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
385 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
386 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900387 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500388 {
Shirish Se1d883c2014-03-13 14:28:27 +0900389 .pixel_clock = 115500000,
390 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530391 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
392 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
393 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900394 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
395 },
396 },
397 {
398 .pixel_clock = 119000000,
399 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530400 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
401 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
402 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900403 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
404 },
405 },
406 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500407 .pixel_clock = 146250000,
408 .conf = {
409 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
410 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
411 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
412 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
413 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900414 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500415 {
416 .pixel_clock = 148500000,
417 .conf = {
418 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
419 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
420 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
421 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
422 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900423 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900424};
425
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530426static const struct hdmiphy_config hdmiphy_5420_configs[] = {
427 {
428 .pixel_clock = 25200000,
429 .conf = {
430 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
431 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
432 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
433 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
434 },
435 },
436 {
437 .pixel_clock = 27000000,
438 .conf = {
439 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
440 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
441 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
442 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
443 },
444 },
445 {
446 .pixel_clock = 27027000,
447 .conf = {
448 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
449 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
450 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
451 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
452 },
453 },
454 {
455 .pixel_clock = 36000000,
456 .conf = {
457 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
458 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
459 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
460 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
461 },
462 },
463 {
464 .pixel_clock = 40000000,
465 .conf = {
466 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
467 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
468 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
469 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
470 },
471 },
472 {
473 .pixel_clock = 65000000,
474 .conf = {
475 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
476 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
477 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
478 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
479 },
480 },
481 {
482 .pixel_clock = 71000000,
483 .conf = {
484 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
485 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
486 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
487 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
488 },
489 },
490 {
491 .pixel_clock = 73250000,
492 .conf = {
493 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
494 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
495 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
496 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
497 },
498 },
499 {
500 .pixel_clock = 74176000,
501 .conf = {
502 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
503 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
504 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
505 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
506 },
507 },
508 {
509 .pixel_clock = 74250000,
510 .conf = {
511 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
512 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
513 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
514 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
515 },
516 },
517 {
518 .pixel_clock = 83500000,
519 .conf = {
520 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
521 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
522 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
523 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
524 },
525 },
526 {
527 .pixel_clock = 88750000,
528 .conf = {
529 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
530 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
531 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
532 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
533 },
534 },
535 {
536 .pixel_clock = 106500000,
537 .conf = {
538 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
539 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
540 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
541 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
542 },
543 },
544 {
545 .pixel_clock = 108000000,
546 .conf = {
547 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
548 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
549 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
550 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
551 },
552 },
553 {
554 .pixel_clock = 115500000,
555 .conf = {
556 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
557 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
558 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
559 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
560 },
561 },
562 {
563 .pixel_clock = 146250000,
564 .conf = {
565 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
566 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
567 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
568 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
569 },
570 },
571 {
572 .pixel_clock = 148500000,
573 .conf = {
574 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
575 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
576 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
577 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
578 },
579 },
580};
581
Sachin Kamat16337072014-05-22 10:32:56 +0530582static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530583 .type = HDMI_TYPE14,
584 .phy_confs = hdmiphy_5420_configs,
585 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
586 .is_apb_phy = 1,
587};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900588
Sachin Kamat16337072014-05-22 10:32:56 +0530589static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900590 .type = HDMI_TYPE14,
591 .phy_confs = hdmiphy_v14_configs,
592 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
593 .is_apb_phy = 0,
594};
595
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200596static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
597 .type = HDMI_TYPE13,
598 .phy_confs = hdmiphy_v13_configs,
599 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
600 .is_apb_phy = 0,
601};
602
Sachin Kamat16337072014-05-22 10:32:56 +0530603static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900604 .type = HDMI_TYPE14,
605 .phy_confs = hdmiphy_v13_configs,
606 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
607 .is_apb_phy = 0,
608};
609
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
611{
612 return readl(hdata->regs + reg_id);
613}
614
615static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
616 u32 reg_id, u8 value)
617{
618 writeb(value, hdata->regs + reg_id);
619}
620
621static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
622 u32 reg_id, u32 value, u32 mask)
623{
624 u32 old = readl(hdata->regs + reg_id);
625 value = (value & mask) | (old & ~mask);
626 writel(value, hdata->regs + reg_id);
627}
628
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900629static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
630 u32 reg_offset, u8 value)
631{
632 if (hdata->hdmiphy_port) {
633 u8 buffer[2];
634 int ret;
635
636 buffer[0] = reg_offset;
637 buffer[1] = value;
638
639 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
640 if (ret == 2)
641 return 0;
642 return ret;
643 } else {
644 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
645 return 0;
646 }
647}
648
649static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
650 u32 reg_offset, const u8 *buf, u32 len)
651{
652 if ((reg_offset + len) > 32)
653 return -EINVAL;
654
655 if (hdata->hdmiphy_port) {
656 int ret;
657
658 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
659 if (ret == len)
660 return 0;
661 return ret;
662 } else {
663 int i;
664 for (i = 0; i < len; i++)
665 writeb(buf[i], hdata->regs_hdmiphy +
666 ((reg_offset + i)<<2));
667 return 0;
668 }
669}
670
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900671static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900672{
673#define DUMPREG(reg_id) \
674 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
675 readl(hdata->regs + reg_id))
676 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
677 DUMPREG(HDMI_INTC_FLAG);
678 DUMPREG(HDMI_INTC_CON);
679 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900680 DUMPREG(HDMI_V13_PHY_RSTOUT);
681 DUMPREG(HDMI_V13_PHY_VPLL);
682 DUMPREG(HDMI_V13_PHY_CMU);
683 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900684
685 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
686 DUMPREG(HDMI_CON_0);
687 DUMPREG(HDMI_CON_1);
688 DUMPREG(HDMI_CON_2);
689 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900690 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900691 DUMPREG(HDMI_STATUS_EN);
692 DUMPREG(HDMI_HPD);
693 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900694 DUMPREG(HDMI_V13_HPD_GEN);
695 DUMPREG(HDMI_V13_DC_CONTROL);
696 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900697
698 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
699 DUMPREG(HDMI_H_BLANK_0);
700 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900701 DUMPREG(HDMI_V13_V_BLANK_0);
702 DUMPREG(HDMI_V13_V_BLANK_1);
703 DUMPREG(HDMI_V13_V_BLANK_2);
704 DUMPREG(HDMI_V13_H_V_LINE_0);
705 DUMPREG(HDMI_V13_H_V_LINE_1);
706 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900707 DUMPREG(HDMI_VSYNC_POL);
708 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900709 DUMPREG(HDMI_V13_V_BLANK_F_0);
710 DUMPREG(HDMI_V13_V_BLANK_F_1);
711 DUMPREG(HDMI_V13_V_BLANK_F_2);
712 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
713 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
714 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
715 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
716 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
717 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
718 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
719 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
720 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
721 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
722 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
723 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900724
725 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
726 DUMPREG(HDMI_TG_CMD);
727 DUMPREG(HDMI_TG_H_FSZ_L);
728 DUMPREG(HDMI_TG_H_FSZ_H);
729 DUMPREG(HDMI_TG_HACT_ST_L);
730 DUMPREG(HDMI_TG_HACT_ST_H);
731 DUMPREG(HDMI_TG_HACT_SZ_L);
732 DUMPREG(HDMI_TG_HACT_SZ_H);
733 DUMPREG(HDMI_TG_V_FSZ_L);
734 DUMPREG(HDMI_TG_V_FSZ_H);
735 DUMPREG(HDMI_TG_VSYNC_L);
736 DUMPREG(HDMI_TG_VSYNC_H);
737 DUMPREG(HDMI_TG_VSYNC2_L);
738 DUMPREG(HDMI_TG_VSYNC2_H);
739 DUMPREG(HDMI_TG_VACT_ST_L);
740 DUMPREG(HDMI_TG_VACT_ST_H);
741 DUMPREG(HDMI_TG_VACT_SZ_L);
742 DUMPREG(HDMI_TG_VACT_SZ_H);
743 DUMPREG(HDMI_TG_FIELD_CHG_L);
744 DUMPREG(HDMI_TG_FIELD_CHG_H);
745 DUMPREG(HDMI_TG_VACT_ST2_L);
746 DUMPREG(HDMI_TG_VACT_ST2_H);
747 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
748 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
749 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
750 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
751 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
752 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
753 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
754 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
755#undef DUMPREG
756}
757
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900758static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
759{
760 int i;
761
762#define DUMPREG(reg_id) \
763 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
764 readl(hdata->regs + reg_id))
765
766 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
767 DUMPREG(HDMI_INTC_CON);
768 DUMPREG(HDMI_INTC_FLAG);
769 DUMPREG(HDMI_HPD_STATUS);
770 DUMPREG(HDMI_INTC_CON_1);
771 DUMPREG(HDMI_INTC_FLAG_1);
772 DUMPREG(HDMI_PHY_STATUS_0);
773 DUMPREG(HDMI_PHY_STATUS_PLL);
774 DUMPREG(HDMI_PHY_CON_0);
775 DUMPREG(HDMI_PHY_RSTOUT);
776 DUMPREG(HDMI_PHY_VPLL);
777 DUMPREG(HDMI_PHY_CMU);
778 DUMPREG(HDMI_CORE_RSTOUT);
779
780 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
781 DUMPREG(HDMI_CON_0);
782 DUMPREG(HDMI_CON_1);
783 DUMPREG(HDMI_CON_2);
784 DUMPREG(HDMI_SYS_STATUS);
785 DUMPREG(HDMI_PHY_STATUS_0);
786 DUMPREG(HDMI_STATUS_EN);
787 DUMPREG(HDMI_HPD);
788 DUMPREG(HDMI_MODE_SEL);
789 DUMPREG(HDMI_ENC_EN);
790 DUMPREG(HDMI_DC_CONTROL);
791 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
792
793 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
794 DUMPREG(HDMI_H_BLANK_0);
795 DUMPREG(HDMI_H_BLANK_1);
796 DUMPREG(HDMI_V2_BLANK_0);
797 DUMPREG(HDMI_V2_BLANK_1);
798 DUMPREG(HDMI_V1_BLANK_0);
799 DUMPREG(HDMI_V1_BLANK_1);
800 DUMPREG(HDMI_V_LINE_0);
801 DUMPREG(HDMI_V_LINE_1);
802 DUMPREG(HDMI_H_LINE_0);
803 DUMPREG(HDMI_H_LINE_1);
804 DUMPREG(HDMI_HSYNC_POL);
805
806 DUMPREG(HDMI_VSYNC_POL);
807 DUMPREG(HDMI_INT_PRO_MODE);
808 DUMPREG(HDMI_V_BLANK_F0_0);
809 DUMPREG(HDMI_V_BLANK_F0_1);
810 DUMPREG(HDMI_V_BLANK_F1_0);
811 DUMPREG(HDMI_V_BLANK_F1_1);
812
813 DUMPREG(HDMI_H_SYNC_START_0);
814 DUMPREG(HDMI_H_SYNC_START_1);
815 DUMPREG(HDMI_H_SYNC_END_0);
816 DUMPREG(HDMI_H_SYNC_END_1);
817
818 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
819 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
820 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
821 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
822
823 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
824 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
825 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
826 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
827
828 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
829 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
830 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
831 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
832
833 DUMPREG(HDMI_V_BLANK_F2_0);
834 DUMPREG(HDMI_V_BLANK_F2_1);
835 DUMPREG(HDMI_V_BLANK_F3_0);
836 DUMPREG(HDMI_V_BLANK_F3_1);
837 DUMPREG(HDMI_V_BLANK_F4_0);
838 DUMPREG(HDMI_V_BLANK_F4_1);
839 DUMPREG(HDMI_V_BLANK_F5_0);
840 DUMPREG(HDMI_V_BLANK_F5_1);
841
842 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
843 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
844 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
845 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
846 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
850
851 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
852 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
853 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
854 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
855 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
856 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
857 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
858 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
859
860 DUMPREG(HDMI_VACT_SPACE_1_0);
861 DUMPREG(HDMI_VACT_SPACE_1_1);
862 DUMPREG(HDMI_VACT_SPACE_2_0);
863 DUMPREG(HDMI_VACT_SPACE_2_1);
864 DUMPREG(HDMI_VACT_SPACE_3_0);
865 DUMPREG(HDMI_VACT_SPACE_3_1);
866 DUMPREG(HDMI_VACT_SPACE_4_0);
867 DUMPREG(HDMI_VACT_SPACE_4_1);
868 DUMPREG(HDMI_VACT_SPACE_5_0);
869 DUMPREG(HDMI_VACT_SPACE_5_1);
870 DUMPREG(HDMI_VACT_SPACE_6_0);
871 DUMPREG(HDMI_VACT_SPACE_6_1);
872
873 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
874 DUMPREG(HDMI_TG_CMD);
875 DUMPREG(HDMI_TG_H_FSZ_L);
876 DUMPREG(HDMI_TG_H_FSZ_H);
877 DUMPREG(HDMI_TG_HACT_ST_L);
878 DUMPREG(HDMI_TG_HACT_ST_H);
879 DUMPREG(HDMI_TG_HACT_SZ_L);
880 DUMPREG(HDMI_TG_HACT_SZ_H);
881 DUMPREG(HDMI_TG_V_FSZ_L);
882 DUMPREG(HDMI_TG_V_FSZ_H);
883 DUMPREG(HDMI_TG_VSYNC_L);
884 DUMPREG(HDMI_TG_VSYNC_H);
885 DUMPREG(HDMI_TG_VSYNC2_L);
886 DUMPREG(HDMI_TG_VSYNC2_H);
887 DUMPREG(HDMI_TG_VACT_ST_L);
888 DUMPREG(HDMI_TG_VACT_ST_H);
889 DUMPREG(HDMI_TG_VACT_SZ_L);
890 DUMPREG(HDMI_TG_VACT_SZ_H);
891 DUMPREG(HDMI_TG_FIELD_CHG_L);
892 DUMPREG(HDMI_TG_FIELD_CHG_H);
893 DUMPREG(HDMI_TG_VACT_ST2_L);
894 DUMPREG(HDMI_TG_VACT_ST2_H);
895 DUMPREG(HDMI_TG_VACT_ST3_L);
896 DUMPREG(HDMI_TG_VACT_ST3_H);
897 DUMPREG(HDMI_TG_VACT_ST4_L);
898 DUMPREG(HDMI_TG_VACT_ST4_H);
899 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
900 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
901 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
902 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
903 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
904 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
905 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
906 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
907 DUMPREG(HDMI_TG_3D);
908
909 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
910 DUMPREG(HDMI_AVI_CON);
911 DUMPREG(HDMI_AVI_HEADER0);
912 DUMPREG(HDMI_AVI_HEADER1);
913 DUMPREG(HDMI_AVI_HEADER2);
914 DUMPREG(HDMI_AVI_CHECK_SUM);
915 DUMPREG(HDMI_VSI_CON);
916 DUMPREG(HDMI_VSI_HEADER0);
917 DUMPREG(HDMI_VSI_HEADER1);
918 DUMPREG(HDMI_VSI_HEADER2);
919 for (i = 0; i < 7; ++i)
920 DUMPREG(HDMI_VSI_DATA(i));
921
922#undef DUMPREG
923}
924
925static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
926{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200927 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900928 hdmi_v13_regs_dump(hdata, prefix);
929 else
930 hdmi_v14_regs_dump(hdata, prefix);
931}
932
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530933static u8 hdmi_chksum(struct hdmi_context *hdata,
934 u32 start, u8 len, u32 hdr_sum)
935{
936 int i;
937
938 /* hdr_sum : header0 + header1 + header2
939 * start : start address of packet byte1
940 * len : packet bytes - 1 */
941 for (i = 0; i < len; ++i)
942 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
943
944 /* return 2's complement of 8 bit hdr_sum */
945 return (u8)(~(hdr_sum & 0xff) + 1);
946}
947
948static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530949 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530950{
951 u32 hdr_sum;
952 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530953 u32 mod;
954 u32 vic;
955
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530956 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
957 if (hdata->dvi_mode) {
958 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
959 HDMI_VSI_CON_DO_NOT_TRANSMIT);
960 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
961 HDMI_AVI_CON_DO_NOT_TRANSMIT);
962 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
963 return;
964 }
965
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530966 switch (infoframe->any.type) {
967 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530968 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530969 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
970 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
971 infoframe->any.version);
972 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
973 hdr_sum = infoframe->any.type + infoframe->any.version +
974 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530975
976 /* Output format zero hardcoded ,RGB YBCR selection */
977 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
978 AVI_ACTIVE_FORMAT_VALID |
979 AVI_UNDERSCANNED_DISPLAY_VALID);
980
Shirish S46154152014-03-13 10:58:28 +0530981 /*
982 * Set the aspect ratio as per the mode, mentioned in
983 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
984 */
985 switch (hdata->mode_conf.aspect_ratio) {
986 case HDMI_PICTURE_ASPECT_4_3:
987 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
988 hdata->mode_conf.aspect_ratio |
989 AVI_4_3_CENTER_RATIO);
990 break;
991 case HDMI_PICTURE_ASPECT_16_9:
992 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
993 hdata->mode_conf.aspect_ratio |
994 AVI_16_9_CENTER_RATIO);
995 break;
996 case HDMI_PICTURE_ASPECT_NONE:
997 default:
998 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
999 hdata->mode_conf.aspect_ratio |
1000 AVI_SAME_AS_PIC_ASPECT_RATIO);
1001 break;
1002 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301003
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001004 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301005 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
1006
1007 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301008 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301009 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1010 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1011 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301012 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301013 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301014 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1015 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1016 infoframe->any.version);
1017 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1018 hdr_sum = infoframe->any.type + infoframe->any.version +
1019 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301020 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301021 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301022 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1023 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1024 break;
1025 default:
1026 break;
1027 }
1028}
1029
Sean Pauld9716ee2014-01-30 16:19:29 -05001030static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1031 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001032{
Sean Pauld9716ee2014-01-30 16:19:29 -05001033 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001034
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001035 if (gpio_get_value(hdata->hpd_gpio))
1036 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301037
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001038 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001039}
1040
Sean Pauld9716ee2014-01-30 16:19:29 -05001041static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001042{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001043 drm_connector_unregister(connector);
1044 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001045}
1046
Sean Pauld9716ee2014-01-30 16:19:29 -05001047static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001048 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001049 .fill_modes = drm_helper_probe_single_connector_modes,
1050 .detect = hdmi_detect,
1051 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001052 .reset = drm_atomic_helper_connector_reset,
1053 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1054 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001055};
1056
1057static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001058{
Sean Pauld9716ee2014-01-30 16:19:29 -05001059 struct hdmi_context *hdata = ctx_from_connector(connector);
1060 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001061 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001062
Inki Dae8fa04aa2014-03-13 16:38:31 +09001063 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001064 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001065
Inki Dae8fa04aa2014-03-13 16:38:31 +09001066 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001067 if (!edid)
1068 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001069
Sean Pauld9716ee2014-01-30 16:19:29 -05001070 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001071 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1072 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001073 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001074
Sean Pauld9716ee2014-01-30 16:19:29 -05001075 drm_mode_connector_update_edid_property(connector, edid);
1076
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001077 ret = drm_add_edid_modes(connector, edid);
1078
1079 kfree(edid);
1080
1081 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001082}
1083
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001084static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001085{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001086 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001087
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001088 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1089 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001090 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001091
1092 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1093 return -EINVAL;
1094}
1095
Sean Pauld9716ee2014-01-30 16:19:29 -05001096static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001097 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001098{
Sean Pauld9716ee2014-01-30 16:19:29 -05001099 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001100 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001101
Rahul Sharma16844fb2013-06-10 14:50:00 +05301102 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1103 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1104 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1105 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001106
Sean Paulf041b252014-01-30 16:19:15 -05001107 ret = mixer_check_mode(mode);
1108 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001109 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001110
Rahul Sharma16844fb2013-06-10 14:50:00 +05301111 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001112 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001113 return MODE_BAD;
1114
1115 return MODE_OK;
1116}
1117
1118static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1119{
1120 struct hdmi_context *hdata = ctx_from_connector(connector);
1121
1122 return hdata->encoder;
1123}
1124
1125static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1126 .get_modes = hdmi_get_modes,
1127 .mode_valid = hdmi_mode_valid,
1128 .best_encoder = hdmi_best_encoder,
1129};
1130
1131static int hdmi_create_connector(struct exynos_drm_display *display,
1132 struct drm_encoder *encoder)
1133{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001134 struct hdmi_context *hdata = display_to_hdmi(display);
Sean Pauld9716ee2014-01-30 16:19:29 -05001135 struct drm_connector *connector = &hdata->connector;
1136 int ret;
1137
1138 hdata->encoder = encoder;
1139 connector->interlace_allowed = true;
1140 connector->polled = DRM_CONNECTOR_POLL_HPD;
1141
1142 ret = drm_connector_init(hdata->drm_dev, connector,
1143 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1144 if (ret) {
1145 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001146 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001147 }
1148
1149 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001150 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001151 drm_mode_connector_attach_encoder(connector, encoder);
1152
1153 return 0;
1154}
1155
Sean Paulf041b252014-01-30 16:19:15 -05001156static void hdmi_mode_fixup(struct exynos_drm_display *display,
1157 struct drm_connector *connector,
1158 const struct drm_display_mode *mode,
1159 struct drm_display_mode *adjusted_mode)
1160{
1161 struct drm_display_mode *m;
1162 int mode_ok;
1163
1164 DRM_DEBUG_KMS("%s\n", __FILE__);
1165
1166 drm_mode_set_crtcinfo(adjusted_mode, 0);
1167
Sean Pauld9716ee2014-01-30 16:19:29 -05001168 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001169
1170 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001171 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001172 return;
1173
1174 /*
1175 * otherwise, find the most suitable mode among modes and change it
1176 * to adjusted_mode.
1177 */
1178 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001179 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001180
Sean Pauld9716ee2014-01-30 16:19:29 -05001181 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001182 DRM_INFO("desired mode doesn't exist so\n");
1183 DRM_INFO("use the most suitable mode among modes.\n");
1184
1185 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1186 m->hdisplay, m->vdisplay, m->vrefresh);
1187
Sean Paul75626852014-01-30 16:19:16 -05001188 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001189 break;
1190 }
1191 }
1192}
1193
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001194static void hdmi_set_acr(u32 freq, u8 *acr)
1195{
1196 u32 n, cts;
1197
1198 switch (freq) {
1199 case 32000:
1200 n = 4096;
1201 cts = 27000;
1202 break;
1203 case 44100:
1204 n = 6272;
1205 cts = 30000;
1206 break;
1207 case 88200:
1208 n = 12544;
1209 cts = 30000;
1210 break;
1211 case 176400:
1212 n = 25088;
1213 cts = 30000;
1214 break;
1215 case 48000:
1216 n = 6144;
1217 cts = 27000;
1218 break;
1219 case 96000:
1220 n = 12288;
1221 cts = 27000;
1222 break;
1223 case 192000:
1224 n = 24576;
1225 cts = 27000;
1226 break;
1227 default:
1228 n = 0;
1229 cts = 0;
1230 break;
1231 }
1232
1233 acr[1] = cts >> 16;
1234 acr[2] = cts >> 8 & 0xff;
1235 acr[3] = cts & 0xff;
1236
1237 acr[4] = n >> 16;
1238 acr[5] = n >> 8 & 0xff;
1239 acr[6] = n & 0xff;
1240}
1241
1242static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1243{
1244 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1245 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1246 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1247 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1248 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1249 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1250 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1251 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1252 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1253
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001254 if (hdata->drv_data->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001255 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1256 else
1257 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1258}
1259
1260static void hdmi_audio_init(struct hdmi_context *hdata)
1261{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301262 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001263 u32 data_num, bit_ch, sample_frq;
1264 u32 val;
1265 u8 acr[7];
1266
1267 sample_rate = 44100;
1268 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001269
1270 switch (bits_per_sample) {
1271 case 20:
1272 data_num = 2;
1273 bit_ch = 1;
1274 break;
1275 case 24:
1276 data_num = 3;
1277 bit_ch = 1;
1278 break;
1279 default:
1280 data_num = 1;
1281 bit_ch = 0;
1282 break;
1283 }
1284
1285 hdmi_set_acr(sample_rate, acr);
1286 hdmi_reg_acr(hdata, acr);
1287
1288 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1289 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1290 | HDMI_I2S_MUX_ENABLE);
1291
1292 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1293 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1294
1295 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1296
1297 sample_frq = (sample_rate == 44100) ? 0 :
1298 (sample_rate == 48000) ? 2 :
1299 (sample_rate == 32000) ? 3 :
1300 (sample_rate == 96000) ? 0xa : 0x0;
1301
1302 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1303 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1304
1305 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1306 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1307
1308 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1309 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1310 | HDMI_I2S_SEL_LRCK(6));
1311 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1312 | HDMI_I2S_SEL_SDATA2(4));
1313 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1314 | HDMI_I2S_SEL_SDATA2(2));
1315 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1316
1317 /* I2S_CON_1 & 2 */
1318 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1319 | HDMI_I2S_L_CH_LOW_POL);
1320 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1321 | HDMI_I2S_SET_BIT_CH(bit_ch)
1322 | HDMI_I2S_SET_SDATA_BIT(data_num)
1323 | HDMI_I2S_BASIC_FORMAT);
1324
1325 /* Configure register related to CUV information */
1326 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1327 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1328 | HDMI_I2S_COPYRIGHT
1329 | HDMI_I2S_LINEAR_PCM
1330 | HDMI_I2S_CONSUMER_FORMAT);
1331 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1332 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1333 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1334 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1335 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1336 HDMI_I2S_ORG_SMP_FREQ_44_1
1337 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1338 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1339
1340 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1341}
1342
1343static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1344{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001345 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001346 return;
1347
1348 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1349 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1350 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1351}
1352
Rahul Sharmabfa48422014-04-03 20:41:04 +05301353static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001354{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301355 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001356
Rahul Sharmabfa48422014-04-03 20:41:04 +05301357 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1358 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001359
Rahul Sharmabfa48422014-04-03 20:41:04 +05301360 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1361 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001362}
1363
1364static void hdmi_conf_init(struct hdmi_context *hdata)
1365{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301366 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301367
Sean Paul77006a72013-01-16 10:17:20 -05001368 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001369 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1370 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001371
1372 /* choose HDMI mode */
1373 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1374 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301375 /* Apply Video preable and Guard band in HDMI mode only */
1376 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001377 /* disable bluescreen */
1378 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001379
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001380 if (hdata->dvi_mode) {
1381 /* choose DVI mode */
1382 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1383 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1384 hdmi_reg_writeb(hdata, HDMI_CON_2,
1385 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1386 }
1387
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001388 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001389 /* choose bluescreen (fecal) color */
1390 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1391 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1392 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1393
1394 /* enable AVI packet every vsync, fixes purple line problem */
1395 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1396 /* force RGB, look to CEA-861-D, table 7 for more detail */
1397 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1398 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1399
1400 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1401 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1402 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1403 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301404 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1405 infoframe.any.version = HDMI_AVI_VERSION;
1406 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301407 hdmi_reg_infoframe(hdata, &infoframe);
1408
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301409 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1410 infoframe.any.version = HDMI_AUI_VERSION;
1411 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301412 hdmi_reg_infoframe(hdata, &infoframe);
1413
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001414 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001415 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1416 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001417}
1418
Rahul Sharma16844fb2013-06-10 14:50:00 +05301419static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001420{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001421 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1422 const struct hdmi_v13_core_regs *core =
1423 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001424 int tries;
1425
1426 /* setting core registers */
1427 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1428 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001429 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1430 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1431 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1432 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1433 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1434 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001435 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1436 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001437 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1438 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1439 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1440 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1441 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1442 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1443 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1444 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1445 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1446 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1447 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1448 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1449 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1450 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1451 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001452 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001453 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1454 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1455 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1456 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1457 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1463 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1464 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1465 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1466 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1467 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1468 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1469 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1470 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1471 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1472 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1473 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1474 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1475 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1476 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1477 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1478 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1479 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1480 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001481
1482 /* waiting for HDMIPHY's PLL to get to steady state */
1483 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001484 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001485 if (val & HDMI_PHY_STATUS_READY)
1486 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001487 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001488 }
1489 /* steady state not achieved */
1490 if (tries == 0) {
1491 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1492 hdmi_regs_dump(hdata, "timing apply");
1493 }
1494
Sean Paul0bfb1f82013-06-11 12:24:02 +05301495 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301496 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301497 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001498
1499 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301500 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001501}
1502
Rahul Sharma16844fb2013-06-10 14:50:00 +05301503static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001504{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001505 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1506 const struct hdmi_v14_core_regs *core =
1507 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001508 int tries;
1509
1510 /* setting core registers */
1511 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1512 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1513 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1514 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1515 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1516 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1517 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1518 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1519 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1520 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1521 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1522 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1523 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1524 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1525 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1526 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1527 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1528 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1529 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1530 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1531 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1532 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1533 core->v_sync_line_bef_2[0]);
1534 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1535 core->v_sync_line_bef_2[1]);
1536 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1537 core->v_sync_line_bef_1[0]);
1538 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1539 core->v_sync_line_bef_1[1]);
1540 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1541 core->v_sync_line_aft_2[0]);
1542 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1543 core->v_sync_line_aft_2[1]);
1544 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1545 core->v_sync_line_aft_1[0]);
1546 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1547 core->v_sync_line_aft_1[1]);
1548 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1549 core->v_sync_line_aft_pxl_2[0]);
1550 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1551 core->v_sync_line_aft_pxl_2[1]);
1552 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1553 core->v_sync_line_aft_pxl_1[0]);
1554 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1555 core->v_sync_line_aft_pxl_1[1]);
1556 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1557 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1558 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1559 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1560 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1561 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1562 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1563 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1564 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1565 core->v_sync_line_aft_3[0]);
1566 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1567 core->v_sync_line_aft_3[1]);
1568 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1569 core->v_sync_line_aft_4[0]);
1570 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1571 core->v_sync_line_aft_4[1]);
1572 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1573 core->v_sync_line_aft_5[0]);
1574 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1575 core->v_sync_line_aft_5[1]);
1576 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1577 core->v_sync_line_aft_6[0]);
1578 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1579 core->v_sync_line_aft_6[1]);
1580 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1581 core->v_sync_line_aft_pxl_3[0]);
1582 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1583 core->v_sync_line_aft_pxl_3[1]);
1584 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1585 core->v_sync_line_aft_pxl_4[0]);
1586 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1587 core->v_sync_line_aft_pxl_4[1]);
1588 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1589 core->v_sync_line_aft_pxl_5[0]);
1590 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1591 core->v_sync_line_aft_pxl_5[1]);
1592 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1593 core->v_sync_line_aft_pxl_6[0]);
1594 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1595 core->v_sync_line_aft_pxl_6[1]);
1596 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1597 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1598 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1599 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1600 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1601 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1602 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1603 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1604 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1605 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1606 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1607 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1608
1609 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001610 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1611 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1612 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1613 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1614 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1615 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1626 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1627 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1628 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1629 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1630 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1631 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1632 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1633 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1634 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1635 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1636 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1637 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1638 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1639 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1640 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1641 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1642 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001643
1644 /* waiting for HDMIPHY's PLL to get to steady state */
1645 for (tries = 100; tries; --tries) {
1646 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1647 if (val & HDMI_PHY_STATUS_READY)
1648 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001649 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001650 }
1651 /* steady state not achieved */
1652 if (tries == 0) {
1653 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1654 hdmi_regs_dump(hdata, "timing apply");
1655 }
1656
Sean Paul0bfb1f82013-06-11 12:24:02 +05301657 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301658 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301659 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001660
1661 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301662 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001663}
1664
Rahul Sharma16844fb2013-06-10 14:50:00 +05301665static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001666{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001667 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301668 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001669 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301670 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001671}
1672
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001673static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1674{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001675 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001676
Sean Paul0bfb1f82013-06-11 12:24:02 +05301677 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301678 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301679 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001680
1681 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001682 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1683 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001684
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001685 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001686 reg = HDMI_V13_PHY_RSTOUT;
1687 else
1688 reg = HDMI_PHY_RSTOUT;
1689
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001690 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001691 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001692 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001693 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001694 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001695}
1696
Rahul Sharmaa5562252012-11-28 11:30:25 +05301697static void hdmiphy_poweron(struct hdmi_context *hdata)
1698{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001699 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301700 return;
1701
1702 DRM_DEBUG_KMS("\n");
1703
1704 /* For PHY Mode Setting */
1705 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1706 HDMI_PHY_ENABLE_MODE_SET);
1707 /* Phy Power On */
1708 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1709 HDMI_PHY_POWER_ON);
1710 /* For PHY Mode Setting */
1711 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1712 HDMI_PHY_DISABLE_MODE_SET);
1713 /* PHY SW Reset */
1714 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301715}
1716
1717static void hdmiphy_poweroff(struct hdmi_context *hdata)
1718{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001719 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301720 return;
1721
1722 DRM_DEBUG_KMS("\n");
1723
1724 /* PHY SW Reset */
1725 hdmiphy_conf_reset(hdata);
1726 /* For PHY Mode Setting */
1727 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1728 HDMI_PHY_ENABLE_MODE_SET);
1729
1730 /* PHY Power Off */
1731 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1732 HDMI_PHY_POWER_OFF);
1733
1734 /* For PHY Mode Setting */
1735 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1736 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301737}
1738
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001739static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1740{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001741 int ret;
1742 int i;
1743
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001744 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001745 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1746 if (i < 0) {
1747 DRM_ERROR("failed to find hdmiphy conf\n");
1748 return;
1749 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001750
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001751 ret = hdmiphy_reg_write_buf(hdata, 0,
1752 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001753 if (ret) {
1754 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001755 return;
1756 }
1757
Sean Paul09760ea2013-01-14 17:03:20 -05001758 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001759
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001760 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1761 HDMI_PHY_DISABLE_MODE_SET);
1762 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001763 DRM_ERROR("failed to enable hdmiphy\n");
1764 return;
1765 }
1766
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001767}
1768
1769static void hdmi_conf_apply(struct hdmi_context *hdata)
1770{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001771 hdmiphy_conf_reset(hdata);
1772 hdmiphy_conf_apply(hdata);
1773
Rahul Sharmabfa48422014-04-03 20:41:04 +05301774 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001775 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001776
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001777 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001778
1779 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301780 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001781 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001782
1783 hdmi_regs_dump(hdata, "start");
1784}
1785
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001786static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1787{
1788 int i;
1789 BUG_ON(num_bytes > 4);
1790 for (i = 0; i < num_bytes; i++)
1791 reg_pair[i] = (value >> (8 * i)) & 0xff;
1792}
1793
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001794static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1795 struct drm_display_mode *m)
1796{
1797 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1798 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1799 unsigned int val;
1800
1801 hdata->mode_conf.cea_video_id =
1802 drm_match_cea_mode((struct drm_display_mode *)m);
1803 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301804 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001805
1806 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1807 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1808
1809 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1810 hdmi_set_reg(core->vsync_pol, 1, val);
1811
1812 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1813 hdmi_set_reg(core->int_pro_mode, 1, val);
1814
1815 val = (m->hsync_start - m->hdisplay - 2);
1816 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1817 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1818 hdmi_set_reg(core->h_sync_gen, 3, val);
1819
1820 /*
1821 * Quirk requirement for exynos HDMI IP design,
1822 * 2 pixels less than the actual calculation for hsync_start
1823 * and end.
1824 */
1825
1826 /* Following values & calculations differ for different type of modes */
1827 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1828 /* Interlaced Mode */
1829 val = ((m->vsync_end - m->vdisplay) / 2);
1830 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1831 hdmi_set_reg(core->v_sync_gen1, 3, val);
1832
1833 val = m->vtotal / 2;
1834 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1835 hdmi_set_reg(core->v_blank, 3, val);
1836
1837 val = (m->vtotal +
1838 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1839 val |= m->vtotal << 11;
1840 hdmi_set_reg(core->v_blank_f, 3, val);
1841
1842 val = ((m->vtotal / 2) + 7);
1843 val |= ((m->vtotal / 2) + 2) << 12;
1844 hdmi_set_reg(core->v_sync_gen2, 3, val);
1845
1846 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1847 val |= ((m->htotal / 2) +
1848 (m->hsync_start - m->hdisplay)) << 12;
1849 hdmi_set_reg(core->v_sync_gen3, 3, val);
1850
1851 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1852 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1853
1854 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1855 } else {
1856 /* Progressive Mode */
1857
1858 val = m->vtotal;
1859 val |= (m->vtotal - m->vdisplay) << 11;
1860 hdmi_set_reg(core->v_blank, 3, val);
1861
1862 hdmi_set_reg(core->v_blank_f, 3, 0);
1863
1864 val = (m->vsync_end - m->vdisplay);
1865 val |= ((m->vsync_start - m->vdisplay) << 12);
1866 hdmi_set_reg(core->v_sync_gen1, 3, val);
1867
1868 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1869 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1870 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1871 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1872 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1873 }
1874
1875 /* Timing generator registers */
1876 hdmi_set_reg(tg->cmd, 1, 0x0);
1877 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1878 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1879 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1880 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1881 hdmi_set_reg(tg->vsync, 2, 0x1);
1882 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1883 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1884 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1885 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1886 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1887 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1888 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1889}
1890
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001891static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1892 struct drm_display_mode *m)
1893{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001894 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1895 struct hdmi_v14_core_regs *core =
1896 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001897
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001898 hdata->mode_conf.cea_video_id =
1899 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001900 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301901 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001902
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001903 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1904 hdmi_set_reg(core->v_line, 2, m->vtotal);
1905 hdmi_set_reg(core->h_line, 2, m->htotal);
1906 hdmi_set_reg(core->hsync_pol, 1,
1907 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1908 hdmi_set_reg(core->vsync_pol, 1,
1909 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1910 hdmi_set_reg(core->int_pro_mode, 1,
1911 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1912
1913 /*
1914 * Quirk requirement for exynos 5 HDMI IP design,
1915 * 2 pixels less than the actual calculation for hsync_start
1916 * and end.
1917 */
1918
1919 /* Following values & calculations differ for different type of modes */
1920 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1921 /* Interlaced Mode */
1922 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1923 (m->vsync_end - m->vdisplay) / 2);
1924 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1925 (m->vsync_start - m->vdisplay) / 2);
1926 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1927 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301928 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001929 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1930 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1931 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1932 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1933 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1934 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1935 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1936 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1937 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301938 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1939 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1940 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1941 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001942 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1943 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1944 } else {
1945 /* Progressive Mode */
1946 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1947 m->vsync_end - m->vdisplay);
1948 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1949 m->vsync_start - m->vdisplay);
1950 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1951 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1952 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1953 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1954 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1955 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1956 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1957 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1958 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1959 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1960 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1961 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1962 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301963 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1964 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1965 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001966 }
1967
1968 /* Following values & calculations are same irrespective of mode type */
1969 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1970 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1971 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1972 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1973 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1974 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1975 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1976 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1977 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1978 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1979 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1980 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1981 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1982 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1983 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1984 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1985 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1986 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1987 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1988 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1989
1990 /* Timing generator registers */
1991 hdmi_set_reg(tg->cmd, 1, 0x0);
1992 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1993 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1994 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1995 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1996 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001997 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1998 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001999 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002000 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002001}
2002
Sean Paulf041b252014-01-30 16:19:15 -05002003static void hdmi_mode_set(struct exynos_drm_display *display,
2004 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002005{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002006 struct hdmi_context *hdata = display_to_hdmi(display);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002007 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002008
YoungJun Chocbc4c332013-06-12 10:44:40 +09002009 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
2010 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002011 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02002012 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002013
Rahul Sharmabfa48422014-04-03 20:41:04 +05302014 /* preserve mode information for later use. */
2015 drm_mode_copy(&hdata->current_mode, mode);
2016
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002017 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002018 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302019 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002020 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002021}
2022
Sean Paulf041b252014-01-30 16:19:15 -05002023static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002024{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002025 struct hdmi_context *hdata = display_to_hdmi(display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002026
Andrzej Hajda882a0642015-07-09 16:28:08 +02002027 if (!hdata->powered)
Shirish Sdda90122013-01-23 22:03:18 -05002028 return;
Shirish Sdda90122013-01-23 22:03:18 -05002029
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002030 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002031}
2032
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002033static void hdmi_poweron(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002034{
2035 struct hdmi_resources *res = &hdata->res;
2036
Andrzej Hajda882a0642015-07-09 16:28:08 +02002037 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002038 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002039
2040 hdata->powered = true;
2041
Sean Paulaf65c802014-01-30 16:19:27 -05002042 pm_runtime_get_sync(hdata->dev);
2043
Seung-Woo Kimad079452013-06-05 14:34:38 +09002044 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2045 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2046
Rahul Sharma049d34e2014-05-20 10:36:05 +05302047 /* set pmu hdmiphy control bit to enable hdmiphy */
2048 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2049 PMU_HDMI_PHY_ENABLE_BIT, 1);
2050
Sean Paul0bfb1f82013-06-11 12:24:02 +05302051 clk_prepare_enable(res->hdmi);
2052 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302053
2054 hdmiphy_poweron(hdata);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002055 hdmi_commit(&hdata->display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002056}
2057
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002058static void hdmi_poweroff(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002059{
2060 struct hdmi_resources *res = &hdata->res;
2061
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002062 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02002063 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002064
Rahul Sharmabfa48422014-04-03 20:41:04 +05302065 /* HDMI System Disable */
2066 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2067
Rahul Sharmaa5562252012-11-28 11:30:25 +05302068 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002069
Sean Paul724fd142014-05-09 15:05:10 +09002070 cancel_delayed_work(&hdata->hotplug_work);
2071
Sean Paul0bfb1f82013-06-11 12:24:02 +05302072 clk_disable_unprepare(res->sclk_hdmi);
2073 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302074
2075 /* reset pmu hdmiphy control bit to disable hdmiphy */
2076 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2077 PMU_HDMI_PHY_ENABLE_BIT, 0);
2078
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002079 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2080
Sean Paulaf65c802014-01-30 16:19:27 -05002081 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002082
2083 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002084}
2085
Sean Paulf041b252014-01-30 16:19:15 -05002086static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002087{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002088 struct hdmi_context *hdata = display_to_hdmi(display);
Inki Dae245f98f2014-06-13 17:44:40 +09002089 struct drm_encoder *encoder = hdata->encoder;
2090 struct drm_crtc *crtc = encoder->crtc;
Jani Nikulab0f87782015-03-11 11:50:59 +02002091 const struct drm_crtc_helper_funcs *funcs = NULL;
Inki Dae245f98f2014-06-13 17:44:40 +09002092
YoungJun Chocbc4c332013-06-12 10:44:40 +09002093 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002094
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002095 switch (mode) {
2096 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002097 hdmi_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002098 break;
2099 case DRM_MODE_DPMS_STANDBY:
2100 case DRM_MODE_DPMS_SUSPEND:
2101 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002102 /*
2103 * The SFRs of VP and Mixer are updated by Vertical Sync of
2104 * Timing generator which is a part of HDMI so the sequence
2105 * to disable TV Subsystem should be as following,
2106 * VP -> Mixer -> HDMI
2107 *
2108 * Below codes will try to disable Mixer and VP(if used)
2109 * prior to disabling HDMI.
2110 */
2111 if (crtc)
2112 funcs = crtc->helper_private;
Gustavo Padovan63498e32015-06-01 12:04:53 -03002113 if (funcs && funcs->disable)
2114 (*funcs->disable)(crtc);
Inki Dae245f98f2014-06-13 17:44:40 +09002115
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002116 hdmi_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002117 break;
2118 default:
2119 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2120 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002121 }
2122}
2123
Sean Paulf041b252014-01-30 16:19:15 -05002124static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002125 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002126 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002127 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002128 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002129 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002130};
2131
Sean Paul724fd142014-05-09 15:05:10 +09002132static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002133{
Sean Paul724fd142014-05-09 15:05:10 +09002134 struct hdmi_context *hdata;
2135
2136 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002137
Sean Paul45517892014-01-30 16:19:05 -05002138 if (hdata->drm_dev)
2139 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002140}
2141
2142static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2143{
2144 struct hdmi_context *hdata = arg;
2145
2146 mod_delayed_work(system_wq, &hdata->hotplug_work,
2147 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002148
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002149 return IRQ_HANDLED;
2150}
2151
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002152static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002153{
2154 struct device *dev = hdata->dev;
2155 struct hdmi_resources *res = &hdata->res;
2156 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002157 "vdd",
2158 "vdd_osc",
2159 "vdd_pll",
2160 };
2161 int i, ret;
2162
2163 DRM_DEBUG_KMS("HDMI resource init\n");
2164
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002165 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302166 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302167 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002168 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002169 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002170 goto fail;
2171 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302172 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302173 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002174 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002175 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002176 goto fail;
2177 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302178 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302179 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002180 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002181 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002182 goto fail;
2183 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302184 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302185 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002186 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002187 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002188 goto fail;
2189 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302190 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2191 if (IS_ERR(res->mout_hdmi)) {
2192 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002193 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302194 goto fail;
2195 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196
Rahul Sharma59956d32013-06-11 12:24:03 +05302197 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002198
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302199 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302200 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002201 if (!res->regul_bulk) {
2202 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002203 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002204 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002205 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2206 res->regul_bulk[i].supply = supply[i];
2207 res->regul_bulk[i].consumer = NULL;
2208 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302209 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002210 if (ret) {
2211 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002212 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002213 }
2214 res->regul_count = ARRAY_SIZE(supply);
2215
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002216 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2217 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2218 DRM_ERROR("failed to get hdmi-en regulator\n");
2219 return PTR_ERR(res->reg_hdmi_en);
2220 }
2221 if (!IS_ERR(res->reg_hdmi_en)) {
2222 ret = regulator_enable(res->reg_hdmi_en);
2223 if (ret) {
2224 DRM_ERROR("failed to enable hdmi-en regulator\n");
2225 return ret;
2226 }
2227 } else
2228 res->reg_hdmi_en = NULL;
2229
Inki Daedf5225b2014-05-29 18:28:02 +09002230 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002231fail:
2232 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002233 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002234}
2235
Rahul Sharma22c4f422012-10-04 20:48:55 +05302236static struct of_device_id hdmi_match_types[] = {
2237 {
2238 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002239 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302240 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02002241 .compatible = "samsung,exynos4210-hdmi",
2242 .data = &exynos4210_hdmi_driver_data,
2243 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302244 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002245 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302246 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302247 .compatible = "samsung,exynos5420-hdmi",
2248 .data = &exynos5420_hdmi_driver_data,
2249 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302250 /* end node */
2251 }
2252};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02002253MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302254
Inki Daef37cd5e2014-05-09 14:25:20 +09002255static int hdmi_bind(struct device *dev, struct device *master, void *data)
2256{
2257 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002258 struct hdmi_context *hdata = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002259
Inki Daef37cd5e2014-05-09 14:25:20 +09002260 hdata->drm_dev = drm_dev;
2261
Andrzej Hajda930865f2014-11-17 09:54:20 +01002262 return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
Inki Daef37cd5e2014-05-09 14:25:20 +09002263}
2264
2265static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2266{
Inki Daef37cd5e2014-05-09 14:25:20 +09002267}
2268
2269static const struct component_ops hdmi_component_ops = {
2270 .bind = hdmi_bind,
2271 .unbind = hdmi_unbind,
2272};
2273
Inki Daee2a562d2014-05-09 16:46:10 +09002274static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2275{
2276 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2277 struct device_node *np;
2278
2279 np = of_find_compatible_node(NULL, NULL, compatible_str);
2280 if (np)
2281 return of_get_next_parent(np);
2282
2283 return NULL;
2284}
2285
2286static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2287{
2288 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2289
2290 return of_find_compatible_node(NULL, NULL, compatible_str);
2291}
2292
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002293static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002294{
Inki Daef37cd5e2014-05-09 14:25:20 +09002295 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09002296 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002297 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002298 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002299 struct resource *res;
2300 int ret;
2301
Andrzej Hajda930865f2014-11-17 09:54:20 +01002302 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2303 if (!hdata)
2304 return -ENOMEM;
2305
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002306 match = of_match_device(hdmi_match_types, dev);
2307 if (!match)
2308 return -ENODEV;
2309
2310 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002311 hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
2312 hdata->display.ops = &hdmi_display_ops;
2313
Andrzej Hajda930865f2014-11-17 09:54:20 +01002314 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002315
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002316 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002317 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2318 if (hdata->hpd_gpio < 0) {
2319 DRM_ERROR("cannot get hpd gpio property\n");
2320 return hdata->hpd_gpio;
2321 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002322
2323 ret = hdmi_resources_init(hdata);
2324 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302325 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002326 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002327 }
2328
2329 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002330 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002331 if (IS_ERR(hdata->regs)) {
2332 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002333 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002334 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002335
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002336 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302337 if (ret) {
2338 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002339 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302340 }
2341
Inki Daee2a562d2014-05-09 16:46:10 +09002342 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2343 if (ddc_node)
2344 goto out_get_ddc_adpt;
2345
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002346 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002347 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2348 if (!ddc_node) {
2349 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002350 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002351 }
Inki Daee2a562d2014-05-09 16:46:10 +09002352
2353out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002354 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2355 if (!hdata->ddc_adpt) {
2356 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002357 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002358 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002359
Inki Daee2a562d2014-05-09 16:46:10 +09002360 phy_node = hdmi_legacy_phy_dt_binding(dev);
2361 if (phy_node)
2362 goto out_get_phy_port;
2363
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002364 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002365 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2366 if (!phy_node) {
2367 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2368 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002369 goto err_ddc;
2370 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002371
Inki Daee2a562d2014-05-09 16:46:10 +09002372out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002373 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002374 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2375 if (!hdata->regs_hdmiphy) {
2376 DRM_ERROR("failed to ioremap hdmi phy\n");
2377 ret = -ENOMEM;
2378 goto err_ddc;
2379 }
2380 } else {
2381 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2382 if (!hdata->hdmiphy_port) {
2383 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002384 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002385 goto err_ddc;
2386 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002387 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002388
Sean Paul77006a72013-01-16 10:17:20 -05002389 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2390 if (hdata->irq < 0) {
2391 DRM_ERROR("failed to get GPIO irq\n");
2392 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002393 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002394 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002395
Sean Paul724fd142014-05-09 15:05:10 +09002396 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2397
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002398 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002399 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002400 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002401 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002402 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002403 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002404 goto err_hdmiphy;
2405 }
2406
Rahul Sharma049d34e2014-05-20 10:36:05 +05302407 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2408 "samsung,syscon-phandle");
2409 if (IS_ERR(hdata->pmureg)) {
2410 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002411 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302412 goto err_hdmiphy;
2413 }
2414
Sean Paulaf65c802014-01-30 16:19:27 -05002415 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002416
Inki Daedf5225b2014-05-29 18:28:02 +09002417 ret = component_add(&pdev->dev, &hdmi_component_ops);
2418 if (ret)
2419 goto err_disable_pm_runtime;
2420
2421 return ret;
2422
2423err_disable_pm_runtime:
2424 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002425
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002426err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002427 if (hdata->hdmiphy_port)
2428 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002429err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002430 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002431
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002432 return ret;
2433}
2434
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002435static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002436{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002437 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002438
Sean Paul724fd142014-05-09 15:05:10 +09002439 cancel_delayed_work_sync(&hdata->hotplug_work);
2440
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002441 if (hdata->res.reg_hdmi_en)
2442 regulator_disable(hdata->res.reg_hdmi_en);
2443
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002444 if (hdata->hdmiphy_port)
2445 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002446 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002447
Sean Paulaf65c802014-01-30 16:19:27 -05002448 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002449 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002450
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002451 return 0;
2452}
2453
2454struct platform_driver hdmi_driver = {
2455 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002456 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002457 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302458 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002459 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302460 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002461 },
2462};