blob: fd8141f43b35554952ecca1589fc08ecbdf234bb [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;
Marek Szyprowski05fdf982014-07-01 10:10:06 +020087 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +090088 int regul_count;
89};
90
Sean Paul2f7e2ed2013-01-15 08:11:08 -050091struct hdmi_tg_regs {
92 u8 cmd[1];
93 u8 h_fsz[2];
94 u8 hact_st[2];
95 u8 hact_sz[2];
96 u8 v_fsz[2];
97 u8 vsync[2];
98 u8 vsync2[2];
99 u8 vact_st[2];
100 u8 vact_sz[2];
101 u8 field_chg[2];
102 u8 vact_st2[2];
103 u8 vact_st3[2];
104 u8 vact_st4[2];
105 u8 vsync_top_hdmi[2];
106 u8 vsync_bot_hdmi[2];
107 u8 field_top_hdmi[2];
108 u8 field_bot_hdmi[2];
109 u8 tg_3d[1];
110};
111
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900112struct hdmi_v13_core_regs {
113 u8 h_blank[2];
114 u8 v_blank[3];
115 u8 h_v_line[3];
116 u8 vsync_pol[1];
117 u8 int_pro_mode[1];
118 u8 v_blank_f[3];
119 u8 h_sync_gen[3];
120 u8 v_sync_gen1[3];
121 u8 v_sync_gen2[3];
122 u8 v_sync_gen3[3];
123};
124
125struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500126 u8 h_blank[2];
127 u8 v2_blank[2];
128 u8 v1_blank[2];
129 u8 v_line[2];
130 u8 h_line[2];
131 u8 hsync_pol[1];
132 u8 vsync_pol[1];
133 u8 int_pro_mode[1];
134 u8 v_blank_f0[2];
135 u8 v_blank_f1[2];
136 u8 h_sync_start[2];
137 u8 h_sync_end[2];
138 u8 v_sync_line_bef_2[2];
139 u8 v_sync_line_bef_1[2];
140 u8 v_sync_line_aft_2[2];
141 u8 v_sync_line_aft_1[2];
142 u8 v_sync_line_aft_pxl_2[2];
143 u8 v_sync_line_aft_pxl_1[2];
144 u8 v_blank_f2[2]; /* for 3D mode */
145 u8 v_blank_f3[2]; /* for 3D mode */
146 u8 v_blank_f4[2]; /* for 3D mode */
147 u8 v_blank_f5[2]; /* for 3D mode */
148 u8 v_sync_line_aft_3[2];
149 u8 v_sync_line_aft_4[2];
150 u8 v_sync_line_aft_5[2];
151 u8 v_sync_line_aft_6[2];
152 u8 v_sync_line_aft_pxl_3[2];
153 u8 v_sync_line_aft_pxl_4[2];
154 u8 v_sync_line_aft_pxl_5[2];
155 u8 v_sync_line_aft_pxl_6[2];
156 u8 vact_space_1[2];
157 u8 vact_space_2[2];
158 u8 vact_space_3[2];
159 u8 vact_space_4[2];
160 u8 vact_space_5[2];
161 u8 vact_space_6[2];
162};
163
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900164struct hdmi_v13_conf {
165 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500166 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900167};
168
169struct hdmi_v14_conf {
170 struct hdmi_v14_core_regs core;
171 struct hdmi_tg_regs tg;
172};
173
174struct hdmi_conf_regs {
175 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500176 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530177 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900178 union {
179 struct hdmi_v13_conf v13_conf;
180 struct hdmi_v14_conf v14_conf;
181 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500182};
183
Joonyoung Shim590f4182012-03-16 18:47:14 +0900184struct hdmi_context {
185 struct device *dev;
186 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500187 struct drm_connector connector;
188 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900189 bool hpd;
190 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900191 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900192 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900193
Joonyoung Shim590f4182012-03-16 18:47:14 +0900194 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500195 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900196 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900197
Inki Dae8fa04aa2014-03-13 16:38:31 +0900198 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900199 struct i2c_client *hdmiphy_port;
200
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900201 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530202 struct drm_display_mode current_mode;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900203 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900204
205 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900206
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530207 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900208 void __iomem *regs_hdmiphy;
209 const struct hdmiphy_config *phy_confs;
210 unsigned int phy_conf_count;
Rahul Sharma5a325072012-10-04 20:48:54 +0530211
Rahul Sharma049d34e2014-05-20 10:36:05 +0530212 struct regmap *pmureg;
Rahul Sharma5a325072012-10-04 20:48:54 +0530213 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900214};
215
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500216struct hdmiphy_config {
217 int pixel_clock;
218 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900219};
220
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900221/* list of phy config settings */
222static const struct hdmiphy_config hdmiphy_v13_configs[] = {
223 {
224 .pixel_clock = 27000000,
225 .conf = {
226 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
227 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
228 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
229 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
230 },
231 },
232 {
233 .pixel_clock = 27027000,
234 .conf = {
235 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
236 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
237 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
238 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
239 },
240 },
241 {
242 .pixel_clock = 74176000,
243 .conf = {
244 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
245 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
246 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
247 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
248 },
249 },
250 {
251 .pixel_clock = 74250000,
252 .conf = {
253 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
254 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
255 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
256 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
257 },
258 },
259 {
260 .pixel_clock = 148500000,
261 .conf = {
262 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
263 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
264 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
265 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
266 },
267 },
268};
269
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500270static const struct hdmiphy_config hdmiphy_v14_configs[] = {
271 {
272 .pixel_clock = 25200000,
273 .conf = {
274 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
275 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
276 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
277 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
278 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900279 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500280 {
281 .pixel_clock = 27000000,
282 .conf = {
283 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
284 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
285 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
286 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
287 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900288 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500289 {
290 .pixel_clock = 27027000,
291 .conf = {
292 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
293 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
294 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
295 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
296 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900297 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 {
299 .pixel_clock = 36000000,
300 .conf = {
301 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
302 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
303 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
304 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
305 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900306 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500307 {
308 .pixel_clock = 40000000,
309 .conf = {
310 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
311 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
312 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
313 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
314 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900315 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500316 {
317 .pixel_clock = 65000000,
318 .conf = {
319 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
320 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
321 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
322 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
323 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900324 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 {
Shirish Se1d883c2014-03-13 14:28:27 +0900326 .pixel_clock = 71000000,
327 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530328 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
329 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
330 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900331 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
332 },
333 },
334 {
335 .pixel_clock = 73250000,
336 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530337 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
338 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
339 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900340 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
341 },
342 },
343 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500344 .pixel_clock = 74176000,
345 .conf = {
346 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
347 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
348 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
349 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
350 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900351 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500352 {
353 .pixel_clock = 74250000,
354 .conf = {
355 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
356 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
357 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
358 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
359 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900360 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500361 {
362 .pixel_clock = 83500000,
363 .conf = {
364 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
365 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
366 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
367 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
368 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900369 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500370 {
371 .pixel_clock = 106500000,
372 .conf = {
373 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
374 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
375 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
376 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
377 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900378 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500379 {
380 .pixel_clock = 108000000,
381 .conf = {
382 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
383 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
384 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
385 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
386 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900387 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500388 {
Shirish Se1d883c2014-03-13 14:28:27 +0900389 .pixel_clock = 115500000,
390 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530391 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
392 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
393 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900394 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
395 },
396 },
397 {
398 .pixel_clock = 119000000,
399 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530400 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
401 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
402 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900403 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
404 },
405 },
406 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500407 .pixel_clock = 146250000,
408 .conf = {
409 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
410 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
411 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
412 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
413 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900414 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500415 {
416 .pixel_clock = 148500000,
417 .conf = {
418 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
419 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
420 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
421 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
422 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900423 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900424};
425
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530426static const struct hdmiphy_config hdmiphy_5420_configs[] = {
427 {
428 .pixel_clock = 25200000,
429 .conf = {
430 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
431 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
432 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
433 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
434 },
435 },
436 {
437 .pixel_clock = 27000000,
438 .conf = {
439 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
440 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
441 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
442 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
443 },
444 },
445 {
446 .pixel_clock = 27027000,
447 .conf = {
448 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
449 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
450 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
451 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
452 },
453 },
454 {
455 .pixel_clock = 36000000,
456 .conf = {
457 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
458 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
459 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
460 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
461 },
462 },
463 {
464 .pixel_clock = 40000000,
465 .conf = {
466 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
467 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
468 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
469 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
470 },
471 },
472 {
473 .pixel_clock = 65000000,
474 .conf = {
475 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
476 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
477 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
478 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
479 },
480 },
481 {
482 .pixel_clock = 71000000,
483 .conf = {
484 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
485 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
486 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
487 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
488 },
489 },
490 {
491 .pixel_clock = 73250000,
492 .conf = {
493 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
494 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
495 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
496 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
497 },
498 },
499 {
500 .pixel_clock = 74176000,
501 .conf = {
502 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
503 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
504 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
505 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
506 },
507 },
508 {
509 .pixel_clock = 74250000,
510 .conf = {
511 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
512 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
513 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
514 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
515 },
516 },
517 {
518 .pixel_clock = 83500000,
519 .conf = {
520 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
521 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
522 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
523 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
524 },
525 },
526 {
527 .pixel_clock = 88750000,
528 .conf = {
529 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
530 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
531 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
532 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
533 },
534 },
535 {
536 .pixel_clock = 106500000,
537 .conf = {
538 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
539 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
540 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
541 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
542 },
543 },
544 {
545 .pixel_clock = 108000000,
546 .conf = {
547 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
548 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
549 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
550 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
551 },
552 },
553 {
554 .pixel_clock = 115500000,
555 .conf = {
556 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
557 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
558 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
559 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
560 },
561 },
562 {
563 .pixel_clock = 146250000,
564 .conf = {
565 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
566 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
567 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
568 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
569 },
570 },
571 {
572 .pixel_clock = 148500000,
573 .conf = {
574 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
575 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
576 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
577 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
578 },
579 },
580};
581
Sachin Kamat16337072014-05-22 10:32:56 +0530582static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530583 .type = HDMI_TYPE14,
584 .phy_confs = hdmiphy_5420_configs,
585 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
586 .is_apb_phy = 1,
587};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900588
Sachin Kamat16337072014-05-22 10:32:56 +0530589static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900590 .type = HDMI_TYPE14,
591 .phy_confs = hdmiphy_v14_configs,
592 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
593 .is_apb_phy = 0,
594};
595
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200596static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
597 .type = HDMI_TYPE13,
598 .phy_confs = hdmiphy_v13_configs,
599 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
600 .is_apb_phy = 0,
601};
602
Sachin Kamat16337072014-05-22 10:32:56 +0530603static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900604 .type = HDMI_TYPE14,
605 .phy_confs = hdmiphy_v13_configs,
606 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
607 .is_apb_phy = 0,
608};
609
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
611{
612 return readl(hdata->regs + reg_id);
613}
614
615static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
616 u32 reg_id, u8 value)
617{
618 writeb(value, hdata->regs + reg_id);
619}
620
621static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
622 u32 reg_id, u32 value, u32 mask)
623{
624 u32 old = readl(hdata->regs + reg_id);
625 value = (value & mask) | (old & ~mask);
626 writel(value, hdata->regs + reg_id);
627}
628
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900629static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
630 u32 reg_offset, u8 value)
631{
632 if (hdata->hdmiphy_port) {
633 u8 buffer[2];
634 int ret;
635
636 buffer[0] = reg_offset;
637 buffer[1] = value;
638
639 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
640 if (ret == 2)
641 return 0;
642 return ret;
643 } else {
644 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
645 return 0;
646 }
647}
648
649static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
650 u32 reg_offset, const u8 *buf, u32 len)
651{
652 if ((reg_offset + len) > 32)
653 return -EINVAL;
654
655 if (hdata->hdmiphy_port) {
656 int ret;
657
658 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
659 if (ret == len)
660 return 0;
661 return ret;
662 } else {
663 int i;
664 for (i = 0; i < len; i++)
665 writeb(buf[i], hdata->regs_hdmiphy +
666 ((reg_offset + i)<<2));
667 return 0;
668 }
669}
670
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900671static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900672{
673#define DUMPREG(reg_id) \
674 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
675 readl(hdata->regs + reg_id))
676 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
677 DUMPREG(HDMI_INTC_FLAG);
678 DUMPREG(HDMI_INTC_CON);
679 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900680 DUMPREG(HDMI_V13_PHY_RSTOUT);
681 DUMPREG(HDMI_V13_PHY_VPLL);
682 DUMPREG(HDMI_V13_PHY_CMU);
683 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900684
685 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
686 DUMPREG(HDMI_CON_0);
687 DUMPREG(HDMI_CON_1);
688 DUMPREG(HDMI_CON_2);
689 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900690 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900691 DUMPREG(HDMI_STATUS_EN);
692 DUMPREG(HDMI_HPD);
693 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900694 DUMPREG(HDMI_V13_HPD_GEN);
695 DUMPREG(HDMI_V13_DC_CONTROL);
696 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900697
698 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
699 DUMPREG(HDMI_H_BLANK_0);
700 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900701 DUMPREG(HDMI_V13_V_BLANK_0);
702 DUMPREG(HDMI_V13_V_BLANK_1);
703 DUMPREG(HDMI_V13_V_BLANK_2);
704 DUMPREG(HDMI_V13_H_V_LINE_0);
705 DUMPREG(HDMI_V13_H_V_LINE_1);
706 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900707 DUMPREG(HDMI_VSYNC_POL);
708 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900709 DUMPREG(HDMI_V13_V_BLANK_F_0);
710 DUMPREG(HDMI_V13_V_BLANK_F_1);
711 DUMPREG(HDMI_V13_V_BLANK_F_2);
712 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
713 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
714 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
715 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
716 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
717 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
718 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
719 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
720 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
721 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
722 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
723 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900724
725 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
726 DUMPREG(HDMI_TG_CMD);
727 DUMPREG(HDMI_TG_H_FSZ_L);
728 DUMPREG(HDMI_TG_H_FSZ_H);
729 DUMPREG(HDMI_TG_HACT_ST_L);
730 DUMPREG(HDMI_TG_HACT_ST_H);
731 DUMPREG(HDMI_TG_HACT_SZ_L);
732 DUMPREG(HDMI_TG_HACT_SZ_H);
733 DUMPREG(HDMI_TG_V_FSZ_L);
734 DUMPREG(HDMI_TG_V_FSZ_H);
735 DUMPREG(HDMI_TG_VSYNC_L);
736 DUMPREG(HDMI_TG_VSYNC_H);
737 DUMPREG(HDMI_TG_VSYNC2_L);
738 DUMPREG(HDMI_TG_VSYNC2_H);
739 DUMPREG(HDMI_TG_VACT_ST_L);
740 DUMPREG(HDMI_TG_VACT_ST_H);
741 DUMPREG(HDMI_TG_VACT_SZ_L);
742 DUMPREG(HDMI_TG_VACT_SZ_H);
743 DUMPREG(HDMI_TG_FIELD_CHG_L);
744 DUMPREG(HDMI_TG_FIELD_CHG_H);
745 DUMPREG(HDMI_TG_VACT_ST2_L);
746 DUMPREG(HDMI_TG_VACT_ST2_H);
747 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
748 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
749 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
750 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
751 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
752 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
753 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
754 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
755#undef DUMPREG
756}
757
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900758static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
759{
760 int i;
761
762#define DUMPREG(reg_id) \
763 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
764 readl(hdata->regs + reg_id))
765
766 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
767 DUMPREG(HDMI_INTC_CON);
768 DUMPREG(HDMI_INTC_FLAG);
769 DUMPREG(HDMI_HPD_STATUS);
770 DUMPREG(HDMI_INTC_CON_1);
771 DUMPREG(HDMI_INTC_FLAG_1);
772 DUMPREG(HDMI_PHY_STATUS_0);
773 DUMPREG(HDMI_PHY_STATUS_PLL);
774 DUMPREG(HDMI_PHY_CON_0);
775 DUMPREG(HDMI_PHY_RSTOUT);
776 DUMPREG(HDMI_PHY_VPLL);
777 DUMPREG(HDMI_PHY_CMU);
778 DUMPREG(HDMI_CORE_RSTOUT);
779
780 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
781 DUMPREG(HDMI_CON_0);
782 DUMPREG(HDMI_CON_1);
783 DUMPREG(HDMI_CON_2);
784 DUMPREG(HDMI_SYS_STATUS);
785 DUMPREG(HDMI_PHY_STATUS_0);
786 DUMPREG(HDMI_STATUS_EN);
787 DUMPREG(HDMI_HPD);
788 DUMPREG(HDMI_MODE_SEL);
789 DUMPREG(HDMI_ENC_EN);
790 DUMPREG(HDMI_DC_CONTROL);
791 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
792
793 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
794 DUMPREG(HDMI_H_BLANK_0);
795 DUMPREG(HDMI_H_BLANK_1);
796 DUMPREG(HDMI_V2_BLANK_0);
797 DUMPREG(HDMI_V2_BLANK_1);
798 DUMPREG(HDMI_V1_BLANK_0);
799 DUMPREG(HDMI_V1_BLANK_1);
800 DUMPREG(HDMI_V_LINE_0);
801 DUMPREG(HDMI_V_LINE_1);
802 DUMPREG(HDMI_H_LINE_0);
803 DUMPREG(HDMI_H_LINE_1);
804 DUMPREG(HDMI_HSYNC_POL);
805
806 DUMPREG(HDMI_VSYNC_POL);
807 DUMPREG(HDMI_INT_PRO_MODE);
808 DUMPREG(HDMI_V_BLANK_F0_0);
809 DUMPREG(HDMI_V_BLANK_F0_1);
810 DUMPREG(HDMI_V_BLANK_F1_0);
811 DUMPREG(HDMI_V_BLANK_F1_1);
812
813 DUMPREG(HDMI_H_SYNC_START_0);
814 DUMPREG(HDMI_H_SYNC_START_1);
815 DUMPREG(HDMI_H_SYNC_END_0);
816 DUMPREG(HDMI_H_SYNC_END_1);
817
818 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
819 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
820 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
821 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
822
823 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
824 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
825 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
826 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
827
828 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
829 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
830 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
831 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
832
833 DUMPREG(HDMI_V_BLANK_F2_0);
834 DUMPREG(HDMI_V_BLANK_F2_1);
835 DUMPREG(HDMI_V_BLANK_F3_0);
836 DUMPREG(HDMI_V_BLANK_F3_1);
837 DUMPREG(HDMI_V_BLANK_F4_0);
838 DUMPREG(HDMI_V_BLANK_F4_1);
839 DUMPREG(HDMI_V_BLANK_F5_0);
840 DUMPREG(HDMI_V_BLANK_F5_1);
841
842 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
843 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
844 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
845 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
846 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
850
851 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
852 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
853 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
854 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
855 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
856 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
857 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
858 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
859
860 DUMPREG(HDMI_VACT_SPACE_1_0);
861 DUMPREG(HDMI_VACT_SPACE_1_1);
862 DUMPREG(HDMI_VACT_SPACE_2_0);
863 DUMPREG(HDMI_VACT_SPACE_2_1);
864 DUMPREG(HDMI_VACT_SPACE_3_0);
865 DUMPREG(HDMI_VACT_SPACE_3_1);
866 DUMPREG(HDMI_VACT_SPACE_4_0);
867 DUMPREG(HDMI_VACT_SPACE_4_1);
868 DUMPREG(HDMI_VACT_SPACE_5_0);
869 DUMPREG(HDMI_VACT_SPACE_5_1);
870 DUMPREG(HDMI_VACT_SPACE_6_0);
871 DUMPREG(HDMI_VACT_SPACE_6_1);
872
873 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
874 DUMPREG(HDMI_TG_CMD);
875 DUMPREG(HDMI_TG_H_FSZ_L);
876 DUMPREG(HDMI_TG_H_FSZ_H);
877 DUMPREG(HDMI_TG_HACT_ST_L);
878 DUMPREG(HDMI_TG_HACT_ST_H);
879 DUMPREG(HDMI_TG_HACT_SZ_L);
880 DUMPREG(HDMI_TG_HACT_SZ_H);
881 DUMPREG(HDMI_TG_V_FSZ_L);
882 DUMPREG(HDMI_TG_V_FSZ_H);
883 DUMPREG(HDMI_TG_VSYNC_L);
884 DUMPREG(HDMI_TG_VSYNC_H);
885 DUMPREG(HDMI_TG_VSYNC2_L);
886 DUMPREG(HDMI_TG_VSYNC2_H);
887 DUMPREG(HDMI_TG_VACT_ST_L);
888 DUMPREG(HDMI_TG_VACT_ST_H);
889 DUMPREG(HDMI_TG_VACT_SZ_L);
890 DUMPREG(HDMI_TG_VACT_SZ_H);
891 DUMPREG(HDMI_TG_FIELD_CHG_L);
892 DUMPREG(HDMI_TG_FIELD_CHG_H);
893 DUMPREG(HDMI_TG_VACT_ST2_L);
894 DUMPREG(HDMI_TG_VACT_ST2_H);
895 DUMPREG(HDMI_TG_VACT_ST3_L);
896 DUMPREG(HDMI_TG_VACT_ST3_H);
897 DUMPREG(HDMI_TG_VACT_ST4_L);
898 DUMPREG(HDMI_TG_VACT_ST4_H);
899 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
900 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
901 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
902 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
903 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
904 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
905 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
906 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
907 DUMPREG(HDMI_TG_3D);
908
909 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
910 DUMPREG(HDMI_AVI_CON);
911 DUMPREG(HDMI_AVI_HEADER0);
912 DUMPREG(HDMI_AVI_HEADER1);
913 DUMPREG(HDMI_AVI_HEADER2);
914 DUMPREG(HDMI_AVI_CHECK_SUM);
915 DUMPREG(HDMI_VSI_CON);
916 DUMPREG(HDMI_VSI_HEADER0);
917 DUMPREG(HDMI_VSI_HEADER1);
918 DUMPREG(HDMI_VSI_HEADER2);
919 for (i = 0; i < 7; ++i)
920 DUMPREG(HDMI_VSI_DATA(i));
921
922#undef DUMPREG
923}
924
925static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
926{
Rahul Sharma5a325072012-10-04 20:48:54 +0530927 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900928 hdmi_v13_regs_dump(hdata, prefix);
929 else
930 hdmi_v14_regs_dump(hdata, prefix);
931}
932
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530933static u8 hdmi_chksum(struct hdmi_context *hdata,
934 u32 start, u8 len, u32 hdr_sum)
935{
936 int i;
937
938 /* hdr_sum : header0 + header1 + header2
939 * start : start address of packet byte1
940 * len : packet bytes - 1 */
941 for (i = 0; i < len; ++i)
942 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
943
944 /* return 2's complement of 8 bit hdr_sum */
945 return (u8)(~(hdr_sum & 0xff) + 1);
946}
947
948static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530949 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530950{
951 u32 hdr_sum;
952 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530953 u32 mod;
954 u32 vic;
955
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530956 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
957 if (hdata->dvi_mode) {
958 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
959 HDMI_VSI_CON_DO_NOT_TRANSMIT);
960 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
961 HDMI_AVI_CON_DO_NOT_TRANSMIT);
962 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
963 return;
964 }
965
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530966 switch (infoframe->any.type) {
967 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530968 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530969 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
970 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
971 infoframe->any.version);
972 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
973 hdr_sum = infoframe->any.type + infoframe->any.version +
974 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530975
976 /* Output format zero hardcoded ,RGB YBCR selection */
977 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
978 AVI_ACTIVE_FORMAT_VALID |
979 AVI_UNDERSCANNED_DISPLAY_VALID);
980
Shirish S46154152014-03-13 10:58:28 +0530981 /*
982 * Set the aspect ratio as per the mode, mentioned in
983 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
984 */
985 switch (hdata->mode_conf.aspect_ratio) {
986 case HDMI_PICTURE_ASPECT_4_3:
987 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
988 hdata->mode_conf.aspect_ratio |
989 AVI_4_3_CENTER_RATIO);
990 break;
991 case HDMI_PICTURE_ASPECT_16_9:
992 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
993 hdata->mode_conf.aspect_ratio |
994 AVI_16_9_CENTER_RATIO);
995 break;
996 case HDMI_PICTURE_ASPECT_NONE:
997 default:
998 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
999 hdata->mode_conf.aspect_ratio |
1000 AVI_SAME_AS_PIC_ASPECT_RATIO);
1001 break;
1002 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301003
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001004 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301005 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
1006
1007 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301008 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301009 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1010 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1011 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301012 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301013 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301014 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1015 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1016 infoframe->any.version);
1017 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1018 hdr_sum = infoframe->any.type + infoframe->any.version +
1019 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301020 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301021 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301022 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1023 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1024 break;
1025 default:
1026 break;
1027 }
1028}
1029
Sean Pauld9716ee2014-01-30 16:19:29 -05001030static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1031 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001032{
Sean Pauld9716ee2014-01-30 16:19:29 -05001033 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001034
Sean Paul5137c8c2014-04-03 20:41:03 +05301035 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1036
Sean Pauld9716ee2014-01-30 16:19:29 -05001037 return hdata->hpd ? connector_status_connected :
1038 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001039}
1040
Sean Pauld9716ee2014-01-30 16:19:29 -05001041static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001042{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001043}
1044
Sean Pauld9716ee2014-01-30 16:19:29 -05001045static struct drm_connector_funcs hdmi_connector_funcs = {
1046 .dpms = drm_helper_connector_dpms,
1047 .fill_modes = drm_helper_probe_single_connector_modes,
1048 .detect = hdmi_detect,
1049 .destroy = hdmi_connector_destroy,
1050};
1051
1052static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001053{
Sean Pauld9716ee2014-01-30 16:19:29 -05001054 struct hdmi_context *hdata = ctx_from_connector(connector);
1055 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001056
Inki Dae8fa04aa2014-03-13 16:38:31 +09001057 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001058 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001059
Inki Dae8fa04aa2014-03-13 16:38:31 +09001060 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001061 if (!edid)
1062 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001063
Sean Pauld9716ee2014-01-30 16:19:29 -05001064 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001065 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1066 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001067 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001068
Sean Pauld9716ee2014-01-30 16:19:29 -05001069 drm_mode_connector_update_edid_property(connector, edid);
1070
1071 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001072}
1073
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001074static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001075{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001076 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001077
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001078 for (i = 0; i < hdata->phy_conf_count; i++)
1079 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001080 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001081
1082 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1083 return -EINVAL;
1084}
1085
Sean Pauld9716ee2014-01-30 16:19:29 -05001086static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001087 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001088{
Sean Pauld9716ee2014-01-30 16:19:29 -05001089 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001090 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001091
Rahul Sharma16844fb2013-06-10 14:50:00 +05301092 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1093 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1094 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1095 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001096
Sean Paulf041b252014-01-30 16:19:15 -05001097 ret = mixer_check_mode(mode);
1098 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001099 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001100
Rahul Sharma16844fb2013-06-10 14:50:00 +05301101 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001102 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001103 return MODE_BAD;
1104
1105 return MODE_OK;
1106}
1107
1108static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1109{
1110 struct hdmi_context *hdata = ctx_from_connector(connector);
1111
1112 return hdata->encoder;
1113}
1114
1115static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1116 .get_modes = hdmi_get_modes,
1117 .mode_valid = hdmi_mode_valid,
1118 .best_encoder = hdmi_best_encoder,
1119};
1120
1121static int hdmi_create_connector(struct exynos_drm_display *display,
1122 struct drm_encoder *encoder)
1123{
1124 struct hdmi_context *hdata = display->ctx;
1125 struct drm_connector *connector = &hdata->connector;
1126 int ret;
1127
1128 hdata->encoder = encoder;
1129 connector->interlace_allowed = true;
1130 connector->polled = DRM_CONNECTOR_POLL_HPD;
1131
1132 ret = drm_connector_init(hdata->drm_dev, connector,
1133 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1134 if (ret) {
1135 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001136 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001137 }
1138
1139 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001140 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001141 drm_mode_connector_attach_encoder(connector, encoder);
1142
1143 return 0;
1144}
1145
Sean Paulf041b252014-01-30 16:19:15 -05001146static void hdmi_mode_fixup(struct exynos_drm_display *display,
1147 struct drm_connector *connector,
1148 const struct drm_display_mode *mode,
1149 struct drm_display_mode *adjusted_mode)
1150{
1151 struct drm_display_mode *m;
1152 int mode_ok;
1153
1154 DRM_DEBUG_KMS("%s\n", __FILE__);
1155
1156 drm_mode_set_crtcinfo(adjusted_mode, 0);
1157
Sean Pauld9716ee2014-01-30 16:19:29 -05001158 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001159
1160 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001161 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001162 return;
1163
1164 /*
1165 * otherwise, find the most suitable mode among modes and change it
1166 * to adjusted_mode.
1167 */
1168 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001169 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001170
Sean Pauld9716ee2014-01-30 16:19:29 -05001171 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001172 DRM_INFO("desired mode doesn't exist so\n");
1173 DRM_INFO("use the most suitable mode among modes.\n");
1174
1175 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1176 m->hdisplay, m->vdisplay, m->vrefresh);
1177
Sean Paul75626852014-01-30 16:19:16 -05001178 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001179 break;
1180 }
1181 }
1182}
1183
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001184static void hdmi_set_acr(u32 freq, u8 *acr)
1185{
1186 u32 n, cts;
1187
1188 switch (freq) {
1189 case 32000:
1190 n = 4096;
1191 cts = 27000;
1192 break;
1193 case 44100:
1194 n = 6272;
1195 cts = 30000;
1196 break;
1197 case 88200:
1198 n = 12544;
1199 cts = 30000;
1200 break;
1201 case 176400:
1202 n = 25088;
1203 cts = 30000;
1204 break;
1205 case 48000:
1206 n = 6144;
1207 cts = 27000;
1208 break;
1209 case 96000:
1210 n = 12288;
1211 cts = 27000;
1212 break;
1213 case 192000:
1214 n = 24576;
1215 cts = 27000;
1216 break;
1217 default:
1218 n = 0;
1219 cts = 0;
1220 break;
1221 }
1222
1223 acr[1] = cts >> 16;
1224 acr[2] = cts >> 8 & 0xff;
1225 acr[3] = cts & 0xff;
1226
1227 acr[4] = n >> 16;
1228 acr[5] = n >> 8 & 0xff;
1229 acr[6] = n & 0xff;
1230}
1231
1232static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1233{
1234 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1235 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1236 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1237 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1238 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1239 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1240 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1241 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1242 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1243
Rahul Sharma5a325072012-10-04 20:48:54 +05301244 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001245 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1246 else
1247 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1248}
1249
1250static void hdmi_audio_init(struct hdmi_context *hdata)
1251{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301252 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001253 u32 data_num, bit_ch, sample_frq;
1254 u32 val;
1255 u8 acr[7];
1256
1257 sample_rate = 44100;
1258 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001259
1260 switch (bits_per_sample) {
1261 case 20:
1262 data_num = 2;
1263 bit_ch = 1;
1264 break;
1265 case 24:
1266 data_num = 3;
1267 bit_ch = 1;
1268 break;
1269 default:
1270 data_num = 1;
1271 bit_ch = 0;
1272 break;
1273 }
1274
1275 hdmi_set_acr(sample_rate, acr);
1276 hdmi_reg_acr(hdata, acr);
1277
1278 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1279 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1280 | HDMI_I2S_MUX_ENABLE);
1281
1282 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1283 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1284
1285 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1286
1287 sample_frq = (sample_rate == 44100) ? 0 :
1288 (sample_rate == 48000) ? 2 :
1289 (sample_rate == 32000) ? 3 :
1290 (sample_rate == 96000) ? 0xa : 0x0;
1291
1292 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1293 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1294
1295 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1296 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1297
1298 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1299 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1300 | HDMI_I2S_SEL_LRCK(6));
1301 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1302 | HDMI_I2S_SEL_SDATA2(4));
1303 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1304 | HDMI_I2S_SEL_SDATA2(2));
1305 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1306
1307 /* I2S_CON_1 & 2 */
1308 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1309 | HDMI_I2S_L_CH_LOW_POL);
1310 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1311 | HDMI_I2S_SET_BIT_CH(bit_ch)
1312 | HDMI_I2S_SET_SDATA_BIT(data_num)
1313 | HDMI_I2S_BASIC_FORMAT);
1314
1315 /* Configure register related to CUV information */
1316 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1317 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1318 | HDMI_I2S_COPYRIGHT
1319 | HDMI_I2S_LINEAR_PCM
1320 | HDMI_I2S_CONSUMER_FORMAT);
1321 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1322 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1323 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1324 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1325 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1326 HDMI_I2S_ORG_SMP_FREQ_44_1
1327 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1328 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1329
1330 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1331}
1332
1333static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1334{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001335 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001336 return;
1337
1338 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1339 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1340 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1341}
1342
Rahul Sharmabfa48422014-04-03 20:41:04 +05301343static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001344{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301345 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001346
Rahul Sharmabfa48422014-04-03 20:41:04 +05301347 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1348 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001349
Rahul Sharmabfa48422014-04-03 20:41:04 +05301350 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1351 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001352}
1353
1354static void hdmi_conf_init(struct hdmi_context *hdata)
1355{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301356 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301357
Sean Paul77006a72013-01-16 10:17:20 -05001358 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001359 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1360 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001361
1362 /* choose HDMI mode */
1363 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1364 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301365 /* Apply Video preable and Guard band in HDMI mode only */
1366 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001367 /* disable bluescreen */
1368 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001369
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001370 if (hdata->dvi_mode) {
1371 /* choose DVI mode */
1372 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1373 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1374 hdmi_reg_writeb(hdata, HDMI_CON_2,
1375 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1376 }
1377
Rahul Sharma5a325072012-10-04 20:48:54 +05301378 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001379 /* choose bluescreen (fecal) color */
1380 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1381 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1382 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1383
1384 /* enable AVI packet every vsync, fixes purple line problem */
1385 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1386 /* force RGB, look to CEA-861-D, table 7 for more detail */
1387 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1388 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1389
1390 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1391 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1392 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1393 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301394 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1395 infoframe.any.version = HDMI_AVI_VERSION;
1396 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301397 hdmi_reg_infoframe(hdata, &infoframe);
1398
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301399 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1400 infoframe.any.version = HDMI_AUI_VERSION;
1401 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301402 hdmi_reg_infoframe(hdata, &infoframe);
1403
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001404 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001405 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1406 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001407}
1408
Rahul Sharma16844fb2013-06-10 14:50:00 +05301409static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001410{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001411 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1412 const struct hdmi_v13_core_regs *core =
1413 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001414 int tries;
1415
1416 /* setting core registers */
1417 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1418 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001419 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1420 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1421 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1422 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1423 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1424 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001425 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1426 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001427 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1428 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1429 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1430 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1431 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1432 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1433 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1434 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1435 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1436 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1437 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1438 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1439 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1440 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1441 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001442 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001443 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1444 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1445 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1446 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1447 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1448 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1449 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1450 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1451 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1452 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1453 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1454 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1455 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1456 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1457 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1463 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1464 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1465 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1466 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1467 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1468 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1469 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1470 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001471
1472 /* waiting for HDMIPHY's PLL to get to steady state */
1473 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001474 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001475 if (val & HDMI_PHY_STATUS_READY)
1476 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001477 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001478 }
1479 /* steady state not achieved */
1480 if (tries == 0) {
1481 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1482 hdmi_regs_dump(hdata, "timing apply");
1483 }
1484
Sean Paul0bfb1f82013-06-11 12:24:02 +05301485 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301486 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301487 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001488
1489 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301490 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001491}
1492
Rahul Sharma16844fb2013-06-10 14:50:00 +05301493static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001494{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001495 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1496 const struct hdmi_v14_core_regs *core =
1497 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001498 int tries;
1499
1500 /* setting core registers */
1501 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1502 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1503 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1504 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1505 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1506 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1507 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1508 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1509 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1510 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1511 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1512 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1513 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1514 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1515 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1516 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1517 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1518 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1519 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1520 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1521 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1522 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1523 core->v_sync_line_bef_2[0]);
1524 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1525 core->v_sync_line_bef_2[1]);
1526 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1527 core->v_sync_line_bef_1[0]);
1528 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1529 core->v_sync_line_bef_1[1]);
1530 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1531 core->v_sync_line_aft_2[0]);
1532 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1533 core->v_sync_line_aft_2[1]);
1534 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1535 core->v_sync_line_aft_1[0]);
1536 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1537 core->v_sync_line_aft_1[1]);
1538 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1539 core->v_sync_line_aft_pxl_2[0]);
1540 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1541 core->v_sync_line_aft_pxl_2[1]);
1542 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1543 core->v_sync_line_aft_pxl_1[0]);
1544 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1545 core->v_sync_line_aft_pxl_1[1]);
1546 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1547 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1548 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1549 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1550 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1551 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1552 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1553 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1554 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1555 core->v_sync_line_aft_3[0]);
1556 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1557 core->v_sync_line_aft_3[1]);
1558 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1559 core->v_sync_line_aft_4[0]);
1560 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1561 core->v_sync_line_aft_4[1]);
1562 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1563 core->v_sync_line_aft_5[0]);
1564 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1565 core->v_sync_line_aft_5[1]);
1566 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1567 core->v_sync_line_aft_6[0]);
1568 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1569 core->v_sync_line_aft_6[1]);
1570 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1571 core->v_sync_line_aft_pxl_3[0]);
1572 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1573 core->v_sync_line_aft_pxl_3[1]);
1574 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1575 core->v_sync_line_aft_pxl_4[0]);
1576 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1577 core->v_sync_line_aft_pxl_4[1]);
1578 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1579 core->v_sync_line_aft_pxl_5[0]);
1580 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1581 core->v_sync_line_aft_pxl_5[1]);
1582 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1583 core->v_sync_line_aft_pxl_6[0]);
1584 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1585 core->v_sync_line_aft_pxl_6[1]);
1586 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1587 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1588 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1589 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1590 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1591 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1592 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1593 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1594 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1595 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1596 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1597 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1598
1599 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001600 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1601 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1602 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1603 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1604 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1605 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1606 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1607 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1608 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1609 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1610 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1611 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1612 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1613 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1614 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1615 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1626 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1627 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1628 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1629 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1630 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1631 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1632 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001633
1634 /* waiting for HDMIPHY's PLL to get to steady state */
1635 for (tries = 100; tries; --tries) {
1636 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1637 if (val & HDMI_PHY_STATUS_READY)
1638 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001639 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001640 }
1641 /* steady state not achieved */
1642 if (tries == 0) {
1643 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1644 hdmi_regs_dump(hdata, "timing apply");
1645 }
1646
Sean Paul0bfb1f82013-06-11 12:24:02 +05301647 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301648 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301649 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001650
1651 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301652 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001653}
1654
Rahul Sharma16844fb2013-06-10 14:50:00 +05301655static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001656{
Rahul Sharma5a325072012-10-04 20:48:54 +05301657 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301658 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001659 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301660 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001661}
1662
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001663static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1664{
1665 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001666 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001667
Sean Paul0bfb1f82013-06-11 12:24:02 +05301668 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301669 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301670 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001671
1672 /* operation mode */
1673 buffer[0] = 0x1f;
1674 buffer[1] = 0x00;
1675
1676 if (hdata->hdmiphy_port)
1677 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1678
Rahul Sharma5a325072012-10-04 20:48:54 +05301679 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001680 reg = HDMI_V13_PHY_RSTOUT;
1681 else
1682 reg = HDMI_PHY_RSTOUT;
1683
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001684 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001685 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001686 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001687 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001688 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001689}
1690
Rahul Sharmaa5562252012-11-28 11:30:25 +05301691static void hdmiphy_poweron(struct hdmi_context *hdata)
1692{
Shirish S6a296e22014-04-03 20:41:02 +05301693 if (hdata->type != HDMI_TYPE14)
1694 return;
1695
1696 DRM_DEBUG_KMS("\n");
1697
1698 /* For PHY Mode Setting */
1699 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1700 HDMI_PHY_ENABLE_MODE_SET);
1701 /* Phy Power On */
1702 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1703 HDMI_PHY_POWER_ON);
1704 /* For PHY Mode Setting */
1705 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1706 HDMI_PHY_DISABLE_MODE_SET);
1707 /* PHY SW Reset */
1708 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301709}
1710
1711static void hdmiphy_poweroff(struct hdmi_context *hdata)
1712{
Shirish S6a296e22014-04-03 20:41:02 +05301713 if (hdata->type != HDMI_TYPE14)
1714 return;
1715
1716 DRM_DEBUG_KMS("\n");
1717
1718 /* PHY SW Reset */
1719 hdmiphy_conf_reset(hdata);
1720 /* For PHY Mode Setting */
1721 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1722 HDMI_PHY_ENABLE_MODE_SET);
1723
1724 /* PHY Power Off */
1725 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1726 HDMI_PHY_POWER_OFF);
1727
1728 /* For PHY Mode Setting */
1729 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1730 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301731}
1732
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001733static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1734{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001735 int ret;
1736 int i;
1737
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001738 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001739 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1740 if (i < 0) {
1741 DRM_ERROR("failed to find hdmiphy conf\n");
1742 return;
1743 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001744
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001745 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1746 if (ret) {
1747 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001748 return;
1749 }
1750
Sean Paul09760ea2013-01-14 17:03:20 -05001751 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001752
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001753 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1754 HDMI_PHY_DISABLE_MODE_SET);
1755 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001756 DRM_ERROR("failed to enable hdmiphy\n");
1757 return;
1758 }
1759
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001760}
1761
1762static void hdmi_conf_apply(struct hdmi_context *hdata)
1763{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001764 hdmiphy_conf_reset(hdata);
1765 hdmiphy_conf_apply(hdata);
1766
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001767 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301768 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001769 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001770 mutex_unlock(&hdata->hdmi_mutex);
1771
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001772 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001773
1774 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301775 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001776 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001777
1778 hdmi_regs_dump(hdata, "start");
1779}
1780
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001781static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1782{
1783 int i;
1784 BUG_ON(num_bytes > 4);
1785 for (i = 0; i < num_bytes; i++)
1786 reg_pair[i] = (value >> (8 * i)) & 0xff;
1787}
1788
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001789static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1790 struct drm_display_mode *m)
1791{
1792 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1793 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1794 unsigned int val;
1795
1796 hdata->mode_conf.cea_video_id =
1797 drm_match_cea_mode((struct drm_display_mode *)m);
1798 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301799 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001800
1801 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1802 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1803
1804 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1805 hdmi_set_reg(core->vsync_pol, 1, val);
1806
1807 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1808 hdmi_set_reg(core->int_pro_mode, 1, val);
1809
1810 val = (m->hsync_start - m->hdisplay - 2);
1811 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1812 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1813 hdmi_set_reg(core->h_sync_gen, 3, val);
1814
1815 /*
1816 * Quirk requirement for exynos HDMI IP design,
1817 * 2 pixels less than the actual calculation for hsync_start
1818 * and end.
1819 */
1820
1821 /* Following values & calculations differ for different type of modes */
1822 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1823 /* Interlaced Mode */
1824 val = ((m->vsync_end - m->vdisplay) / 2);
1825 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1826 hdmi_set_reg(core->v_sync_gen1, 3, val);
1827
1828 val = m->vtotal / 2;
1829 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1830 hdmi_set_reg(core->v_blank, 3, val);
1831
1832 val = (m->vtotal +
1833 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1834 val |= m->vtotal << 11;
1835 hdmi_set_reg(core->v_blank_f, 3, val);
1836
1837 val = ((m->vtotal / 2) + 7);
1838 val |= ((m->vtotal / 2) + 2) << 12;
1839 hdmi_set_reg(core->v_sync_gen2, 3, val);
1840
1841 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1842 val |= ((m->htotal / 2) +
1843 (m->hsync_start - m->hdisplay)) << 12;
1844 hdmi_set_reg(core->v_sync_gen3, 3, val);
1845
1846 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1847 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1848
1849 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1850 } else {
1851 /* Progressive Mode */
1852
1853 val = m->vtotal;
1854 val |= (m->vtotal - m->vdisplay) << 11;
1855 hdmi_set_reg(core->v_blank, 3, val);
1856
1857 hdmi_set_reg(core->v_blank_f, 3, 0);
1858
1859 val = (m->vsync_end - m->vdisplay);
1860 val |= ((m->vsync_start - m->vdisplay) << 12);
1861 hdmi_set_reg(core->v_sync_gen1, 3, val);
1862
1863 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1864 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1865 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1866 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1867 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1868 }
1869
1870 /* Timing generator registers */
1871 hdmi_set_reg(tg->cmd, 1, 0x0);
1872 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1873 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1874 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1875 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1876 hdmi_set_reg(tg->vsync, 2, 0x1);
1877 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1878 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1879 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1880 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1881 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1882 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1883 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1884}
1885
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001886static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1887 struct drm_display_mode *m)
1888{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001889 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1890 struct hdmi_v14_core_regs *core =
1891 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001892
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001893 hdata->mode_conf.cea_video_id =
1894 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001895 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301896 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001897
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001898 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1899 hdmi_set_reg(core->v_line, 2, m->vtotal);
1900 hdmi_set_reg(core->h_line, 2, m->htotal);
1901 hdmi_set_reg(core->hsync_pol, 1,
1902 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1903 hdmi_set_reg(core->vsync_pol, 1,
1904 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1905 hdmi_set_reg(core->int_pro_mode, 1,
1906 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1907
1908 /*
1909 * Quirk requirement for exynos 5 HDMI IP design,
1910 * 2 pixels less than the actual calculation for hsync_start
1911 * and end.
1912 */
1913
1914 /* Following values & calculations differ for different type of modes */
1915 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1916 /* Interlaced Mode */
1917 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1918 (m->vsync_end - m->vdisplay) / 2);
1919 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1920 (m->vsync_start - m->vdisplay) / 2);
1921 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1922 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301923 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001924 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1925 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1926 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1927 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1928 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1929 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1930 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1931 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1932 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301933 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1934 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1935 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1936 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001937 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1938 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1939 } else {
1940 /* Progressive Mode */
1941 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1942 m->vsync_end - m->vdisplay);
1943 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1944 m->vsync_start - m->vdisplay);
1945 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1946 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1947 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1948 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1949 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1950 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1951 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1952 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1953 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1954 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1955 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1956 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1957 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301958 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1959 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1960 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001961 }
1962
1963 /* Following values & calculations are same irrespective of mode type */
1964 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1965 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1966 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1967 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1968 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1969 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1970 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1971 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1972 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1973 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1974 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1975 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1976 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1977 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1978 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1979 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1980 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1981 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1982 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1983 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1984
1985 /* Timing generator registers */
1986 hdmi_set_reg(tg->cmd, 1, 0x0);
1987 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1988 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1989 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1990 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1991 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001992 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1993 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001994 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001995 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001996}
1997
Sean Paulf041b252014-01-30 16:19:15 -05001998static void hdmi_mode_set(struct exynos_drm_display *display,
1999 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002000{
Sean Paulf041b252014-01-30 16:19:15 -05002001 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002002 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002003
YoungJun Chocbc4c332013-06-12 10:44:40 +09002004 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
2005 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002006 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
2007 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002008
Rahul Sharmabfa48422014-04-03 20:41:04 +05302009 /* preserve mode information for later use. */
2010 drm_mode_copy(&hdata->current_mode, mode);
2011
Sachin Kamat5f46c332013-04-26 11:29:00 +05302012 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002013 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302014 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002015 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002016}
2017
Sean Paulf041b252014-01-30 16:19:15 -05002018static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002019{
Sean Paulf041b252014-01-30 16:19:15 -05002020 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002021
Shirish Sdda90122013-01-23 22:03:18 -05002022 mutex_lock(&hdata->hdmi_mutex);
2023 if (!hdata->powered) {
2024 mutex_unlock(&hdata->hdmi_mutex);
2025 return;
2026 }
2027 mutex_unlock(&hdata->hdmi_mutex);
2028
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002029 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002030}
2031
Sean Paulf041b252014-01-30 16:19:15 -05002032static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002033{
Sean Paulf041b252014-01-30 16:19:15 -05002034 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002035 struct hdmi_resources *res = &hdata->res;
2036
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002037 mutex_lock(&hdata->hdmi_mutex);
2038 if (hdata->powered) {
2039 mutex_unlock(&hdata->hdmi_mutex);
2040 return;
2041 }
2042
2043 hdata->powered = true;
2044
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002045 mutex_unlock(&hdata->hdmi_mutex);
2046
Sean Paulaf65c802014-01-30 16:19:27 -05002047 pm_runtime_get_sync(hdata->dev);
2048
Seung-Woo Kimad079452013-06-05 14:34:38 +09002049 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2050 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2051
Rahul Sharma049d34e2014-05-20 10:36:05 +05302052 /* set pmu hdmiphy control bit to enable hdmiphy */
2053 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2054 PMU_HDMI_PHY_ENABLE_BIT, 1);
2055
Sean Paul0bfb1f82013-06-11 12:24:02 +05302056 clk_prepare_enable(res->hdmi);
2057 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302058
2059 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05002060 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002061}
2062
Sean Paulf041b252014-01-30 16:19:15 -05002063static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002064{
Sean Paulf041b252014-01-30 16:19:15 -05002065 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002066 struct hdmi_resources *res = &hdata->res;
2067
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002068 mutex_lock(&hdata->hdmi_mutex);
2069 if (!hdata->powered)
2070 goto out;
2071 mutex_unlock(&hdata->hdmi_mutex);
2072
Rahul Sharmabfa48422014-04-03 20:41:04 +05302073 /* HDMI System Disable */
2074 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2075
Rahul Sharmaa5562252012-11-28 11:30:25 +05302076 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002077
Sean Paul724fd142014-05-09 15:05:10 +09002078 cancel_delayed_work(&hdata->hotplug_work);
2079
Sean Paul0bfb1f82013-06-11 12:24:02 +05302080 clk_disable_unprepare(res->sclk_hdmi);
2081 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302082
2083 /* reset pmu hdmiphy control bit to disable hdmiphy */
2084 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2085 PMU_HDMI_PHY_ENABLE_BIT, 0);
2086
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002087 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2088
Sean Paulaf65c802014-01-30 16:19:27 -05002089 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002090
Sean Paulaf65c802014-01-30 16:19:27 -05002091 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002092 hdata->powered = false;
2093
2094out:
2095 mutex_unlock(&hdata->hdmi_mutex);
2096}
2097
Sean Paulf041b252014-01-30 16:19:15 -05002098static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002099{
Inki Dae245f98f2014-06-13 17:44:40 +09002100 struct hdmi_context *hdata = display->ctx;
2101 struct drm_encoder *encoder = hdata->encoder;
2102 struct drm_crtc *crtc = encoder->crtc;
2103 struct drm_crtc_helper_funcs *funcs = NULL;
2104
YoungJun Chocbc4c332013-06-12 10:44:40 +09002105 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002106
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002107 switch (mode) {
2108 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05002109 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002110 break;
2111 case DRM_MODE_DPMS_STANDBY:
2112 case DRM_MODE_DPMS_SUSPEND:
2113 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002114 /*
2115 * The SFRs of VP and Mixer are updated by Vertical Sync of
2116 * Timing generator which is a part of HDMI so the sequence
2117 * to disable TV Subsystem should be as following,
2118 * VP -> Mixer -> HDMI
2119 *
2120 * Below codes will try to disable Mixer and VP(if used)
2121 * prior to disabling HDMI.
2122 */
2123 if (crtc)
2124 funcs = crtc->helper_private;
2125 if (funcs && funcs->dpms)
2126 (*funcs->dpms)(crtc, mode);
2127
Sean Paulaf65c802014-01-30 16:19:27 -05002128 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002129 break;
2130 default:
2131 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2132 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133 }
2134}
2135
Sean Paulf041b252014-01-30 16:19:15 -05002136static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002137 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002138 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002139 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002140 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002141 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002142};
2143
Sean Paulf041b252014-01-30 16:19:15 -05002144static struct exynos_drm_display hdmi_display = {
2145 .type = EXYNOS_DISPLAY_TYPE_HDMI,
2146 .ops = &hdmi_display_ops,
2147};
2148
Sean Paul724fd142014-05-09 15:05:10 +09002149static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002150{
Sean Paul724fd142014-05-09 15:05:10 +09002151 struct hdmi_context *hdata;
2152
2153 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002154
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002155 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302156 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002157 mutex_unlock(&hdata->hdmi_mutex);
2158
Sean Paul45517892014-01-30 16:19:05 -05002159 if (hdata->drm_dev)
2160 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002161}
2162
2163static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2164{
2165 struct hdmi_context *hdata = arg;
2166
2167 mod_delayed_work(system_wq, &hdata->hotplug_work,
2168 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002169
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002170 return IRQ_HANDLED;
2171}
2172
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002173static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002174{
2175 struct device *dev = hdata->dev;
2176 struct hdmi_resources *res = &hdata->res;
2177 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002178 "vdd",
2179 "vdd_osc",
2180 "vdd_pll",
2181 };
2182 int i, ret;
2183
2184 DRM_DEBUG_KMS("HDMI resource init\n");
2185
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002186 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302187 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302188 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002189 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002190 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002191 goto fail;
2192 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302193 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302194 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002195 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002196 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002197 goto fail;
2198 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302199 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302200 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002201 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002202 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002203 goto fail;
2204 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302205 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302206 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002207 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002208 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002209 goto fail;
2210 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302211 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2212 if (IS_ERR(res->mout_hdmi)) {
2213 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002214 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302215 goto fail;
2216 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002217
Rahul Sharma59956d32013-06-11 12:24:03 +05302218 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002219
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302220 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302221 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002222 if (!res->regul_bulk) {
2223 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002224 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002225 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002226 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2227 res->regul_bulk[i].supply = supply[i];
2228 res->regul_bulk[i].consumer = NULL;
2229 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302230 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002231 if (ret) {
2232 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002233 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002234 }
2235 res->regul_count = ARRAY_SIZE(supply);
2236
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002237 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2238 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2239 DRM_ERROR("failed to get hdmi-en regulator\n");
2240 return PTR_ERR(res->reg_hdmi_en);
2241 }
2242 if (!IS_ERR(res->reg_hdmi_en)) {
2243 ret = regulator_enable(res->reg_hdmi_en);
2244 if (ret) {
2245 DRM_ERROR("failed to enable hdmi-en regulator\n");
2246 return ret;
2247 }
2248 } else
2249 res->reg_hdmi_en = NULL;
2250
Inki Daedf5225b2014-05-29 18:28:02 +09002251 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002252fail:
2253 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002254 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002255}
2256
Rahul Sharma22c4f422012-10-04 20:48:55 +05302257static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2258 (struct device *dev)
2259{
2260 struct device_node *np = dev->of_node;
2261 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302262 u32 value;
2263
2264 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002265 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302266 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302267
2268 if (!of_find_property(np, "hpd-gpio", &value)) {
2269 DRM_ERROR("no hpd gpio property found\n");
2270 goto err_data;
2271 }
2272
Rahul Sharma5f916e22013-06-11 19:41:29 +05302273 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302274
2275 return pd;
2276
2277err_data:
2278 return NULL;
2279}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302280
Rahul Sharma22c4f422012-10-04 20:48:55 +05302281static struct of_device_id hdmi_match_types[] = {
2282 {
2283 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002284 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302285 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02002286 .compatible = "samsung,exynos4210-hdmi",
2287 .data = &exynos4210_hdmi_driver_data,
2288 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302289 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002290 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302291 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302292 .compatible = "samsung,exynos5420-hdmi",
2293 .data = &exynos5420_hdmi_driver_data,
2294 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302295 /* end node */
2296 }
2297};
2298
Inki Daef37cd5e2014-05-09 14:25:20 +09002299static int hdmi_bind(struct device *dev, struct device *master, void *data)
2300{
2301 struct drm_device *drm_dev = data;
2302 struct hdmi_context *hdata;
2303
2304 hdata = hdmi_display.ctx;
2305 hdata->drm_dev = drm_dev;
2306
2307 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2308}
2309
2310static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2311{
2312 struct exynos_drm_display *display = get_hdmi_display(dev);
2313 struct drm_encoder *encoder = display->encoder;
2314 struct hdmi_context *hdata = display->ctx;
2315
2316 encoder->funcs->destroy(encoder);
2317 drm_connector_cleanup(&hdata->connector);
2318}
2319
2320static const struct component_ops hdmi_component_ops = {
2321 .bind = hdmi_bind,
2322 .unbind = hdmi_unbind,
2323};
2324
Inki Daee2a562d2014-05-09 16:46:10 +09002325static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2326{
2327 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2328 struct device_node *np;
2329
2330 np = of_find_compatible_node(NULL, NULL, compatible_str);
2331 if (np)
2332 return of_get_next_parent(np);
2333
2334 return NULL;
2335}
2336
2337static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2338{
2339 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2340
2341 return of_find_compatible_node(NULL, NULL, compatible_str);
2342}
2343
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002344static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002345{
Inki Daef37cd5e2014-05-09 14:25:20 +09002346 struct device_node *ddc_node, *phy_node;
2347 struct s5p_hdmi_platform_data *pdata;
2348 struct hdmi_driver_data *drv_data;
2349 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002350 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002351 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002352 struct resource *res;
2353 int ret;
2354
Inki Daedf5225b2014-05-29 18:28:02 +09002355 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
2356 hdmi_display.type);
2357 if (ret)
2358 return ret;
2359
2360 if (!dev->of_node) {
2361 ret = -ENODEV;
2362 goto err_del_component;
2363 }
Rahul Sharma22c4f422012-10-04 20:48:55 +05302364
Sachin Kamat88c49812013-08-28 10:47:57 +05302365 pdata = drm_hdmi_dt_parse_pdata(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002366 if (!pdata) {
2367 ret = -EINVAL;
2368 goto err_del_component;
2369 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002370
Sachin Kamat88c49812013-08-28 10:47:57 +05302371 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002372 if (!hdata) {
2373 ret = -ENOMEM;
2374 goto err_del_component;
2375 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002376
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002377 mutex_init(&hdata->hdmi_mutex);
2378
Sean Paulf041b252014-01-30 16:19:15 -05002379 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002380
Sachin Kamat88c49812013-08-28 10:47:57 +05302381 match = of_match_node(hdmi_match_types, dev->of_node);
Inki Daedf5225b2014-05-29 18:28:02 +09002382 if (!match) {
2383 ret = -ENODEV;
2384 goto err_del_component;
2385 }
Inki Daebfe4e842014-03-06 14:18:17 +09002386
2387 drv_data = (struct hdmi_driver_data *)match->data;
2388 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002389 hdata->phy_confs = drv_data->phy_confs;
2390 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302391
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302392 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002393 hdata->dev = dev;
2394
2395 ret = hdmi_resources_init(hdata);
2396 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302397 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002398 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002399 }
2400
2401 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002402 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002403 if (IS_ERR(hdata->regs)) {
2404 ret = PTR_ERR(hdata->regs);
2405 goto err_del_component;
2406 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002407
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002408 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302409 if (ret) {
2410 DRM_ERROR("failed to request HPD gpio\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002411 goto err_del_component;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302412 }
2413
Inki Daee2a562d2014-05-09 16:46:10 +09002414 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2415 if (ddc_node)
2416 goto out_get_ddc_adpt;
2417
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002418 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002419 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2420 if (!ddc_node) {
2421 DRM_ERROR("Failed to find ddc node in device tree\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002422 ret = -ENODEV;
2423 goto err_del_component;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002424 }
Inki Daee2a562d2014-05-09 16:46:10 +09002425
2426out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002427 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2428 if (!hdata->ddc_adpt) {
2429 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002430 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002431 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002432
Inki Daee2a562d2014-05-09 16:46:10 +09002433 phy_node = hdmi_legacy_phy_dt_binding(dev);
2434 if (phy_node)
2435 goto out_get_phy_port;
2436
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002437 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002438 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2439 if (!phy_node) {
2440 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2441 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002442 goto err_ddc;
2443 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002444
Inki Daee2a562d2014-05-09 16:46:10 +09002445out_get_phy_port:
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002446 if (drv_data->is_apb_phy) {
2447 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2448 if (!hdata->regs_hdmiphy) {
2449 DRM_ERROR("failed to ioremap hdmi phy\n");
2450 ret = -ENOMEM;
2451 goto err_ddc;
2452 }
2453 } else {
2454 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2455 if (!hdata->hdmiphy_port) {
2456 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002457 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002458 goto err_ddc;
2459 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002460 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002461
Sean Paul77006a72013-01-16 10:17:20 -05002462 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2463 if (hdata->irq < 0) {
2464 DRM_ERROR("failed to get GPIO irq\n");
2465 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002466 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002467 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002468
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302469 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2470
Sean Paul724fd142014-05-09 15:05:10 +09002471 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2472
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002473 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002474 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002475 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002476 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002477 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002478 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002479 goto err_hdmiphy;
2480 }
2481
Rahul Sharma049d34e2014-05-20 10:36:05 +05302482 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2483 "samsung,syscon-phandle");
2484 if (IS_ERR(hdata->pmureg)) {
2485 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002486 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302487 goto err_hdmiphy;
2488 }
2489
Sean Paulaf65c802014-01-30 16:19:27 -05002490 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002491 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002492
Inki Daedf5225b2014-05-29 18:28:02 +09002493 ret = component_add(&pdev->dev, &hdmi_component_ops);
2494 if (ret)
2495 goto err_disable_pm_runtime;
2496
2497 return ret;
2498
2499err_disable_pm_runtime:
2500 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002501
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002502err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002503 if (hdata->hdmiphy_port)
2504 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002505err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002506 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002507
2508err_del_component:
2509 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
2510
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002511 return ret;
2512}
2513
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002514static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002515{
Inki Daef37cd5e2014-05-09 14:25:20 +09002516 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002517
Sean Paul724fd142014-05-09 15:05:10 +09002518 cancel_delayed_work_sync(&hdata->hotplug_work);
2519
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002520 if (hdata->res.reg_hdmi_en)
2521 regulator_disable(hdata->res.reg_hdmi_en);
2522
Daniel Kurtz2b768132014-02-24 18:52:51 +09002523 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002524 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002525
Sean Paulaf65c802014-01-30 16:19:27 -05002526 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002527 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002528
Inki Daedf5225b2014-05-29 18:28:02 +09002529 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002530 return 0;
2531}
2532
2533struct platform_driver hdmi_driver = {
2534 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002535 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002536 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302537 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002538 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302539 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002540 },
2541};