blob: 60663ad9891ff06cc25c67c06d804dae6b47c2c7 [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_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500111 u8 h_blank[2];
112 u8 v2_blank[2];
113 u8 v1_blank[2];
114 u8 v_line[2];
115 u8 h_line[2];
116 u8 hsync_pol[1];
117 u8 vsync_pol[1];
118 u8 int_pro_mode[1];
119 u8 v_blank_f0[2];
120 u8 v_blank_f1[2];
121 u8 h_sync_start[2];
122 u8 h_sync_end[2];
123 u8 v_sync_line_bef_2[2];
124 u8 v_sync_line_bef_1[2];
125 u8 v_sync_line_aft_2[2];
126 u8 v_sync_line_aft_1[2];
127 u8 v_sync_line_aft_pxl_2[2];
128 u8 v_sync_line_aft_pxl_1[2];
129 u8 v_blank_f2[2]; /* for 3D mode */
130 u8 v_blank_f3[2]; /* for 3D mode */
131 u8 v_blank_f4[2]; /* for 3D mode */
132 u8 v_blank_f5[2]; /* for 3D mode */
133 u8 v_sync_line_aft_3[2];
134 u8 v_sync_line_aft_4[2];
135 u8 v_sync_line_aft_5[2];
136 u8 v_sync_line_aft_6[2];
137 u8 v_sync_line_aft_pxl_3[2];
138 u8 v_sync_line_aft_pxl_4[2];
139 u8 v_sync_line_aft_pxl_5[2];
140 u8 v_sync_line_aft_pxl_6[2];
141 u8 vact_space_1[2];
142 u8 vact_space_2[2];
143 u8 vact_space_3[2];
144 u8 vact_space_4[2];
145 u8 vact_space_5[2];
146 u8 vact_space_6[2];
147};
148
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900149struct hdmi_v14_conf {
150 struct hdmi_v14_core_regs core;
151 struct hdmi_tg_regs tg;
152};
153
Joonyoung Shim590f4182012-03-16 18:47:14 +0900154struct hdmi_context {
Andrzej Hajda930865f2014-11-17 09:54:20 +0100155 struct exynos_drm_display display;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900156 struct device *dev;
157 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500158 struct drm_connector connector;
159 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900160 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900161 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900162
Joonyoung Shim590f4182012-03-16 18:47:14 +0900163 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500164 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900165 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900166
Inki Dae8fa04aa2014-03-13 16:38:31 +0900167 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900168 struct i2c_client *hdmiphy_port;
169
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900170 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530171 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200172 u8 cea_video_id;
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200173 struct hdmi_v14_conf mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900174
175 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200176 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900177
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530178 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900179 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530180
Rahul Sharma049d34e2014-05-20 10:36:05 +0530181 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900182};
183
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100184static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
185{
186 return container_of(d, struct hdmi_context, display);
187}
188
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500189struct hdmiphy_config {
190 int pixel_clock;
191 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900192};
193
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900194/* list of phy config settings */
195static const struct hdmiphy_config hdmiphy_v13_configs[] = {
196 {
197 .pixel_clock = 27000000,
198 .conf = {
199 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
200 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
201 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
202 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
203 },
204 },
205 {
206 .pixel_clock = 27027000,
207 .conf = {
208 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
209 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
210 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
211 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
212 },
213 },
214 {
215 .pixel_clock = 74176000,
216 .conf = {
217 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
218 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
219 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
220 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
221 },
222 },
223 {
224 .pixel_clock = 74250000,
225 .conf = {
226 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
227 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
228 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
229 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
230 },
231 },
232 {
233 .pixel_clock = 148500000,
234 .conf = {
235 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
236 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
237 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
238 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
239 },
240 },
241};
242
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500243static const struct hdmiphy_config hdmiphy_v14_configs[] = {
244 {
245 .pixel_clock = 25200000,
246 .conf = {
247 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
248 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
249 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
250 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
251 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900252 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500253 {
254 .pixel_clock = 27000000,
255 .conf = {
256 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
257 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
258 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
259 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
260 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900261 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500262 {
263 .pixel_clock = 27027000,
264 .conf = {
265 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
266 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
267 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
268 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
269 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900270 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500271 {
272 .pixel_clock = 36000000,
273 .conf = {
274 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
275 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
276 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
277 0x54, 0xab, 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 = 40000000,
282 .conf = {
283 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
284 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
285 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
286 0x54, 0x9a, 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 = 65000000,
291 .conf = {
292 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
293 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
294 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
295 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
296 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900297 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 {
Shirish Se1d883c2014-03-13 14:28:27 +0900299 .pixel_clock = 71000000,
300 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530301 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
302 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
303 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900304 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
305 },
306 },
307 {
308 .pixel_clock = 73250000,
309 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530310 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
311 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
312 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900313 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
314 },
315 },
316 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500317 .pixel_clock = 74176000,
318 .conf = {
319 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
320 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
321 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
322 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
323 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900324 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 {
326 .pixel_clock = 74250000,
327 .conf = {
328 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
329 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
330 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
331 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
332 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900333 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500334 {
335 .pixel_clock = 83500000,
336 .conf = {
337 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
338 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
339 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
340 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
341 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900342 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500343 {
344 .pixel_clock = 106500000,
345 .conf = {
346 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
347 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
348 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
349 0x54, 0x73, 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 = 108000000,
354 .conf = {
355 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
356 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
357 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
358 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
359 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900360 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500361 {
Shirish Se1d883c2014-03-13 14:28:27 +0900362 .pixel_clock = 115500000,
363 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530364 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
365 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
366 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900367 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
368 },
369 },
370 {
371 .pixel_clock = 119000000,
372 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530373 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
374 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
375 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900376 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
377 },
378 },
379 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500380 .pixel_clock = 146250000,
381 .conf = {
382 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
383 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
384 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
385 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
386 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900387 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500388 {
389 .pixel_clock = 148500000,
390 .conf = {
391 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
392 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
393 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
394 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
395 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900396 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900397};
398
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530399static const struct hdmiphy_config hdmiphy_5420_configs[] = {
400 {
401 .pixel_clock = 25200000,
402 .conf = {
403 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
404 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
405 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
406 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
407 },
408 },
409 {
410 .pixel_clock = 27000000,
411 .conf = {
412 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
413 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
414 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
415 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
416 },
417 },
418 {
419 .pixel_clock = 27027000,
420 .conf = {
421 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
422 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
423 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
424 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
425 },
426 },
427 {
428 .pixel_clock = 36000000,
429 .conf = {
430 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
431 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
432 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
433 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
434 },
435 },
436 {
437 .pixel_clock = 40000000,
438 .conf = {
439 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
440 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
441 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
442 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
443 },
444 },
445 {
446 .pixel_clock = 65000000,
447 .conf = {
448 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
449 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
450 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
451 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
452 },
453 },
454 {
455 .pixel_clock = 71000000,
456 .conf = {
457 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
458 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
459 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
460 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
461 },
462 },
463 {
464 .pixel_clock = 73250000,
465 .conf = {
466 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
467 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
468 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
469 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
470 },
471 },
472 {
473 .pixel_clock = 74176000,
474 .conf = {
475 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
476 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
477 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
478 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
479 },
480 },
481 {
482 .pixel_clock = 74250000,
483 .conf = {
484 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
485 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
486 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
487 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
488 },
489 },
490 {
491 .pixel_clock = 83500000,
492 .conf = {
493 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
494 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
495 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
496 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
497 },
498 },
499 {
500 .pixel_clock = 88750000,
501 .conf = {
502 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
503 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
504 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
505 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
506 },
507 },
508 {
509 .pixel_clock = 106500000,
510 .conf = {
511 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
512 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
513 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
514 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
515 },
516 },
517 {
518 .pixel_clock = 108000000,
519 .conf = {
520 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
521 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
522 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
523 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
524 },
525 },
526 {
527 .pixel_clock = 115500000,
528 .conf = {
529 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
530 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
531 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
532 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
533 },
534 },
535 {
536 .pixel_clock = 146250000,
537 .conf = {
538 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
539 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
540 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
541 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
542 },
543 },
544 {
545 .pixel_clock = 148500000,
546 .conf = {
547 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
548 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
549 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
550 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
551 },
552 },
553};
554
Sachin Kamat16337072014-05-22 10:32:56 +0530555static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530556 .type = HDMI_TYPE14,
557 .phy_confs = hdmiphy_5420_configs,
558 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
559 .is_apb_phy = 1,
560};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900561
Sachin Kamat16337072014-05-22 10:32:56 +0530562static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900563 .type = HDMI_TYPE14,
564 .phy_confs = hdmiphy_v14_configs,
565 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
566 .is_apb_phy = 0,
567};
568
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200569static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
570 .type = HDMI_TYPE13,
571 .phy_confs = hdmiphy_v13_configs,
572 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
573 .is_apb_phy = 0,
574};
575
Sachin Kamat16337072014-05-22 10:32:56 +0530576static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900577 .type = HDMI_TYPE14,
578 .phy_confs = hdmiphy_v13_configs,
579 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
580 .is_apb_phy = 0,
581};
582
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900583static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
584{
585 return readl(hdata->regs + reg_id);
586}
587
588static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
589 u32 reg_id, u8 value)
590{
591 writeb(value, hdata->regs + reg_id);
592}
593
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200594static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
595 int bytes, u32 val)
596{
597 while (--bytes >= 0) {
598 writeb(val & 0xff, hdata->regs + reg_id);
599 val >>= 8;
600 reg_id += 4;
601 }
602}
603
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900604static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
605 u32 reg_id, u32 value, u32 mask)
606{
607 u32 old = readl(hdata->regs + reg_id);
608 value = (value & mask) | (old & ~mask);
609 writel(value, hdata->regs + reg_id);
610}
611
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900612static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
613 u32 reg_offset, u8 value)
614{
615 if (hdata->hdmiphy_port) {
616 u8 buffer[2];
617 int ret;
618
619 buffer[0] = reg_offset;
620 buffer[1] = value;
621
622 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
623 if (ret == 2)
624 return 0;
625 return ret;
626 } else {
627 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
628 return 0;
629 }
630}
631
632static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
633 u32 reg_offset, const u8 *buf, u32 len)
634{
635 if ((reg_offset + len) > 32)
636 return -EINVAL;
637
638 if (hdata->hdmiphy_port) {
639 int ret;
640
641 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
642 if (ret == len)
643 return 0;
644 return ret;
645 } else {
646 int i;
647 for (i = 0; i < len; i++)
648 writeb(buf[i], hdata->regs_hdmiphy +
649 ((reg_offset + i)<<2));
650 return 0;
651 }
652}
653
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900654static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900655{
656#define DUMPREG(reg_id) \
657 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
658 readl(hdata->regs + reg_id))
659 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
660 DUMPREG(HDMI_INTC_FLAG);
661 DUMPREG(HDMI_INTC_CON);
662 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900663 DUMPREG(HDMI_V13_PHY_RSTOUT);
664 DUMPREG(HDMI_V13_PHY_VPLL);
665 DUMPREG(HDMI_V13_PHY_CMU);
666 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900667
668 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
669 DUMPREG(HDMI_CON_0);
670 DUMPREG(HDMI_CON_1);
671 DUMPREG(HDMI_CON_2);
672 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900673 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900674 DUMPREG(HDMI_STATUS_EN);
675 DUMPREG(HDMI_HPD);
676 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900677 DUMPREG(HDMI_V13_HPD_GEN);
678 DUMPREG(HDMI_V13_DC_CONTROL);
679 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900680
681 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
682 DUMPREG(HDMI_H_BLANK_0);
683 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900684 DUMPREG(HDMI_V13_V_BLANK_0);
685 DUMPREG(HDMI_V13_V_BLANK_1);
686 DUMPREG(HDMI_V13_V_BLANK_2);
687 DUMPREG(HDMI_V13_H_V_LINE_0);
688 DUMPREG(HDMI_V13_H_V_LINE_1);
689 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900690 DUMPREG(HDMI_VSYNC_POL);
691 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900692 DUMPREG(HDMI_V13_V_BLANK_F_0);
693 DUMPREG(HDMI_V13_V_BLANK_F_1);
694 DUMPREG(HDMI_V13_V_BLANK_F_2);
695 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
696 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
697 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
698 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
699 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
700 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
701 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
702 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
703 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
704 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
705 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
706 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900707
708 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
709 DUMPREG(HDMI_TG_CMD);
710 DUMPREG(HDMI_TG_H_FSZ_L);
711 DUMPREG(HDMI_TG_H_FSZ_H);
712 DUMPREG(HDMI_TG_HACT_ST_L);
713 DUMPREG(HDMI_TG_HACT_ST_H);
714 DUMPREG(HDMI_TG_HACT_SZ_L);
715 DUMPREG(HDMI_TG_HACT_SZ_H);
716 DUMPREG(HDMI_TG_V_FSZ_L);
717 DUMPREG(HDMI_TG_V_FSZ_H);
718 DUMPREG(HDMI_TG_VSYNC_L);
719 DUMPREG(HDMI_TG_VSYNC_H);
720 DUMPREG(HDMI_TG_VSYNC2_L);
721 DUMPREG(HDMI_TG_VSYNC2_H);
722 DUMPREG(HDMI_TG_VACT_ST_L);
723 DUMPREG(HDMI_TG_VACT_ST_H);
724 DUMPREG(HDMI_TG_VACT_SZ_L);
725 DUMPREG(HDMI_TG_VACT_SZ_H);
726 DUMPREG(HDMI_TG_FIELD_CHG_L);
727 DUMPREG(HDMI_TG_FIELD_CHG_H);
728 DUMPREG(HDMI_TG_VACT_ST2_L);
729 DUMPREG(HDMI_TG_VACT_ST2_H);
730 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
731 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
732 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
733 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
734 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
735 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
736 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
737 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
738#undef DUMPREG
739}
740
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900741static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
742{
743 int i;
744
745#define DUMPREG(reg_id) \
746 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
747 readl(hdata->regs + reg_id))
748
749 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
750 DUMPREG(HDMI_INTC_CON);
751 DUMPREG(HDMI_INTC_FLAG);
752 DUMPREG(HDMI_HPD_STATUS);
753 DUMPREG(HDMI_INTC_CON_1);
754 DUMPREG(HDMI_INTC_FLAG_1);
755 DUMPREG(HDMI_PHY_STATUS_0);
756 DUMPREG(HDMI_PHY_STATUS_PLL);
757 DUMPREG(HDMI_PHY_CON_0);
758 DUMPREG(HDMI_PHY_RSTOUT);
759 DUMPREG(HDMI_PHY_VPLL);
760 DUMPREG(HDMI_PHY_CMU);
761 DUMPREG(HDMI_CORE_RSTOUT);
762
763 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
764 DUMPREG(HDMI_CON_0);
765 DUMPREG(HDMI_CON_1);
766 DUMPREG(HDMI_CON_2);
767 DUMPREG(HDMI_SYS_STATUS);
768 DUMPREG(HDMI_PHY_STATUS_0);
769 DUMPREG(HDMI_STATUS_EN);
770 DUMPREG(HDMI_HPD);
771 DUMPREG(HDMI_MODE_SEL);
772 DUMPREG(HDMI_ENC_EN);
773 DUMPREG(HDMI_DC_CONTROL);
774 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
775
776 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
777 DUMPREG(HDMI_H_BLANK_0);
778 DUMPREG(HDMI_H_BLANK_1);
779 DUMPREG(HDMI_V2_BLANK_0);
780 DUMPREG(HDMI_V2_BLANK_1);
781 DUMPREG(HDMI_V1_BLANK_0);
782 DUMPREG(HDMI_V1_BLANK_1);
783 DUMPREG(HDMI_V_LINE_0);
784 DUMPREG(HDMI_V_LINE_1);
785 DUMPREG(HDMI_H_LINE_0);
786 DUMPREG(HDMI_H_LINE_1);
787 DUMPREG(HDMI_HSYNC_POL);
788
789 DUMPREG(HDMI_VSYNC_POL);
790 DUMPREG(HDMI_INT_PRO_MODE);
791 DUMPREG(HDMI_V_BLANK_F0_0);
792 DUMPREG(HDMI_V_BLANK_F0_1);
793 DUMPREG(HDMI_V_BLANK_F1_0);
794 DUMPREG(HDMI_V_BLANK_F1_1);
795
796 DUMPREG(HDMI_H_SYNC_START_0);
797 DUMPREG(HDMI_H_SYNC_START_1);
798 DUMPREG(HDMI_H_SYNC_END_0);
799 DUMPREG(HDMI_H_SYNC_END_1);
800
801 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
802 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
803 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
804 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
805
806 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
807 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
808 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
809 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
810
811 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
812 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
813 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
814 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
815
816 DUMPREG(HDMI_V_BLANK_F2_0);
817 DUMPREG(HDMI_V_BLANK_F2_1);
818 DUMPREG(HDMI_V_BLANK_F3_0);
819 DUMPREG(HDMI_V_BLANK_F3_1);
820 DUMPREG(HDMI_V_BLANK_F4_0);
821 DUMPREG(HDMI_V_BLANK_F4_1);
822 DUMPREG(HDMI_V_BLANK_F5_0);
823 DUMPREG(HDMI_V_BLANK_F5_1);
824
825 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
826 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
827 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
828 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
829 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
830 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
831 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
832 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
833
834 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
836 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
837 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
838 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
839 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
840 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
841 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
842
843 DUMPREG(HDMI_VACT_SPACE_1_0);
844 DUMPREG(HDMI_VACT_SPACE_1_1);
845 DUMPREG(HDMI_VACT_SPACE_2_0);
846 DUMPREG(HDMI_VACT_SPACE_2_1);
847 DUMPREG(HDMI_VACT_SPACE_3_0);
848 DUMPREG(HDMI_VACT_SPACE_3_1);
849 DUMPREG(HDMI_VACT_SPACE_4_0);
850 DUMPREG(HDMI_VACT_SPACE_4_1);
851 DUMPREG(HDMI_VACT_SPACE_5_0);
852 DUMPREG(HDMI_VACT_SPACE_5_1);
853 DUMPREG(HDMI_VACT_SPACE_6_0);
854 DUMPREG(HDMI_VACT_SPACE_6_1);
855
856 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
857 DUMPREG(HDMI_TG_CMD);
858 DUMPREG(HDMI_TG_H_FSZ_L);
859 DUMPREG(HDMI_TG_H_FSZ_H);
860 DUMPREG(HDMI_TG_HACT_ST_L);
861 DUMPREG(HDMI_TG_HACT_ST_H);
862 DUMPREG(HDMI_TG_HACT_SZ_L);
863 DUMPREG(HDMI_TG_HACT_SZ_H);
864 DUMPREG(HDMI_TG_V_FSZ_L);
865 DUMPREG(HDMI_TG_V_FSZ_H);
866 DUMPREG(HDMI_TG_VSYNC_L);
867 DUMPREG(HDMI_TG_VSYNC_H);
868 DUMPREG(HDMI_TG_VSYNC2_L);
869 DUMPREG(HDMI_TG_VSYNC2_H);
870 DUMPREG(HDMI_TG_VACT_ST_L);
871 DUMPREG(HDMI_TG_VACT_ST_H);
872 DUMPREG(HDMI_TG_VACT_SZ_L);
873 DUMPREG(HDMI_TG_VACT_SZ_H);
874 DUMPREG(HDMI_TG_FIELD_CHG_L);
875 DUMPREG(HDMI_TG_FIELD_CHG_H);
876 DUMPREG(HDMI_TG_VACT_ST2_L);
877 DUMPREG(HDMI_TG_VACT_ST2_H);
878 DUMPREG(HDMI_TG_VACT_ST3_L);
879 DUMPREG(HDMI_TG_VACT_ST3_H);
880 DUMPREG(HDMI_TG_VACT_ST4_L);
881 DUMPREG(HDMI_TG_VACT_ST4_H);
882 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
883 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
884 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
885 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
886 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
887 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
888 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
889 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
890 DUMPREG(HDMI_TG_3D);
891
892 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
893 DUMPREG(HDMI_AVI_CON);
894 DUMPREG(HDMI_AVI_HEADER0);
895 DUMPREG(HDMI_AVI_HEADER1);
896 DUMPREG(HDMI_AVI_HEADER2);
897 DUMPREG(HDMI_AVI_CHECK_SUM);
898 DUMPREG(HDMI_VSI_CON);
899 DUMPREG(HDMI_VSI_HEADER0);
900 DUMPREG(HDMI_VSI_HEADER1);
901 DUMPREG(HDMI_VSI_HEADER2);
902 for (i = 0; i < 7; ++i)
903 DUMPREG(HDMI_VSI_DATA(i));
904
905#undef DUMPREG
906}
907
908static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
909{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200910 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900911 hdmi_v13_regs_dump(hdata, prefix);
912 else
913 hdmi_v14_regs_dump(hdata, prefix);
914}
915
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530916static u8 hdmi_chksum(struct hdmi_context *hdata,
917 u32 start, u8 len, u32 hdr_sum)
918{
919 int i;
920
921 /* hdr_sum : header0 + header1 + header2
922 * start : start address of packet byte1
923 * len : packet bytes - 1 */
924 for (i = 0; i < len; ++i)
925 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
926
927 /* return 2's complement of 8 bit hdr_sum */
928 return (u8)(~(hdr_sum & 0xff) + 1);
929}
930
931static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530932 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530933{
934 u32 hdr_sum;
935 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530936 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200937 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530938
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530939 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
940 if (hdata->dvi_mode) {
941 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
942 HDMI_VSI_CON_DO_NOT_TRANSMIT);
943 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
944 HDMI_AVI_CON_DO_NOT_TRANSMIT);
945 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
946 return;
947 }
948
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530949 switch (infoframe->any.type) {
950 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530951 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530952 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
953 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
954 infoframe->any.version);
955 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
956 hdr_sum = infoframe->any.type + infoframe->any.version +
957 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530958
959 /* Output format zero hardcoded ,RGB YBCR selection */
960 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
961 AVI_ACTIVE_FORMAT_VALID |
962 AVI_UNDERSCANNED_DISPLAY_VALID);
963
Shirish S46154152014-03-13 10:58:28 +0530964 /*
965 * Set the aspect ratio as per the mode, mentioned in
966 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
967 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200968 ar = hdata->current_mode.picture_aspect_ratio;
969 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530970 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200971 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530972 break;
973 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200974 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530975 break;
976 case HDMI_PICTURE_ASPECT_NONE:
977 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200978 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530979 break;
980 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200981 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530982
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200983 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530984
985 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530986 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530987 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
988 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
989 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530990 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530991 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530992 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
993 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
994 infoframe->any.version);
995 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
996 hdr_sum = infoframe->any.type + infoframe->any.version +
997 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530998 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530999 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301000 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1001 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1002 break;
1003 default:
1004 break;
1005 }
1006}
1007
Sean Pauld9716ee2014-01-30 16:19:29 -05001008static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1009 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001010{
Sean Pauld9716ee2014-01-30 16:19:29 -05001011 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001012
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001013 if (gpio_get_value(hdata->hpd_gpio))
1014 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301015
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001016 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001017}
1018
Sean Pauld9716ee2014-01-30 16:19:29 -05001019static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001020{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001021 drm_connector_unregister(connector);
1022 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001023}
1024
Sean Pauld9716ee2014-01-30 16:19:29 -05001025static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001026 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001027 .fill_modes = drm_helper_probe_single_connector_modes,
1028 .detect = hdmi_detect,
1029 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001030 .reset = drm_atomic_helper_connector_reset,
1031 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1032 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001033};
1034
1035static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001036{
Sean Pauld9716ee2014-01-30 16:19:29 -05001037 struct hdmi_context *hdata = ctx_from_connector(connector);
1038 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001039 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001040
Inki Dae8fa04aa2014-03-13 16:38:31 +09001041 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001043
Inki Dae8fa04aa2014-03-13 16:38:31 +09001044 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001045 if (!edid)
1046 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001047
Sean Pauld9716ee2014-01-30 16:19:29 -05001048 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001049 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1050 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001051 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001052
Sean Pauld9716ee2014-01-30 16:19:29 -05001053 drm_mode_connector_update_edid_property(connector, edid);
1054
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001055 ret = drm_add_edid_modes(connector, edid);
1056
1057 kfree(edid);
1058
1059 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001060}
1061
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001062static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001063{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001064 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001065
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001066 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1067 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001068 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001069
1070 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1071 return -EINVAL;
1072}
1073
Sean Pauld9716ee2014-01-30 16:19:29 -05001074static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001075 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001076{
Sean Pauld9716ee2014-01-30 16:19:29 -05001077 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001078 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001079
Rahul Sharma16844fb2013-06-10 14:50:00 +05301080 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1081 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1082 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1083 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001084
Sean Paulf041b252014-01-30 16:19:15 -05001085 ret = mixer_check_mode(mode);
1086 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001087 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001088
Rahul Sharma16844fb2013-06-10 14:50:00 +05301089 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001090 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001091 return MODE_BAD;
1092
1093 return MODE_OK;
1094}
1095
1096static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1097{
1098 struct hdmi_context *hdata = ctx_from_connector(connector);
1099
1100 return hdata->encoder;
1101}
1102
1103static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1104 .get_modes = hdmi_get_modes,
1105 .mode_valid = hdmi_mode_valid,
1106 .best_encoder = hdmi_best_encoder,
1107};
1108
1109static int hdmi_create_connector(struct exynos_drm_display *display,
1110 struct drm_encoder *encoder)
1111{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001112 struct hdmi_context *hdata = display_to_hdmi(display);
Sean Pauld9716ee2014-01-30 16:19:29 -05001113 struct drm_connector *connector = &hdata->connector;
1114 int ret;
1115
1116 hdata->encoder = encoder;
1117 connector->interlace_allowed = true;
1118 connector->polled = DRM_CONNECTOR_POLL_HPD;
1119
1120 ret = drm_connector_init(hdata->drm_dev, connector,
1121 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1122 if (ret) {
1123 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001124 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001125 }
1126
1127 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001128 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001129 drm_mode_connector_attach_encoder(connector, encoder);
1130
1131 return 0;
1132}
1133
Sean Paulf041b252014-01-30 16:19:15 -05001134static void hdmi_mode_fixup(struct exynos_drm_display *display,
1135 struct drm_connector *connector,
1136 const struct drm_display_mode *mode,
1137 struct drm_display_mode *adjusted_mode)
1138{
1139 struct drm_display_mode *m;
1140 int mode_ok;
1141
1142 DRM_DEBUG_KMS("%s\n", __FILE__);
1143
1144 drm_mode_set_crtcinfo(adjusted_mode, 0);
1145
Sean Pauld9716ee2014-01-30 16:19:29 -05001146 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001147
1148 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001149 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001150 return;
1151
1152 /*
1153 * otherwise, find the most suitable mode among modes and change it
1154 * to adjusted_mode.
1155 */
1156 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001157 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001158
Sean Pauld9716ee2014-01-30 16:19:29 -05001159 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001160 DRM_INFO("desired mode doesn't exist so\n");
1161 DRM_INFO("use the most suitable mode among modes.\n");
1162
1163 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1164 m->hdisplay, m->vdisplay, m->vrefresh);
1165
Sean Paul75626852014-01-30 16:19:16 -05001166 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001167 break;
1168 }
1169 }
1170}
1171
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001172static void hdmi_set_acr(u32 freq, u8 *acr)
1173{
1174 u32 n, cts;
1175
1176 switch (freq) {
1177 case 32000:
1178 n = 4096;
1179 cts = 27000;
1180 break;
1181 case 44100:
1182 n = 6272;
1183 cts = 30000;
1184 break;
1185 case 88200:
1186 n = 12544;
1187 cts = 30000;
1188 break;
1189 case 176400:
1190 n = 25088;
1191 cts = 30000;
1192 break;
1193 case 48000:
1194 n = 6144;
1195 cts = 27000;
1196 break;
1197 case 96000:
1198 n = 12288;
1199 cts = 27000;
1200 break;
1201 case 192000:
1202 n = 24576;
1203 cts = 27000;
1204 break;
1205 default:
1206 n = 0;
1207 cts = 0;
1208 break;
1209 }
1210
1211 acr[1] = cts >> 16;
1212 acr[2] = cts >> 8 & 0xff;
1213 acr[3] = cts & 0xff;
1214
1215 acr[4] = n >> 16;
1216 acr[5] = n >> 8 & 0xff;
1217 acr[6] = n & 0xff;
1218}
1219
1220static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1221{
1222 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1223 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1224 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1225 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1226 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1227 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1228 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1229 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1230 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1231
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001232 if (hdata->drv_data->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001233 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1234 else
1235 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1236}
1237
1238static void hdmi_audio_init(struct hdmi_context *hdata)
1239{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301240 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001241 u32 data_num, bit_ch, sample_frq;
1242 u32 val;
1243 u8 acr[7];
1244
1245 sample_rate = 44100;
1246 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001247
1248 switch (bits_per_sample) {
1249 case 20:
1250 data_num = 2;
1251 bit_ch = 1;
1252 break;
1253 case 24:
1254 data_num = 3;
1255 bit_ch = 1;
1256 break;
1257 default:
1258 data_num = 1;
1259 bit_ch = 0;
1260 break;
1261 }
1262
1263 hdmi_set_acr(sample_rate, acr);
1264 hdmi_reg_acr(hdata, acr);
1265
1266 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1267 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1268 | HDMI_I2S_MUX_ENABLE);
1269
1270 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1271 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1272
1273 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1274
1275 sample_frq = (sample_rate == 44100) ? 0 :
1276 (sample_rate == 48000) ? 2 :
1277 (sample_rate == 32000) ? 3 :
1278 (sample_rate == 96000) ? 0xa : 0x0;
1279
1280 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1281 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1282
1283 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1284 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1285
1286 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1287 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1288 | HDMI_I2S_SEL_LRCK(6));
1289 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1290 | HDMI_I2S_SEL_SDATA2(4));
1291 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1292 | HDMI_I2S_SEL_SDATA2(2));
1293 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1294
1295 /* I2S_CON_1 & 2 */
1296 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1297 | HDMI_I2S_L_CH_LOW_POL);
1298 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1299 | HDMI_I2S_SET_BIT_CH(bit_ch)
1300 | HDMI_I2S_SET_SDATA_BIT(data_num)
1301 | HDMI_I2S_BASIC_FORMAT);
1302
1303 /* Configure register related to CUV information */
1304 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1305 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1306 | HDMI_I2S_COPYRIGHT
1307 | HDMI_I2S_LINEAR_PCM
1308 | HDMI_I2S_CONSUMER_FORMAT);
1309 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1310 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1311 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1312 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1313 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1314 HDMI_I2S_ORG_SMP_FREQ_44_1
1315 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1316 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1317
1318 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1319}
1320
1321static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1322{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001323 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001324 return;
1325
1326 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1327 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1328 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1329}
1330
Rahul Sharmabfa48422014-04-03 20:41:04 +05301331static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001332{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301333 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001334
Rahul Sharmabfa48422014-04-03 20:41:04 +05301335 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1336 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001337
Rahul Sharmabfa48422014-04-03 20:41:04 +05301338 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1339 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001340}
1341
1342static void hdmi_conf_init(struct hdmi_context *hdata)
1343{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301344 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301345
Sean Paul77006a72013-01-16 10:17:20 -05001346 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001347 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1348 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001349
1350 /* choose HDMI mode */
1351 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1352 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301353 /* Apply Video preable and Guard band in HDMI mode only */
1354 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001355 /* disable bluescreen */
1356 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001357
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001358 if (hdata->dvi_mode) {
1359 /* choose DVI mode */
1360 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1361 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1362 hdmi_reg_writeb(hdata, HDMI_CON_2,
1363 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1364 }
1365
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001366 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001367 /* choose bluescreen (fecal) color */
1368 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1369 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1370 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1371
1372 /* enable AVI packet every vsync, fixes purple line problem */
1373 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1374 /* force RGB, look to CEA-861-D, table 7 for more detail */
1375 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1376 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1377
1378 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1379 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1380 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1381 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301382 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1383 infoframe.any.version = HDMI_AVI_VERSION;
1384 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301385 hdmi_reg_infoframe(hdata, &infoframe);
1386
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301387 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1388 infoframe.any.version = HDMI_AUI_VERSION;
1389 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301390 hdmi_reg_infoframe(hdata, &infoframe);
1391
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001392 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001393 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1394 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001395}
1396
Rahul Sharma16844fb2013-06-10 14:50:00 +05301397static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001398{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001399 struct drm_display_mode *m = &hdata->current_mode;
1400 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001401 int tries;
1402
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001403 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1404 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1405 (m->htotal << 12) | m->vtotal);
1406
1407 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1408 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1409
1410 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1411 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1412
1413 val = (m->hsync_start - m->hdisplay - 2);
1414 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1415 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1416 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1417
1418 /*
1419 * Quirk requirement for exynos HDMI IP design,
1420 * 2 pixels less than the actual calculation for hsync_start
1421 * and end.
1422 */
1423
1424 /* Following values & calculations differ for different type of modes */
1425 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1426 /* Interlaced Mode */
1427 val = ((m->vsync_end - m->vdisplay) / 2);
1428 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1429 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1430
1431 val = m->vtotal / 2;
1432 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1433 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1434
1435 val = (m->vtotal +
1436 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1437 val |= m->vtotal << 11;
1438 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1439
1440 val = ((m->vtotal / 2) + 7);
1441 val |= ((m->vtotal / 2) + 2) << 12;
1442 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1443
1444 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1445 val |= ((m->htotal / 2) +
1446 (m->hsync_start - m->hdisplay)) << 12;
1447 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1448
1449 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1450 (m->vtotal - m->vdisplay) / 2);
1451 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1452
1453 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1454 } else {
1455 /* Progressive Mode */
1456
1457 val = m->vtotal;
1458 val |= (m->vtotal - m->vdisplay) << 11;
1459 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1460
1461 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1462
1463 val = (m->vsync_end - m->vdisplay);
1464 val |= ((m->vsync_start - m->vdisplay) << 12);
1465 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1466
1467 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1468 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1469 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1470 m->vtotal - m->vdisplay);
1471 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1472 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1473 }
1474
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001475 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001476 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1477 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1478 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1479 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1480 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1481 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1482 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1483 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1484 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1485 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1486 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001487
1488 /* waiting for HDMIPHY's PLL to get to steady state */
1489 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001490 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001491 if (val & HDMI_PHY_STATUS_READY)
1492 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001493 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001494 }
1495 /* steady state not achieved */
1496 if (tries == 0) {
1497 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1498 hdmi_regs_dump(hdata, "timing apply");
1499 }
1500
Sean Paul0bfb1f82013-06-11 12:24:02 +05301501 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301502 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301503 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001504
1505 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301506 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001507}
1508
Rahul Sharma16844fb2013-06-10 14:50:00 +05301509static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001510{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001511 const struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
1512 const struct hdmi_v14_core_regs *core = &hdata->mode_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001513 int tries;
1514
1515 /* setting core registers */
1516 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1517 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1518 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1519 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1520 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1521 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1522 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1523 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1524 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1525 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1526 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1527 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1528 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1529 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1530 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1531 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1532 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1533 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1534 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1535 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1536 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1537 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1538 core->v_sync_line_bef_2[0]);
1539 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1540 core->v_sync_line_bef_2[1]);
1541 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1542 core->v_sync_line_bef_1[0]);
1543 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1544 core->v_sync_line_bef_1[1]);
1545 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1546 core->v_sync_line_aft_2[0]);
1547 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1548 core->v_sync_line_aft_2[1]);
1549 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1550 core->v_sync_line_aft_1[0]);
1551 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1552 core->v_sync_line_aft_1[1]);
1553 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1554 core->v_sync_line_aft_pxl_2[0]);
1555 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1556 core->v_sync_line_aft_pxl_2[1]);
1557 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1558 core->v_sync_line_aft_pxl_1[0]);
1559 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1560 core->v_sync_line_aft_pxl_1[1]);
1561 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1562 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1563 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1564 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1565 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1566 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1567 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1568 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1569 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1570 core->v_sync_line_aft_3[0]);
1571 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1572 core->v_sync_line_aft_3[1]);
1573 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1574 core->v_sync_line_aft_4[0]);
1575 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1576 core->v_sync_line_aft_4[1]);
1577 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1578 core->v_sync_line_aft_5[0]);
1579 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1580 core->v_sync_line_aft_5[1]);
1581 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1582 core->v_sync_line_aft_6[0]);
1583 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1584 core->v_sync_line_aft_6[1]);
1585 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1586 core->v_sync_line_aft_pxl_3[0]);
1587 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1588 core->v_sync_line_aft_pxl_3[1]);
1589 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1590 core->v_sync_line_aft_pxl_4[0]);
1591 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1592 core->v_sync_line_aft_pxl_4[1]);
1593 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1594 core->v_sync_line_aft_pxl_5[0]);
1595 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1596 core->v_sync_line_aft_pxl_5[1]);
1597 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1598 core->v_sync_line_aft_pxl_6[0]);
1599 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1600 core->v_sync_line_aft_pxl_6[1]);
1601 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1602 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1603 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1604 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1605 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1606 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1607 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1608 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1609 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1610 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1611 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1612 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1613
1614 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001615 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1626 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1627 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1628 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1629 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1630 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1631 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1632 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1633 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1634 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1635 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1636 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1637 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1638 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1639 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1640 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1641 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1642 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1643 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1644 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1645 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1646 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1647 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001648
1649 /* waiting for HDMIPHY's PLL to get to steady state */
1650 for (tries = 100; tries; --tries) {
1651 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1652 if (val & HDMI_PHY_STATUS_READY)
1653 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001654 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001655 }
1656 /* steady state not achieved */
1657 if (tries == 0) {
1658 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1659 hdmi_regs_dump(hdata, "timing apply");
1660 }
1661
Sean Paul0bfb1f82013-06-11 12:24:02 +05301662 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301663 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301664 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001665
1666 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301667 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001668}
1669
Rahul Sharma16844fb2013-06-10 14:50:00 +05301670static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001671{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001672 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301673 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001674 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301675 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001676}
1677
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001678static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1679{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001680 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001681
Sean Paul0bfb1f82013-06-11 12:24:02 +05301682 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301683 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301684 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001685
1686 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001687 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1688 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001689
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001690 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001691 reg = HDMI_V13_PHY_RSTOUT;
1692 else
1693 reg = HDMI_PHY_RSTOUT;
1694
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001695 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001696 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001697 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001698 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001699 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001700}
1701
Rahul Sharmaa5562252012-11-28 11:30:25 +05301702static void hdmiphy_poweron(struct hdmi_context *hdata)
1703{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001704 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301705 return;
1706
1707 DRM_DEBUG_KMS("\n");
1708
1709 /* For PHY Mode Setting */
1710 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1711 HDMI_PHY_ENABLE_MODE_SET);
1712 /* Phy Power On */
1713 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1714 HDMI_PHY_POWER_ON);
1715 /* For PHY Mode Setting */
1716 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1717 HDMI_PHY_DISABLE_MODE_SET);
1718 /* PHY SW Reset */
1719 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301720}
1721
1722static void hdmiphy_poweroff(struct hdmi_context *hdata)
1723{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001724 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301725 return;
1726
1727 DRM_DEBUG_KMS("\n");
1728
1729 /* PHY SW Reset */
1730 hdmiphy_conf_reset(hdata);
1731 /* For PHY Mode Setting */
1732 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1733 HDMI_PHY_ENABLE_MODE_SET);
1734
1735 /* PHY Power Off */
1736 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1737 HDMI_PHY_POWER_OFF);
1738
1739 /* For PHY Mode Setting */
1740 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1741 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301742}
1743
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001744static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1745{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001746 int ret;
1747 int i;
1748
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001749 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001750 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001751 if (i < 0) {
1752 DRM_ERROR("failed to find hdmiphy conf\n");
1753 return;
1754 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001755
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001756 ret = hdmiphy_reg_write_buf(hdata, 0,
1757 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001758 if (ret) {
1759 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001760 return;
1761 }
1762
Sean Paul09760ea2013-01-14 17:03:20 -05001763 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001764
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001765 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1766 HDMI_PHY_DISABLE_MODE_SET);
1767 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001768 DRM_ERROR("failed to enable hdmiphy\n");
1769 return;
1770 }
1771
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001772}
1773
1774static void hdmi_conf_apply(struct hdmi_context *hdata)
1775{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001776 hdmiphy_conf_reset(hdata);
1777 hdmiphy_conf_apply(hdata);
1778
Rahul Sharmabfa48422014-04-03 20:41:04 +05301779 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001780 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001781
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001782 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001783
1784 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301785 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001786 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001787
1788 hdmi_regs_dump(hdata, "start");
1789}
1790
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001791static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1792{
1793 int i;
1794 BUG_ON(num_bytes > 4);
1795 for (i = 0; i < num_bytes; i++)
1796 reg_pair[i] = (value >> (8 * i)) & 0xff;
1797}
1798
1799static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1800 struct drm_display_mode *m)
1801{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001802 struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
1803 struct hdmi_v14_core_regs *core = &hdata->mode_conf.core;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001804
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001805 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1806 hdmi_set_reg(core->v_line, 2, m->vtotal);
1807 hdmi_set_reg(core->h_line, 2, m->htotal);
1808 hdmi_set_reg(core->hsync_pol, 1,
1809 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1810 hdmi_set_reg(core->vsync_pol, 1,
1811 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1812 hdmi_set_reg(core->int_pro_mode, 1,
1813 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1814
1815 /*
1816 * Quirk requirement for exynos 5 HDMI IP design,
1817 * 2 pixels less than the actual calculation for hsync_start
1818 * and end.
1819 */
1820
1821 /* Following values & calculations differ for different type of modes */
1822 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1823 /* Interlaced Mode */
1824 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1825 (m->vsync_end - m->vdisplay) / 2);
1826 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1827 (m->vsync_start - m->vdisplay) / 2);
1828 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1829 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301830 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001831 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1832 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1833 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1834 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1835 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1836 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1837 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1838 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1839 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301840 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1841 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1842 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1843 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001844 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1845 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1846 } else {
1847 /* Progressive Mode */
1848 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1849 m->vsync_end - m->vdisplay);
1850 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1851 m->vsync_start - m->vdisplay);
1852 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1853 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1854 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1855 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1856 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1857 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1858 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1859 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1860 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1861 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1862 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1863 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1864 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301865 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1866 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1867 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001868 }
1869
1870 /* Following values & calculations are same irrespective of mode type */
1871 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1872 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1873 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1874 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1875 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1876 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1877 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1878 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1879 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1880 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1881 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1882 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1883 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1884 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1885 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1886 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1887 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1888 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1889 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1890 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1891
1892 /* Timing generator registers */
1893 hdmi_set_reg(tg->cmd, 1, 0x0);
1894 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1895 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1896 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1897 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1898 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001899 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1900 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001901 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001902 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001903}
1904
Sean Paulf041b252014-01-30 16:19:15 -05001905static void hdmi_mode_set(struct exynos_drm_display *display,
1906 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001907{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001908 struct hdmi_context *hdata = display_to_hdmi(display);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001909 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001910
YoungJun Chocbc4c332013-06-12 10:44:40 +09001911 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1912 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001913 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001914 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001915
Rahul Sharmabfa48422014-04-03 20:41:04 +05301916 /* preserve mode information for later use. */
1917 drm_mode_copy(&hdata->current_mode, mode);
1918
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001919 hdata->cea_video_id = drm_match_cea_mode(mode);
1920
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001921 if (hdata->drv_data->type == HDMI_TYPE14)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001922 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001923}
1924
Sean Paulf041b252014-01-30 16:19:15 -05001925static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001926{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001927 struct hdmi_context *hdata = display_to_hdmi(display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001928
Andrzej Hajda882a0642015-07-09 16:28:08 +02001929 if (!hdata->powered)
Shirish Sdda90122013-01-23 22:03:18 -05001930 return;
Shirish Sdda90122013-01-23 22:03:18 -05001931
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001932 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001933}
1934
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001935static void hdmi_poweron(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001936{
1937 struct hdmi_resources *res = &hdata->res;
1938
Andrzej Hajda882a0642015-07-09 16:28:08 +02001939 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001940 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001941
1942 hdata->powered = true;
1943
Sean Paulaf65c802014-01-30 16:19:27 -05001944 pm_runtime_get_sync(hdata->dev);
1945
Seung-Woo Kimad079452013-06-05 14:34:38 +09001946 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1947 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1948
Rahul Sharma049d34e2014-05-20 10:36:05 +05301949 /* set pmu hdmiphy control bit to enable hdmiphy */
1950 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1951 PMU_HDMI_PHY_ENABLE_BIT, 1);
1952
Sean Paul0bfb1f82013-06-11 12:24:02 +05301953 clk_prepare_enable(res->hdmi);
1954 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301955
1956 hdmiphy_poweron(hdata);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001957 hdmi_commit(&hdata->display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001958}
1959
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001960static void hdmi_poweroff(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001961{
1962 struct hdmi_resources *res = &hdata->res;
1963
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001964 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001965 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001966
Rahul Sharmabfa48422014-04-03 20:41:04 +05301967 /* HDMI System Disable */
1968 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1969
Rahul Sharmaa5562252012-11-28 11:30:25 +05301970 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001971
Sean Paul724fd142014-05-09 15:05:10 +09001972 cancel_delayed_work(&hdata->hotplug_work);
1973
Sean Paul0bfb1f82013-06-11 12:24:02 +05301974 clk_disable_unprepare(res->sclk_hdmi);
1975 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301976
1977 /* reset pmu hdmiphy control bit to disable hdmiphy */
1978 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1979 PMU_HDMI_PHY_ENABLE_BIT, 0);
1980
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001981 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1982
Sean Paulaf65c802014-01-30 16:19:27 -05001983 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001984
1985 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001986}
1987
Sean Paulf041b252014-01-30 16:19:15 -05001988static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001989{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001990 struct hdmi_context *hdata = display_to_hdmi(display);
Inki Dae245f98f2014-06-13 17:44:40 +09001991 struct drm_encoder *encoder = hdata->encoder;
1992 struct drm_crtc *crtc = encoder->crtc;
Jani Nikulab0f87782015-03-11 11:50:59 +02001993 const struct drm_crtc_helper_funcs *funcs = NULL;
Inki Dae245f98f2014-06-13 17:44:40 +09001994
YoungJun Chocbc4c332013-06-12 10:44:40 +09001995 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001996
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001997 switch (mode) {
1998 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09001999 hdmi_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002000 break;
2001 case DRM_MODE_DPMS_STANDBY:
2002 case DRM_MODE_DPMS_SUSPEND:
2003 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002004 /*
2005 * The SFRs of VP and Mixer are updated by Vertical Sync of
2006 * Timing generator which is a part of HDMI so the sequence
2007 * to disable TV Subsystem should be as following,
2008 * VP -> Mixer -> HDMI
2009 *
2010 * Below codes will try to disable Mixer and VP(if used)
2011 * prior to disabling HDMI.
2012 */
2013 if (crtc)
2014 funcs = crtc->helper_private;
Gustavo Padovan63498e32015-06-01 12:04:53 -03002015 if (funcs && funcs->disable)
2016 (*funcs->disable)(crtc);
Inki Dae245f98f2014-06-13 17:44:40 +09002017
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002018 hdmi_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002019 break;
2020 default:
2021 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2022 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002023 }
2024}
2025
Sean Paulf041b252014-01-30 16:19:15 -05002026static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002027 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002028 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002029 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002030 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002031 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002032};
2033
Sean Paul724fd142014-05-09 15:05:10 +09002034static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002035{
Sean Paul724fd142014-05-09 15:05:10 +09002036 struct hdmi_context *hdata;
2037
2038 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002039
Sean Paul45517892014-01-30 16:19:05 -05002040 if (hdata->drm_dev)
2041 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002042}
2043
2044static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2045{
2046 struct hdmi_context *hdata = arg;
2047
2048 mod_delayed_work(system_wq, &hdata->hotplug_work,
2049 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002050
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002051 return IRQ_HANDLED;
2052}
2053
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002054static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002055{
2056 struct device *dev = hdata->dev;
2057 struct hdmi_resources *res = &hdata->res;
2058 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002059 "vdd",
2060 "vdd_osc",
2061 "vdd_pll",
2062 };
2063 int i, ret;
2064
2065 DRM_DEBUG_KMS("HDMI resource init\n");
2066
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002067 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302068 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302069 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002070 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002071 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002072 goto fail;
2073 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302074 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302075 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002076 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002077 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002078 goto fail;
2079 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302080 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302081 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002082 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002083 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002084 goto fail;
2085 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302086 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302087 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002088 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002089 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002090 goto fail;
2091 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302092 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2093 if (IS_ERR(res->mout_hdmi)) {
2094 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002095 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302096 goto fail;
2097 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002098
Rahul Sharma59956d32013-06-11 12:24:03 +05302099 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002100
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302101 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302102 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002103 if (!res->regul_bulk) {
2104 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002105 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002106 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002107 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2108 res->regul_bulk[i].supply = supply[i];
2109 res->regul_bulk[i].consumer = NULL;
2110 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302111 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002112 if (ret) {
2113 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002114 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002115 }
2116 res->regul_count = ARRAY_SIZE(supply);
2117
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002118 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2119 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2120 DRM_ERROR("failed to get hdmi-en regulator\n");
2121 return PTR_ERR(res->reg_hdmi_en);
2122 }
2123 if (!IS_ERR(res->reg_hdmi_en)) {
2124 ret = regulator_enable(res->reg_hdmi_en);
2125 if (ret) {
2126 DRM_ERROR("failed to enable hdmi-en regulator\n");
2127 return ret;
2128 }
2129 } else
2130 res->reg_hdmi_en = NULL;
2131
Inki Daedf5225b2014-05-29 18:28:02 +09002132 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133fail:
2134 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002135 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002136}
2137
Rahul Sharma22c4f422012-10-04 20:48:55 +05302138static struct of_device_id hdmi_match_types[] = {
2139 {
2140 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002141 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302142 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02002143 .compatible = "samsung,exynos4210-hdmi",
2144 .data = &exynos4210_hdmi_driver_data,
2145 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302146 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002147 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302148 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302149 .compatible = "samsung,exynos5420-hdmi",
2150 .data = &exynos5420_hdmi_driver_data,
2151 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302152 /* end node */
2153 }
2154};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02002155MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302156
Inki Daef37cd5e2014-05-09 14:25:20 +09002157static int hdmi_bind(struct device *dev, struct device *master, void *data)
2158{
2159 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002160 struct hdmi_context *hdata = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002161
Inki Daef37cd5e2014-05-09 14:25:20 +09002162 hdata->drm_dev = drm_dev;
2163
Andrzej Hajda930865f2014-11-17 09:54:20 +01002164 return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
Inki Daef37cd5e2014-05-09 14:25:20 +09002165}
2166
2167static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2168{
Inki Daef37cd5e2014-05-09 14:25:20 +09002169}
2170
2171static const struct component_ops hdmi_component_ops = {
2172 .bind = hdmi_bind,
2173 .unbind = hdmi_unbind,
2174};
2175
Inki Daee2a562d2014-05-09 16:46:10 +09002176static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2177{
2178 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2179 struct device_node *np;
2180
2181 np = of_find_compatible_node(NULL, NULL, compatible_str);
2182 if (np)
2183 return of_get_next_parent(np);
2184
2185 return NULL;
2186}
2187
2188static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2189{
2190 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2191
2192 return of_find_compatible_node(NULL, NULL, compatible_str);
2193}
2194
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002195static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196{
Inki Daef37cd5e2014-05-09 14:25:20 +09002197 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09002198 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002199 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002200 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002201 struct resource *res;
2202 int ret;
2203
Andrzej Hajda930865f2014-11-17 09:54:20 +01002204 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2205 if (!hdata)
2206 return -ENOMEM;
2207
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002208 match = of_match_device(hdmi_match_types, dev);
2209 if (!match)
2210 return -ENODEV;
2211
2212 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002213 hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
2214 hdata->display.ops = &hdmi_display_ops;
2215
Andrzej Hajda930865f2014-11-17 09:54:20 +01002216 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002217
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002218 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002219 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2220 if (hdata->hpd_gpio < 0) {
2221 DRM_ERROR("cannot get hpd gpio property\n");
2222 return hdata->hpd_gpio;
2223 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002224
2225 ret = hdmi_resources_init(hdata);
2226 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302227 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002228 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002229 }
2230
2231 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002232 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002233 if (IS_ERR(hdata->regs)) {
2234 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002235 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002236 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002237
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002238 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302239 if (ret) {
2240 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002241 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302242 }
2243
Inki Daee2a562d2014-05-09 16:46:10 +09002244 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2245 if (ddc_node)
2246 goto out_get_ddc_adpt;
2247
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002248 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002249 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2250 if (!ddc_node) {
2251 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002252 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002253 }
Inki Daee2a562d2014-05-09 16:46:10 +09002254
2255out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002256 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2257 if (!hdata->ddc_adpt) {
2258 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002259 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002260 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002261
Inki Daee2a562d2014-05-09 16:46:10 +09002262 phy_node = hdmi_legacy_phy_dt_binding(dev);
2263 if (phy_node)
2264 goto out_get_phy_port;
2265
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002266 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002267 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2268 if (!phy_node) {
2269 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2270 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002271 goto err_ddc;
2272 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002273
Inki Daee2a562d2014-05-09 16:46:10 +09002274out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002275 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002276 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2277 if (!hdata->regs_hdmiphy) {
2278 DRM_ERROR("failed to ioremap hdmi phy\n");
2279 ret = -ENOMEM;
2280 goto err_ddc;
2281 }
2282 } else {
2283 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2284 if (!hdata->hdmiphy_port) {
2285 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002286 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002287 goto err_ddc;
2288 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002289 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002290
Sean Paul77006a72013-01-16 10:17:20 -05002291 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2292 if (hdata->irq < 0) {
2293 DRM_ERROR("failed to get GPIO irq\n");
2294 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002295 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002296 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002297
Sean Paul724fd142014-05-09 15:05:10 +09002298 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2299
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002300 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002301 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002302 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002303 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002304 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002305 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002306 goto err_hdmiphy;
2307 }
2308
Rahul Sharma049d34e2014-05-20 10:36:05 +05302309 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2310 "samsung,syscon-phandle");
2311 if (IS_ERR(hdata->pmureg)) {
2312 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002313 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302314 goto err_hdmiphy;
2315 }
2316
Sean Paulaf65c802014-01-30 16:19:27 -05002317 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002318
Inki Daedf5225b2014-05-29 18:28:02 +09002319 ret = component_add(&pdev->dev, &hdmi_component_ops);
2320 if (ret)
2321 goto err_disable_pm_runtime;
2322
2323 return ret;
2324
2325err_disable_pm_runtime:
2326 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002327
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002328err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002329 if (hdata->hdmiphy_port)
2330 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002331err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002332 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002333
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002334 return ret;
2335}
2336
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002337static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002338{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002339 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002340
Sean Paul724fd142014-05-09 15:05:10 +09002341 cancel_delayed_work_sync(&hdata->hotplug_work);
2342
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002343 if (hdata->res.reg_hdmi_en)
2344 regulator_disable(hdata->res.reg_hdmi_en);
2345
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002346 if (hdata->hdmiphy_port)
2347 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002348 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002349
Sean Paulaf65c802014-01-30 16:19:27 -05002350 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002351 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002352
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002353 return 0;
2354}
2355
2356struct platform_driver hdmi_driver = {
2357 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002358 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002359 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302360 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002361 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302362 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002363 },
2364};