blob: 83bd496ca6a3faec875809cc6083b85a2b58feb1 [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>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/irq.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/clk.h>
34#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
36#include <linux/of_gpio.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090037
38#include <drm/exynos_drm.h>
39
40#include "exynos_drm_drv.h"
41#include "exynos_drm_hdmi.h"
42
43#include "exynos_hdmi.h"
44
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053045#include <linux/gpio.h>
46#include <media/s5p_hdmi.h>
47
Inki Dae1de425b2012-03-16 18:47:04 +090048#define MAX_WIDTH 1920
49#define MAX_HEIGHT 1080
Seung-Woo Kimd8408322011-12-21 17:39:39 +090050#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
51
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053052/* AVI header and aspect ratio */
53#define HDMI_AVI_VERSION 0x02
54#define HDMI_AVI_LENGTH 0x0D
55#define AVI_PIC_ASPECT_RATIO_16_9 (2 << 4)
56#define AVI_SAME_AS_PIC_ASPECT_RATIO 8
57
58/* AUI header info */
59#define HDMI_AUI_VERSION 0x01
60#define HDMI_AUI_LENGTH 0x0A
61
62/* HDMI infoframe to configure HDMI out packet header, AUI and AVI */
63enum HDMI_PACKET_TYPE {
64 /* refer to Table 5-8 Packet Type in HDMI specification v1.4a */
65 /* InfoFrame packet type */
66 HDMI_PACKET_TYPE_INFOFRAME = 0x80,
67 /* Vendor-Specific InfoFrame */
68 HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1,
69 /* Auxiliary Video information InfoFrame */
70 HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2,
71 /* Audio information InfoFrame */
72 HDMI_PACKET_TYPE_AUI = HDMI_PACKET_TYPE_INFOFRAME + 4
73};
74
Rahul Sharma5a325072012-10-04 20:48:54 +053075enum hdmi_type {
76 HDMI_TYPE13,
77 HDMI_TYPE14,
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;
85 struct clk *hdmiphy;
86 struct regulator_bulk_data *regul_bulk;
87 int regul_count;
88};
89
Sean Paul2f7e2ed2013-01-15 08:11:08 -050090struct hdmi_tg_regs {
91 u8 cmd[1];
92 u8 h_fsz[2];
93 u8 hact_st[2];
94 u8 hact_sz[2];
95 u8 v_fsz[2];
96 u8 vsync[2];
97 u8 vsync2[2];
98 u8 vact_st[2];
99 u8 vact_sz[2];
100 u8 field_chg[2];
101 u8 vact_st2[2];
102 u8 vact_st3[2];
103 u8 vact_st4[2];
104 u8 vsync_top_hdmi[2];
105 u8 vsync_bot_hdmi[2];
106 u8 field_top_hdmi[2];
107 u8 field_bot_hdmi[2];
108 u8 tg_3d[1];
109};
110
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900111struct hdmi_v13_core_regs {
112 u8 h_blank[2];
113 u8 v_blank[3];
114 u8 h_v_line[3];
115 u8 vsync_pol[1];
116 u8 int_pro_mode[1];
117 u8 v_blank_f[3];
118 u8 h_sync_gen[3];
119 u8 v_sync_gen1[3];
120 u8 v_sync_gen2[3];
121 u8 v_sync_gen3[3];
122};
123
124struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500125 u8 h_blank[2];
126 u8 v2_blank[2];
127 u8 v1_blank[2];
128 u8 v_line[2];
129 u8 h_line[2];
130 u8 hsync_pol[1];
131 u8 vsync_pol[1];
132 u8 int_pro_mode[1];
133 u8 v_blank_f0[2];
134 u8 v_blank_f1[2];
135 u8 h_sync_start[2];
136 u8 h_sync_end[2];
137 u8 v_sync_line_bef_2[2];
138 u8 v_sync_line_bef_1[2];
139 u8 v_sync_line_aft_2[2];
140 u8 v_sync_line_aft_1[2];
141 u8 v_sync_line_aft_pxl_2[2];
142 u8 v_sync_line_aft_pxl_1[2];
143 u8 v_blank_f2[2]; /* for 3D mode */
144 u8 v_blank_f3[2]; /* for 3D mode */
145 u8 v_blank_f4[2]; /* for 3D mode */
146 u8 v_blank_f5[2]; /* for 3D mode */
147 u8 v_sync_line_aft_3[2];
148 u8 v_sync_line_aft_4[2];
149 u8 v_sync_line_aft_5[2];
150 u8 v_sync_line_aft_6[2];
151 u8 v_sync_line_aft_pxl_3[2];
152 u8 v_sync_line_aft_pxl_4[2];
153 u8 v_sync_line_aft_pxl_5[2];
154 u8 v_sync_line_aft_pxl_6[2];
155 u8 vact_space_1[2];
156 u8 vact_space_2[2];
157 u8 vact_space_3[2];
158 u8 vact_space_4[2];
159 u8 vact_space_5[2];
160 u8 vact_space_6[2];
161};
162
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163struct hdmi_v13_conf {
164 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500165 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166};
167
168struct hdmi_v14_conf {
169 struct hdmi_v14_core_regs core;
170 struct hdmi_tg_regs tg;
171};
172
173struct hdmi_conf_regs {
174 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500175 int cea_video_id;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900176 union {
177 struct hdmi_v13_conf v13_conf;
178 struct hdmi_v14_conf v14_conf;
179 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500180};
181
Joonyoung Shim590f4182012-03-16 18:47:14 +0900182struct hdmi_context {
183 struct device *dev;
184 struct drm_device *drm_dev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900185 bool hpd;
186 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900187 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900188 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900189
Joonyoung Shim590f4182012-03-16 18:47:14 +0900190 void __iomem *regs;
Inki Dae1055b392012-10-19 17:37:35 +0900191 void *parent_ctx;
Sean Paul77006a72013-01-16 10:17:20 -0500192 int irq;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900193
194 struct i2c_client *ddc_port;
195 struct i2c_client *hdmiphy_port;
196
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900197 /* current hdmiphy conf regs */
198 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900199
200 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900201
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530202 int hpd_gpio;
Rahul Sharma5a325072012-10-04 20:48:54 +0530203
204 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900205};
206
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500207struct hdmiphy_config {
208 int pixel_clock;
209 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900210};
211
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900212/* list of phy config settings */
213static const struct hdmiphy_config hdmiphy_v13_configs[] = {
214 {
215 .pixel_clock = 27000000,
216 .conf = {
217 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
218 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
219 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
220 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
221 },
222 },
223 {
224 .pixel_clock = 27027000,
225 .conf = {
226 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
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 = 74176000,
234 .conf = {
235 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
236 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
237 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
238 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
239 },
240 },
241 {
242 .pixel_clock = 74250000,
243 .conf = {
244 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
245 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
246 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
247 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
248 },
249 },
250 {
251 .pixel_clock = 148500000,
252 .conf = {
253 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
254 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
255 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
256 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
257 },
258 },
259};
260
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500261static const struct hdmiphy_config hdmiphy_v14_configs[] = {
262 {
263 .pixel_clock = 25200000,
264 .conf = {
265 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
266 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
267 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
268 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
269 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900270 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500271 {
272 .pixel_clock = 27000000,
273 .conf = {
274 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
275 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
276 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
277 0x54, 0xe4, 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 = 27027000,
282 .conf = {
283 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
284 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
285 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
286 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
287 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900288 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500289 {
290 .pixel_clock = 36000000,
291 .conf = {
292 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
293 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
294 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
295 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
296 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900297 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 {
299 .pixel_clock = 40000000,
300 .conf = {
301 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
302 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
303 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
304 0x54, 0x9a, 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 = 65000000,
309 .conf = {
310 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
311 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
312 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
313 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
314 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900315 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500316 {
317 .pixel_clock = 74176000,
318 .conf = {
319 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
320 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
321 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
322 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
323 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900324 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 {
326 .pixel_clock = 74250000,
327 .conf = {
328 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
329 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
330 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
331 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
332 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900333 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500334 {
335 .pixel_clock = 83500000,
336 .conf = {
337 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
338 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
339 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
340 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
341 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900342 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500343 {
344 .pixel_clock = 106500000,
345 .conf = {
346 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
347 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
348 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
349 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
350 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900351 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500352 {
353 .pixel_clock = 108000000,
354 .conf = {
355 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
356 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
357 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
358 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
359 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900360 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500361 {
362 .pixel_clock = 146250000,
363 .conf = {
364 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
365 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
366 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
367 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
368 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900369 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500370 {
371 .pixel_clock = 148500000,
372 .conf = {
373 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
374 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
375 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
376 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
377 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900378 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900379};
380
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530381struct hdmi_infoframe {
382 enum HDMI_PACKET_TYPE type;
383 u8 ver;
384 u8 len;
385};
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900386
387static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
388{
389 return readl(hdata->regs + reg_id);
390}
391
392static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
393 u32 reg_id, u8 value)
394{
395 writeb(value, hdata->regs + reg_id);
396}
397
398static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
399 u32 reg_id, u32 value, u32 mask)
400{
401 u32 old = readl(hdata->regs + reg_id);
402 value = (value & mask) | (old & ~mask);
403 writel(value, hdata->regs + reg_id);
404}
405
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900406static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900407{
408#define DUMPREG(reg_id) \
409 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
410 readl(hdata->regs + reg_id))
411 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
412 DUMPREG(HDMI_INTC_FLAG);
413 DUMPREG(HDMI_INTC_CON);
414 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900415 DUMPREG(HDMI_V13_PHY_RSTOUT);
416 DUMPREG(HDMI_V13_PHY_VPLL);
417 DUMPREG(HDMI_V13_PHY_CMU);
418 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900419
420 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
421 DUMPREG(HDMI_CON_0);
422 DUMPREG(HDMI_CON_1);
423 DUMPREG(HDMI_CON_2);
424 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900425 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900426 DUMPREG(HDMI_STATUS_EN);
427 DUMPREG(HDMI_HPD);
428 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900429 DUMPREG(HDMI_V13_HPD_GEN);
430 DUMPREG(HDMI_V13_DC_CONTROL);
431 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900432
433 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
434 DUMPREG(HDMI_H_BLANK_0);
435 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900436 DUMPREG(HDMI_V13_V_BLANK_0);
437 DUMPREG(HDMI_V13_V_BLANK_1);
438 DUMPREG(HDMI_V13_V_BLANK_2);
439 DUMPREG(HDMI_V13_H_V_LINE_0);
440 DUMPREG(HDMI_V13_H_V_LINE_1);
441 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900442 DUMPREG(HDMI_VSYNC_POL);
443 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900444 DUMPREG(HDMI_V13_V_BLANK_F_0);
445 DUMPREG(HDMI_V13_V_BLANK_F_1);
446 DUMPREG(HDMI_V13_V_BLANK_F_2);
447 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
448 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
449 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
450 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
451 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
452 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
453 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
454 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
455 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
456 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
457 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
458 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900459
460 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
461 DUMPREG(HDMI_TG_CMD);
462 DUMPREG(HDMI_TG_H_FSZ_L);
463 DUMPREG(HDMI_TG_H_FSZ_H);
464 DUMPREG(HDMI_TG_HACT_ST_L);
465 DUMPREG(HDMI_TG_HACT_ST_H);
466 DUMPREG(HDMI_TG_HACT_SZ_L);
467 DUMPREG(HDMI_TG_HACT_SZ_H);
468 DUMPREG(HDMI_TG_V_FSZ_L);
469 DUMPREG(HDMI_TG_V_FSZ_H);
470 DUMPREG(HDMI_TG_VSYNC_L);
471 DUMPREG(HDMI_TG_VSYNC_H);
472 DUMPREG(HDMI_TG_VSYNC2_L);
473 DUMPREG(HDMI_TG_VSYNC2_H);
474 DUMPREG(HDMI_TG_VACT_ST_L);
475 DUMPREG(HDMI_TG_VACT_ST_H);
476 DUMPREG(HDMI_TG_VACT_SZ_L);
477 DUMPREG(HDMI_TG_VACT_SZ_H);
478 DUMPREG(HDMI_TG_FIELD_CHG_L);
479 DUMPREG(HDMI_TG_FIELD_CHG_H);
480 DUMPREG(HDMI_TG_VACT_ST2_L);
481 DUMPREG(HDMI_TG_VACT_ST2_H);
482 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
483 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
484 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
485 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
486 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
487 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
488 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
489 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
490#undef DUMPREG
491}
492
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900493static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
494{
495 int i;
496
497#define DUMPREG(reg_id) \
498 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
499 readl(hdata->regs + reg_id))
500
501 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
502 DUMPREG(HDMI_INTC_CON);
503 DUMPREG(HDMI_INTC_FLAG);
504 DUMPREG(HDMI_HPD_STATUS);
505 DUMPREG(HDMI_INTC_CON_1);
506 DUMPREG(HDMI_INTC_FLAG_1);
507 DUMPREG(HDMI_PHY_STATUS_0);
508 DUMPREG(HDMI_PHY_STATUS_PLL);
509 DUMPREG(HDMI_PHY_CON_0);
510 DUMPREG(HDMI_PHY_RSTOUT);
511 DUMPREG(HDMI_PHY_VPLL);
512 DUMPREG(HDMI_PHY_CMU);
513 DUMPREG(HDMI_CORE_RSTOUT);
514
515 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
516 DUMPREG(HDMI_CON_0);
517 DUMPREG(HDMI_CON_1);
518 DUMPREG(HDMI_CON_2);
519 DUMPREG(HDMI_SYS_STATUS);
520 DUMPREG(HDMI_PHY_STATUS_0);
521 DUMPREG(HDMI_STATUS_EN);
522 DUMPREG(HDMI_HPD);
523 DUMPREG(HDMI_MODE_SEL);
524 DUMPREG(HDMI_ENC_EN);
525 DUMPREG(HDMI_DC_CONTROL);
526 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
527
528 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
529 DUMPREG(HDMI_H_BLANK_0);
530 DUMPREG(HDMI_H_BLANK_1);
531 DUMPREG(HDMI_V2_BLANK_0);
532 DUMPREG(HDMI_V2_BLANK_1);
533 DUMPREG(HDMI_V1_BLANK_0);
534 DUMPREG(HDMI_V1_BLANK_1);
535 DUMPREG(HDMI_V_LINE_0);
536 DUMPREG(HDMI_V_LINE_1);
537 DUMPREG(HDMI_H_LINE_0);
538 DUMPREG(HDMI_H_LINE_1);
539 DUMPREG(HDMI_HSYNC_POL);
540
541 DUMPREG(HDMI_VSYNC_POL);
542 DUMPREG(HDMI_INT_PRO_MODE);
543 DUMPREG(HDMI_V_BLANK_F0_0);
544 DUMPREG(HDMI_V_BLANK_F0_1);
545 DUMPREG(HDMI_V_BLANK_F1_0);
546 DUMPREG(HDMI_V_BLANK_F1_1);
547
548 DUMPREG(HDMI_H_SYNC_START_0);
549 DUMPREG(HDMI_H_SYNC_START_1);
550 DUMPREG(HDMI_H_SYNC_END_0);
551 DUMPREG(HDMI_H_SYNC_END_1);
552
553 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
554 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
555 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
556 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
557
558 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
559 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
560 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
561 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
562
563 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
564 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
565 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
566 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
567
568 DUMPREG(HDMI_V_BLANK_F2_0);
569 DUMPREG(HDMI_V_BLANK_F2_1);
570 DUMPREG(HDMI_V_BLANK_F3_0);
571 DUMPREG(HDMI_V_BLANK_F3_1);
572 DUMPREG(HDMI_V_BLANK_F4_0);
573 DUMPREG(HDMI_V_BLANK_F4_1);
574 DUMPREG(HDMI_V_BLANK_F5_0);
575 DUMPREG(HDMI_V_BLANK_F5_1);
576
577 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
578 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
579 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
580 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
581 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
582 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
583 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
584 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
585
586 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
587 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
588 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
589 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
590 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
591 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
592 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
593 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
594
595 DUMPREG(HDMI_VACT_SPACE_1_0);
596 DUMPREG(HDMI_VACT_SPACE_1_1);
597 DUMPREG(HDMI_VACT_SPACE_2_0);
598 DUMPREG(HDMI_VACT_SPACE_2_1);
599 DUMPREG(HDMI_VACT_SPACE_3_0);
600 DUMPREG(HDMI_VACT_SPACE_3_1);
601 DUMPREG(HDMI_VACT_SPACE_4_0);
602 DUMPREG(HDMI_VACT_SPACE_4_1);
603 DUMPREG(HDMI_VACT_SPACE_5_0);
604 DUMPREG(HDMI_VACT_SPACE_5_1);
605 DUMPREG(HDMI_VACT_SPACE_6_0);
606 DUMPREG(HDMI_VACT_SPACE_6_1);
607
608 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
609 DUMPREG(HDMI_TG_CMD);
610 DUMPREG(HDMI_TG_H_FSZ_L);
611 DUMPREG(HDMI_TG_H_FSZ_H);
612 DUMPREG(HDMI_TG_HACT_ST_L);
613 DUMPREG(HDMI_TG_HACT_ST_H);
614 DUMPREG(HDMI_TG_HACT_SZ_L);
615 DUMPREG(HDMI_TG_HACT_SZ_H);
616 DUMPREG(HDMI_TG_V_FSZ_L);
617 DUMPREG(HDMI_TG_V_FSZ_H);
618 DUMPREG(HDMI_TG_VSYNC_L);
619 DUMPREG(HDMI_TG_VSYNC_H);
620 DUMPREG(HDMI_TG_VSYNC2_L);
621 DUMPREG(HDMI_TG_VSYNC2_H);
622 DUMPREG(HDMI_TG_VACT_ST_L);
623 DUMPREG(HDMI_TG_VACT_ST_H);
624 DUMPREG(HDMI_TG_VACT_SZ_L);
625 DUMPREG(HDMI_TG_VACT_SZ_H);
626 DUMPREG(HDMI_TG_FIELD_CHG_L);
627 DUMPREG(HDMI_TG_FIELD_CHG_H);
628 DUMPREG(HDMI_TG_VACT_ST2_L);
629 DUMPREG(HDMI_TG_VACT_ST2_H);
630 DUMPREG(HDMI_TG_VACT_ST3_L);
631 DUMPREG(HDMI_TG_VACT_ST3_H);
632 DUMPREG(HDMI_TG_VACT_ST4_L);
633 DUMPREG(HDMI_TG_VACT_ST4_H);
634 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
635 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
636 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
637 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
638 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
639 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
640 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
641 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
642 DUMPREG(HDMI_TG_3D);
643
644 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
645 DUMPREG(HDMI_AVI_CON);
646 DUMPREG(HDMI_AVI_HEADER0);
647 DUMPREG(HDMI_AVI_HEADER1);
648 DUMPREG(HDMI_AVI_HEADER2);
649 DUMPREG(HDMI_AVI_CHECK_SUM);
650 DUMPREG(HDMI_VSI_CON);
651 DUMPREG(HDMI_VSI_HEADER0);
652 DUMPREG(HDMI_VSI_HEADER1);
653 DUMPREG(HDMI_VSI_HEADER2);
654 for (i = 0; i < 7; ++i)
655 DUMPREG(HDMI_VSI_DATA(i));
656
657#undef DUMPREG
658}
659
660static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
661{
Rahul Sharma5a325072012-10-04 20:48:54 +0530662 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900663 hdmi_v13_regs_dump(hdata, prefix);
664 else
665 hdmi_v14_regs_dump(hdata, prefix);
666}
667
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530668static u8 hdmi_chksum(struct hdmi_context *hdata,
669 u32 start, u8 len, u32 hdr_sum)
670{
671 int i;
672
673 /* hdr_sum : header0 + header1 + header2
674 * start : start address of packet byte1
675 * len : packet bytes - 1 */
676 for (i = 0; i < len; ++i)
677 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
678
679 /* return 2's complement of 8 bit hdr_sum */
680 return (u8)(~(hdr_sum & 0xff) + 1);
681}
682
683static void hdmi_reg_infoframe(struct hdmi_context *hdata,
684 struct hdmi_infoframe *infoframe)
685{
686 u32 hdr_sum;
687 u8 chksum;
688 u32 aspect_ratio;
689 u32 mod;
690 u32 vic;
691
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530692 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
693 if (hdata->dvi_mode) {
694 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
695 HDMI_VSI_CON_DO_NOT_TRANSMIT);
696 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
697 HDMI_AVI_CON_DO_NOT_TRANSMIT);
698 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
699 return;
700 }
701
702 switch (infoframe->type) {
703 case HDMI_PACKET_TYPE_AVI:
704 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
705 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->type);
706 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, infoframe->ver);
707 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->len);
708 hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
709
710 /* Output format zero hardcoded ,RGB YBCR selection */
711 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
712 AVI_ACTIVE_FORMAT_VALID |
713 AVI_UNDERSCANNED_DISPLAY_VALID);
714
715 aspect_ratio = AVI_PIC_ASPECT_RATIO_16_9;
716
717 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio |
718 AVI_SAME_AS_PIC_ASPECT_RATIO);
719
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900720 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530721 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
722
723 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
724 infoframe->len, hdr_sum);
725 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
726 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
727 break;
728 case HDMI_PACKET_TYPE_AUI:
729 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
730 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->type);
731 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, infoframe->ver);
732 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->len);
733 hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
734 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
735 infoframe->len, hdr_sum);
736 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
737 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
738 break;
739 default:
740 break;
741 }
742}
743
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900744static bool hdmi_is_connected(void *ctx)
745{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900746 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900747
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900748 return hdata->hpd;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900749}
750
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500751static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900752{
753 struct edid *raw_edid;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900754 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900755
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900756 if (!hdata->ddc_port)
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500757 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900758
759 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500760 if (!raw_edid)
761 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900762
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500763 hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
764 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
765 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
766 raw_edid->width_cm, raw_edid->height_cm);
767
768 return raw_edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900769}
770
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900771static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900772{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900773 const struct hdmiphy_config *confs;
774 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900775
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900776 if (hdata->type == HDMI_TYPE13) {
777 confs = hdmiphy_v13_configs;
778 count = ARRAY_SIZE(hdmiphy_v13_configs);
779 } else if (hdata->type == HDMI_TYPE14) {
780 confs = hdmiphy_v14_configs;
781 count = ARRAY_SIZE(hdmiphy_v14_configs);
782 } else
783 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900784
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900785 for (i = 0; i < count; i++)
786 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500787 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500788
789 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
790 return -EINVAL;
791}
792
Rahul Sharma16844fb2013-06-10 14:50:00 +0530793static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900794{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900795 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900796 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900797
Rahul Sharma16844fb2013-06-10 14:50:00 +0530798 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
799 mode->hdisplay, mode->vdisplay, mode->vrefresh,
800 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
801 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900802
Rahul Sharma16844fb2013-06-10 14:50:00 +0530803 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900804 if (ret < 0)
805 return ret;
806 return 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900807}
808
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900809static void hdmi_set_acr(u32 freq, u8 *acr)
810{
811 u32 n, cts;
812
813 switch (freq) {
814 case 32000:
815 n = 4096;
816 cts = 27000;
817 break;
818 case 44100:
819 n = 6272;
820 cts = 30000;
821 break;
822 case 88200:
823 n = 12544;
824 cts = 30000;
825 break;
826 case 176400:
827 n = 25088;
828 cts = 30000;
829 break;
830 case 48000:
831 n = 6144;
832 cts = 27000;
833 break;
834 case 96000:
835 n = 12288;
836 cts = 27000;
837 break;
838 case 192000:
839 n = 24576;
840 cts = 27000;
841 break;
842 default:
843 n = 0;
844 cts = 0;
845 break;
846 }
847
848 acr[1] = cts >> 16;
849 acr[2] = cts >> 8 & 0xff;
850 acr[3] = cts & 0xff;
851
852 acr[4] = n >> 16;
853 acr[5] = n >> 8 & 0xff;
854 acr[6] = n & 0xff;
855}
856
857static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
858{
859 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
860 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
861 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
862 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
863 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
864 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
865 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
866 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
867 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
868
Rahul Sharma5a325072012-10-04 20:48:54 +0530869 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900870 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
871 else
872 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
873}
874
875static void hdmi_audio_init(struct hdmi_context *hdata)
876{
877 u32 sample_rate, bits_per_sample, frame_size_code;
878 u32 data_num, bit_ch, sample_frq;
879 u32 val;
880 u8 acr[7];
881
882 sample_rate = 44100;
883 bits_per_sample = 16;
884 frame_size_code = 0;
885
886 switch (bits_per_sample) {
887 case 20:
888 data_num = 2;
889 bit_ch = 1;
890 break;
891 case 24:
892 data_num = 3;
893 bit_ch = 1;
894 break;
895 default:
896 data_num = 1;
897 bit_ch = 0;
898 break;
899 }
900
901 hdmi_set_acr(sample_rate, acr);
902 hdmi_reg_acr(hdata, acr);
903
904 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
905 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
906 | HDMI_I2S_MUX_ENABLE);
907
908 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
909 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
910
911 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
912
913 sample_frq = (sample_rate == 44100) ? 0 :
914 (sample_rate == 48000) ? 2 :
915 (sample_rate == 32000) ? 3 :
916 (sample_rate == 96000) ? 0xa : 0x0;
917
918 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
919 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
920
921 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
922 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
923
924 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
925 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
926 | HDMI_I2S_SEL_LRCK(6));
927 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
928 | HDMI_I2S_SEL_SDATA2(4));
929 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
930 | HDMI_I2S_SEL_SDATA2(2));
931 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
932
933 /* I2S_CON_1 & 2 */
934 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
935 | HDMI_I2S_L_CH_LOW_POL);
936 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
937 | HDMI_I2S_SET_BIT_CH(bit_ch)
938 | HDMI_I2S_SET_SDATA_BIT(data_num)
939 | HDMI_I2S_BASIC_FORMAT);
940
941 /* Configure register related to CUV information */
942 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
943 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
944 | HDMI_I2S_COPYRIGHT
945 | HDMI_I2S_LINEAR_PCM
946 | HDMI_I2S_CONSUMER_FORMAT);
947 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
948 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
949 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
950 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
951 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
952 HDMI_I2S_ORG_SMP_FREQ_44_1
953 | HDMI_I2S_WORD_LEN_MAX24_24BITS
954 | HDMI_I2S_WORD_LEN_MAX_24BITS);
955
956 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
957}
958
959static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
960{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900961 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900962 return;
963
964 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
965 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
966 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
967}
968
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900969static void hdmi_conf_reset(struct hdmi_context *hdata)
970{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900971 u32 reg;
972
Rahul Sharma5a325072012-10-04 20:48:54 +0530973 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900974 reg = HDMI_V13_CORE_RSTOUT;
975 else
976 reg = HDMI_CORE_RSTOUT;
977
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900978 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900979 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -0500980 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900981 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -0500982 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900983}
984
985static void hdmi_conf_init(struct hdmi_context *hdata)
986{
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530987 struct hdmi_infoframe infoframe;
988
Sean Paul77006a72013-01-16 10:17:20 -0500989 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
991 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900992
993 /* choose HDMI mode */
994 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
995 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
996 /* disable bluescreen */
997 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900998
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900999 if (hdata->dvi_mode) {
1000 /* choose DVI mode */
1001 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1002 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1003 hdmi_reg_writeb(hdata, HDMI_CON_2,
1004 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1005 }
1006
Rahul Sharma5a325072012-10-04 20:48:54 +05301007 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001008 /* choose bluescreen (fecal) color */
1009 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1010 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1011 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1012
1013 /* enable AVI packet every vsync, fixes purple line problem */
1014 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1015 /* force RGB, look to CEA-861-D, table 7 for more detail */
1016 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1017 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1018
1019 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1020 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1021 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1022 } else {
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301023 infoframe.type = HDMI_PACKET_TYPE_AVI;
1024 infoframe.ver = HDMI_AVI_VERSION;
1025 infoframe.len = HDMI_AVI_LENGTH;
1026 hdmi_reg_infoframe(hdata, &infoframe);
1027
1028 infoframe.type = HDMI_PACKET_TYPE_AUI;
1029 infoframe.ver = HDMI_AUI_VERSION;
1030 infoframe.len = HDMI_AUI_LENGTH;
1031 hdmi_reg_infoframe(hdata, &infoframe);
1032
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001033 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001034 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1035 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001036}
1037
Rahul Sharma16844fb2013-06-10 14:50:00 +05301038static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001039{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001040 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1041 const struct hdmi_v13_core_regs *core =
1042 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001043 int tries;
1044
1045 /* setting core registers */
1046 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1047 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001048 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1049 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1050 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1051 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1052 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1053 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001054 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1055 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001056 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1057 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1058 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1059 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1060 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1061 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1062 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1063 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1064 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1065 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1066 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1067 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1068 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1069 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1070 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001071 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001072 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1073 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1074 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1075 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1076 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1077 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1078 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1079 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1080 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1081 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1082 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1083 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1084 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1085 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1086 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1087 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1088 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1089 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1090 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1091 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1092 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1093 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1094 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1095 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1096 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1097 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1098 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1099 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001100
1101 /* waiting for HDMIPHY's PLL to get to steady state */
1102 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001103 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001104 if (val & HDMI_PHY_STATUS_READY)
1105 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001106 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001107 }
1108 /* steady state not achieved */
1109 if (tries == 0) {
1110 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1111 hdmi_regs_dump(hdata, "timing apply");
1112 }
1113
Sean Paul0bfb1f82013-06-11 12:24:02 +05301114 clk_disable_unprepare(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001115 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301116 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001117
1118 /* enable HDMI and timing generator */
1119 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1120 if (core->int_pro_mode[0])
1121 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1122 HDMI_FIELD_EN);
1123 else
1124 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1125}
1126
Rahul Sharma16844fb2013-06-10 14:50:00 +05301127static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001128{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001129 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1130 const struct hdmi_v14_core_regs *core =
1131 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001132 int tries;
1133
1134 /* setting core registers */
1135 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1136 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1137 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1138 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1139 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1140 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1141 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1142 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1143 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1144 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1145 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1146 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1147 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1148 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1149 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1150 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1151 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1152 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1153 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1154 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1155 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1156 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1157 core->v_sync_line_bef_2[0]);
1158 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1159 core->v_sync_line_bef_2[1]);
1160 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1161 core->v_sync_line_bef_1[0]);
1162 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1163 core->v_sync_line_bef_1[1]);
1164 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1165 core->v_sync_line_aft_2[0]);
1166 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1167 core->v_sync_line_aft_2[1]);
1168 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1169 core->v_sync_line_aft_1[0]);
1170 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1171 core->v_sync_line_aft_1[1]);
1172 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1173 core->v_sync_line_aft_pxl_2[0]);
1174 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1175 core->v_sync_line_aft_pxl_2[1]);
1176 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1177 core->v_sync_line_aft_pxl_1[0]);
1178 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1179 core->v_sync_line_aft_pxl_1[1]);
1180 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1181 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1182 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1183 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1184 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1185 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1186 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1187 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1188 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1189 core->v_sync_line_aft_3[0]);
1190 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1191 core->v_sync_line_aft_3[1]);
1192 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1193 core->v_sync_line_aft_4[0]);
1194 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1195 core->v_sync_line_aft_4[1]);
1196 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1197 core->v_sync_line_aft_5[0]);
1198 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1199 core->v_sync_line_aft_5[1]);
1200 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1201 core->v_sync_line_aft_6[0]);
1202 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1203 core->v_sync_line_aft_6[1]);
1204 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1205 core->v_sync_line_aft_pxl_3[0]);
1206 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1207 core->v_sync_line_aft_pxl_3[1]);
1208 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1209 core->v_sync_line_aft_pxl_4[0]);
1210 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1211 core->v_sync_line_aft_pxl_4[1]);
1212 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1213 core->v_sync_line_aft_pxl_5[0]);
1214 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1215 core->v_sync_line_aft_pxl_5[1]);
1216 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1217 core->v_sync_line_aft_pxl_6[0]);
1218 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1219 core->v_sync_line_aft_pxl_6[1]);
1220 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1221 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1222 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1223 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1224 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1225 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1226 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1227 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1228 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1229 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1230 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1231 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1232
1233 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001234 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1235 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1236 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1237 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1238 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1239 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1240 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1241 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1242 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1243 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1244 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1245 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1246 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1247 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1248 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1249 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1250 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1251 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1252 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1253 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1254 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1255 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1256 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1257 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1258 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1259 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1260 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1261 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1262 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1263 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1264 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1265 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1266 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001267
1268 /* waiting for HDMIPHY's PLL to get to steady state */
1269 for (tries = 100; tries; --tries) {
1270 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1271 if (val & HDMI_PHY_STATUS_READY)
1272 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001273 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001274 }
1275 /* steady state not achieved */
1276 if (tries == 0) {
1277 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1278 hdmi_regs_dump(hdata, "timing apply");
1279 }
1280
Sean Paul0bfb1f82013-06-11 12:24:02 +05301281 clk_disable_unprepare(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001282 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301283 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001284
1285 /* enable HDMI and timing generator */
1286 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1287 if (core->int_pro_mode[0])
1288 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1289 HDMI_FIELD_EN);
1290 else
1291 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1292}
1293
Rahul Sharma16844fb2013-06-10 14:50:00 +05301294static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001295{
Rahul Sharma5a325072012-10-04 20:48:54 +05301296 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301297 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001298 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301299 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001300}
1301
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001302static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1303{
1304 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001305 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001306
Sean Paul0bfb1f82013-06-11 12:24:02 +05301307 clk_disable_unprepare(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001308 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301309 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001310
1311 /* operation mode */
1312 buffer[0] = 0x1f;
1313 buffer[1] = 0x00;
1314
1315 if (hdata->hdmiphy_port)
1316 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1317
Rahul Sharma5a325072012-10-04 20:48:54 +05301318 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001319 reg = HDMI_V13_PHY_RSTOUT;
1320 else
1321 reg = HDMI_PHY_RSTOUT;
1322
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001323 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001324 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001325 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001326 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001327 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001328}
1329
Rahul Sharmaa5562252012-11-28 11:30:25 +05301330static void hdmiphy_poweron(struct hdmi_context *hdata)
1331{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301332 if (hdata->type == HDMI_TYPE14)
1333 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1334 HDMI_PHY_POWER_OFF_EN);
1335}
1336
1337static void hdmiphy_poweroff(struct hdmi_context *hdata)
1338{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301339 if (hdata->type == HDMI_TYPE14)
1340 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1341 HDMI_PHY_POWER_OFF_EN);
1342}
1343
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001344static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1345{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001346 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001347 u8 buffer[32];
1348 u8 operation[2];
1349 u8 read_buffer[32] = {0, };
1350 int ret;
1351 int i;
1352
1353 if (!hdata->hdmiphy_port) {
1354 DRM_ERROR("hdmiphy is not attached\n");
1355 return;
1356 }
1357
1358 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001359 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1360 if (i < 0) {
1361 DRM_ERROR("failed to find hdmiphy conf\n");
1362 return;
1363 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001364
Sachin Kamat5f46c332013-04-26 11:29:00 +05301365 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001366 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301367 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001368 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001369
1370 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001371 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1372 if (ret != 32) {
1373 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1374 return;
1375 }
1376
Sean Paul09760ea2013-01-14 17:03:20 -05001377 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001378
1379 /* operation mode */
1380 operation[0] = 0x1f;
1381 operation[1] = 0x80;
1382
1383 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1384 if (ret != 2) {
1385 DRM_ERROR("failed to enable hdmiphy\n");
1386 return;
1387 }
1388
1389 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1390 if (ret < 0) {
1391 DRM_ERROR("failed to read hdmiphy config\n");
1392 return;
1393 }
1394
1395 for (i = 0; i < ret; i++)
1396 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1397 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1398}
1399
1400static void hdmi_conf_apply(struct hdmi_context *hdata)
1401{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001402 hdmiphy_conf_reset(hdata);
1403 hdmiphy_conf_apply(hdata);
1404
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001405 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001406 hdmi_conf_reset(hdata);
1407 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001408 mutex_unlock(&hdata->hdmi_mutex);
1409
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001410 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001411
1412 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301413 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001414 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001415
1416 hdmi_regs_dump(hdata, "start");
1417}
1418
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001419static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1420{
1421 int i;
1422 BUG_ON(num_bytes > 4);
1423 for (i = 0; i < num_bytes; i++)
1424 reg_pair[i] = (value >> (8 * i)) & 0xff;
1425}
1426
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001427static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1428 struct drm_display_mode *m)
1429{
1430 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1431 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1432 unsigned int val;
1433
1434 hdata->mode_conf.cea_video_id =
1435 drm_match_cea_mode((struct drm_display_mode *)m);
1436 hdata->mode_conf.pixel_clock = m->clock * 1000;
1437
1438 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1439 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1440
1441 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1442 hdmi_set_reg(core->vsync_pol, 1, val);
1443
1444 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1445 hdmi_set_reg(core->int_pro_mode, 1, val);
1446
1447 val = (m->hsync_start - m->hdisplay - 2);
1448 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1449 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1450 hdmi_set_reg(core->h_sync_gen, 3, val);
1451
1452 /*
1453 * Quirk requirement for exynos HDMI IP design,
1454 * 2 pixels less than the actual calculation for hsync_start
1455 * and end.
1456 */
1457
1458 /* Following values & calculations differ for different type of modes */
1459 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1460 /* Interlaced Mode */
1461 val = ((m->vsync_end - m->vdisplay) / 2);
1462 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1463 hdmi_set_reg(core->v_sync_gen1, 3, val);
1464
1465 val = m->vtotal / 2;
1466 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1467 hdmi_set_reg(core->v_blank, 3, val);
1468
1469 val = (m->vtotal +
1470 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1471 val |= m->vtotal << 11;
1472 hdmi_set_reg(core->v_blank_f, 3, val);
1473
1474 val = ((m->vtotal / 2) + 7);
1475 val |= ((m->vtotal / 2) + 2) << 12;
1476 hdmi_set_reg(core->v_sync_gen2, 3, val);
1477
1478 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1479 val |= ((m->htotal / 2) +
1480 (m->hsync_start - m->hdisplay)) << 12;
1481 hdmi_set_reg(core->v_sync_gen3, 3, val);
1482
1483 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1484 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1485
1486 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1487 } else {
1488 /* Progressive Mode */
1489
1490 val = m->vtotal;
1491 val |= (m->vtotal - m->vdisplay) << 11;
1492 hdmi_set_reg(core->v_blank, 3, val);
1493
1494 hdmi_set_reg(core->v_blank_f, 3, 0);
1495
1496 val = (m->vsync_end - m->vdisplay);
1497 val |= ((m->vsync_start - m->vdisplay) << 12);
1498 hdmi_set_reg(core->v_sync_gen1, 3, val);
1499
1500 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1501 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1502 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1503 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1504 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1505 }
1506
1507 /* Timing generator registers */
1508 hdmi_set_reg(tg->cmd, 1, 0x0);
1509 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1510 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1511 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1512 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1513 hdmi_set_reg(tg->vsync, 2, 0x1);
1514 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1515 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1516 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1517 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1518 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1519 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1520 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1521}
1522
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001523static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1524 struct drm_display_mode *m)
1525{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001526 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1527 struct hdmi_v14_core_regs *core =
1528 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001529
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001530 hdata->mode_conf.cea_video_id =
1531 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001532 hdata->mode_conf.pixel_clock = m->clock * 1000;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001533
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001534 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1535 hdmi_set_reg(core->v_line, 2, m->vtotal);
1536 hdmi_set_reg(core->h_line, 2, m->htotal);
1537 hdmi_set_reg(core->hsync_pol, 1,
1538 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1539 hdmi_set_reg(core->vsync_pol, 1,
1540 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1541 hdmi_set_reg(core->int_pro_mode, 1,
1542 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1543
1544 /*
1545 * Quirk requirement for exynos 5 HDMI IP design,
1546 * 2 pixels less than the actual calculation for hsync_start
1547 * and end.
1548 */
1549
1550 /* Following values & calculations differ for different type of modes */
1551 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1552 /* Interlaced Mode */
1553 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1554 (m->vsync_end - m->vdisplay) / 2);
1555 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1556 (m->vsync_start - m->vdisplay) / 2);
1557 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1558 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
1559 hdmi_set_reg(core->v_blank_f0, 2, (m->vtotal +
1560 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2);
1561 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1562 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1563 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1564 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1565 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1566 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1567 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1568 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1569 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1570 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1571 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1572 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1573 } else {
1574 /* Progressive Mode */
1575 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1576 m->vsync_end - m->vdisplay);
1577 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1578 m->vsync_start - m->vdisplay);
1579 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1580 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1581 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1582 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1583 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1584 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1585 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1586 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1587 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1588 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1589 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1590 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1591 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
1592 }
1593
1594 /* Following values & calculations are same irrespective of mode type */
1595 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1596 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1597 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1598 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1599 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1600 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1601 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1602 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1603 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1604 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1605 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1606 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1607 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1608 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1609 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1610 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1611 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1612 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1613 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1614 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1615
1616 /* Timing generator registers */
1617 hdmi_set_reg(tg->cmd, 1, 0x0);
1618 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1619 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1620 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1621 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1622 hdmi_set_reg(tg->vsync, 2, 0x1);
1623 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1624 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1625 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1626 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1627 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1628 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1629 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001630}
1631
Rahul Sharma16844fb2013-06-10 14:50:00 +05301632static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001633{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001634 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001635 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001636
YoungJun Chocbc4c332013-06-12 10:44:40 +09001637 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1638 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001639 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1640 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001641
Sachin Kamat5f46c332013-04-26 11:29:00 +05301642 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001643 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301644 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001645 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001646}
1647
Inki Dae1de425b2012-03-16 18:47:04 +09001648static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1649 unsigned int *height)
1650{
Inki Dae1de425b2012-03-16 18:47:04 +09001651 *width = MAX_WIDTH;
1652 *height = MAX_HEIGHT;
1653}
1654
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001655static void hdmi_commit(void *ctx)
1656{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001657 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001658
Shirish Sdda90122013-01-23 22:03:18 -05001659 mutex_lock(&hdata->hdmi_mutex);
1660 if (!hdata->powered) {
1661 mutex_unlock(&hdata->hdmi_mutex);
1662 return;
1663 }
1664 mutex_unlock(&hdata->hdmi_mutex);
1665
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001666 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001667}
1668
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001669static void hdmi_poweron(struct hdmi_context *hdata)
1670{
1671 struct hdmi_resources *res = &hdata->res;
1672
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001673 mutex_lock(&hdata->hdmi_mutex);
1674 if (hdata->powered) {
1675 mutex_unlock(&hdata->hdmi_mutex);
1676 return;
1677 }
1678
1679 hdata->powered = true;
1680
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001681 mutex_unlock(&hdata->hdmi_mutex);
1682
Seung-Woo Kimad079452013-06-05 14:34:38 +09001683 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1684 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1685
Sean Paul0bfb1f82013-06-11 12:24:02 +05301686 clk_prepare_enable(res->hdmiphy);
1687 clk_prepare_enable(res->hdmi);
1688 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301689
1690 hdmiphy_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001691}
1692
1693static void hdmi_poweroff(struct hdmi_context *hdata)
1694{
1695 struct hdmi_resources *res = &hdata->res;
1696
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001697 mutex_lock(&hdata->hdmi_mutex);
1698 if (!hdata->powered)
1699 goto out;
1700 mutex_unlock(&hdata->hdmi_mutex);
1701
1702 /*
1703 * The TV power domain needs any condition of hdmiphy to turn off and
1704 * its reset state seems to meet the condition.
1705 */
1706 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301707 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001708
Sean Paul0bfb1f82013-06-11 12:24:02 +05301709 clk_disable_unprepare(res->sclk_hdmi);
1710 clk_disable_unprepare(res->hdmi);
1711 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001712 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1713
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001714 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001715
1716 hdata->powered = false;
1717
1718out:
1719 mutex_unlock(&hdata->hdmi_mutex);
1720}
1721
1722static void hdmi_dpms(void *ctx, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001723{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001724 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001725
YoungJun Chocbc4c332013-06-12 10:44:40 +09001726 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001727
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001728 switch (mode) {
1729 case DRM_MODE_DPMS_ON:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301730 if (pm_runtime_suspended(hdata->dev))
1731 pm_runtime_get_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001732 break;
1733 case DRM_MODE_DPMS_STANDBY:
1734 case DRM_MODE_DPMS_SUSPEND:
1735 case DRM_MODE_DPMS_OFF:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301736 if (!pm_runtime_suspended(hdata->dev))
1737 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001738 break;
1739 default:
1740 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1741 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001742 }
1743}
1744
Joonyoung Shim578b6062012-04-05 20:49:26 +09001745static struct exynos_hdmi_ops hdmi_ops = {
1746 /* display */
1747 .is_connected = hdmi_is_connected,
1748 .get_edid = hdmi_get_edid,
Rahul Sharma16844fb2013-06-10 14:50:00 +05301749 .check_mode = hdmi_check_mode,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001750
1751 /* manager */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001752 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09001753 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001754 .commit = hdmi_commit,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001755 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001756};
1757
Sean Paul77006a72013-01-16 10:17:20 -05001758static irqreturn_t hdmi_irq_thread(int irq, void *arg)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001759{
1760 struct exynos_drm_hdmi_context *ctx = arg;
1761 struct hdmi_context *hdata = ctx->ctx;
1762
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001763 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301764 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001765 mutex_unlock(&hdata->hdmi_mutex);
1766
1767 if (ctx->drm_dev)
1768 drm_helper_hpd_irq_event(ctx->drm_dev);
1769
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001770 return IRQ_HANDLED;
1771}
1772
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001773static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001774{
1775 struct device *dev = hdata->dev;
1776 struct hdmi_resources *res = &hdata->res;
1777 static char *supply[] = {
1778 "hdmi-en",
1779 "vdd",
1780 "vdd_osc",
1781 "vdd_pll",
1782 };
1783 int i, ret;
1784
1785 DRM_DEBUG_KMS("HDMI resource init\n");
1786
Sachin Kamatadc837a2012-08-31 15:50:47 +05301787 memset(res, 0, sizeof(*res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001788
1789 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301790 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301791 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001792 DRM_ERROR("failed to get clock 'hdmi'\n");
1793 goto fail;
1794 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301795 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301796 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001797 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1798 goto fail;
1799 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301800 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301801 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001802 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1803 goto fail;
1804 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301805 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301806 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001807 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1808 goto fail;
1809 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301810 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301811 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001812 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1813 goto fail;
1814 }
1815
1816 clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
1817
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301818 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301819 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001820 if (!res->regul_bulk) {
1821 DRM_ERROR("failed to get memory for regulators\n");
1822 goto fail;
1823 }
1824 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1825 res->regul_bulk[i].supply = supply[i];
1826 res->regul_bulk[i].consumer = NULL;
1827 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301828 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001829 if (ret) {
1830 DRM_ERROR("failed to get regulators\n");
1831 goto fail;
1832 }
1833 res->regul_count = ARRAY_SIZE(supply);
1834
1835 return 0;
1836fail:
1837 DRM_ERROR("HDMI resource init - failed\n");
1838 return -ENODEV;
1839}
1840
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001841static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
1842
1843void hdmi_attach_ddc_client(struct i2c_client *ddc)
1844{
1845 if (ddc)
1846 hdmi_ddc = ddc;
1847}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001848
1849void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
1850{
1851 if (hdmiphy)
1852 hdmi_hdmiphy = hdmiphy;
1853}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001854
Rahul Sharma22c4f422012-10-04 20:48:55 +05301855#ifdef CONFIG_OF
1856static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1857 (struct device *dev)
1858{
1859 struct device_node *np = dev->of_node;
1860 struct s5p_hdmi_platform_data *pd;
1861 enum of_gpio_flags flags;
1862 u32 value;
1863
1864 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
1865 if (!pd) {
1866 DRM_ERROR("memory allocation for pdata failed\n");
1867 goto err_data;
1868 }
1869
1870 if (!of_find_property(np, "hpd-gpio", &value)) {
1871 DRM_ERROR("no hpd gpio property found\n");
1872 goto err_data;
1873 }
1874
1875 pd->hpd_gpio = of_get_named_gpio_flags(np, "hpd-gpio", 0, &flags);
1876
1877 return pd;
1878
1879err_data:
1880 return NULL;
1881}
1882#else
1883static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1884 (struct device *dev)
1885{
1886 return NULL;
1887}
1888#endif
1889
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301890static struct platform_device_id hdmi_driver_types[] = {
1891 {
1892 .name = "s5pv210-hdmi",
1893 .driver_data = HDMI_TYPE13,
1894 }, {
1895 .name = "exynos4-hdmi",
1896 .driver_data = HDMI_TYPE13,
1897 }, {
1898 .name = "exynos4-hdmi14",
Rahul Sharma22c4f422012-10-04 20:48:55 +05301899 .driver_data = HDMI_TYPE14,
1900 }, {
1901 .name = "exynos5-hdmi",
1902 .driver_data = HDMI_TYPE14,
1903 }, {
1904 /* end node */
1905 }
1906};
1907
Sachin Kamat65da0352012-12-12 14:24:07 +05301908#ifdef CONFIG_OF
Rahul Sharma22c4f422012-10-04 20:48:55 +05301909static struct of_device_id hdmi_match_types[] = {
1910 {
1911 .compatible = "samsung,exynos5-hdmi",
1912 .data = (void *)HDMI_TYPE14,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301913 }, {
1914 /* end node */
1915 }
1916};
Sachin Kamat65da0352012-12-12 14:24:07 +05301917#endif
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301918
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001919static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001920{
1921 struct device *dev = &pdev->dev;
1922 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1923 struct hdmi_context *hdata;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301924 struct s5p_hdmi_platform_data *pdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001925 struct resource *res;
1926 int ret;
1927
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001928 if (dev->of_node) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301929 pdata = drm_hdmi_dt_parse_pdata(dev);
1930 if (IS_ERR(pdata)) {
1931 DRM_ERROR("failed to parse dt\n");
1932 return PTR_ERR(pdata);
1933 }
1934 } else {
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001935 pdata = dev->platform_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301936 }
1937
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001938 if (!pdata) {
1939 DRM_ERROR("no platform data specified\n");
1940 return -EINVAL;
1941 }
1942
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001943 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
Sachin Kamata6e65072012-06-19 11:47:40 +05301944 GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001945 if (!drm_hdmi_ctx) {
1946 DRM_ERROR("failed to allocate common hdmi context.\n");
1947 return -ENOMEM;
1948 }
1949
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001950 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context),
Sachin Kamata6e65072012-06-19 11:47:40 +05301951 GFP_KERNEL);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952 if (!hdata) {
1953 DRM_ERROR("out of memory\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001954 return -ENOMEM;
1955 }
1956
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001957 mutex_init(&hdata->hdmi_mutex);
1958
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001959 drm_hdmi_ctx->ctx = (void *)hdata;
1960 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1961
1962 platform_set_drvdata(pdev, drm_hdmi_ctx);
1963
Rahul Sharma22c4f422012-10-04 20:48:55 +05301964 if (dev->of_node) {
1965 const struct of_device_id *match;
1966 match = of_match_node(of_match_ptr(hdmi_match_types),
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001967 dev->of_node);
Sachin Kamat1a4513b2012-12-12 14:24:08 +05301968 if (match == NULL)
1969 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301970 hdata->type = (enum hdmi_type)match->data;
1971 } else {
1972 hdata->type = (enum hdmi_type)platform_get_device_id
Rahul Sharma5a325072012-10-04 20:48:54 +05301973 (pdev)->driver_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301974 }
1975
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301976 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001977 hdata->dev = dev;
1978
1979 ret = hdmi_resources_init(hdata);
Rahul Sharma22c4f422012-10-04 20:48:55 +05301980
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001981 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301982 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301983 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984 }
1985
1986 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001987 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001988 if (IS_ERR(hdata->regs))
1989 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001990
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001991 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301992 if (ret) {
1993 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301994 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301995 }
1996
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001997 /* DDC i2c driver */
1998 if (i2c_add_driver(&ddc_driver)) {
1999 DRM_ERROR("failed to register ddc i2c driver\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302000 return -ENOENT;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002001 }
2002
2003 hdata->ddc_port = hdmi_ddc;
2004
2005 /* hdmiphy i2c driver */
2006 if (i2c_add_driver(&hdmiphy_driver)) {
2007 DRM_ERROR("failed to register hdmiphy i2c driver\n");
2008 ret = -ENOENT;
2009 goto err_ddc;
2010 }
2011
2012 hdata->hdmiphy_port = hdmi_hdmiphy;
2013
Sean Paul77006a72013-01-16 10:17:20 -05002014 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2015 if (hdata->irq < 0) {
2016 DRM_ERROR("failed to get GPIO irq\n");
2017 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002018 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002019 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302021 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2022
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002023 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002024 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002025 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paul77006a72013-01-16 10:17:20 -05002026 "hdmi", drm_hdmi_ctx);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002027 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002028 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002029 goto err_hdmiphy;
2030 }
2031
Rahul Sharma768c3052012-10-04 20:48:56 +05302032 /* Attach HDMI Driver to common hdmi. */
2033 exynos_hdmi_drv_attach(drm_hdmi_ctx);
2034
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002035 /* register specific callbacks to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09002036 exynos_hdmi_ops_register(&hdmi_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002037
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002038 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002039
2040 return 0;
2041
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002042err_hdmiphy:
2043 i2c_del_driver(&hdmiphy_driver);
2044err_ddc:
2045 i2c_del_driver(&ddc_driver);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002046 return ret;
2047}
2048
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002049static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002050{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002051 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002052
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002053 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002055 /* hdmiphy i2c driver */
2056 i2c_del_driver(&hdmiphy_driver);
2057 /* DDC i2c driver */
2058 i2c_del_driver(&ddc_driver);
2059
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002060 return 0;
2061}
2062
Joonyoung Shimab27af82012-04-23 19:35:51 +09002063#ifdef CONFIG_PM_SLEEP
2064static int hdmi_suspend(struct device *dev)
2065{
2066 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2067 struct hdmi_context *hdata = ctx->ctx;
2068
Sean Paul77006a72013-01-16 10:17:20 -05002069 disable_irq(hdata->irq);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002070
2071 hdata->hpd = false;
2072 if (ctx->drm_dev)
2073 drm_helper_hpd_irq_event(ctx->drm_dev);
2074
Rahul Sharma64327cb2012-11-28 11:30:23 +05302075 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002076 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302077 return 0;
2078 }
2079
Joonyoung Shimab27af82012-04-23 19:35:51 +09002080 hdmi_poweroff(hdata);
2081
2082 return 0;
2083}
2084
2085static int hdmi_resume(struct device *dev)
2086{
2087 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2088 struct hdmi_context *hdata = ctx->ctx;
2089
Rahul Sharma64327cb2012-11-28 11:30:23 +05302090 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2091
Sean Paul77006a72013-01-16 10:17:20 -05002092 enable_irq(hdata->irq);
Rahul Sharma64327cb2012-11-28 11:30:23 +05302093
2094 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002095 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302096 return 0;
2097 }
2098
2099 hdmi_poweron(hdata);
2100
Joonyoung Shimab27af82012-04-23 19:35:51 +09002101 return 0;
2102}
2103#endif
2104
Rahul Sharma64327cb2012-11-28 11:30:23 +05302105#ifdef CONFIG_PM_RUNTIME
2106static int hdmi_runtime_suspend(struct device *dev)
2107{
2108 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2109 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302110
2111 hdmi_poweroff(hdata);
2112
2113 return 0;
2114}
2115
2116static int hdmi_runtime_resume(struct device *dev)
2117{
2118 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2119 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302120
2121 hdmi_poweron(hdata);
2122
2123 return 0;
2124}
2125#endif
2126
2127static const struct dev_pm_ops hdmi_pm_ops = {
2128 SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
2129 SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
2130};
Joonyoung Shimab27af82012-04-23 19:35:51 +09002131
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002132struct platform_driver hdmi_driver = {
2133 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002134 .remove = hdmi_remove,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302135 .id_table = hdmi_driver_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002136 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302137 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002138 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09002139 .pm = &hdmi_pm_ops,
Sachin Kamat65da0352012-12-12 14:24:07 +05302140 .of_match_table = of_match_ptr(hdmi_match_types),
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002141 },
2142};