blob: 738f2d7e16a121c93ab565b5806df5f30c550ed4 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090020
21#include "regs-hdmi.h"
22
23#include <linux/kernel.h>
24#include <linux/spinlock.h>
25#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053034#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053035#include <linux/of.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053037#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053049#include <linux/gpio.h>
50#include <media/s5p_hdmi.h>
51
Sean Paulf041b252014-01-30 16:19:15 -050052#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev))
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;
87 int regul_count;
88};
89
Sean Paul2f7e2ed2013-01-15 08:11:08 -050090struct hdmi_tg_regs {
91 u8 cmd[1];
92 u8 h_fsz[2];
93 u8 hact_st[2];
94 u8 hact_sz[2];
95 u8 v_fsz[2];
96 u8 vsync[2];
97 u8 vsync2[2];
98 u8 vact_st[2];
99 u8 vact_sz[2];
100 u8 field_chg[2];
101 u8 vact_st2[2];
102 u8 vact_st3[2];
103 u8 vact_st4[2];
104 u8 vsync_top_hdmi[2];
105 u8 vsync_bot_hdmi[2];
106 u8 field_top_hdmi[2];
107 u8 field_bot_hdmi[2];
108 u8 tg_3d[1];
109};
110
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900111struct hdmi_v13_core_regs {
112 u8 h_blank[2];
113 u8 v_blank[3];
114 u8 h_v_line[3];
115 u8 vsync_pol[1];
116 u8 int_pro_mode[1];
117 u8 v_blank_f[3];
118 u8 h_sync_gen[3];
119 u8 v_sync_gen1[3];
120 u8 v_sync_gen2[3];
121 u8 v_sync_gen3[3];
122};
123
124struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500125 u8 h_blank[2];
126 u8 v2_blank[2];
127 u8 v1_blank[2];
128 u8 v_line[2];
129 u8 h_line[2];
130 u8 hsync_pol[1];
131 u8 vsync_pol[1];
132 u8 int_pro_mode[1];
133 u8 v_blank_f0[2];
134 u8 v_blank_f1[2];
135 u8 h_sync_start[2];
136 u8 h_sync_end[2];
137 u8 v_sync_line_bef_2[2];
138 u8 v_sync_line_bef_1[2];
139 u8 v_sync_line_aft_2[2];
140 u8 v_sync_line_aft_1[2];
141 u8 v_sync_line_aft_pxl_2[2];
142 u8 v_sync_line_aft_pxl_1[2];
143 u8 v_blank_f2[2]; /* for 3D mode */
144 u8 v_blank_f3[2]; /* for 3D mode */
145 u8 v_blank_f4[2]; /* for 3D mode */
146 u8 v_blank_f5[2]; /* for 3D mode */
147 u8 v_sync_line_aft_3[2];
148 u8 v_sync_line_aft_4[2];
149 u8 v_sync_line_aft_5[2];
150 u8 v_sync_line_aft_6[2];
151 u8 v_sync_line_aft_pxl_3[2];
152 u8 v_sync_line_aft_pxl_4[2];
153 u8 v_sync_line_aft_pxl_5[2];
154 u8 v_sync_line_aft_pxl_6[2];
155 u8 vact_space_1[2];
156 u8 vact_space_2[2];
157 u8 vact_space_3[2];
158 u8 vact_space_4[2];
159 u8 vact_space_5[2];
160 u8 vact_space_6[2];
161};
162
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163struct hdmi_v13_conf {
164 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500165 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166};
167
168struct hdmi_v14_conf {
169 struct hdmi_v14_core_regs core;
170 struct hdmi_tg_regs tg;
171};
172
173struct hdmi_conf_regs {
174 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500175 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530176 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900177 union {
178 struct hdmi_v13_conf v13_conf;
179 struct hdmi_v14_conf v14_conf;
180 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500181};
182
Joonyoung Shim590f4182012-03-16 18:47:14 +0900183struct hdmi_context {
184 struct device *dev;
185 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500186 struct drm_connector connector;
187 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900188 bool hpd;
189 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900190 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900191 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900192
Joonyoung Shim590f4182012-03-16 18:47:14 +0900193 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500194 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900195 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900196
Inki Dae8fa04aa2014-03-13 16:38:31 +0900197 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900198 struct i2c_client *hdmiphy_port;
199
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900200 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530201 struct drm_display_mode current_mode;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900202 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900203
204 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900205
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530206 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900207 void __iomem *regs_hdmiphy;
208 const struct hdmiphy_config *phy_confs;
209 unsigned int phy_conf_count;
Rahul Sharma5a325072012-10-04 20:48:54 +0530210
Rahul Sharma049d34e2014-05-20 10:36:05 +0530211 struct regmap *pmureg;
Rahul Sharma5a325072012-10-04 20:48:54 +0530212 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900213};
214
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500215struct hdmiphy_config {
216 int pixel_clock;
217 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900218};
219
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900220/* list of phy config settings */
221static const struct hdmiphy_config hdmiphy_v13_configs[] = {
222 {
223 .pixel_clock = 27000000,
224 .conf = {
225 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
226 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
227 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
228 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
229 },
230 },
231 {
232 .pixel_clock = 27027000,
233 .conf = {
234 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
235 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
236 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
237 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
238 },
239 },
240 {
241 .pixel_clock = 74176000,
242 .conf = {
243 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
244 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
245 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
246 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
247 },
248 },
249 {
250 .pixel_clock = 74250000,
251 .conf = {
252 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
253 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
254 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
255 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
256 },
257 },
258 {
259 .pixel_clock = 148500000,
260 .conf = {
261 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
262 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
263 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
264 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
265 },
266 },
267};
268
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500269static const struct hdmiphy_config hdmiphy_v14_configs[] = {
270 {
271 .pixel_clock = 25200000,
272 .conf = {
273 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
274 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
275 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
276 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
277 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900278 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500279 {
280 .pixel_clock = 27000000,
281 .conf = {
282 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
283 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
284 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
285 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
286 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900287 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500288 {
289 .pixel_clock = 27027000,
290 .conf = {
291 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
292 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
293 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
294 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
295 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900296 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500297 {
298 .pixel_clock = 36000000,
299 .conf = {
300 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
301 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
302 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
303 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
304 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900305 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500306 {
307 .pixel_clock = 40000000,
308 .conf = {
309 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
310 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
311 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
312 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
313 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900314 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500315 {
316 .pixel_clock = 65000000,
317 .conf = {
318 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
319 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
320 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
321 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
322 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900323 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500324 {
Shirish Se1d883c2014-03-13 14:28:27 +0900325 .pixel_clock = 71000000,
326 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530327 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
328 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
329 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900330 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
331 },
332 },
333 {
334 .pixel_clock = 73250000,
335 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530336 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
337 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
338 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900339 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
340 },
341 },
342 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500343 .pixel_clock = 74176000,
344 .conf = {
345 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
346 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
347 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
348 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
349 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900350 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500351 {
352 .pixel_clock = 74250000,
353 .conf = {
354 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
355 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
356 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
357 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
358 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900359 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500360 {
361 .pixel_clock = 83500000,
362 .conf = {
363 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
364 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
365 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
366 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
367 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900368 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500369 {
370 .pixel_clock = 106500000,
371 .conf = {
372 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
373 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
374 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
375 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
376 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900377 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500378 {
379 .pixel_clock = 108000000,
380 .conf = {
381 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
382 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
383 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
384 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
385 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900386 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500387 {
Shirish Se1d883c2014-03-13 14:28:27 +0900388 .pixel_clock = 115500000,
389 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530390 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
391 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
392 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900393 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
394 },
395 },
396 {
397 .pixel_clock = 119000000,
398 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530399 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
400 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
401 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900402 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
403 },
404 },
405 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500406 .pixel_clock = 146250000,
407 .conf = {
408 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
409 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
410 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
411 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
412 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900413 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500414 {
415 .pixel_clock = 148500000,
416 .conf = {
417 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
418 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
419 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
420 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
421 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900422 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900423};
424
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530425static const struct hdmiphy_config hdmiphy_5420_configs[] = {
426 {
427 .pixel_clock = 25200000,
428 .conf = {
429 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
430 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
431 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
432 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
433 },
434 },
435 {
436 .pixel_clock = 27000000,
437 .conf = {
438 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
439 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
440 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
441 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
442 },
443 },
444 {
445 .pixel_clock = 27027000,
446 .conf = {
447 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
448 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
449 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
450 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
451 },
452 },
453 {
454 .pixel_clock = 36000000,
455 .conf = {
456 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
457 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
458 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
459 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
460 },
461 },
462 {
463 .pixel_clock = 40000000,
464 .conf = {
465 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
466 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
467 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
468 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
469 },
470 },
471 {
472 .pixel_clock = 65000000,
473 .conf = {
474 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
475 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
476 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
477 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
478 },
479 },
480 {
481 .pixel_clock = 71000000,
482 .conf = {
483 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
484 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
485 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
486 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
487 },
488 },
489 {
490 .pixel_clock = 73250000,
491 .conf = {
492 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
493 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
494 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
495 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
496 },
497 },
498 {
499 .pixel_clock = 74176000,
500 .conf = {
501 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
502 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
503 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
504 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
505 },
506 },
507 {
508 .pixel_clock = 74250000,
509 .conf = {
510 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
511 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
512 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
513 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
514 },
515 },
516 {
517 .pixel_clock = 83500000,
518 .conf = {
519 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
520 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
521 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
522 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
523 },
524 },
525 {
526 .pixel_clock = 88750000,
527 .conf = {
528 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
529 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
530 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
531 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
532 },
533 },
534 {
535 .pixel_clock = 106500000,
536 .conf = {
537 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
538 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
539 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
540 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
541 },
542 },
543 {
544 .pixel_clock = 108000000,
545 .conf = {
546 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
547 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
548 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
549 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
550 },
551 },
552 {
553 .pixel_clock = 115500000,
554 .conf = {
555 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
556 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
557 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
558 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
559 },
560 },
561 {
562 .pixel_clock = 146250000,
563 .conf = {
564 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
565 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
566 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
567 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
568 },
569 },
570 {
571 .pixel_clock = 148500000,
572 .conf = {
573 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
574 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
575 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
576 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
577 },
578 },
579};
580
Sachin Kamat16337072014-05-22 10:32:56 +0530581static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530582 .type = HDMI_TYPE14,
583 .phy_confs = hdmiphy_5420_configs,
584 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
585 .is_apb_phy = 1,
586};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900587
Sachin Kamat16337072014-05-22 10:32:56 +0530588static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900589 .type = HDMI_TYPE14,
590 .phy_confs = hdmiphy_v14_configs,
591 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
592 .is_apb_phy = 0,
593};
594
Sachin Kamat16337072014-05-22 10:32:56 +0530595static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900596 .type = HDMI_TYPE14,
597 .phy_confs = hdmiphy_v13_configs,
598 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
599 .is_apb_phy = 0,
600};
601
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900602static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
603{
604 return readl(hdata->regs + reg_id);
605}
606
607static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
608 u32 reg_id, u8 value)
609{
610 writeb(value, hdata->regs + reg_id);
611}
612
613static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
614 u32 reg_id, u32 value, u32 mask)
615{
616 u32 old = readl(hdata->regs + reg_id);
617 value = (value & mask) | (old & ~mask);
618 writel(value, hdata->regs + reg_id);
619}
620
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900621static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
622 u32 reg_offset, u8 value)
623{
624 if (hdata->hdmiphy_port) {
625 u8 buffer[2];
626 int ret;
627
628 buffer[0] = reg_offset;
629 buffer[1] = value;
630
631 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
632 if (ret == 2)
633 return 0;
634 return ret;
635 } else {
636 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
637 return 0;
638 }
639}
640
641static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
642 u32 reg_offset, const u8 *buf, u32 len)
643{
644 if ((reg_offset + len) > 32)
645 return -EINVAL;
646
647 if (hdata->hdmiphy_port) {
648 int ret;
649
650 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
651 if (ret == len)
652 return 0;
653 return ret;
654 } else {
655 int i;
656 for (i = 0; i < len; i++)
657 writeb(buf[i], hdata->regs_hdmiphy +
658 ((reg_offset + i)<<2));
659 return 0;
660 }
661}
662
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900663static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900664{
665#define DUMPREG(reg_id) \
666 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
667 readl(hdata->regs + reg_id))
668 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
669 DUMPREG(HDMI_INTC_FLAG);
670 DUMPREG(HDMI_INTC_CON);
671 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900672 DUMPREG(HDMI_V13_PHY_RSTOUT);
673 DUMPREG(HDMI_V13_PHY_VPLL);
674 DUMPREG(HDMI_V13_PHY_CMU);
675 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900676
677 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
678 DUMPREG(HDMI_CON_0);
679 DUMPREG(HDMI_CON_1);
680 DUMPREG(HDMI_CON_2);
681 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900682 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900683 DUMPREG(HDMI_STATUS_EN);
684 DUMPREG(HDMI_HPD);
685 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900686 DUMPREG(HDMI_V13_HPD_GEN);
687 DUMPREG(HDMI_V13_DC_CONTROL);
688 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900689
690 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
691 DUMPREG(HDMI_H_BLANK_0);
692 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900693 DUMPREG(HDMI_V13_V_BLANK_0);
694 DUMPREG(HDMI_V13_V_BLANK_1);
695 DUMPREG(HDMI_V13_V_BLANK_2);
696 DUMPREG(HDMI_V13_H_V_LINE_0);
697 DUMPREG(HDMI_V13_H_V_LINE_1);
698 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900699 DUMPREG(HDMI_VSYNC_POL);
700 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900701 DUMPREG(HDMI_V13_V_BLANK_F_0);
702 DUMPREG(HDMI_V13_V_BLANK_F_1);
703 DUMPREG(HDMI_V13_V_BLANK_F_2);
704 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
705 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
706 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
707 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
708 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
709 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
710 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
711 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
712 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
713 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
714 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
715 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900716
717 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
718 DUMPREG(HDMI_TG_CMD);
719 DUMPREG(HDMI_TG_H_FSZ_L);
720 DUMPREG(HDMI_TG_H_FSZ_H);
721 DUMPREG(HDMI_TG_HACT_ST_L);
722 DUMPREG(HDMI_TG_HACT_ST_H);
723 DUMPREG(HDMI_TG_HACT_SZ_L);
724 DUMPREG(HDMI_TG_HACT_SZ_H);
725 DUMPREG(HDMI_TG_V_FSZ_L);
726 DUMPREG(HDMI_TG_V_FSZ_H);
727 DUMPREG(HDMI_TG_VSYNC_L);
728 DUMPREG(HDMI_TG_VSYNC_H);
729 DUMPREG(HDMI_TG_VSYNC2_L);
730 DUMPREG(HDMI_TG_VSYNC2_H);
731 DUMPREG(HDMI_TG_VACT_ST_L);
732 DUMPREG(HDMI_TG_VACT_ST_H);
733 DUMPREG(HDMI_TG_VACT_SZ_L);
734 DUMPREG(HDMI_TG_VACT_SZ_H);
735 DUMPREG(HDMI_TG_FIELD_CHG_L);
736 DUMPREG(HDMI_TG_FIELD_CHG_H);
737 DUMPREG(HDMI_TG_VACT_ST2_L);
738 DUMPREG(HDMI_TG_VACT_ST2_H);
739 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
740 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
741 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
742 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
743 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
744 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
745 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
746 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
747#undef DUMPREG
748}
749
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900750static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
751{
752 int i;
753
754#define DUMPREG(reg_id) \
755 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
756 readl(hdata->regs + reg_id))
757
758 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
759 DUMPREG(HDMI_INTC_CON);
760 DUMPREG(HDMI_INTC_FLAG);
761 DUMPREG(HDMI_HPD_STATUS);
762 DUMPREG(HDMI_INTC_CON_1);
763 DUMPREG(HDMI_INTC_FLAG_1);
764 DUMPREG(HDMI_PHY_STATUS_0);
765 DUMPREG(HDMI_PHY_STATUS_PLL);
766 DUMPREG(HDMI_PHY_CON_0);
767 DUMPREG(HDMI_PHY_RSTOUT);
768 DUMPREG(HDMI_PHY_VPLL);
769 DUMPREG(HDMI_PHY_CMU);
770 DUMPREG(HDMI_CORE_RSTOUT);
771
772 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
773 DUMPREG(HDMI_CON_0);
774 DUMPREG(HDMI_CON_1);
775 DUMPREG(HDMI_CON_2);
776 DUMPREG(HDMI_SYS_STATUS);
777 DUMPREG(HDMI_PHY_STATUS_0);
778 DUMPREG(HDMI_STATUS_EN);
779 DUMPREG(HDMI_HPD);
780 DUMPREG(HDMI_MODE_SEL);
781 DUMPREG(HDMI_ENC_EN);
782 DUMPREG(HDMI_DC_CONTROL);
783 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
784
785 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
786 DUMPREG(HDMI_H_BLANK_0);
787 DUMPREG(HDMI_H_BLANK_1);
788 DUMPREG(HDMI_V2_BLANK_0);
789 DUMPREG(HDMI_V2_BLANK_1);
790 DUMPREG(HDMI_V1_BLANK_0);
791 DUMPREG(HDMI_V1_BLANK_1);
792 DUMPREG(HDMI_V_LINE_0);
793 DUMPREG(HDMI_V_LINE_1);
794 DUMPREG(HDMI_H_LINE_0);
795 DUMPREG(HDMI_H_LINE_1);
796 DUMPREG(HDMI_HSYNC_POL);
797
798 DUMPREG(HDMI_VSYNC_POL);
799 DUMPREG(HDMI_INT_PRO_MODE);
800 DUMPREG(HDMI_V_BLANK_F0_0);
801 DUMPREG(HDMI_V_BLANK_F0_1);
802 DUMPREG(HDMI_V_BLANK_F1_0);
803 DUMPREG(HDMI_V_BLANK_F1_1);
804
805 DUMPREG(HDMI_H_SYNC_START_0);
806 DUMPREG(HDMI_H_SYNC_START_1);
807 DUMPREG(HDMI_H_SYNC_END_0);
808 DUMPREG(HDMI_H_SYNC_END_1);
809
810 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
811 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
812 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
813 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
814
815 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
816 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
817 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
818 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
819
820 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
821 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
822 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
823 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
824
825 DUMPREG(HDMI_V_BLANK_F2_0);
826 DUMPREG(HDMI_V_BLANK_F2_1);
827 DUMPREG(HDMI_V_BLANK_F3_0);
828 DUMPREG(HDMI_V_BLANK_F3_1);
829 DUMPREG(HDMI_V_BLANK_F4_0);
830 DUMPREG(HDMI_V_BLANK_F4_1);
831 DUMPREG(HDMI_V_BLANK_F5_0);
832 DUMPREG(HDMI_V_BLANK_F5_1);
833
834 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
836 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
837 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
838 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
839 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
840 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
841 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
842
843 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
844 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
845 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
846 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
850 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
851
852 DUMPREG(HDMI_VACT_SPACE_1_0);
853 DUMPREG(HDMI_VACT_SPACE_1_1);
854 DUMPREG(HDMI_VACT_SPACE_2_0);
855 DUMPREG(HDMI_VACT_SPACE_2_1);
856 DUMPREG(HDMI_VACT_SPACE_3_0);
857 DUMPREG(HDMI_VACT_SPACE_3_1);
858 DUMPREG(HDMI_VACT_SPACE_4_0);
859 DUMPREG(HDMI_VACT_SPACE_4_1);
860 DUMPREG(HDMI_VACT_SPACE_5_0);
861 DUMPREG(HDMI_VACT_SPACE_5_1);
862 DUMPREG(HDMI_VACT_SPACE_6_0);
863 DUMPREG(HDMI_VACT_SPACE_6_1);
864
865 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
866 DUMPREG(HDMI_TG_CMD);
867 DUMPREG(HDMI_TG_H_FSZ_L);
868 DUMPREG(HDMI_TG_H_FSZ_H);
869 DUMPREG(HDMI_TG_HACT_ST_L);
870 DUMPREG(HDMI_TG_HACT_ST_H);
871 DUMPREG(HDMI_TG_HACT_SZ_L);
872 DUMPREG(HDMI_TG_HACT_SZ_H);
873 DUMPREG(HDMI_TG_V_FSZ_L);
874 DUMPREG(HDMI_TG_V_FSZ_H);
875 DUMPREG(HDMI_TG_VSYNC_L);
876 DUMPREG(HDMI_TG_VSYNC_H);
877 DUMPREG(HDMI_TG_VSYNC2_L);
878 DUMPREG(HDMI_TG_VSYNC2_H);
879 DUMPREG(HDMI_TG_VACT_ST_L);
880 DUMPREG(HDMI_TG_VACT_ST_H);
881 DUMPREG(HDMI_TG_VACT_SZ_L);
882 DUMPREG(HDMI_TG_VACT_SZ_H);
883 DUMPREG(HDMI_TG_FIELD_CHG_L);
884 DUMPREG(HDMI_TG_FIELD_CHG_H);
885 DUMPREG(HDMI_TG_VACT_ST2_L);
886 DUMPREG(HDMI_TG_VACT_ST2_H);
887 DUMPREG(HDMI_TG_VACT_ST3_L);
888 DUMPREG(HDMI_TG_VACT_ST3_H);
889 DUMPREG(HDMI_TG_VACT_ST4_L);
890 DUMPREG(HDMI_TG_VACT_ST4_H);
891 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
892 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
893 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
894 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
895 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
896 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
897 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
898 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
899 DUMPREG(HDMI_TG_3D);
900
901 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
902 DUMPREG(HDMI_AVI_CON);
903 DUMPREG(HDMI_AVI_HEADER0);
904 DUMPREG(HDMI_AVI_HEADER1);
905 DUMPREG(HDMI_AVI_HEADER2);
906 DUMPREG(HDMI_AVI_CHECK_SUM);
907 DUMPREG(HDMI_VSI_CON);
908 DUMPREG(HDMI_VSI_HEADER0);
909 DUMPREG(HDMI_VSI_HEADER1);
910 DUMPREG(HDMI_VSI_HEADER2);
911 for (i = 0; i < 7; ++i)
912 DUMPREG(HDMI_VSI_DATA(i));
913
914#undef DUMPREG
915}
916
917static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
918{
Rahul Sharma5a325072012-10-04 20:48:54 +0530919 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900920 hdmi_v13_regs_dump(hdata, prefix);
921 else
922 hdmi_v14_regs_dump(hdata, prefix);
923}
924
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530925static u8 hdmi_chksum(struct hdmi_context *hdata,
926 u32 start, u8 len, u32 hdr_sum)
927{
928 int i;
929
930 /* hdr_sum : header0 + header1 + header2
931 * start : start address of packet byte1
932 * len : packet bytes - 1 */
933 for (i = 0; i < len; ++i)
934 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
935
936 /* return 2's complement of 8 bit hdr_sum */
937 return (u8)(~(hdr_sum & 0xff) + 1);
938}
939
940static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530941 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530942{
943 u32 hdr_sum;
944 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530945 u32 mod;
946 u32 vic;
947
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530948 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
949 if (hdata->dvi_mode) {
950 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
951 HDMI_VSI_CON_DO_NOT_TRANSMIT);
952 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
953 HDMI_AVI_CON_DO_NOT_TRANSMIT);
954 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
955 return;
956 }
957
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530958 switch (infoframe->any.type) {
959 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530960 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530961 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
962 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
963 infoframe->any.version);
964 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
965 hdr_sum = infoframe->any.type + infoframe->any.version +
966 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530967
968 /* Output format zero hardcoded ,RGB YBCR selection */
969 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
970 AVI_ACTIVE_FORMAT_VALID |
971 AVI_UNDERSCANNED_DISPLAY_VALID);
972
Shirish S46154152014-03-13 10:58:28 +0530973 /*
974 * Set the aspect ratio as per the mode, mentioned in
975 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
976 */
977 switch (hdata->mode_conf.aspect_ratio) {
978 case HDMI_PICTURE_ASPECT_4_3:
979 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
980 hdata->mode_conf.aspect_ratio |
981 AVI_4_3_CENTER_RATIO);
982 break;
983 case HDMI_PICTURE_ASPECT_16_9:
984 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
985 hdata->mode_conf.aspect_ratio |
986 AVI_16_9_CENTER_RATIO);
987 break;
988 case HDMI_PICTURE_ASPECT_NONE:
989 default:
990 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
991 hdata->mode_conf.aspect_ratio |
992 AVI_SAME_AS_PIC_ASPECT_RATIO);
993 break;
994 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530995
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900996 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530997 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
998
999 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301000 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301001 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1002 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1003 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301004 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301005 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301006 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1007 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1008 infoframe->any.version);
1009 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1010 hdr_sum = infoframe->any.type + infoframe->any.version +
1011 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301012 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301013 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301014 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1015 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1016 break;
1017 default:
1018 break;
1019 }
1020}
1021
Sean Pauld9716ee2014-01-30 16:19:29 -05001022static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1023 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001024{
Sean Pauld9716ee2014-01-30 16:19:29 -05001025 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001026
Sean Paul5137c8c2014-04-03 20:41:03 +05301027 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1028
Sean Pauld9716ee2014-01-30 16:19:29 -05001029 return hdata->hpd ? connector_status_connected :
1030 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001031}
1032
Sean Pauld9716ee2014-01-30 16:19:29 -05001033static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001034{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001035}
1036
Sean Pauld9716ee2014-01-30 16:19:29 -05001037static struct drm_connector_funcs hdmi_connector_funcs = {
1038 .dpms = drm_helper_connector_dpms,
1039 .fill_modes = drm_helper_probe_single_connector_modes,
1040 .detect = hdmi_detect,
1041 .destroy = hdmi_connector_destroy,
1042};
1043
1044static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001045{
Sean Pauld9716ee2014-01-30 16:19:29 -05001046 struct hdmi_context *hdata = ctx_from_connector(connector);
1047 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001048
Inki Dae8fa04aa2014-03-13 16:38:31 +09001049 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001050 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001051
Inki Dae8fa04aa2014-03-13 16:38:31 +09001052 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001053 if (!edid)
1054 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001055
Sean Pauld9716ee2014-01-30 16:19:29 -05001056 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001057 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1058 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001059 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001060
Sean Pauld9716ee2014-01-30 16:19:29 -05001061 drm_mode_connector_update_edid_property(connector, edid);
1062
1063 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001064}
1065
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001066static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001067{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001068 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001069
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001070 for (i = 0; i < hdata->phy_conf_count; i++)
1071 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001072 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001073
1074 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1075 return -EINVAL;
1076}
1077
Sean Pauld9716ee2014-01-30 16:19:29 -05001078static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001079 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001080{
Sean Pauld9716ee2014-01-30 16:19:29 -05001081 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001082 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001083
Rahul Sharma16844fb2013-06-10 14:50:00 +05301084 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1085 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1086 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1087 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001088
Sean Paulf041b252014-01-30 16:19:15 -05001089 ret = mixer_check_mode(mode);
1090 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001091 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001092
Rahul Sharma16844fb2013-06-10 14:50:00 +05301093 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001094 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001095 return MODE_BAD;
1096
1097 return MODE_OK;
1098}
1099
1100static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1101{
1102 struct hdmi_context *hdata = ctx_from_connector(connector);
1103
1104 return hdata->encoder;
1105}
1106
1107static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1108 .get_modes = hdmi_get_modes,
1109 .mode_valid = hdmi_mode_valid,
1110 .best_encoder = hdmi_best_encoder,
1111};
1112
1113static int hdmi_create_connector(struct exynos_drm_display *display,
1114 struct drm_encoder *encoder)
1115{
1116 struct hdmi_context *hdata = display->ctx;
1117 struct drm_connector *connector = &hdata->connector;
1118 int ret;
1119
1120 hdata->encoder = encoder;
1121 connector->interlace_allowed = true;
1122 connector->polled = DRM_CONNECTOR_POLL_HPD;
1123
1124 ret = drm_connector_init(hdata->drm_dev, connector,
1125 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1126 if (ret) {
1127 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001128 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001129 }
1130
1131 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001132 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001133 drm_mode_connector_attach_encoder(connector, encoder);
1134
1135 return 0;
1136}
1137
Sean Paulf041b252014-01-30 16:19:15 -05001138static void hdmi_mode_fixup(struct exynos_drm_display *display,
1139 struct drm_connector *connector,
1140 const struct drm_display_mode *mode,
1141 struct drm_display_mode *adjusted_mode)
1142{
1143 struct drm_display_mode *m;
1144 int mode_ok;
1145
1146 DRM_DEBUG_KMS("%s\n", __FILE__);
1147
1148 drm_mode_set_crtcinfo(adjusted_mode, 0);
1149
Sean Pauld9716ee2014-01-30 16:19:29 -05001150 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001151
1152 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001153 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001154 return;
1155
1156 /*
1157 * otherwise, find the most suitable mode among modes and change it
1158 * to adjusted_mode.
1159 */
1160 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001161 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001162
Sean Pauld9716ee2014-01-30 16:19:29 -05001163 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001164 DRM_INFO("desired mode doesn't exist so\n");
1165 DRM_INFO("use the most suitable mode among modes.\n");
1166
1167 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1168 m->hdisplay, m->vdisplay, m->vrefresh);
1169
Sean Paul75626852014-01-30 16:19:16 -05001170 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001171 break;
1172 }
1173 }
1174}
1175
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001176static void hdmi_set_acr(u32 freq, u8 *acr)
1177{
1178 u32 n, cts;
1179
1180 switch (freq) {
1181 case 32000:
1182 n = 4096;
1183 cts = 27000;
1184 break;
1185 case 44100:
1186 n = 6272;
1187 cts = 30000;
1188 break;
1189 case 88200:
1190 n = 12544;
1191 cts = 30000;
1192 break;
1193 case 176400:
1194 n = 25088;
1195 cts = 30000;
1196 break;
1197 case 48000:
1198 n = 6144;
1199 cts = 27000;
1200 break;
1201 case 96000:
1202 n = 12288;
1203 cts = 27000;
1204 break;
1205 case 192000:
1206 n = 24576;
1207 cts = 27000;
1208 break;
1209 default:
1210 n = 0;
1211 cts = 0;
1212 break;
1213 }
1214
1215 acr[1] = cts >> 16;
1216 acr[2] = cts >> 8 & 0xff;
1217 acr[3] = cts & 0xff;
1218
1219 acr[4] = n >> 16;
1220 acr[5] = n >> 8 & 0xff;
1221 acr[6] = n & 0xff;
1222}
1223
1224static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1225{
1226 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1227 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1228 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1229 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1230 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1231 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1232 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1233 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1234 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1235
Rahul Sharma5a325072012-10-04 20:48:54 +05301236 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001237 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1238 else
1239 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1240}
1241
1242static void hdmi_audio_init(struct hdmi_context *hdata)
1243{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301244 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001245 u32 data_num, bit_ch, sample_frq;
1246 u32 val;
1247 u8 acr[7];
1248
1249 sample_rate = 44100;
1250 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001251
1252 switch (bits_per_sample) {
1253 case 20:
1254 data_num = 2;
1255 bit_ch = 1;
1256 break;
1257 case 24:
1258 data_num = 3;
1259 bit_ch = 1;
1260 break;
1261 default:
1262 data_num = 1;
1263 bit_ch = 0;
1264 break;
1265 }
1266
1267 hdmi_set_acr(sample_rate, acr);
1268 hdmi_reg_acr(hdata, acr);
1269
1270 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1271 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1272 | HDMI_I2S_MUX_ENABLE);
1273
1274 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1275 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1276
1277 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1278
1279 sample_frq = (sample_rate == 44100) ? 0 :
1280 (sample_rate == 48000) ? 2 :
1281 (sample_rate == 32000) ? 3 :
1282 (sample_rate == 96000) ? 0xa : 0x0;
1283
1284 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1285 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1286
1287 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1288 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1289
1290 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1291 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1292 | HDMI_I2S_SEL_LRCK(6));
1293 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1294 | HDMI_I2S_SEL_SDATA2(4));
1295 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1296 | HDMI_I2S_SEL_SDATA2(2));
1297 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1298
1299 /* I2S_CON_1 & 2 */
1300 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1301 | HDMI_I2S_L_CH_LOW_POL);
1302 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1303 | HDMI_I2S_SET_BIT_CH(bit_ch)
1304 | HDMI_I2S_SET_SDATA_BIT(data_num)
1305 | HDMI_I2S_BASIC_FORMAT);
1306
1307 /* Configure register related to CUV information */
1308 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1309 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1310 | HDMI_I2S_COPYRIGHT
1311 | HDMI_I2S_LINEAR_PCM
1312 | HDMI_I2S_CONSUMER_FORMAT);
1313 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1314 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1315 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1316 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1317 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1318 HDMI_I2S_ORG_SMP_FREQ_44_1
1319 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1320 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1321
1322 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1323}
1324
1325static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1326{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001327 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001328 return;
1329
1330 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1331 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1332 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1333}
1334
Rahul Sharmabfa48422014-04-03 20:41:04 +05301335static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001336{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301337 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001338
Rahul Sharmabfa48422014-04-03 20:41:04 +05301339 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1340 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001341
Rahul Sharmabfa48422014-04-03 20:41:04 +05301342 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1343 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001344}
1345
1346static void hdmi_conf_init(struct hdmi_context *hdata)
1347{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301348 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301349
Sean Paul77006a72013-01-16 10:17:20 -05001350 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001351 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1352 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001353
1354 /* choose HDMI mode */
1355 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1356 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301357 /* Apply Video preable and Guard band in HDMI mode only */
1358 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001359 /* disable bluescreen */
1360 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001361
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001362 if (hdata->dvi_mode) {
1363 /* choose DVI mode */
1364 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1365 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1366 hdmi_reg_writeb(hdata, HDMI_CON_2,
1367 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1368 }
1369
Rahul Sharma5a325072012-10-04 20:48:54 +05301370 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001371 /* choose bluescreen (fecal) color */
1372 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1373 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1374 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1375
1376 /* enable AVI packet every vsync, fixes purple line problem */
1377 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1378 /* force RGB, look to CEA-861-D, table 7 for more detail */
1379 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1380 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1381
1382 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1383 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1384 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1385 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301386 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1387 infoframe.any.version = HDMI_AVI_VERSION;
1388 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301389 hdmi_reg_infoframe(hdata, &infoframe);
1390
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301391 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1392 infoframe.any.version = HDMI_AUI_VERSION;
1393 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301394 hdmi_reg_infoframe(hdata, &infoframe);
1395
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001396 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001397 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1398 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001399}
1400
Rahul Sharma16844fb2013-06-10 14:50:00 +05301401static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001402{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001403 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1404 const struct hdmi_v13_core_regs *core =
1405 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001406 int tries;
1407
1408 /* setting core registers */
1409 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1410 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001411 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1412 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1413 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1414 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1415 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1416 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001417 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1418 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001419 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1420 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1421 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1422 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1423 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1424 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1425 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1426 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1427 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1428 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1429 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1430 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1431 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1432 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1433 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001434 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001435 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1436 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1437 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1438 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1439 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1440 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1441 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1442 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1443 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1444 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1445 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1446 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1447 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1448 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1449 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1450 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1451 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1452 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1453 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1454 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1455 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1456 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1457 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001463
1464 /* waiting for HDMIPHY's PLL to get to steady state */
1465 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001466 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001467 if (val & HDMI_PHY_STATUS_READY)
1468 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001469 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001470 }
1471 /* steady state not achieved */
1472 if (tries == 0) {
1473 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1474 hdmi_regs_dump(hdata, "timing apply");
1475 }
1476
Sean Paul0bfb1f82013-06-11 12:24:02 +05301477 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301478 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301479 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001480
1481 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301482 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001483}
1484
Rahul Sharma16844fb2013-06-10 14:50:00 +05301485static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001486{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001487 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1488 const struct hdmi_v14_core_regs *core =
1489 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001490 int tries;
1491
1492 /* setting core registers */
1493 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1494 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1495 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1496 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1497 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1498 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1499 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1500 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1501 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1502 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1503 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1504 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1505 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1506 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1507 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1508 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1509 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1510 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1511 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1512 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1513 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1514 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1515 core->v_sync_line_bef_2[0]);
1516 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1517 core->v_sync_line_bef_2[1]);
1518 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1519 core->v_sync_line_bef_1[0]);
1520 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1521 core->v_sync_line_bef_1[1]);
1522 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1523 core->v_sync_line_aft_2[0]);
1524 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1525 core->v_sync_line_aft_2[1]);
1526 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1527 core->v_sync_line_aft_1[0]);
1528 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1529 core->v_sync_line_aft_1[1]);
1530 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1531 core->v_sync_line_aft_pxl_2[0]);
1532 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1533 core->v_sync_line_aft_pxl_2[1]);
1534 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1535 core->v_sync_line_aft_pxl_1[0]);
1536 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1537 core->v_sync_line_aft_pxl_1[1]);
1538 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1539 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1540 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1541 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1542 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1543 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1544 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1545 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1546 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1547 core->v_sync_line_aft_3[0]);
1548 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1549 core->v_sync_line_aft_3[1]);
1550 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1551 core->v_sync_line_aft_4[0]);
1552 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1553 core->v_sync_line_aft_4[1]);
1554 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1555 core->v_sync_line_aft_5[0]);
1556 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1557 core->v_sync_line_aft_5[1]);
1558 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1559 core->v_sync_line_aft_6[0]);
1560 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1561 core->v_sync_line_aft_6[1]);
1562 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1563 core->v_sync_line_aft_pxl_3[0]);
1564 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1565 core->v_sync_line_aft_pxl_3[1]);
1566 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1567 core->v_sync_line_aft_pxl_4[0]);
1568 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1569 core->v_sync_line_aft_pxl_4[1]);
1570 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1571 core->v_sync_line_aft_pxl_5[0]);
1572 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1573 core->v_sync_line_aft_pxl_5[1]);
1574 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1575 core->v_sync_line_aft_pxl_6[0]);
1576 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1577 core->v_sync_line_aft_pxl_6[1]);
1578 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1579 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1580 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1581 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1582 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1583 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1584 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1585 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1586 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1587 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1588 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1589 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1590
1591 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001592 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1593 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1594 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1595 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1596 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1597 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1598 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1599 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1600 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1601 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1602 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1603 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1604 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1605 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1606 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1607 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1608 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1609 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1610 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1611 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1612 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1613 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1614 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1615 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001625
1626 /* waiting for HDMIPHY's PLL to get to steady state */
1627 for (tries = 100; tries; --tries) {
1628 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1629 if (val & HDMI_PHY_STATUS_READY)
1630 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001631 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001632 }
1633 /* steady state not achieved */
1634 if (tries == 0) {
1635 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1636 hdmi_regs_dump(hdata, "timing apply");
1637 }
1638
Sean Paul0bfb1f82013-06-11 12:24:02 +05301639 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301640 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301641 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001642
1643 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301644 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001645}
1646
Rahul Sharma16844fb2013-06-10 14:50:00 +05301647static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001648{
Rahul Sharma5a325072012-10-04 20:48:54 +05301649 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301650 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001651 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301652 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001653}
1654
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001655static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1656{
1657 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001658 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001659
Sean Paul0bfb1f82013-06-11 12:24:02 +05301660 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301661 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301662 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001663
1664 /* operation mode */
1665 buffer[0] = 0x1f;
1666 buffer[1] = 0x00;
1667
1668 if (hdata->hdmiphy_port)
1669 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1670
Rahul Sharma5a325072012-10-04 20:48:54 +05301671 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001672 reg = HDMI_V13_PHY_RSTOUT;
1673 else
1674 reg = HDMI_PHY_RSTOUT;
1675
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001676 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001677 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001678 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001679 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001680 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001681}
1682
Rahul Sharmaa5562252012-11-28 11:30:25 +05301683static void hdmiphy_poweron(struct hdmi_context *hdata)
1684{
Shirish S6a296e22014-04-03 20:41:02 +05301685 if (hdata->type != HDMI_TYPE14)
1686 return;
1687
1688 DRM_DEBUG_KMS("\n");
1689
1690 /* For PHY Mode Setting */
1691 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1692 HDMI_PHY_ENABLE_MODE_SET);
1693 /* Phy Power On */
1694 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1695 HDMI_PHY_POWER_ON);
1696 /* For PHY Mode Setting */
1697 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1698 HDMI_PHY_DISABLE_MODE_SET);
1699 /* PHY SW Reset */
1700 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301701}
1702
1703static void hdmiphy_poweroff(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 /* PHY SW Reset */
1711 hdmiphy_conf_reset(hdata);
1712 /* For PHY Mode Setting */
1713 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1714 HDMI_PHY_ENABLE_MODE_SET);
1715
1716 /* PHY Power Off */
1717 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1718 HDMI_PHY_POWER_OFF);
1719
1720 /* For PHY Mode Setting */
1721 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1722 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301723}
1724
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001725static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1726{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001727 int ret;
1728 int i;
1729
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001730 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001731 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1732 if (i < 0) {
1733 DRM_ERROR("failed to find hdmiphy conf\n");
1734 return;
1735 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001736
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001737 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1738 if (ret) {
1739 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001740 return;
1741 }
1742
Sean Paul09760ea2013-01-14 17:03:20 -05001743 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001744
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001745 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1746 HDMI_PHY_DISABLE_MODE_SET);
1747 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001748 DRM_ERROR("failed to enable hdmiphy\n");
1749 return;
1750 }
1751
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001752}
1753
1754static void hdmi_conf_apply(struct hdmi_context *hdata)
1755{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001756 hdmiphy_conf_reset(hdata);
1757 hdmiphy_conf_apply(hdata);
1758
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001759 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301760 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001761 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001762 mutex_unlock(&hdata->hdmi_mutex);
1763
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001764 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001765
1766 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301767 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001768 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001769
1770 hdmi_regs_dump(hdata, "start");
1771}
1772
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001773static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1774{
1775 int i;
1776 BUG_ON(num_bytes > 4);
1777 for (i = 0; i < num_bytes; i++)
1778 reg_pair[i] = (value >> (8 * i)) & 0xff;
1779}
1780
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001781static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1782 struct drm_display_mode *m)
1783{
1784 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1785 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1786 unsigned int val;
1787
1788 hdata->mode_conf.cea_video_id =
1789 drm_match_cea_mode((struct drm_display_mode *)m);
1790 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301791 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001792
1793 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1794 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1795
1796 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1797 hdmi_set_reg(core->vsync_pol, 1, val);
1798
1799 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1800 hdmi_set_reg(core->int_pro_mode, 1, val);
1801
1802 val = (m->hsync_start - m->hdisplay - 2);
1803 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1804 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1805 hdmi_set_reg(core->h_sync_gen, 3, val);
1806
1807 /*
1808 * Quirk requirement for exynos HDMI IP design,
1809 * 2 pixels less than the actual calculation for hsync_start
1810 * and end.
1811 */
1812
1813 /* Following values & calculations differ for different type of modes */
1814 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1815 /* Interlaced Mode */
1816 val = ((m->vsync_end - m->vdisplay) / 2);
1817 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1818 hdmi_set_reg(core->v_sync_gen1, 3, val);
1819
1820 val = m->vtotal / 2;
1821 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1822 hdmi_set_reg(core->v_blank, 3, val);
1823
1824 val = (m->vtotal +
1825 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1826 val |= m->vtotal << 11;
1827 hdmi_set_reg(core->v_blank_f, 3, val);
1828
1829 val = ((m->vtotal / 2) + 7);
1830 val |= ((m->vtotal / 2) + 2) << 12;
1831 hdmi_set_reg(core->v_sync_gen2, 3, val);
1832
1833 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1834 val |= ((m->htotal / 2) +
1835 (m->hsync_start - m->hdisplay)) << 12;
1836 hdmi_set_reg(core->v_sync_gen3, 3, val);
1837
1838 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1839 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1840
1841 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1842 } else {
1843 /* Progressive Mode */
1844
1845 val = m->vtotal;
1846 val |= (m->vtotal - m->vdisplay) << 11;
1847 hdmi_set_reg(core->v_blank, 3, val);
1848
1849 hdmi_set_reg(core->v_blank_f, 3, 0);
1850
1851 val = (m->vsync_end - m->vdisplay);
1852 val |= ((m->vsync_start - m->vdisplay) << 12);
1853 hdmi_set_reg(core->v_sync_gen1, 3, val);
1854
1855 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1856 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1857 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1858 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1859 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1860 }
1861
1862 /* Timing generator registers */
1863 hdmi_set_reg(tg->cmd, 1, 0x0);
1864 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1865 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1866 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1867 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1868 hdmi_set_reg(tg->vsync, 2, 0x1);
1869 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1870 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1871 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1872 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1873 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1874 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1875 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1876}
1877
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001878static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1879 struct drm_display_mode *m)
1880{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001881 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1882 struct hdmi_v14_core_regs *core =
1883 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001884
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001885 hdata->mode_conf.cea_video_id =
1886 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001887 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301888 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001889
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001890 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1891 hdmi_set_reg(core->v_line, 2, m->vtotal);
1892 hdmi_set_reg(core->h_line, 2, m->htotal);
1893 hdmi_set_reg(core->hsync_pol, 1,
1894 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1895 hdmi_set_reg(core->vsync_pol, 1,
1896 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1897 hdmi_set_reg(core->int_pro_mode, 1,
1898 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1899
1900 /*
1901 * Quirk requirement for exynos 5 HDMI IP design,
1902 * 2 pixels less than the actual calculation for hsync_start
1903 * and end.
1904 */
1905
1906 /* Following values & calculations differ for different type of modes */
1907 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1908 /* Interlaced Mode */
1909 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1910 (m->vsync_end - m->vdisplay) / 2);
1911 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1912 (m->vsync_start - m->vdisplay) / 2);
1913 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1914 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301915 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001916 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1917 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1918 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1919 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1920 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1921 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1922 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1923 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1924 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301925 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1926 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1927 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1928 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001929 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1930 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1931 } else {
1932 /* Progressive Mode */
1933 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1934 m->vsync_end - m->vdisplay);
1935 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1936 m->vsync_start - m->vdisplay);
1937 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1938 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1939 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1940 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1941 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1942 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1943 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1944 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1945 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1946 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1947 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1948 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1949 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301950 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1951 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1952 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001953 }
1954
1955 /* Following values & calculations are same irrespective of mode type */
1956 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1957 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1958 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1959 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1960 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1961 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1962 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1963 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1964 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1965 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1966 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1967 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1968 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1969 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1970 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1971 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1972 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1973 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1974 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1975 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1976
1977 /* Timing generator registers */
1978 hdmi_set_reg(tg->cmd, 1, 0x0);
1979 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1980 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1981 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1982 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1983 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001984 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1985 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001986 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001987 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001988}
1989
Sean Paulf041b252014-01-30 16:19:15 -05001990static void hdmi_mode_set(struct exynos_drm_display *display,
1991 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001992{
Sean Paulf041b252014-01-30 16:19:15 -05001993 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001994 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001995
YoungJun Chocbc4c332013-06-12 10:44:40 +09001996 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1997 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001998 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1999 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002000
Rahul Sharmabfa48422014-04-03 20:41:04 +05302001 /* preserve mode information for later use. */
2002 drm_mode_copy(&hdata->current_mode, mode);
2003
Sachin Kamat5f46c332013-04-26 11:29:00 +05302004 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002005 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302006 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002007 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002008}
2009
Sean Paulf041b252014-01-30 16:19:15 -05002010static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011{
Sean Paulf041b252014-01-30 16:19:15 -05002012 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002013
Shirish Sdda90122013-01-23 22:03:18 -05002014 mutex_lock(&hdata->hdmi_mutex);
2015 if (!hdata->powered) {
2016 mutex_unlock(&hdata->hdmi_mutex);
2017 return;
2018 }
2019 mutex_unlock(&hdata->hdmi_mutex);
2020
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002021 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002022}
2023
Sean Paulf041b252014-01-30 16:19:15 -05002024static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002025{
Sean Paulf041b252014-01-30 16:19:15 -05002026 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002027 struct hdmi_resources *res = &hdata->res;
2028
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002029 mutex_lock(&hdata->hdmi_mutex);
2030 if (hdata->powered) {
2031 mutex_unlock(&hdata->hdmi_mutex);
2032 return;
2033 }
2034
2035 hdata->powered = true;
2036
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002037 mutex_unlock(&hdata->hdmi_mutex);
2038
Sean Paulaf65c802014-01-30 16:19:27 -05002039 pm_runtime_get_sync(hdata->dev);
2040
Seung-Woo Kimad079452013-06-05 14:34:38 +09002041 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2042 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2043
Rahul Sharma049d34e2014-05-20 10:36:05 +05302044 /* set pmu hdmiphy control bit to enable hdmiphy */
2045 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2046 PMU_HDMI_PHY_ENABLE_BIT, 1);
2047
Sean Paul0bfb1f82013-06-11 12:24:02 +05302048 clk_prepare_enable(res->hdmi);
2049 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302050
2051 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05002052 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002053}
2054
Sean Paulf041b252014-01-30 16:19:15 -05002055static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002056{
Sean Paulf041b252014-01-30 16:19:15 -05002057 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002058 struct hdmi_resources *res = &hdata->res;
2059
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002060 mutex_lock(&hdata->hdmi_mutex);
2061 if (!hdata->powered)
2062 goto out;
2063 mutex_unlock(&hdata->hdmi_mutex);
2064
Rahul Sharmabfa48422014-04-03 20:41:04 +05302065 /* HDMI System Disable */
2066 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2067
Rahul Sharmaa5562252012-11-28 11:30:25 +05302068 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002069
Sean Paul724fd142014-05-09 15:05:10 +09002070 cancel_delayed_work(&hdata->hotplug_work);
2071
Sean Paul0bfb1f82013-06-11 12:24:02 +05302072 clk_disable_unprepare(res->sclk_hdmi);
2073 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302074
2075 /* reset pmu hdmiphy control bit to disable hdmiphy */
2076 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2077 PMU_HDMI_PHY_ENABLE_BIT, 0);
2078
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002079 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2080
Sean Paulaf65c802014-01-30 16:19:27 -05002081 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002082
Sean Paulaf65c802014-01-30 16:19:27 -05002083 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002084 hdata->powered = false;
2085
2086out:
2087 mutex_unlock(&hdata->hdmi_mutex);
2088}
2089
Sean Paulf041b252014-01-30 16:19:15 -05002090static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002091{
Inki Dae245f98f2014-06-13 17:44:40 +09002092 struct hdmi_context *hdata = display->ctx;
2093 struct drm_encoder *encoder = hdata->encoder;
2094 struct drm_crtc *crtc = encoder->crtc;
2095 struct drm_crtc_helper_funcs *funcs = NULL;
2096
YoungJun Chocbc4c332013-06-12 10:44:40 +09002097 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002098
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002099 switch (mode) {
2100 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05002101 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002102 break;
2103 case DRM_MODE_DPMS_STANDBY:
2104 case DRM_MODE_DPMS_SUSPEND:
2105 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002106 /*
2107 * The SFRs of VP and Mixer are updated by Vertical Sync of
2108 * Timing generator which is a part of HDMI so the sequence
2109 * to disable TV Subsystem should be as following,
2110 * VP -> Mixer -> HDMI
2111 *
2112 * Below codes will try to disable Mixer and VP(if used)
2113 * prior to disabling HDMI.
2114 */
2115 if (crtc)
2116 funcs = crtc->helper_private;
2117 if (funcs && funcs->dpms)
2118 (*funcs->dpms)(crtc, mode);
2119
Sean Paulaf65c802014-01-30 16:19:27 -05002120 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002121 break;
2122 default:
2123 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2124 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002125 }
2126}
2127
Sean Paulf041b252014-01-30 16:19:15 -05002128static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002129 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002130 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002131 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002132 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002134};
2135
Sean Paulf041b252014-01-30 16:19:15 -05002136static struct exynos_drm_display hdmi_display = {
2137 .type = EXYNOS_DISPLAY_TYPE_HDMI,
2138 .ops = &hdmi_display_ops,
2139};
2140
Sean Paul724fd142014-05-09 15:05:10 +09002141static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002142{
Sean Paul724fd142014-05-09 15:05:10 +09002143 struct hdmi_context *hdata;
2144
2145 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002146
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002147 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302148 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002149 mutex_unlock(&hdata->hdmi_mutex);
2150
Sean Paul45517892014-01-30 16:19:05 -05002151 if (hdata->drm_dev)
2152 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002153}
2154
2155static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2156{
2157 struct hdmi_context *hdata = arg;
2158
2159 mod_delayed_work(system_wq, &hdata->hotplug_work,
2160 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002161
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002162 return IRQ_HANDLED;
2163}
2164
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002165static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002166{
2167 struct device *dev = hdata->dev;
2168 struct hdmi_resources *res = &hdata->res;
2169 static char *supply[] = {
2170 "hdmi-en",
2171 "vdd",
2172 "vdd_osc",
2173 "vdd_pll",
2174 };
2175 int i, ret;
2176
2177 DRM_DEBUG_KMS("HDMI resource init\n");
2178
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002179 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302180 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302181 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002182 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002183 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002184 goto fail;
2185 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302186 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302187 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002188 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002189 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002190 goto fail;
2191 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302192 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302193 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002195 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196 goto fail;
2197 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302198 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302199 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002200 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002201 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002202 goto fail;
2203 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302204 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2205 if (IS_ERR(res->mout_hdmi)) {
2206 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002207 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302208 goto fail;
2209 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002210
Rahul Sharma59956d32013-06-11 12:24:03 +05302211 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002212
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302213 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302214 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002215 if (!res->regul_bulk) {
2216 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002217 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002218 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002219 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2220 res->regul_bulk[i].supply = supply[i];
2221 res->regul_bulk[i].consumer = NULL;
2222 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302223 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002224 if (ret) {
2225 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002226 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002227 }
2228 res->regul_count = ARRAY_SIZE(supply);
2229
Inki Daedf5225b2014-05-29 18:28:02 +09002230 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002231fail:
2232 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002233 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002234}
2235
Rahul Sharma22c4f422012-10-04 20:48:55 +05302236static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2237 (struct device *dev)
2238{
2239 struct device_node *np = dev->of_node;
2240 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302241 u32 value;
2242
2243 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002244 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302245 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302246
2247 if (!of_find_property(np, "hpd-gpio", &value)) {
2248 DRM_ERROR("no hpd gpio property found\n");
2249 goto err_data;
2250 }
2251
Rahul Sharma5f916e22013-06-11 19:41:29 +05302252 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302253
2254 return pd;
2255
2256err_data:
2257 return NULL;
2258}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302259
Rahul Sharma22c4f422012-10-04 20:48:55 +05302260static struct of_device_id hdmi_match_types[] = {
2261 {
2262 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002263 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302264 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302265 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002266 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302267 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302268 .compatible = "samsung,exynos5420-hdmi",
2269 .data = &exynos5420_hdmi_driver_data,
2270 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302271 /* end node */
2272 }
2273};
2274
Inki Daef37cd5e2014-05-09 14:25:20 +09002275static int hdmi_bind(struct device *dev, struct device *master, void *data)
2276{
2277 struct drm_device *drm_dev = data;
2278 struct hdmi_context *hdata;
2279
2280 hdata = hdmi_display.ctx;
2281 hdata->drm_dev = drm_dev;
2282
2283 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2284}
2285
2286static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2287{
2288 struct exynos_drm_display *display = get_hdmi_display(dev);
2289 struct drm_encoder *encoder = display->encoder;
2290 struct hdmi_context *hdata = display->ctx;
2291
2292 encoder->funcs->destroy(encoder);
2293 drm_connector_cleanup(&hdata->connector);
2294}
2295
2296static const struct component_ops hdmi_component_ops = {
2297 .bind = hdmi_bind,
2298 .unbind = hdmi_unbind,
2299};
2300
Inki Daee2a562d2014-05-09 16:46:10 +09002301static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2302{
2303 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2304 struct device_node *np;
2305
2306 np = of_find_compatible_node(NULL, NULL, compatible_str);
2307 if (np)
2308 return of_get_next_parent(np);
2309
2310 return NULL;
2311}
2312
2313static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2314{
2315 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2316
2317 return of_find_compatible_node(NULL, NULL, compatible_str);
2318}
2319
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002320static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002321{
Inki Daef37cd5e2014-05-09 14:25:20 +09002322 struct device_node *ddc_node, *phy_node;
2323 struct s5p_hdmi_platform_data *pdata;
2324 struct hdmi_driver_data *drv_data;
2325 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002326 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002327 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002328 struct resource *res;
2329 int ret;
2330
Inki Daedf5225b2014-05-29 18:28:02 +09002331 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
2332 hdmi_display.type);
2333 if (ret)
2334 return ret;
2335
2336 if (!dev->of_node) {
2337 ret = -ENODEV;
2338 goto err_del_component;
2339 }
Rahul Sharma22c4f422012-10-04 20:48:55 +05302340
Sachin Kamat88c49812013-08-28 10:47:57 +05302341 pdata = drm_hdmi_dt_parse_pdata(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002342 if (!pdata) {
2343 ret = -EINVAL;
2344 goto err_del_component;
2345 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002346
Sachin Kamat88c49812013-08-28 10:47:57 +05302347 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002348 if (!hdata) {
2349 ret = -ENOMEM;
2350 goto err_del_component;
2351 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002352
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002353 mutex_init(&hdata->hdmi_mutex);
2354
Sean Paulf041b252014-01-30 16:19:15 -05002355 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002356
Sachin Kamat88c49812013-08-28 10:47:57 +05302357 match = of_match_node(hdmi_match_types, dev->of_node);
Inki Daedf5225b2014-05-29 18:28:02 +09002358 if (!match) {
2359 ret = -ENODEV;
2360 goto err_del_component;
2361 }
Inki Daebfe4e842014-03-06 14:18:17 +09002362
2363 drv_data = (struct hdmi_driver_data *)match->data;
2364 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002365 hdata->phy_confs = drv_data->phy_confs;
2366 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302367
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302368 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002369 hdata->dev = dev;
2370
2371 ret = hdmi_resources_init(hdata);
2372 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302373 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002374 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002375 }
2376
2377 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002378 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002379 if (IS_ERR(hdata->regs)) {
2380 ret = PTR_ERR(hdata->regs);
2381 goto err_del_component;
2382 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002383
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002384 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302385 if (ret) {
2386 DRM_ERROR("failed to request HPD gpio\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002387 goto err_del_component;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302388 }
2389
Inki Daee2a562d2014-05-09 16:46:10 +09002390 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2391 if (ddc_node)
2392 goto out_get_ddc_adpt;
2393
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002394 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002395 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2396 if (!ddc_node) {
2397 DRM_ERROR("Failed to find ddc node in device tree\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002398 ret = -ENODEV;
2399 goto err_del_component;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002400 }
Inki Daee2a562d2014-05-09 16:46:10 +09002401
2402out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002403 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2404 if (!hdata->ddc_adpt) {
2405 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002406 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002407 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002408
Inki Daee2a562d2014-05-09 16:46:10 +09002409 phy_node = hdmi_legacy_phy_dt_binding(dev);
2410 if (phy_node)
2411 goto out_get_phy_port;
2412
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002413 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002414 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2415 if (!phy_node) {
2416 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2417 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002418 goto err_ddc;
2419 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002420
Inki Daee2a562d2014-05-09 16:46:10 +09002421out_get_phy_port:
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002422 if (drv_data->is_apb_phy) {
2423 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2424 if (!hdata->regs_hdmiphy) {
2425 DRM_ERROR("failed to ioremap hdmi phy\n");
2426 ret = -ENOMEM;
2427 goto err_ddc;
2428 }
2429 } else {
2430 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2431 if (!hdata->hdmiphy_port) {
2432 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002433 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002434 goto err_ddc;
2435 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002436 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002437
Sean Paul77006a72013-01-16 10:17:20 -05002438 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2439 if (hdata->irq < 0) {
2440 DRM_ERROR("failed to get GPIO irq\n");
2441 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002442 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002443 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002444
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302445 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2446
Sean Paul724fd142014-05-09 15:05:10 +09002447 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2448
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002449 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002450 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002451 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002452 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002453 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002454 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002455 goto err_hdmiphy;
2456 }
2457
Rahul Sharma049d34e2014-05-20 10:36:05 +05302458 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2459 "samsung,syscon-phandle");
2460 if (IS_ERR(hdata->pmureg)) {
2461 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002462 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302463 goto err_hdmiphy;
2464 }
2465
Sean Paulaf65c802014-01-30 16:19:27 -05002466 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002467 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002468
Inki Daedf5225b2014-05-29 18:28:02 +09002469 ret = component_add(&pdev->dev, &hdmi_component_ops);
2470 if (ret)
2471 goto err_disable_pm_runtime;
2472
2473 return ret;
2474
2475err_disable_pm_runtime:
2476 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002477
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002478err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002479 if (hdata->hdmiphy_port)
2480 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002481err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002482 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002483
2484err_del_component:
2485 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
2486
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002487 return ret;
2488}
2489
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002490static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002491{
Inki Daef37cd5e2014-05-09 14:25:20 +09002492 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002493
Sean Paul724fd142014-05-09 15:05:10 +09002494 cancel_delayed_work_sync(&hdata->hotplug_work);
2495
Daniel Kurtz2b768132014-02-24 18:52:51 +09002496 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002497 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002498
Sean Paulaf65c802014-01-30 16:19:27 -05002499 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002500 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002501
Inki Daedf5225b2014-05-29 18:28:02 +09002502 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002503 return 0;
2504}
2505
2506struct platform_driver hdmi_driver = {
2507 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002508 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002509 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302510 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002511 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302512 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002513 },
2514};