blob: 4a00990e4ae4e8459b94a9a007044af1cc11af62 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
25#include <linux/spinlock.h>
26#include <linux/wait.h>
27#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090028#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/irq.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/clk.h>
34#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053036#include <linux/of.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090037#include <linux/of_address.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053038#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053039#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090040#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053041#include <linux/mfd/syscon.h>
42#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090043
44#include <drm/exynos_drm.h>
45
46#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090047#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050048#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090049
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053050#include <linux/gpio.h>
51#include <media/s5p_hdmi.h>
52
Sean Pauld9716ee2014-01-30 16:19:29 -050053#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090054
Sean Paul724fd142014-05-09 15:05:10 +090055#define HOTPLUG_DEBOUNCE_MS 1100
56
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053057/* AVI header and aspect ratio */
58#define HDMI_AVI_VERSION 0x02
59#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053060
61/* AUI header info */
62#define HDMI_AUI_VERSION 0x01
63#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053064#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
65#define AVI_4_3_CENTER_RATIO 0x9
66#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053067
Rahul Sharma5a325072012-10-04 20:48:54 +053068enum hdmi_type {
69 HDMI_TYPE13,
70 HDMI_TYPE14,
71};
72
Inki Daebfe4e842014-03-06 14:18:17 +090073struct hdmi_driver_data {
74 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090075 const struct hdmiphy_config *phy_confs;
76 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090077 unsigned int is_apb_phy:1;
78};
79
Joonyoung Shim590f4182012-03-16 18:47:14 +090080struct hdmi_resources {
81 struct clk *hdmi;
82 struct clk *sclk_hdmi;
83 struct clk *sclk_pixel;
84 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053085 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090086 struct regulator_bulk_data *regul_bulk;
Marek Szyprowski05fdf982014-07-01 10:10:06 +020087 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +090088 int regul_count;
89};
90
Sean Paul2f7e2ed2013-01-15 08:11:08 -050091struct hdmi_tg_regs {
92 u8 cmd[1];
93 u8 h_fsz[2];
94 u8 hact_st[2];
95 u8 hact_sz[2];
96 u8 v_fsz[2];
97 u8 vsync[2];
98 u8 vsync2[2];
99 u8 vact_st[2];
100 u8 vact_sz[2];
101 u8 field_chg[2];
102 u8 vact_st2[2];
103 u8 vact_st3[2];
104 u8 vact_st4[2];
105 u8 vsync_top_hdmi[2];
106 u8 vsync_bot_hdmi[2];
107 u8 field_top_hdmi[2];
108 u8 field_bot_hdmi[2];
109 u8 tg_3d[1];
110};
111
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900112struct hdmi_v13_core_regs {
113 u8 h_blank[2];
114 u8 v_blank[3];
115 u8 h_v_line[3];
116 u8 vsync_pol[1];
117 u8 int_pro_mode[1];
118 u8 v_blank_f[3];
119 u8 h_sync_gen[3];
120 u8 v_sync_gen1[3];
121 u8 v_sync_gen2[3];
122 u8 v_sync_gen3[3];
123};
124
125struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500126 u8 h_blank[2];
127 u8 v2_blank[2];
128 u8 v1_blank[2];
129 u8 v_line[2];
130 u8 h_line[2];
131 u8 hsync_pol[1];
132 u8 vsync_pol[1];
133 u8 int_pro_mode[1];
134 u8 v_blank_f0[2];
135 u8 v_blank_f1[2];
136 u8 h_sync_start[2];
137 u8 h_sync_end[2];
138 u8 v_sync_line_bef_2[2];
139 u8 v_sync_line_bef_1[2];
140 u8 v_sync_line_aft_2[2];
141 u8 v_sync_line_aft_1[2];
142 u8 v_sync_line_aft_pxl_2[2];
143 u8 v_sync_line_aft_pxl_1[2];
144 u8 v_blank_f2[2]; /* for 3D mode */
145 u8 v_blank_f3[2]; /* for 3D mode */
146 u8 v_blank_f4[2]; /* for 3D mode */
147 u8 v_blank_f5[2]; /* for 3D mode */
148 u8 v_sync_line_aft_3[2];
149 u8 v_sync_line_aft_4[2];
150 u8 v_sync_line_aft_5[2];
151 u8 v_sync_line_aft_6[2];
152 u8 v_sync_line_aft_pxl_3[2];
153 u8 v_sync_line_aft_pxl_4[2];
154 u8 v_sync_line_aft_pxl_5[2];
155 u8 v_sync_line_aft_pxl_6[2];
156 u8 vact_space_1[2];
157 u8 vact_space_2[2];
158 u8 vact_space_3[2];
159 u8 vact_space_4[2];
160 u8 vact_space_5[2];
161 u8 vact_space_6[2];
162};
163
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900164struct hdmi_v13_conf {
165 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500166 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900167};
168
169struct hdmi_v14_conf {
170 struct hdmi_v14_core_regs core;
171 struct hdmi_tg_regs tg;
172};
173
174struct hdmi_conf_regs {
175 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500176 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530177 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900178 union {
179 struct hdmi_v13_conf v13_conf;
180 struct hdmi_v14_conf v14_conf;
181 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500182};
183
Joonyoung Shim590f4182012-03-16 18:47:14 +0900184struct hdmi_context {
Andrzej Hajda930865f2014-11-17 09:54:20 +0100185 struct exynos_drm_display display;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900186 struct device *dev;
187 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500188 struct drm_connector connector;
189 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900190 bool hpd;
191 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900192 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900193 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900194
Joonyoung Shim590f4182012-03-16 18:47:14 +0900195 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500196 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900197 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900198
Inki Dae8fa04aa2014-03-13 16:38:31 +0900199 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900200 struct i2c_client *hdmiphy_port;
201
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900202 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530203 struct drm_display_mode current_mode;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900204 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900205
206 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900207
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530208 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900209 void __iomem *regs_hdmiphy;
210 const struct hdmiphy_config *phy_confs;
211 unsigned int phy_conf_count;
Rahul Sharma5a325072012-10-04 20:48:54 +0530212
Rahul Sharma049d34e2014-05-20 10:36:05 +0530213 struct regmap *pmureg;
Rahul Sharma5a325072012-10-04 20:48:54 +0530214 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900215};
216
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100217static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
218{
219 return container_of(d, struct hdmi_context, display);
220}
221
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500222struct hdmiphy_config {
223 int pixel_clock;
224 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900225};
226
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900227/* list of phy config settings */
228static const struct hdmiphy_config hdmiphy_v13_configs[] = {
229 {
230 .pixel_clock = 27000000,
231 .conf = {
232 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
233 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
234 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
235 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
236 },
237 },
238 {
239 .pixel_clock = 27027000,
240 .conf = {
241 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
242 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
243 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
244 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
245 },
246 },
247 {
248 .pixel_clock = 74176000,
249 .conf = {
250 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
251 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
252 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
253 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
254 },
255 },
256 {
257 .pixel_clock = 74250000,
258 .conf = {
259 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
260 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
261 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
262 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
263 },
264 },
265 {
266 .pixel_clock = 148500000,
267 .conf = {
268 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
269 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
270 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
271 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
272 },
273 },
274};
275
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500276static const struct hdmiphy_config hdmiphy_v14_configs[] = {
277 {
278 .pixel_clock = 25200000,
279 .conf = {
280 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
281 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
282 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
283 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
284 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900285 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500286 {
287 .pixel_clock = 27000000,
288 .conf = {
289 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
290 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
291 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
292 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
293 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900294 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500295 {
296 .pixel_clock = 27027000,
297 .conf = {
298 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
299 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
300 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
301 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
302 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900303 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500304 {
305 .pixel_clock = 36000000,
306 .conf = {
307 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
308 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
309 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
310 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
311 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900312 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500313 {
314 .pixel_clock = 40000000,
315 .conf = {
316 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
317 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
318 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
319 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
320 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900321 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500322 {
323 .pixel_clock = 65000000,
324 .conf = {
325 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
326 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
327 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
328 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
329 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900330 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500331 {
Shirish Se1d883c2014-03-13 14:28:27 +0900332 .pixel_clock = 71000000,
333 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530334 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
335 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
336 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900337 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
338 },
339 },
340 {
341 .pixel_clock = 73250000,
342 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530343 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
344 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
345 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900346 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
347 },
348 },
349 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500350 .pixel_clock = 74176000,
351 .conf = {
352 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
353 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
354 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
355 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
356 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900357 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500358 {
359 .pixel_clock = 74250000,
360 .conf = {
361 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
362 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
363 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
364 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
365 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900366 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500367 {
368 .pixel_clock = 83500000,
369 .conf = {
370 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
371 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
372 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
373 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
374 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900375 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500376 {
377 .pixel_clock = 106500000,
378 .conf = {
379 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
380 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
381 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
382 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
383 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900384 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500385 {
386 .pixel_clock = 108000000,
387 .conf = {
388 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
389 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
390 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
391 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
392 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900393 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500394 {
Shirish Se1d883c2014-03-13 14:28:27 +0900395 .pixel_clock = 115500000,
396 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530397 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
398 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
399 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900400 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
401 },
402 },
403 {
404 .pixel_clock = 119000000,
405 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530406 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
407 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
408 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900409 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
410 },
411 },
412 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500413 .pixel_clock = 146250000,
414 .conf = {
415 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
416 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
417 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
418 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
419 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900420 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500421 {
422 .pixel_clock = 148500000,
423 .conf = {
424 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
425 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
426 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
427 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
428 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900429 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900430};
431
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530432static const struct hdmiphy_config hdmiphy_5420_configs[] = {
433 {
434 .pixel_clock = 25200000,
435 .conf = {
436 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
437 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
438 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
439 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
440 },
441 },
442 {
443 .pixel_clock = 27000000,
444 .conf = {
445 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
446 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
447 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
448 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
449 },
450 },
451 {
452 .pixel_clock = 27027000,
453 .conf = {
454 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
455 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
456 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
457 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
458 },
459 },
460 {
461 .pixel_clock = 36000000,
462 .conf = {
463 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
464 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
465 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
466 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
467 },
468 },
469 {
470 .pixel_clock = 40000000,
471 .conf = {
472 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
473 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
474 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
475 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
476 },
477 },
478 {
479 .pixel_clock = 65000000,
480 .conf = {
481 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
482 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
483 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
484 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
485 },
486 },
487 {
488 .pixel_clock = 71000000,
489 .conf = {
490 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
491 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
492 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
493 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
494 },
495 },
496 {
497 .pixel_clock = 73250000,
498 .conf = {
499 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
500 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
501 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
502 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
503 },
504 },
505 {
506 .pixel_clock = 74176000,
507 .conf = {
508 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
509 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
510 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
511 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
512 },
513 },
514 {
515 .pixel_clock = 74250000,
516 .conf = {
517 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
518 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
519 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
520 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
521 },
522 },
523 {
524 .pixel_clock = 83500000,
525 .conf = {
526 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
527 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
528 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
529 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
530 },
531 },
532 {
533 .pixel_clock = 88750000,
534 .conf = {
535 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
536 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
537 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
538 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
539 },
540 },
541 {
542 .pixel_clock = 106500000,
543 .conf = {
544 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
545 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
546 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
547 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
548 },
549 },
550 {
551 .pixel_clock = 108000000,
552 .conf = {
553 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
554 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
555 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
556 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
557 },
558 },
559 {
560 .pixel_clock = 115500000,
561 .conf = {
562 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
563 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
564 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
565 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
566 },
567 },
568 {
569 .pixel_clock = 146250000,
570 .conf = {
571 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
572 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
573 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
574 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
575 },
576 },
577 {
578 .pixel_clock = 148500000,
579 .conf = {
580 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
581 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
582 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
583 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
584 },
585 },
586};
587
Sachin Kamat16337072014-05-22 10:32:56 +0530588static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530589 .type = HDMI_TYPE14,
590 .phy_confs = hdmiphy_5420_configs,
591 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
592 .is_apb_phy = 1,
593};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900594
Sachin Kamat16337072014-05-22 10:32:56 +0530595static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900596 .type = HDMI_TYPE14,
597 .phy_confs = hdmiphy_v14_configs,
598 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
599 .is_apb_phy = 0,
600};
601
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200602static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
603 .type = HDMI_TYPE13,
604 .phy_confs = hdmiphy_v13_configs,
605 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
606 .is_apb_phy = 0,
607};
608
Sachin Kamat16337072014-05-22 10:32:56 +0530609static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900610 .type = HDMI_TYPE14,
611 .phy_confs = hdmiphy_v13_configs,
612 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
613 .is_apb_phy = 0,
614};
615
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900616static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
617{
618 return readl(hdata->regs + reg_id);
619}
620
621static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
622 u32 reg_id, u8 value)
623{
624 writeb(value, hdata->regs + reg_id);
625}
626
627static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
628 u32 reg_id, u32 value, u32 mask)
629{
630 u32 old = readl(hdata->regs + reg_id);
631 value = (value & mask) | (old & ~mask);
632 writel(value, hdata->regs + reg_id);
633}
634
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900635static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
636 u32 reg_offset, u8 value)
637{
638 if (hdata->hdmiphy_port) {
639 u8 buffer[2];
640 int ret;
641
642 buffer[0] = reg_offset;
643 buffer[1] = value;
644
645 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
646 if (ret == 2)
647 return 0;
648 return ret;
649 } else {
650 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
651 return 0;
652 }
653}
654
655static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
656 u32 reg_offset, const u8 *buf, u32 len)
657{
658 if ((reg_offset + len) > 32)
659 return -EINVAL;
660
661 if (hdata->hdmiphy_port) {
662 int ret;
663
664 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
665 if (ret == len)
666 return 0;
667 return ret;
668 } else {
669 int i;
670 for (i = 0; i < len; i++)
671 writeb(buf[i], hdata->regs_hdmiphy +
672 ((reg_offset + i)<<2));
673 return 0;
674 }
675}
676
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900677static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900678{
679#define DUMPREG(reg_id) \
680 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
681 readl(hdata->regs + reg_id))
682 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
683 DUMPREG(HDMI_INTC_FLAG);
684 DUMPREG(HDMI_INTC_CON);
685 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900686 DUMPREG(HDMI_V13_PHY_RSTOUT);
687 DUMPREG(HDMI_V13_PHY_VPLL);
688 DUMPREG(HDMI_V13_PHY_CMU);
689 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900690
691 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
692 DUMPREG(HDMI_CON_0);
693 DUMPREG(HDMI_CON_1);
694 DUMPREG(HDMI_CON_2);
695 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900696 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900697 DUMPREG(HDMI_STATUS_EN);
698 DUMPREG(HDMI_HPD);
699 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900700 DUMPREG(HDMI_V13_HPD_GEN);
701 DUMPREG(HDMI_V13_DC_CONTROL);
702 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900703
704 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
705 DUMPREG(HDMI_H_BLANK_0);
706 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900707 DUMPREG(HDMI_V13_V_BLANK_0);
708 DUMPREG(HDMI_V13_V_BLANK_1);
709 DUMPREG(HDMI_V13_V_BLANK_2);
710 DUMPREG(HDMI_V13_H_V_LINE_0);
711 DUMPREG(HDMI_V13_H_V_LINE_1);
712 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900713 DUMPREG(HDMI_VSYNC_POL);
714 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900715 DUMPREG(HDMI_V13_V_BLANK_F_0);
716 DUMPREG(HDMI_V13_V_BLANK_F_1);
717 DUMPREG(HDMI_V13_V_BLANK_F_2);
718 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
719 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
720 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
721 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
722 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
723 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
724 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
725 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
726 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
727 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
728 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
729 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900730
731 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
732 DUMPREG(HDMI_TG_CMD);
733 DUMPREG(HDMI_TG_H_FSZ_L);
734 DUMPREG(HDMI_TG_H_FSZ_H);
735 DUMPREG(HDMI_TG_HACT_ST_L);
736 DUMPREG(HDMI_TG_HACT_ST_H);
737 DUMPREG(HDMI_TG_HACT_SZ_L);
738 DUMPREG(HDMI_TG_HACT_SZ_H);
739 DUMPREG(HDMI_TG_V_FSZ_L);
740 DUMPREG(HDMI_TG_V_FSZ_H);
741 DUMPREG(HDMI_TG_VSYNC_L);
742 DUMPREG(HDMI_TG_VSYNC_H);
743 DUMPREG(HDMI_TG_VSYNC2_L);
744 DUMPREG(HDMI_TG_VSYNC2_H);
745 DUMPREG(HDMI_TG_VACT_ST_L);
746 DUMPREG(HDMI_TG_VACT_ST_H);
747 DUMPREG(HDMI_TG_VACT_SZ_L);
748 DUMPREG(HDMI_TG_VACT_SZ_H);
749 DUMPREG(HDMI_TG_FIELD_CHG_L);
750 DUMPREG(HDMI_TG_FIELD_CHG_H);
751 DUMPREG(HDMI_TG_VACT_ST2_L);
752 DUMPREG(HDMI_TG_VACT_ST2_H);
753 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
754 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
755 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
756 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
757 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
758 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
759 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
760 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
761#undef DUMPREG
762}
763
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900764static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
765{
766 int i;
767
768#define DUMPREG(reg_id) \
769 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
770 readl(hdata->regs + reg_id))
771
772 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
773 DUMPREG(HDMI_INTC_CON);
774 DUMPREG(HDMI_INTC_FLAG);
775 DUMPREG(HDMI_HPD_STATUS);
776 DUMPREG(HDMI_INTC_CON_1);
777 DUMPREG(HDMI_INTC_FLAG_1);
778 DUMPREG(HDMI_PHY_STATUS_0);
779 DUMPREG(HDMI_PHY_STATUS_PLL);
780 DUMPREG(HDMI_PHY_CON_0);
781 DUMPREG(HDMI_PHY_RSTOUT);
782 DUMPREG(HDMI_PHY_VPLL);
783 DUMPREG(HDMI_PHY_CMU);
784 DUMPREG(HDMI_CORE_RSTOUT);
785
786 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
787 DUMPREG(HDMI_CON_0);
788 DUMPREG(HDMI_CON_1);
789 DUMPREG(HDMI_CON_2);
790 DUMPREG(HDMI_SYS_STATUS);
791 DUMPREG(HDMI_PHY_STATUS_0);
792 DUMPREG(HDMI_STATUS_EN);
793 DUMPREG(HDMI_HPD);
794 DUMPREG(HDMI_MODE_SEL);
795 DUMPREG(HDMI_ENC_EN);
796 DUMPREG(HDMI_DC_CONTROL);
797 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
798
799 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
800 DUMPREG(HDMI_H_BLANK_0);
801 DUMPREG(HDMI_H_BLANK_1);
802 DUMPREG(HDMI_V2_BLANK_0);
803 DUMPREG(HDMI_V2_BLANK_1);
804 DUMPREG(HDMI_V1_BLANK_0);
805 DUMPREG(HDMI_V1_BLANK_1);
806 DUMPREG(HDMI_V_LINE_0);
807 DUMPREG(HDMI_V_LINE_1);
808 DUMPREG(HDMI_H_LINE_0);
809 DUMPREG(HDMI_H_LINE_1);
810 DUMPREG(HDMI_HSYNC_POL);
811
812 DUMPREG(HDMI_VSYNC_POL);
813 DUMPREG(HDMI_INT_PRO_MODE);
814 DUMPREG(HDMI_V_BLANK_F0_0);
815 DUMPREG(HDMI_V_BLANK_F0_1);
816 DUMPREG(HDMI_V_BLANK_F1_0);
817 DUMPREG(HDMI_V_BLANK_F1_1);
818
819 DUMPREG(HDMI_H_SYNC_START_0);
820 DUMPREG(HDMI_H_SYNC_START_1);
821 DUMPREG(HDMI_H_SYNC_END_0);
822 DUMPREG(HDMI_H_SYNC_END_1);
823
824 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
825 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
826 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
827 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
828
829 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
830 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
831 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
832 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
833
834 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
836 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
837 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
838
839 DUMPREG(HDMI_V_BLANK_F2_0);
840 DUMPREG(HDMI_V_BLANK_F2_1);
841 DUMPREG(HDMI_V_BLANK_F3_0);
842 DUMPREG(HDMI_V_BLANK_F3_1);
843 DUMPREG(HDMI_V_BLANK_F4_0);
844 DUMPREG(HDMI_V_BLANK_F4_1);
845 DUMPREG(HDMI_V_BLANK_F5_0);
846 DUMPREG(HDMI_V_BLANK_F5_1);
847
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
850 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
851 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
852 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
853 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
854 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
855 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
856
857 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
858 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
859 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
860 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
861 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
862 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
863 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
864 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
865
866 DUMPREG(HDMI_VACT_SPACE_1_0);
867 DUMPREG(HDMI_VACT_SPACE_1_1);
868 DUMPREG(HDMI_VACT_SPACE_2_0);
869 DUMPREG(HDMI_VACT_SPACE_2_1);
870 DUMPREG(HDMI_VACT_SPACE_3_0);
871 DUMPREG(HDMI_VACT_SPACE_3_1);
872 DUMPREG(HDMI_VACT_SPACE_4_0);
873 DUMPREG(HDMI_VACT_SPACE_4_1);
874 DUMPREG(HDMI_VACT_SPACE_5_0);
875 DUMPREG(HDMI_VACT_SPACE_5_1);
876 DUMPREG(HDMI_VACT_SPACE_6_0);
877 DUMPREG(HDMI_VACT_SPACE_6_1);
878
879 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
880 DUMPREG(HDMI_TG_CMD);
881 DUMPREG(HDMI_TG_H_FSZ_L);
882 DUMPREG(HDMI_TG_H_FSZ_H);
883 DUMPREG(HDMI_TG_HACT_ST_L);
884 DUMPREG(HDMI_TG_HACT_ST_H);
885 DUMPREG(HDMI_TG_HACT_SZ_L);
886 DUMPREG(HDMI_TG_HACT_SZ_H);
887 DUMPREG(HDMI_TG_V_FSZ_L);
888 DUMPREG(HDMI_TG_V_FSZ_H);
889 DUMPREG(HDMI_TG_VSYNC_L);
890 DUMPREG(HDMI_TG_VSYNC_H);
891 DUMPREG(HDMI_TG_VSYNC2_L);
892 DUMPREG(HDMI_TG_VSYNC2_H);
893 DUMPREG(HDMI_TG_VACT_ST_L);
894 DUMPREG(HDMI_TG_VACT_ST_H);
895 DUMPREG(HDMI_TG_VACT_SZ_L);
896 DUMPREG(HDMI_TG_VACT_SZ_H);
897 DUMPREG(HDMI_TG_FIELD_CHG_L);
898 DUMPREG(HDMI_TG_FIELD_CHG_H);
899 DUMPREG(HDMI_TG_VACT_ST2_L);
900 DUMPREG(HDMI_TG_VACT_ST2_H);
901 DUMPREG(HDMI_TG_VACT_ST3_L);
902 DUMPREG(HDMI_TG_VACT_ST3_H);
903 DUMPREG(HDMI_TG_VACT_ST4_L);
904 DUMPREG(HDMI_TG_VACT_ST4_H);
905 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
906 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
907 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
908 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
909 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
910 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
911 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
912 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
913 DUMPREG(HDMI_TG_3D);
914
915 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
916 DUMPREG(HDMI_AVI_CON);
917 DUMPREG(HDMI_AVI_HEADER0);
918 DUMPREG(HDMI_AVI_HEADER1);
919 DUMPREG(HDMI_AVI_HEADER2);
920 DUMPREG(HDMI_AVI_CHECK_SUM);
921 DUMPREG(HDMI_VSI_CON);
922 DUMPREG(HDMI_VSI_HEADER0);
923 DUMPREG(HDMI_VSI_HEADER1);
924 DUMPREG(HDMI_VSI_HEADER2);
925 for (i = 0; i < 7; ++i)
926 DUMPREG(HDMI_VSI_DATA(i));
927
928#undef DUMPREG
929}
930
931static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
932{
Rahul Sharma5a325072012-10-04 20:48:54 +0530933 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900934 hdmi_v13_regs_dump(hdata, prefix);
935 else
936 hdmi_v14_regs_dump(hdata, prefix);
937}
938
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530939static u8 hdmi_chksum(struct hdmi_context *hdata,
940 u32 start, u8 len, u32 hdr_sum)
941{
942 int i;
943
944 /* hdr_sum : header0 + header1 + header2
945 * start : start address of packet byte1
946 * len : packet bytes - 1 */
947 for (i = 0; i < len; ++i)
948 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
949
950 /* return 2's complement of 8 bit hdr_sum */
951 return (u8)(~(hdr_sum & 0xff) + 1);
952}
953
954static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530955 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530956{
957 u32 hdr_sum;
958 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530959 u32 mod;
960 u32 vic;
961
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530962 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
963 if (hdata->dvi_mode) {
964 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
965 HDMI_VSI_CON_DO_NOT_TRANSMIT);
966 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
967 HDMI_AVI_CON_DO_NOT_TRANSMIT);
968 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
969 return;
970 }
971
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530972 switch (infoframe->any.type) {
973 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530974 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530975 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
976 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
977 infoframe->any.version);
978 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
979 hdr_sum = infoframe->any.type + infoframe->any.version +
980 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530981
982 /* Output format zero hardcoded ,RGB YBCR selection */
983 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
984 AVI_ACTIVE_FORMAT_VALID |
985 AVI_UNDERSCANNED_DISPLAY_VALID);
986
Shirish S46154152014-03-13 10:58:28 +0530987 /*
988 * Set the aspect ratio as per the mode, mentioned in
989 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
990 */
991 switch (hdata->mode_conf.aspect_ratio) {
992 case HDMI_PICTURE_ASPECT_4_3:
993 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
994 hdata->mode_conf.aspect_ratio |
995 AVI_4_3_CENTER_RATIO);
996 break;
997 case HDMI_PICTURE_ASPECT_16_9:
998 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
999 hdata->mode_conf.aspect_ratio |
1000 AVI_16_9_CENTER_RATIO);
1001 break;
1002 case HDMI_PICTURE_ASPECT_NONE:
1003 default:
1004 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
1005 hdata->mode_conf.aspect_ratio |
1006 AVI_SAME_AS_PIC_ASPECT_RATIO);
1007 break;
1008 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301009
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001010 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301011 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
1012
1013 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301014 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301015 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1016 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1017 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301018 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301019 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301020 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1021 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1022 infoframe->any.version);
1023 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1024 hdr_sum = infoframe->any.type + infoframe->any.version +
1025 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301026 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301027 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301028 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1029 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1030 break;
1031 default:
1032 break;
1033 }
1034}
1035
Sean Pauld9716ee2014-01-30 16:19:29 -05001036static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1037 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001038{
Sean Pauld9716ee2014-01-30 16:19:29 -05001039 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001040
Sean Paul5137c8c2014-04-03 20:41:03 +05301041 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1042
Sean Pauld9716ee2014-01-30 16:19:29 -05001043 return hdata->hpd ? connector_status_connected :
1044 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001045}
1046
Sean Pauld9716ee2014-01-30 16:19:29 -05001047static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001048{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001049 drm_connector_unregister(connector);
1050 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001051}
1052
Sean Pauld9716ee2014-01-30 16:19:29 -05001053static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001054 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001055 .fill_modes = drm_helper_probe_single_connector_modes,
1056 .detect = hdmi_detect,
1057 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001058 .reset = drm_atomic_helper_connector_reset,
1059 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1060 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001061};
1062
1063static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001064{
Sean Pauld9716ee2014-01-30 16:19:29 -05001065 struct hdmi_context *hdata = ctx_from_connector(connector);
1066 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001067 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001068
Inki Dae8fa04aa2014-03-13 16:38:31 +09001069 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001070 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001071
Inki Dae8fa04aa2014-03-13 16:38:31 +09001072 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001073 if (!edid)
1074 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001075
Sean Pauld9716ee2014-01-30 16:19:29 -05001076 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001077 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1078 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001079 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001080
Sean Pauld9716ee2014-01-30 16:19:29 -05001081 drm_mode_connector_update_edid_property(connector, edid);
1082
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001083 ret = drm_add_edid_modes(connector, edid);
1084
1085 kfree(edid);
1086
1087 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001088}
1089
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001090static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001091{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001092 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001093
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001094 for (i = 0; i < hdata->phy_conf_count; i++)
1095 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001096 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001097
1098 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1099 return -EINVAL;
1100}
1101
Sean Pauld9716ee2014-01-30 16:19:29 -05001102static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001103 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001104{
Sean Pauld9716ee2014-01-30 16:19:29 -05001105 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001106 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001107
Rahul Sharma16844fb2013-06-10 14:50:00 +05301108 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1109 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1110 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1111 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001112
Sean Paulf041b252014-01-30 16:19:15 -05001113 ret = mixer_check_mode(mode);
1114 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001115 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001116
Rahul Sharma16844fb2013-06-10 14:50:00 +05301117 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001118 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001119 return MODE_BAD;
1120
1121 return MODE_OK;
1122}
1123
1124static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1125{
1126 struct hdmi_context *hdata = ctx_from_connector(connector);
1127
1128 return hdata->encoder;
1129}
1130
1131static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1132 .get_modes = hdmi_get_modes,
1133 .mode_valid = hdmi_mode_valid,
1134 .best_encoder = hdmi_best_encoder,
1135};
1136
1137static int hdmi_create_connector(struct exynos_drm_display *display,
1138 struct drm_encoder *encoder)
1139{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001140 struct hdmi_context *hdata = display_to_hdmi(display);
Sean Pauld9716ee2014-01-30 16:19:29 -05001141 struct drm_connector *connector = &hdata->connector;
1142 int ret;
1143
1144 hdata->encoder = encoder;
1145 connector->interlace_allowed = true;
1146 connector->polled = DRM_CONNECTOR_POLL_HPD;
1147
1148 ret = drm_connector_init(hdata->drm_dev, connector,
1149 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1150 if (ret) {
1151 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001152 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001153 }
1154
1155 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001156 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001157 drm_mode_connector_attach_encoder(connector, encoder);
1158
1159 return 0;
1160}
1161
Sean Paulf041b252014-01-30 16:19:15 -05001162static void hdmi_mode_fixup(struct exynos_drm_display *display,
1163 struct drm_connector *connector,
1164 const struct drm_display_mode *mode,
1165 struct drm_display_mode *adjusted_mode)
1166{
1167 struct drm_display_mode *m;
1168 int mode_ok;
1169
1170 DRM_DEBUG_KMS("%s\n", __FILE__);
1171
1172 drm_mode_set_crtcinfo(adjusted_mode, 0);
1173
Sean Pauld9716ee2014-01-30 16:19:29 -05001174 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001175
1176 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001177 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001178 return;
1179
1180 /*
1181 * otherwise, find the most suitable mode among modes and change it
1182 * to adjusted_mode.
1183 */
1184 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001185 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001186
Sean Pauld9716ee2014-01-30 16:19:29 -05001187 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001188 DRM_INFO("desired mode doesn't exist so\n");
1189 DRM_INFO("use the most suitable mode among modes.\n");
1190
1191 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1192 m->hdisplay, m->vdisplay, m->vrefresh);
1193
Sean Paul75626852014-01-30 16:19:16 -05001194 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001195 break;
1196 }
1197 }
1198}
1199
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001200static void hdmi_set_acr(u32 freq, u8 *acr)
1201{
1202 u32 n, cts;
1203
1204 switch (freq) {
1205 case 32000:
1206 n = 4096;
1207 cts = 27000;
1208 break;
1209 case 44100:
1210 n = 6272;
1211 cts = 30000;
1212 break;
1213 case 88200:
1214 n = 12544;
1215 cts = 30000;
1216 break;
1217 case 176400:
1218 n = 25088;
1219 cts = 30000;
1220 break;
1221 case 48000:
1222 n = 6144;
1223 cts = 27000;
1224 break;
1225 case 96000:
1226 n = 12288;
1227 cts = 27000;
1228 break;
1229 case 192000:
1230 n = 24576;
1231 cts = 27000;
1232 break;
1233 default:
1234 n = 0;
1235 cts = 0;
1236 break;
1237 }
1238
1239 acr[1] = cts >> 16;
1240 acr[2] = cts >> 8 & 0xff;
1241 acr[3] = cts & 0xff;
1242
1243 acr[4] = n >> 16;
1244 acr[5] = n >> 8 & 0xff;
1245 acr[6] = n & 0xff;
1246}
1247
1248static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1249{
1250 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1251 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1252 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1253 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1254 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1255 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1256 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1257 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1258 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1259
Rahul Sharma5a325072012-10-04 20:48:54 +05301260 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001261 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1262 else
1263 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1264}
1265
1266static void hdmi_audio_init(struct hdmi_context *hdata)
1267{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301268 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001269 u32 data_num, bit_ch, sample_frq;
1270 u32 val;
1271 u8 acr[7];
1272
1273 sample_rate = 44100;
1274 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001275
1276 switch (bits_per_sample) {
1277 case 20:
1278 data_num = 2;
1279 bit_ch = 1;
1280 break;
1281 case 24:
1282 data_num = 3;
1283 bit_ch = 1;
1284 break;
1285 default:
1286 data_num = 1;
1287 bit_ch = 0;
1288 break;
1289 }
1290
1291 hdmi_set_acr(sample_rate, acr);
1292 hdmi_reg_acr(hdata, acr);
1293
1294 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1295 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1296 | HDMI_I2S_MUX_ENABLE);
1297
1298 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1299 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1300
1301 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1302
1303 sample_frq = (sample_rate == 44100) ? 0 :
1304 (sample_rate == 48000) ? 2 :
1305 (sample_rate == 32000) ? 3 :
1306 (sample_rate == 96000) ? 0xa : 0x0;
1307
1308 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1309 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1310
1311 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1312 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1313
1314 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1315 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1316 | HDMI_I2S_SEL_LRCK(6));
1317 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1318 | HDMI_I2S_SEL_SDATA2(4));
1319 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1320 | HDMI_I2S_SEL_SDATA2(2));
1321 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1322
1323 /* I2S_CON_1 & 2 */
1324 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1325 | HDMI_I2S_L_CH_LOW_POL);
1326 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1327 | HDMI_I2S_SET_BIT_CH(bit_ch)
1328 | HDMI_I2S_SET_SDATA_BIT(data_num)
1329 | HDMI_I2S_BASIC_FORMAT);
1330
1331 /* Configure register related to CUV information */
1332 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1333 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1334 | HDMI_I2S_COPYRIGHT
1335 | HDMI_I2S_LINEAR_PCM
1336 | HDMI_I2S_CONSUMER_FORMAT);
1337 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1338 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1339 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1340 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1341 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1342 HDMI_I2S_ORG_SMP_FREQ_44_1
1343 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1344 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1345
1346 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1347}
1348
1349static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1350{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001351 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001352 return;
1353
1354 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1355 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1356 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1357}
1358
Rahul Sharmabfa48422014-04-03 20:41:04 +05301359static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001360{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301361 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001362
Rahul Sharmabfa48422014-04-03 20:41:04 +05301363 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1364 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001365
Rahul Sharmabfa48422014-04-03 20:41:04 +05301366 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1367 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001368}
1369
1370static void hdmi_conf_init(struct hdmi_context *hdata)
1371{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301372 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301373
Sean Paul77006a72013-01-16 10:17:20 -05001374 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001375 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1376 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001377
1378 /* choose HDMI mode */
1379 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1380 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301381 /* Apply Video preable and Guard band in HDMI mode only */
1382 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001383 /* disable bluescreen */
1384 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001385
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001386 if (hdata->dvi_mode) {
1387 /* choose DVI mode */
1388 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1389 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1390 hdmi_reg_writeb(hdata, HDMI_CON_2,
1391 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1392 }
1393
Rahul Sharma5a325072012-10-04 20:48:54 +05301394 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001395 /* choose bluescreen (fecal) color */
1396 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1397 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1398 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1399
1400 /* enable AVI packet every vsync, fixes purple line problem */
1401 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1402 /* force RGB, look to CEA-861-D, table 7 for more detail */
1403 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1404 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1405
1406 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1407 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1408 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1409 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301410 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1411 infoframe.any.version = HDMI_AVI_VERSION;
1412 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301413 hdmi_reg_infoframe(hdata, &infoframe);
1414
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301415 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1416 infoframe.any.version = HDMI_AUI_VERSION;
1417 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301418 hdmi_reg_infoframe(hdata, &infoframe);
1419
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001420 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001421 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1422 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001423}
1424
Rahul Sharma16844fb2013-06-10 14:50:00 +05301425static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001426{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001427 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1428 const struct hdmi_v13_core_regs *core =
1429 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001430 int tries;
1431
1432 /* setting core registers */
1433 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1434 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001435 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1436 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1437 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1438 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1439 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1440 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001441 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1442 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001443 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1444 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1445 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1446 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1447 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1448 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1449 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1450 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1451 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1452 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1453 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1454 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1455 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1456 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1457 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001458 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001459 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1463 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1464 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1465 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1466 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1467 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1468 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1469 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1470 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1471 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1472 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1473 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1474 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1475 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1476 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1477 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1478 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1479 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1480 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1481 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1482 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1483 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1484 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1485 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1486 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
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{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001511 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1512 const struct hdmi_v14_core_regs *core =
1513 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001514 int tries;
1515
1516 /* setting core registers */
1517 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1518 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1519 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1520 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1521 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1522 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1523 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1524 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1525 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1526 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1527 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1528 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1529 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1530 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1531 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1532 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1533 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1534 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1535 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1536 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1537 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1538 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1539 core->v_sync_line_bef_2[0]);
1540 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1541 core->v_sync_line_bef_2[1]);
1542 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1543 core->v_sync_line_bef_1[0]);
1544 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1545 core->v_sync_line_bef_1[1]);
1546 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1547 core->v_sync_line_aft_2[0]);
1548 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1549 core->v_sync_line_aft_2[1]);
1550 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1551 core->v_sync_line_aft_1[0]);
1552 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1553 core->v_sync_line_aft_1[1]);
1554 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1555 core->v_sync_line_aft_pxl_2[0]);
1556 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1557 core->v_sync_line_aft_pxl_2[1]);
1558 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1559 core->v_sync_line_aft_pxl_1[0]);
1560 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1561 core->v_sync_line_aft_pxl_1[1]);
1562 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1563 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1564 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1565 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1566 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1567 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1568 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1569 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1570 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1571 core->v_sync_line_aft_3[0]);
1572 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1573 core->v_sync_line_aft_3[1]);
1574 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1575 core->v_sync_line_aft_4[0]);
1576 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1577 core->v_sync_line_aft_4[1]);
1578 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1579 core->v_sync_line_aft_5[0]);
1580 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1581 core->v_sync_line_aft_5[1]);
1582 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1583 core->v_sync_line_aft_6[0]);
1584 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1585 core->v_sync_line_aft_6[1]);
1586 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1587 core->v_sync_line_aft_pxl_3[0]);
1588 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1589 core->v_sync_line_aft_pxl_3[1]);
1590 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1591 core->v_sync_line_aft_pxl_4[0]);
1592 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1593 core->v_sync_line_aft_pxl_4[1]);
1594 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1595 core->v_sync_line_aft_pxl_5[0]);
1596 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1597 core->v_sync_line_aft_pxl_5[1]);
1598 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1599 core->v_sync_line_aft_pxl_6[0]);
1600 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1601 core->v_sync_line_aft_pxl_6[1]);
1602 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1603 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1604 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1605 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1606 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1607 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1608 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1609 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1610 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1611 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1612 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1613 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1614
1615 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001616 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1626 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1627 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1628 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1629 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1630 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1631 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1632 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1633 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1634 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1635 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1636 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1637 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1638 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1639 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1640 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1641 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1642 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1643 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1644 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1645 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1646 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1647 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1648 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001649
1650 /* waiting for HDMIPHY's PLL to get to steady state */
1651 for (tries = 100; tries; --tries) {
1652 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1653 if (val & HDMI_PHY_STATUS_READY)
1654 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001655 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001656 }
1657 /* steady state not achieved */
1658 if (tries == 0) {
1659 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1660 hdmi_regs_dump(hdata, "timing apply");
1661 }
1662
Sean Paul0bfb1f82013-06-11 12:24:02 +05301663 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301664 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301665 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001666
1667 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301668 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001669}
1670
Rahul Sharma16844fb2013-06-10 14:50:00 +05301671static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001672{
Rahul Sharma5a325072012-10-04 20:48:54 +05301673 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301674 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001675 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301676 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001677}
1678
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001679static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1680{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001681 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001682
Sean Paul0bfb1f82013-06-11 12:24:02 +05301683 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301684 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301685 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001686
1687 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001688 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1689 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001690
Rahul Sharma5a325072012-10-04 20:48:54 +05301691 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001692 reg = HDMI_V13_PHY_RSTOUT;
1693 else
1694 reg = HDMI_PHY_RSTOUT;
1695
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001696 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001697 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001698 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001699 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001700 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001701}
1702
Rahul Sharmaa5562252012-11-28 11:30:25 +05301703static void hdmiphy_poweron(struct hdmi_context *hdata)
1704{
Shirish S6a296e22014-04-03 20:41:02 +05301705 if (hdata->type != HDMI_TYPE14)
1706 return;
1707
1708 DRM_DEBUG_KMS("\n");
1709
1710 /* For PHY Mode Setting */
1711 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1712 HDMI_PHY_ENABLE_MODE_SET);
1713 /* Phy Power On */
1714 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1715 HDMI_PHY_POWER_ON);
1716 /* For PHY Mode Setting */
1717 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1718 HDMI_PHY_DISABLE_MODE_SET);
1719 /* PHY SW Reset */
1720 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301721}
1722
1723static void hdmiphy_poweroff(struct hdmi_context *hdata)
1724{
Shirish S6a296e22014-04-03 20:41:02 +05301725 if (hdata->type != HDMI_TYPE14)
1726 return;
1727
1728 DRM_DEBUG_KMS("\n");
1729
1730 /* PHY SW Reset */
1731 hdmiphy_conf_reset(hdata);
1732 /* For PHY Mode Setting */
1733 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1734 HDMI_PHY_ENABLE_MODE_SET);
1735
1736 /* PHY Power Off */
1737 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1738 HDMI_PHY_POWER_OFF);
1739
1740 /* For PHY Mode Setting */
1741 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1742 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301743}
1744
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001745static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1746{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001747 int ret;
1748 int i;
1749
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001750 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001751 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1752 if (i < 0) {
1753 DRM_ERROR("failed to find hdmiphy conf\n");
1754 return;
1755 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001756
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001757 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1758 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
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001779 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301780 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001781 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001782 mutex_unlock(&hdata->hdmi_mutex);
1783
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001784 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001785
1786 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301787 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001788 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001789
1790 hdmi_regs_dump(hdata, "start");
1791}
1792
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001793static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1794{
1795 int i;
1796 BUG_ON(num_bytes > 4);
1797 for (i = 0; i < num_bytes; i++)
1798 reg_pair[i] = (value >> (8 * i)) & 0xff;
1799}
1800
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001801static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1802 struct drm_display_mode *m)
1803{
1804 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1805 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1806 unsigned int val;
1807
1808 hdata->mode_conf.cea_video_id =
1809 drm_match_cea_mode((struct drm_display_mode *)m);
1810 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301811 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001812
1813 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1814 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1815
1816 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1817 hdmi_set_reg(core->vsync_pol, 1, val);
1818
1819 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1820 hdmi_set_reg(core->int_pro_mode, 1, val);
1821
1822 val = (m->hsync_start - m->hdisplay - 2);
1823 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1824 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1825 hdmi_set_reg(core->h_sync_gen, 3, val);
1826
1827 /*
1828 * Quirk requirement for exynos HDMI IP design,
1829 * 2 pixels less than the actual calculation for hsync_start
1830 * and end.
1831 */
1832
1833 /* Following values & calculations differ for different type of modes */
1834 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1835 /* Interlaced Mode */
1836 val = ((m->vsync_end - m->vdisplay) / 2);
1837 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1838 hdmi_set_reg(core->v_sync_gen1, 3, val);
1839
1840 val = m->vtotal / 2;
1841 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1842 hdmi_set_reg(core->v_blank, 3, val);
1843
1844 val = (m->vtotal +
1845 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1846 val |= m->vtotal << 11;
1847 hdmi_set_reg(core->v_blank_f, 3, val);
1848
1849 val = ((m->vtotal / 2) + 7);
1850 val |= ((m->vtotal / 2) + 2) << 12;
1851 hdmi_set_reg(core->v_sync_gen2, 3, val);
1852
1853 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1854 val |= ((m->htotal / 2) +
1855 (m->hsync_start - m->hdisplay)) << 12;
1856 hdmi_set_reg(core->v_sync_gen3, 3, val);
1857
1858 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1859 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1860
1861 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1862 } else {
1863 /* Progressive Mode */
1864
1865 val = m->vtotal;
1866 val |= (m->vtotal - m->vdisplay) << 11;
1867 hdmi_set_reg(core->v_blank, 3, val);
1868
1869 hdmi_set_reg(core->v_blank_f, 3, 0);
1870
1871 val = (m->vsync_end - m->vdisplay);
1872 val |= ((m->vsync_start - m->vdisplay) << 12);
1873 hdmi_set_reg(core->v_sync_gen1, 3, val);
1874
1875 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1876 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1877 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1878 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1879 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1880 }
1881
1882 /* Timing generator registers */
1883 hdmi_set_reg(tg->cmd, 1, 0x0);
1884 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1885 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1886 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1887 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1888 hdmi_set_reg(tg->vsync, 2, 0x1);
1889 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1890 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1891 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1892 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1893 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1894 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1895 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1896}
1897
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001898static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1899 struct drm_display_mode *m)
1900{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001901 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1902 struct hdmi_v14_core_regs *core =
1903 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001904
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001905 hdata->mode_conf.cea_video_id =
1906 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001907 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301908 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001909
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001910 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1911 hdmi_set_reg(core->v_line, 2, m->vtotal);
1912 hdmi_set_reg(core->h_line, 2, m->htotal);
1913 hdmi_set_reg(core->hsync_pol, 1,
1914 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1915 hdmi_set_reg(core->vsync_pol, 1,
1916 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1917 hdmi_set_reg(core->int_pro_mode, 1,
1918 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1919
1920 /*
1921 * Quirk requirement for exynos 5 HDMI IP design,
1922 * 2 pixels less than the actual calculation for hsync_start
1923 * and end.
1924 */
1925
1926 /* Following values & calculations differ for different type of modes */
1927 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1928 /* Interlaced Mode */
1929 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1930 (m->vsync_end - m->vdisplay) / 2);
1931 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1932 (m->vsync_start - m->vdisplay) / 2);
1933 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1934 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301935 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001936 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1937 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1938 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1939 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1940 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1941 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1942 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1943 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1944 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301945 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1946 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1947 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1948 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001949 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1950 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1951 } else {
1952 /* Progressive Mode */
1953 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1954 m->vsync_end - m->vdisplay);
1955 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1956 m->vsync_start - m->vdisplay);
1957 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1958 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1959 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1960 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1961 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1962 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1963 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1964 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1965 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1966 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1967 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1968 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1969 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301970 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1971 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1972 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001973 }
1974
1975 /* Following values & calculations are same irrespective of mode type */
1976 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1977 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1978 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1979 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1980 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1981 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1982 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1983 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1984 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1985 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1986 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1987 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1988 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1989 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1990 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1991 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1992 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1993 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1994 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1995 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1996
1997 /* Timing generator registers */
1998 hdmi_set_reg(tg->cmd, 1, 0x0);
1999 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
2000 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
2001 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
2002 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
2003 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002004 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
2005 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002006 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002007 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002008}
2009
Sean Paulf041b252014-01-30 16:19:15 -05002010static void hdmi_mode_set(struct exynos_drm_display *display,
2011 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002012{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002013 struct hdmi_context *hdata = display_to_hdmi(display);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002014 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002015
YoungJun Chocbc4c332013-06-12 10:44:40 +09002016 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
2017 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002018 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02002019 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020
Rahul Sharmabfa48422014-04-03 20:41:04 +05302021 /* preserve mode information for later use. */
2022 drm_mode_copy(&hdata->current_mode, mode);
2023
Sachin Kamat5f46c332013-04-26 11:29:00 +05302024 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002025 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302026 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002027 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002028}
2029
Sean Paulf041b252014-01-30 16:19:15 -05002030static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002031{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002032 struct hdmi_context *hdata = display_to_hdmi(display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002033
Shirish Sdda90122013-01-23 22:03:18 -05002034 mutex_lock(&hdata->hdmi_mutex);
2035 if (!hdata->powered) {
2036 mutex_unlock(&hdata->hdmi_mutex);
2037 return;
2038 }
2039 mutex_unlock(&hdata->hdmi_mutex);
2040
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002041 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002042}
2043
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002044static void hdmi_poweron(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002045{
2046 struct hdmi_resources *res = &hdata->res;
2047
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002048 mutex_lock(&hdata->hdmi_mutex);
2049 if (hdata->powered) {
2050 mutex_unlock(&hdata->hdmi_mutex);
2051 return;
2052 }
2053
2054 hdata->powered = true;
2055
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002056 mutex_unlock(&hdata->hdmi_mutex);
2057
Sean Paulaf65c802014-01-30 16:19:27 -05002058 pm_runtime_get_sync(hdata->dev);
2059
Seung-Woo Kimad079452013-06-05 14:34:38 +09002060 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2061 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2062
Rahul Sharma049d34e2014-05-20 10:36:05 +05302063 /* set pmu hdmiphy control bit to enable hdmiphy */
2064 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2065 PMU_HDMI_PHY_ENABLE_BIT, 1);
2066
Sean Paul0bfb1f82013-06-11 12:24:02 +05302067 clk_prepare_enable(res->hdmi);
2068 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302069
2070 hdmiphy_poweron(hdata);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002071 hdmi_commit(&hdata->display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002072}
2073
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002074static void hdmi_poweroff(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002075{
2076 struct hdmi_resources *res = &hdata->res;
2077
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002078 mutex_lock(&hdata->hdmi_mutex);
2079 if (!hdata->powered)
2080 goto out;
2081 mutex_unlock(&hdata->hdmi_mutex);
2082
Rahul Sharmabfa48422014-04-03 20:41:04 +05302083 /* HDMI System Disable */
2084 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2085
Rahul Sharmaa5562252012-11-28 11:30:25 +05302086 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002087
Sean Paul724fd142014-05-09 15:05:10 +09002088 cancel_delayed_work(&hdata->hotplug_work);
2089
Sean Paul0bfb1f82013-06-11 12:24:02 +05302090 clk_disable_unprepare(res->sclk_hdmi);
2091 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302092
2093 /* reset pmu hdmiphy control bit to disable hdmiphy */
2094 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2095 PMU_HDMI_PHY_ENABLE_BIT, 0);
2096
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002097 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2098
Sean Paulaf65c802014-01-30 16:19:27 -05002099 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002100
Sean Paulaf65c802014-01-30 16:19:27 -05002101 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002102 hdata->powered = false;
2103
2104out:
2105 mutex_unlock(&hdata->hdmi_mutex);
2106}
2107
Sean Paulf041b252014-01-30 16:19:15 -05002108static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002109{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002110 struct hdmi_context *hdata = display_to_hdmi(display);
Inki Dae245f98f2014-06-13 17:44:40 +09002111 struct drm_encoder *encoder = hdata->encoder;
2112 struct drm_crtc *crtc = encoder->crtc;
Jani Nikulab0f87782015-03-11 11:50:59 +02002113 const struct drm_crtc_helper_funcs *funcs = NULL;
Inki Dae245f98f2014-06-13 17:44:40 +09002114
YoungJun Chocbc4c332013-06-12 10:44:40 +09002115 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002116
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002117 switch (mode) {
2118 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002119 hdmi_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002120 break;
2121 case DRM_MODE_DPMS_STANDBY:
2122 case DRM_MODE_DPMS_SUSPEND:
2123 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002124 /*
2125 * The SFRs of VP and Mixer are updated by Vertical Sync of
2126 * Timing generator which is a part of HDMI so the sequence
2127 * to disable TV Subsystem should be as following,
2128 * VP -> Mixer -> HDMI
2129 *
2130 * Below codes will try to disable Mixer and VP(if used)
2131 * prior to disabling HDMI.
2132 */
2133 if (crtc)
2134 funcs = crtc->helper_private;
Gustavo Padovan63498e32015-06-01 12:04:53 -03002135 if (funcs && funcs->disable)
2136 (*funcs->disable)(crtc);
Inki Dae245f98f2014-06-13 17:44:40 +09002137
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002138 hdmi_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002139 break;
2140 default:
2141 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2142 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002143 }
2144}
2145
Sean Paulf041b252014-01-30 16:19:15 -05002146static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002147 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002148 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002149 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002150 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002151 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002152};
2153
Sean Paul724fd142014-05-09 15:05:10 +09002154static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002155{
Sean Paul724fd142014-05-09 15:05:10 +09002156 struct hdmi_context *hdata;
2157
2158 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002159
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002160 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302161 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002162 mutex_unlock(&hdata->hdmi_mutex);
2163
Sean Paul45517892014-01-30 16:19:05 -05002164 if (hdata->drm_dev)
2165 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002166}
2167
2168static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2169{
2170 struct hdmi_context *hdata = arg;
2171
2172 mod_delayed_work(system_wq, &hdata->hotplug_work,
2173 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002174
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002175 return IRQ_HANDLED;
2176}
2177
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002178static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002179{
2180 struct device *dev = hdata->dev;
2181 struct hdmi_resources *res = &hdata->res;
2182 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002183 "vdd",
2184 "vdd_osc",
2185 "vdd_pll",
2186 };
2187 int i, ret;
2188
2189 DRM_DEBUG_KMS("HDMI resource init\n");
2190
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002191 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302192 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302193 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002195 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196 goto fail;
2197 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302198 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302199 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002200 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002201 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002202 goto fail;
2203 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302204 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302205 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002206 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002207 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002208 goto fail;
2209 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302210 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302211 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002212 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002213 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002214 goto fail;
2215 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302216 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2217 if (IS_ERR(res->mout_hdmi)) {
2218 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002219 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302220 goto fail;
2221 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002222
Rahul Sharma59956d32013-06-11 12:24:03 +05302223 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002224
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302225 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302226 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002227 if (!res->regul_bulk) {
2228 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002229 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002230 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002231 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2232 res->regul_bulk[i].supply = supply[i];
2233 res->regul_bulk[i].consumer = NULL;
2234 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302235 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002236 if (ret) {
2237 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002238 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002239 }
2240 res->regul_count = ARRAY_SIZE(supply);
2241
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002242 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2243 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2244 DRM_ERROR("failed to get hdmi-en regulator\n");
2245 return PTR_ERR(res->reg_hdmi_en);
2246 }
2247 if (!IS_ERR(res->reg_hdmi_en)) {
2248 ret = regulator_enable(res->reg_hdmi_en);
2249 if (ret) {
2250 DRM_ERROR("failed to enable hdmi-en regulator\n");
2251 return ret;
2252 }
2253 } else
2254 res->reg_hdmi_en = NULL;
2255
Inki Daedf5225b2014-05-29 18:28:02 +09002256 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002257fail:
2258 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002259 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002260}
2261
Rahul Sharma22c4f422012-10-04 20:48:55 +05302262static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2263 (struct device *dev)
2264{
2265 struct device_node *np = dev->of_node;
2266 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302267 u32 value;
2268
2269 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002270 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302271 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302272
2273 if (!of_find_property(np, "hpd-gpio", &value)) {
2274 DRM_ERROR("no hpd gpio property found\n");
2275 goto err_data;
2276 }
2277
Rahul Sharma5f916e22013-06-11 19:41:29 +05302278 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302279
2280 return pd;
2281
2282err_data:
2283 return NULL;
2284}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302285
Rahul Sharma22c4f422012-10-04 20:48:55 +05302286static struct of_device_id hdmi_match_types[] = {
2287 {
2288 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002289 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302290 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02002291 .compatible = "samsung,exynos4210-hdmi",
2292 .data = &exynos4210_hdmi_driver_data,
2293 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302294 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002295 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302296 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302297 .compatible = "samsung,exynos5420-hdmi",
2298 .data = &exynos5420_hdmi_driver_data,
2299 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302300 /* end node */
2301 }
2302};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02002303MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302304
Inki Daef37cd5e2014-05-09 14:25:20 +09002305static int hdmi_bind(struct device *dev, struct device *master, void *data)
2306{
2307 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002308 struct hdmi_context *hdata = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002309
Inki Daef37cd5e2014-05-09 14:25:20 +09002310 hdata->drm_dev = drm_dev;
2311
Andrzej Hajda930865f2014-11-17 09:54:20 +01002312 return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
Inki Daef37cd5e2014-05-09 14:25:20 +09002313}
2314
2315static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2316{
Inki Daef37cd5e2014-05-09 14:25:20 +09002317}
2318
2319static const struct component_ops hdmi_component_ops = {
2320 .bind = hdmi_bind,
2321 .unbind = hdmi_unbind,
2322};
2323
Inki Daee2a562d2014-05-09 16:46:10 +09002324static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2325{
2326 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2327 struct device_node *np;
2328
2329 np = of_find_compatible_node(NULL, NULL, compatible_str);
2330 if (np)
2331 return of_get_next_parent(np);
2332
2333 return NULL;
2334}
2335
2336static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2337{
2338 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2339
2340 return of_find_compatible_node(NULL, NULL, compatible_str);
2341}
2342
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002343static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002344{
Inki Daef37cd5e2014-05-09 14:25:20 +09002345 struct device_node *ddc_node, *phy_node;
2346 struct s5p_hdmi_platform_data *pdata;
2347 struct hdmi_driver_data *drv_data;
2348 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002349 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002350 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002351 struct resource *res;
2352 int ret;
2353
Andrzej Hajda930865f2014-11-17 09:54:20 +01002354 if (!dev->of_node)
2355 return -ENODEV;
2356
2357 pdata = drm_hdmi_dt_parse_pdata(dev);
2358 if (!pdata)
2359 return -EINVAL;
2360
2361 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2362 if (!hdata)
2363 return -ENOMEM;
2364
2365 hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
2366 hdata->display.ops = &hdmi_display_ops;
2367
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002368 mutex_init(&hdata->hdmi_mutex);
2369
Andrzej Hajda930865f2014-11-17 09:54:20 +01002370 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002371
Sachin Kamat88c49812013-08-28 10:47:57 +05302372 match = of_match_node(hdmi_match_types, dev->of_node);
Andrzej Hajda86650402015-06-11 23:23:37 +09002373 if (!match)
2374 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002375
2376 drv_data = (struct hdmi_driver_data *)match->data;
2377 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002378 hdata->phy_confs = drv_data->phy_confs;
2379 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302380
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302381 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002382 hdata->dev = dev;
2383
2384 ret = hdmi_resources_init(hdata);
2385 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302386 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002387 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002388 }
2389
2390 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002391 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002392 if (IS_ERR(hdata->regs)) {
2393 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002394 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002395 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002396
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002397 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302398 if (ret) {
2399 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002400 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302401 }
2402
Inki Daee2a562d2014-05-09 16:46:10 +09002403 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2404 if (ddc_node)
2405 goto out_get_ddc_adpt;
2406
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002407 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002408 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2409 if (!ddc_node) {
2410 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002411 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002412 }
Inki Daee2a562d2014-05-09 16:46:10 +09002413
2414out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002415 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2416 if (!hdata->ddc_adpt) {
2417 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002418 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002419 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002420
Inki Daee2a562d2014-05-09 16:46:10 +09002421 phy_node = hdmi_legacy_phy_dt_binding(dev);
2422 if (phy_node)
2423 goto out_get_phy_port;
2424
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002425 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002426 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2427 if (!phy_node) {
2428 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2429 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002430 goto err_ddc;
2431 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002432
Inki Daee2a562d2014-05-09 16:46:10 +09002433out_get_phy_port:
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002434 if (drv_data->is_apb_phy) {
2435 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2436 if (!hdata->regs_hdmiphy) {
2437 DRM_ERROR("failed to ioremap hdmi phy\n");
2438 ret = -ENOMEM;
2439 goto err_ddc;
2440 }
2441 } else {
2442 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2443 if (!hdata->hdmiphy_port) {
2444 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002445 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002446 goto err_ddc;
2447 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002448 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002449
Sean Paul77006a72013-01-16 10:17:20 -05002450 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2451 if (hdata->irq < 0) {
2452 DRM_ERROR("failed to get GPIO irq\n");
2453 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002454 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002455 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002456
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302457 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2458
Sean Paul724fd142014-05-09 15:05:10 +09002459 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2460
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002461 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002462 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002463 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002464 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002465 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002466 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002467 goto err_hdmiphy;
2468 }
2469
Rahul Sharma049d34e2014-05-20 10:36:05 +05302470 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2471 "samsung,syscon-phandle");
2472 if (IS_ERR(hdata->pmureg)) {
2473 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002474 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302475 goto err_hdmiphy;
2476 }
2477
Sean Paulaf65c802014-01-30 16:19:27 -05002478 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002479
Inki Daedf5225b2014-05-29 18:28:02 +09002480 ret = component_add(&pdev->dev, &hdmi_component_ops);
2481 if (ret)
2482 goto err_disable_pm_runtime;
2483
2484 return ret;
2485
2486err_disable_pm_runtime:
2487 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002488
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002489err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002490 if (hdata->hdmiphy_port)
2491 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002492err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002493 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002494
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002495 return ret;
2496}
2497
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002498static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002499{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002500 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002501
Sean Paul724fd142014-05-09 15:05:10 +09002502 cancel_delayed_work_sync(&hdata->hotplug_work);
2503
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002504 if (hdata->res.reg_hdmi_en)
2505 regulator_disable(hdata->res.reg_hdmi_en);
2506
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002507 if (hdata->hdmiphy_port)
2508 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002509 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002510
Sean Paulaf65c802014-01-30 16:19:27 -05002511 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002512 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002513
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002514 return 0;
2515}
2516
2517struct platform_driver hdmi_driver = {
2518 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002519 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002520 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302521 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002522 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302523 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002524 },
2525};