blob: 9ec787f8529a8d3ff9b2cc297f58a8758d641e83 [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
Sachin Kamat16337072014-05-22 10:32:56 +0530596static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900597 .type = HDMI_TYPE14,
598 .phy_confs = hdmiphy_v13_configs,
599 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
600 .is_apb_phy = 0,
601};
602
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900603static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
604{
605 return readl(hdata->regs + reg_id);
606}
607
608static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
609 u32 reg_id, u8 value)
610{
611 writeb(value, hdata->regs + reg_id);
612}
613
614static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
615 u32 reg_id, u32 value, u32 mask)
616{
617 u32 old = readl(hdata->regs + reg_id);
618 value = (value & mask) | (old & ~mask);
619 writel(value, hdata->regs + reg_id);
620}
621
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900622static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
623 u32 reg_offset, u8 value)
624{
625 if (hdata->hdmiphy_port) {
626 u8 buffer[2];
627 int ret;
628
629 buffer[0] = reg_offset;
630 buffer[1] = value;
631
632 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
633 if (ret == 2)
634 return 0;
635 return ret;
636 } else {
637 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
638 return 0;
639 }
640}
641
642static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
643 u32 reg_offset, const u8 *buf, u32 len)
644{
645 if ((reg_offset + len) > 32)
646 return -EINVAL;
647
648 if (hdata->hdmiphy_port) {
649 int ret;
650
651 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
652 if (ret == len)
653 return 0;
654 return ret;
655 } else {
656 int i;
657 for (i = 0; i < len; i++)
658 writeb(buf[i], hdata->regs_hdmiphy +
659 ((reg_offset + i)<<2));
660 return 0;
661 }
662}
663
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900664static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900665{
666#define DUMPREG(reg_id) \
667 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
668 readl(hdata->regs + reg_id))
669 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
670 DUMPREG(HDMI_INTC_FLAG);
671 DUMPREG(HDMI_INTC_CON);
672 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900673 DUMPREG(HDMI_V13_PHY_RSTOUT);
674 DUMPREG(HDMI_V13_PHY_VPLL);
675 DUMPREG(HDMI_V13_PHY_CMU);
676 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900677
678 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
679 DUMPREG(HDMI_CON_0);
680 DUMPREG(HDMI_CON_1);
681 DUMPREG(HDMI_CON_2);
682 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900683 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900684 DUMPREG(HDMI_STATUS_EN);
685 DUMPREG(HDMI_HPD);
686 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900687 DUMPREG(HDMI_V13_HPD_GEN);
688 DUMPREG(HDMI_V13_DC_CONTROL);
689 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900690
691 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
692 DUMPREG(HDMI_H_BLANK_0);
693 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900694 DUMPREG(HDMI_V13_V_BLANK_0);
695 DUMPREG(HDMI_V13_V_BLANK_1);
696 DUMPREG(HDMI_V13_V_BLANK_2);
697 DUMPREG(HDMI_V13_H_V_LINE_0);
698 DUMPREG(HDMI_V13_H_V_LINE_1);
699 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900700 DUMPREG(HDMI_VSYNC_POL);
701 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900702 DUMPREG(HDMI_V13_V_BLANK_F_0);
703 DUMPREG(HDMI_V13_V_BLANK_F_1);
704 DUMPREG(HDMI_V13_V_BLANK_F_2);
705 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
706 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
707 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
708 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
709 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
710 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
711 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
712 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
713 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
714 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
715 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
716 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900717
718 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
719 DUMPREG(HDMI_TG_CMD);
720 DUMPREG(HDMI_TG_H_FSZ_L);
721 DUMPREG(HDMI_TG_H_FSZ_H);
722 DUMPREG(HDMI_TG_HACT_ST_L);
723 DUMPREG(HDMI_TG_HACT_ST_H);
724 DUMPREG(HDMI_TG_HACT_SZ_L);
725 DUMPREG(HDMI_TG_HACT_SZ_H);
726 DUMPREG(HDMI_TG_V_FSZ_L);
727 DUMPREG(HDMI_TG_V_FSZ_H);
728 DUMPREG(HDMI_TG_VSYNC_L);
729 DUMPREG(HDMI_TG_VSYNC_H);
730 DUMPREG(HDMI_TG_VSYNC2_L);
731 DUMPREG(HDMI_TG_VSYNC2_H);
732 DUMPREG(HDMI_TG_VACT_ST_L);
733 DUMPREG(HDMI_TG_VACT_ST_H);
734 DUMPREG(HDMI_TG_VACT_SZ_L);
735 DUMPREG(HDMI_TG_VACT_SZ_H);
736 DUMPREG(HDMI_TG_FIELD_CHG_L);
737 DUMPREG(HDMI_TG_FIELD_CHG_H);
738 DUMPREG(HDMI_TG_VACT_ST2_L);
739 DUMPREG(HDMI_TG_VACT_ST2_H);
740 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
741 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
742 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
743 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
744 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
745 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
746 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
747 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
748#undef DUMPREG
749}
750
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900751static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
752{
753 int i;
754
755#define DUMPREG(reg_id) \
756 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
757 readl(hdata->regs + reg_id))
758
759 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
760 DUMPREG(HDMI_INTC_CON);
761 DUMPREG(HDMI_INTC_FLAG);
762 DUMPREG(HDMI_HPD_STATUS);
763 DUMPREG(HDMI_INTC_CON_1);
764 DUMPREG(HDMI_INTC_FLAG_1);
765 DUMPREG(HDMI_PHY_STATUS_0);
766 DUMPREG(HDMI_PHY_STATUS_PLL);
767 DUMPREG(HDMI_PHY_CON_0);
768 DUMPREG(HDMI_PHY_RSTOUT);
769 DUMPREG(HDMI_PHY_VPLL);
770 DUMPREG(HDMI_PHY_CMU);
771 DUMPREG(HDMI_CORE_RSTOUT);
772
773 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
774 DUMPREG(HDMI_CON_0);
775 DUMPREG(HDMI_CON_1);
776 DUMPREG(HDMI_CON_2);
777 DUMPREG(HDMI_SYS_STATUS);
778 DUMPREG(HDMI_PHY_STATUS_0);
779 DUMPREG(HDMI_STATUS_EN);
780 DUMPREG(HDMI_HPD);
781 DUMPREG(HDMI_MODE_SEL);
782 DUMPREG(HDMI_ENC_EN);
783 DUMPREG(HDMI_DC_CONTROL);
784 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
785
786 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
787 DUMPREG(HDMI_H_BLANK_0);
788 DUMPREG(HDMI_H_BLANK_1);
789 DUMPREG(HDMI_V2_BLANK_0);
790 DUMPREG(HDMI_V2_BLANK_1);
791 DUMPREG(HDMI_V1_BLANK_0);
792 DUMPREG(HDMI_V1_BLANK_1);
793 DUMPREG(HDMI_V_LINE_0);
794 DUMPREG(HDMI_V_LINE_1);
795 DUMPREG(HDMI_H_LINE_0);
796 DUMPREG(HDMI_H_LINE_1);
797 DUMPREG(HDMI_HSYNC_POL);
798
799 DUMPREG(HDMI_VSYNC_POL);
800 DUMPREG(HDMI_INT_PRO_MODE);
801 DUMPREG(HDMI_V_BLANK_F0_0);
802 DUMPREG(HDMI_V_BLANK_F0_1);
803 DUMPREG(HDMI_V_BLANK_F1_0);
804 DUMPREG(HDMI_V_BLANK_F1_1);
805
806 DUMPREG(HDMI_H_SYNC_START_0);
807 DUMPREG(HDMI_H_SYNC_START_1);
808 DUMPREG(HDMI_H_SYNC_END_0);
809 DUMPREG(HDMI_H_SYNC_END_1);
810
811 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
812 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
813 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
814 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
815
816 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
817 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
818 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
819 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
820
821 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
822 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
823 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
824 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
825
826 DUMPREG(HDMI_V_BLANK_F2_0);
827 DUMPREG(HDMI_V_BLANK_F2_1);
828 DUMPREG(HDMI_V_BLANK_F3_0);
829 DUMPREG(HDMI_V_BLANK_F3_1);
830 DUMPREG(HDMI_V_BLANK_F4_0);
831 DUMPREG(HDMI_V_BLANK_F4_1);
832 DUMPREG(HDMI_V_BLANK_F5_0);
833 DUMPREG(HDMI_V_BLANK_F5_1);
834
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
836 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
837 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
838 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
839 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
840 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
841 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
842 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
843
844 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
845 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
846 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
850 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
851 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
852
853 DUMPREG(HDMI_VACT_SPACE_1_0);
854 DUMPREG(HDMI_VACT_SPACE_1_1);
855 DUMPREG(HDMI_VACT_SPACE_2_0);
856 DUMPREG(HDMI_VACT_SPACE_2_1);
857 DUMPREG(HDMI_VACT_SPACE_3_0);
858 DUMPREG(HDMI_VACT_SPACE_3_1);
859 DUMPREG(HDMI_VACT_SPACE_4_0);
860 DUMPREG(HDMI_VACT_SPACE_4_1);
861 DUMPREG(HDMI_VACT_SPACE_5_0);
862 DUMPREG(HDMI_VACT_SPACE_5_1);
863 DUMPREG(HDMI_VACT_SPACE_6_0);
864 DUMPREG(HDMI_VACT_SPACE_6_1);
865
866 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
867 DUMPREG(HDMI_TG_CMD);
868 DUMPREG(HDMI_TG_H_FSZ_L);
869 DUMPREG(HDMI_TG_H_FSZ_H);
870 DUMPREG(HDMI_TG_HACT_ST_L);
871 DUMPREG(HDMI_TG_HACT_ST_H);
872 DUMPREG(HDMI_TG_HACT_SZ_L);
873 DUMPREG(HDMI_TG_HACT_SZ_H);
874 DUMPREG(HDMI_TG_V_FSZ_L);
875 DUMPREG(HDMI_TG_V_FSZ_H);
876 DUMPREG(HDMI_TG_VSYNC_L);
877 DUMPREG(HDMI_TG_VSYNC_H);
878 DUMPREG(HDMI_TG_VSYNC2_L);
879 DUMPREG(HDMI_TG_VSYNC2_H);
880 DUMPREG(HDMI_TG_VACT_ST_L);
881 DUMPREG(HDMI_TG_VACT_ST_H);
882 DUMPREG(HDMI_TG_VACT_SZ_L);
883 DUMPREG(HDMI_TG_VACT_SZ_H);
884 DUMPREG(HDMI_TG_FIELD_CHG_L);
885 DUMPREG(HDMI_TG_FIELD_CHG_H);
886 DUMPREG(HDMI_TG_VACT_ST2_L);
887 DUMPREG(HDMI_TG_VACT_ST2_H);
888 DUMPREG(HDMI_TG_VACT_ST3_L);
889 DUMPREG(HDMI_TG_VACT_ST3_H);
890 DUMPREG(HDMI_TG_VACT_ST4_L);
891 DUMPREG(HDMI_TG_VACT_ST4_H);
892 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
893 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
894 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
895 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
896 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
897 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
898 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
899 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
900 DUMPREG(HDMI_TG_3D);
901
902 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
903 DUMPREG(HDMI_AVI_CON);
904 DUMPREG(HDMI_AVI_HEADER0);
905 DUMPREG(HDMI_AVI_HEADER1);
906 DUMPREG(HDMI_AVI_HEADER2);
907 DUMPREG(HDMI_AVI_CHECK_SUM);
908 DUMPREG(HDMI_VSI_CON);
909 DUMPREG(HDMI_VSI_HEADER0);
910 DUMPREG(HDMI_VSI_HEADER1);
911 DUMPREG(HDMI_VSI_HEADER2);
912 for (i = 0; i < 7; ++i)
913 DUMPREG(HDMI_VSI_DATA(i));
914
915#undef DUMPREG
916}
917
918static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
919{
Rahul Sharma5a325072012-10-04 20:48:54 +0530920 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900921 hdmi_v13_regs_dump(hdata, prefix);
922 else
923 hdmi_v14_regs_dump(hdata, prefix);
924}
925
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530926static u8 hdmi_chksum(struct hdmi_context *hdata,
927 u32 start, u8 len, u32 hdr_sum)
928{
929 int i;
930
931 /* hdr_sum : header0 + header1 + header2
932 * start : start address of packet byte1
933 * len : packet bytes - 1 */
934 for (i = 0; i < len; ++i)
935 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
936
937 /* return 2's complement of 8 bit hdr_sum */
938 return (u8)(~(hdr_sum & 0xff) + 1);
939}
940
941static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530942 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530943{
944 u32 hdr_sum;
945 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530946 u32 mod;
947 u32 vic;
948
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530949 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
950 if (hdata->dvi_mode) {
951 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
952 HDMI_VSI_CON_DO_NOT_TRANSMIT);
953 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
954 HDMI_AVI_CON_DO_NOT_TRANSMIT);
955 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
956 return;
957 }
958
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530959 switch (infoframe->any.type) {
960 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530961 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530962 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
963 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
964 infoframe->any.version);
965 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
966 hdr_sum = infoframe->any.type + infoframe->any.version +
967 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530968
969 /* Output format zero hardcoded ,RGB YBCR selection */
970 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
971 AVI_ACTIVE_FORMAT_VALID |
972 AVI_UNDERSCANNED_DISPLAY_VALID);
973
Shirish S46154152014-03-13 10:58:28 +0530974 /*
975 * Set the aspect ratio as per the mode, mentioned in
976 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
977 */
978 switch (hdata->mode_conf.aspect_ratio) {
979 case HDMI_PICTURE_ASPECT_4_3:
980 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
981 hdata->mode_conf.aspect_ratio |
982 AVI_4_3_CENTER_RATIO);
983 break;
984 case HDMI_PICTURE_ASPECT_16_9:
985 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
986 hdata->mode_conf.aspect_ratio |
987 AVI_16_9_CENTER_RATIO);
988 break;
989 case HDMI_PICTURE_ASPECT_NONE:
990 default:
991 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
992 hdata->mode_conf.aspect_ratio |
993 AVI_SAME_AS_PIC_ASPECT_RATIO);
994 break;
995 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530996
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900997 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530998 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
999
1000 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301001 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301002 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1003 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1004 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301005 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301006 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301007 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1008 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1009 infoframe->any.version);
1010 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1011 hdr_sum = infoframe->any.type + infoframe->any.version +
1012 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301013 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301014 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301015 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1016 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1017 break;
1018 default:
1019 break;
1020 }
1021}
1022
Sean Pauld9716ee2014-01-30 16:19:29 -05001023static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1024 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001025{
Sean Pauld9716ee2014-01-30 16:19:29 -05001026 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001027
Sean Paul5137c8c2014-04-03 20:41:03 +05301028 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1029
Sean Pauld9716ee2014-01-30 16:19:29 -05001030 return hdata->hpd ? connector_status_connected :
1031 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001032}
1033
Sean Pauld9716ee2014-01-30 16:19:29 -05001034static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001035{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001036}
1037
Sean Pauld9716ee2014-01-30 16:19:29 -05001038static struct drm_connector_funcs hdmi_connector_funcs = {
1039 .dpms = drm_helper_connector_dpms,
1040 .fill_modes = drm_helper_probe_single_connector_modes,
1041 .detect = hdmi_detect,
1042 .destroy = hdmi_connector_destroy,
1043};
1044
1045static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001046{
Sean Pauld9716ee2014-01-30 16:19:29 -05001047 struct hdmi_context *hdata = ctx_from_connector(connector);
1048 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001049
Inki Dae8fa04aa2014-03-13 16:38:31 +09001050 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001051 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001052
Inki Dae8fa04aa2014-03-13 16:38:31 +09001053 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001054 if (!edid)
1055 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001056
Sean Pauld9716ee2014-01-30 16:19:29 -05001057 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001058 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1059 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001060 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001061
Sean Pauld9716ee2014-01-30 16:19:29 -05001062 drm_mode_connector_update_edid_property(connector, edid);
1063
1064 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001065}
1066
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001067static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001068{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001069 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001070
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001071 for (i = 0; i < hdata->phy_conf_count; i++)
1072 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001073 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001074
1075 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1076 return -EINVAL;
1077}
1078
Sean Pauld9716ee2014-01-30 16:19:29 -05001079static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001080 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001081{
Sean Pauld9716ee2014-01-30 16:19:29 -05001082 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001083 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001084
Rahul Sharma16844fb2013-06-10 14:50:00 +05301085 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1086 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1087 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1088 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001089
Sean Paulf041b252014-01-30 16:19:15 -05001090 ret = mixer_check_mode(mode);
1091 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001092 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001093
Rahul Sharma16844fb2013-06-10 14:50:00 +05301094 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001095 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001096 return MODE_BAD;
1097
1098 return MODE_OK;
1099}
1100
1101static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1102{
1103 struct hdmi_context *hdata = ctx_from_connector(connector);
1104
1105 return hdata->encoder;
1106}
1107
1108static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1109 .get_modes = hdmi_get_modes,
1110 .mode_valid = hdmi_mode_valid,
1111 .best_encoder = hdmi_best_encoder,
1112};
1113
1114static int hdmi_create_connector(struct exynos_drm_display *display,
1115 struct drm_encoder *encoder)
1116{
1117 struct hdmi_context *hdata = display->ctx;
1118 struct drm_connector *connector = &hdata->connector;
1119 int ret;
1120
1121 hdata->encoder = encoder;
1122 connector->interlace_allowed = true;
1123 connector->polled = DRM_CONNECTOR_POLL_HPD;
1124
1125 ret = drm_connector_init(hdata->drm_dev, connector,
1126 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1127 if (ret) {
1128 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001129 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001130 }
1131
1132 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001133 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001134 drm_mode_connector_attach_encoder(connector, encoder);
1135
1136 return 0;
1137}
1138
Sean Paulf041b252014-01-30 16:19:15 -05001139static void hdmi_mode_fixup(struct exynos_drm_display *display,
1140 struct drm_connector *connector,
1141 const struct drm_display_mode *mode,
1142 struct drm_display_mode *adjusted_mode)
1143{
1144 struct drm_display_mode *m;
1145 int mode_ok;
1146
1147 DRM_DEBUG_KMS("%s\n", __FILE__);
1148
1149 drm_mode_set_crtcinfo(adjusted_mode, 0);
1150
Sean Pauld9716ee2014-01-30 16:19:29 -05001151 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001152
1153 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001154 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001155 return;
1156
1157 /*
1158 * otherwise, find the most suitable mode among modes and change it
1159 * to adjusted_mode.
1160 */
1161 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001162 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001163
Sean Pauld9716ee2014-01-30 16:19:29 -05001164 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001165 DRM_INFO("desired mode doesn't exist so\n");
1166 DRM_INFO("use the most suitable mode among modes.\n");
1167
1168 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1169 m->hdisplay, m->vdisplay, m->vrefresh);
1170
Sean Paul75626852014-01-30 16:19:16 -05001171 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001172 break;
1173 }
1174 }
1175}
1176
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001177static void hdmi_set_acr(u32 freq, u8 *acr)
1178{
1179 u32 n, cts;
1180
1181 switch (freq) {
1182 case 32000:
1183 n = 4096;
1184 cts = 27000;
1185 break;
1186 case 44100:
1187 n = 6272;
1188 cts = 30000;
1189 break;
1190 case 88200:
1191 n = 12544;
1192 cts = 30000;
1193 break;
1194 case 176400:
1195 n = 25088;
1196 cts = 30000;
1197 break;
1198 case 48000:
1199 n = 6144;
1200 cts = 27000;
1201 break;
1202 case 96000:
1203 n = 12288;
1204 cts = 27000;
1205 break;
1206 case 192000:
1207 n = 24576;
1208 cts = 27000;
1209 break;
1210 default:
1211 n = 0;
1212 cts = 0;
1213 break;
1214 }
1215
1216 acr[1] = cts >> 16;
1217 acr[2] = cts >> 8 & 0xff;
1218 acr[3] = cts & 0xff;
1219
1220 acr[4] = n >> 16;
1221 acr[5] = n >> 8 & 0xff;
1222 acr[6] = n & 0xff;
1223}
1224
1225static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1226{
1227 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1228 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1229 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1230 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1231 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1232 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1233 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1234 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1235 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1236
Rahul Sharma5a325072012-10-04 20:48:54 +05301237 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001238 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1239 else
1240 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1241}
1242
1243static void hdmi_audio_init(struct hdmi_context *hdata)
1244{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301245 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001246 u32 data_num, bit_ch, sample_frq;
1247 u32 val;
1248 u8 acr[7];
1249
1250 sample_rate = 44100;
1251 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001252
1253 switch (bits_per_sample) {
1254 case 20:
1255 data_num = 2;
1256 bit_ch = 1;
1257 break;
1258 case 24:
1259 data_num = 3;
1260 bit_ch = 1;
1261 break;
1262 default:
1263 data_num = 1;
1264 bit_ch = 0;
1265 break;
1266 }
1267
1268 hdmi_set_acr(sample_rate, acr);
1269 hdmi_reg_acr(hdata, acr);
1270
1271 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1272 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1273 | HDMI_I2S_MUX_ENABLE);
1274
1275 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1276 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1277
1278 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1279
1280 sample_frq = (sample_rate == 44100) ? 0 :
1281 (sample_rate == 48000) ? 2 :
1282 (sample_rate == 32000) ? 3 :
1283 (sample_rate == 96000) ? 0xa : 0x0;
1284
1285 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1286 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1287
1288 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1289 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1290
1291 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1292 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1293 | HDMI_I2S_SEL_LRCK(6));
1294 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1295 | HDMI_I2S_SEL_SDATA2(4));
1296 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1297 | HDMI_I2S_SEL_SDATA2(2));
1298 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1299
1300 /* I2S_CON_1 & 2 */
1301 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1302 | HDMI_I2S_L_CH_LOW_POL);
1303 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1304 | HDMI_I2S_SET_BIT_CH(bit_ch)
1305 | HDMI_I2S_SET_SDATA_BIT(data_num)
1306 | HDMI_I2S_BASIC_FORMAT);
1307
1308 /* Configure register related to CUV information */
1309 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1310 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1311 | HDMI_I2S_COPYRIGHT
1312 | HDMI_I2S_LINEAR_PCM
1313 | HDMI_I2S_CONSUMER_FORMAT);
1314 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1315 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1316 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1317 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1318 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1319 HDMI_I2S_ORG_SMP_FREQ_44_1
1320 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1321 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1322
1323 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1324}
1325
1326static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1327{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001328 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001329 return;
1330
1331 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1332 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1333 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1334}
1335
Rahul Sharmabfa48422014-04-03 20:41:04 +05301336static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001337{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301338 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001339
Rahul Sharmabfa48422014-04-03 20:41:04 +05301340 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1341 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001342
Rahul Sharmabfa48422014-04-03 20:41:04 +05301343 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1344 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001345}
1346
1347static void hdmi_conf_init(struct hdmi_context *hdata)
1348{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301349 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301350
Sean Paul77006a72013-01-16 10:17:20 -05001351 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001352 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1353 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001354
1355 /* choose HDMI mode */
1356 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1357 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301358 /* Apply Video preable and Guard band in HDMI mode only */
1359 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001360 /* disable bluescreen */
1361 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001362
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001363 if (hdata->dvi_mode) {
1364 /* choose DVI mode */
1365 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1366 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1367 hdmi_reg_writeb(hdata, HDMI_CON_2,
1368 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1369 }
1370
Rahul Sharma5a325072012-10-04 20:48:54 +05301371 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001372 /* choose bluescreen (fecal) color */
1373 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1374 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1375 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1376
1377 /* enable AVI packet every vsync, fixes purple line problem */
1378 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1379 /* force RGB, look to CEA-861-D, table 7 for more detail */
1380 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1381 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1382
1383 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1384 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1385 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1386 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301387 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1388 infoframe.any.version = HDMI_AVI_VERSION;
1389 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301390 hdmi_reg_infoframe(hdata, &infoframe);
1391
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301392 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1393 infoframe.any.version = HDMI_AUI_VERSION;
1394 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301395 hdmi_reg_infoframe(hdata, &infoframe);
1396
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001397 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001398 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1399 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001400}
1401
Rahul Sharma16844fb2013-06-10 14:50:00 +05301402static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001403{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001404 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1405 const struct hdmi_v13_core_regs *core =
1406 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001407 int tries;
1408
1409 /* setting core registers */
1410 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1411 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001412 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1413 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1414 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1415 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1416 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1417 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001418 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1419 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001420 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1421 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1422 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1423 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1424 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1425 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1426 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1427 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1428 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1429 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1430 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1431 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1432 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1433 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1434 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001435 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001436 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1437 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1438 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1439 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1440 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1441 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1442 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1443 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1444 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1445 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1446 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1447 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1448 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1449 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1450 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1451 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1452 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1453 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1454 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1455 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1456 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1457 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1463 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001464
1465 /* waiting for HDMIPHY's PLL to get to steady state */
1466 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001467 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001468 if (val & HDMI_PHY_STATUS_READY)
1469 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001470 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001471 }
1472 /* steady state not achieved */
1473 if (tries == 0) {
1474 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1475 hdmi_regs_dump(hdata, "timing apply");
1476 }
1477
Sean Paul0bfb1f82013-06-11 12:24:02 +05301478 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301479 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301480 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001481
1482 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301483 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001484}
1485
Rahul Sharma16844fb2013-06-10 14:50:00 +05301486static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001487{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001488 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1489 const struct hdmi_v14_core_regs *core =
1490 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001491 int tries;
1492
1493 /* setting core registers */
1494 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1495 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1496 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1497 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1498 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1499 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1500 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1501 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1502 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1503 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1504 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1505 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1506 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1507 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1508 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1509 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1510 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1511 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1512 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1513 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1514 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1515 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1516 core->v_sync_line_bef_2[0]);
1517 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1518 core->v_sync_line_bef_2[1]);
1519 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1520 core->v_sync_line_bef_1[0]);
1521 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1522 core->v_sync_line_bef_1[1]);
1523 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1524 core->v_sync_line_aft_2[0]);
1525 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1526 core->v_sync_line_aft_2[1]);
1527 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1528 core->v_sync_line_aft_1[0]);
1529 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1530 core->v_sync_line_aft_1[1]);
1531 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1532 core->v_sync_line_aft_pxl_2[0]);
1533 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1534 core->v_sync_line_aft_pxl_2[1]);
1535 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1536 core->v_sync_line_aft_pxl_1[0]);
1537 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1538 core->v_sync_line_aft_pxl_1[1]);
1539 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1540 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1541 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1542 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1543 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1544 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1545 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1546 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1547 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1548 core->v_sync_line_aft_3[0]);
1549 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1550 core->v_sync_line_aft_3[1]);
1551 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1552 core->v_sync_line_aft_4[0]);
1553 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1554 core->v_sync_line_aft_4[1]);
1555 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1556 core->v_sync_line_aft_5[0]);
1557 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1558 core->v_sync_line_aft_5[1]);
1559 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1560 core->v_sync_line_aft_6[0]);
1561 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1562 core->v_sync_line_aft_6[1]);
1563 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1564 core->v_sync_line_aft_pxl_3[0]);
1565 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1566 core->v_sync_line_aft_pxl_3[1]);
1567 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1568 core->v_sync_line_aft_pxl_4[0]);
1569 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1570 core->v_sync_line_aft_pxl_4[1]);
1571 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1572 core->v_sync_line_aft_pxl_5[0]);
1573 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1574 core->v_sync_line_aft_pxl_5[1]);
1575 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1576 core->v_sync_line_aft_pxl_6[0]);
1577 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1578 core->v_sync_line_aft_pxl_6[1]);
1579 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1580 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1581 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1582 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1583 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1584 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1585 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1586 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1587 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1588 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1589 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1590 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1591
1592 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001593 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1594 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1595 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1596 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1597 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1598 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1599 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1600 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1601 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1602 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1603 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1604 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1605 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1606 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1607 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1608 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1609 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1610 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1611 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1612 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1613 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1614 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1615 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001626
1627 /* waiting for HDMIPHY's PLL to get to steady state */
1628 for (tries = 100; tries; --tries) {
1629 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1630 if (val & HDMI_PHY_STATUS_READY)
1631 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001632 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001633 }
1634 /* steady state not achieved */
1635 if (tries == 0) {
1636 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1637 hdmi_regs_dump(hdata, "timing apply");
1638 }
1639
Sean Paul0bfb1f82013-06-11 12:24:02 +05301640 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301641 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301642 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001643
1644 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301645 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001646}
1647
Rahul Sharma16844fb2013-06-10 14:50:00 +05301648static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001649{
Rahul Sharma5a325072012-10-04 20:48:54 +05301650 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301651 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001652 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301653 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001654}
1655
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001656static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1657{
1658 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001659 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001660
Sean Paul0bfb1f82013-06-11 12:24:02 +05301661 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301662 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301663 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001664
1665 /* operation mode */
1666 buffer[0] = 0x1f;
1667 buffer[1] = 0x00;
1668
1669 if (hdata->hdmiphy_port)
1670 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1671
Rahul Sharma5a325072012-10-04 20:48:54 +05301672 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001673 reg = HDMI_V13_PHY_RSTOUT;
1674 else
1675 reg = HDMI_PHY_RSTOUT;
1676
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001677 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001678 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001679 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001680 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001681 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001682}
1683
Rahul Sharmaa5562252012-11-28 11:30:25 +05301684static void hdmiphy_poweron(struct hdmi_context *hdata)
1685{
Shirish S6a296e22014-04-03 20:41:02 +05301686 if (hdata->type != HDMI_TYPE14)
1687 return;
1688
1689 DRM_DEBUG_KMS("\n");
1690
1691 /* For PHY Mode Setting */
1692 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1693 HDMI_PHY_ENABLE_MODE_SET);
1694 /* Phy Power On */
1695 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1696 HDMI_PHY_POWER_ON);
1697 /* For PHY Mode Setting */
1698 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1699 HDMI_PHY_DISABLE_MODE_SET);
1700 /* PHY SW Reset */
1701 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301702}
1703
1704static void hdmiphy_poweroff(struct hdmi_context *hdata)
1705{
Shirish S6a296e22014-04-03 20:41:02 +05301706 if (hdata->type != HDMI_TYPE14)
1707 return;
1708
1709 DRM_DEBUG_KMS("\n");
1710
1711 /* PHY SW Reset */
1712 hdmiphy_conf_reset(hdata);
1713 /* For PHY Mode Setting */
1714 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1715 HDMI_PHY_ENABLE_MODE_SET);
1716
1717 /* PHY Power Off */
1718 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1719 HDMI_PHY_POWER_OFF);
1720
1721 /* For PHY Mode Setting */
1722 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1723 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301724}
1725
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001726static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1727{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001728 int ret;
1729 int i;
1730
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001731 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001732 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1733 if (i < 0) {
1734 DRM_ERROR("failed to find hdmiphy conf\n");
1735 return;
1736 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001737
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001738 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1739 if (ret) {
1740 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001741 return;
1742 }
1743
Sean Paul09760ea2013-01-14 17:03:20 -05001744 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001745
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001746 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1747 HDMI_PHY_DISABLE_MODE_SET);
1748 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001749 DRM_ERROR("failed to enable hdmiphy\n");
1750 return;
1751 }
1752
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001753}
1754
1755static void hdmi_conf_apply(struct hdmi_context *hdata)
1756{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001757 hdmiphy_conf_reset(hdata);
1758 hdmiphy_conf_apply(hdata);
1759
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001760 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301761 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001762 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001763 mutex_unlock(&hdata->hdmi_mutex);
1764
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001765 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001766
1767 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301768 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001769 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001770
1771 hdmi_regs_dump(hdata, "start");
1772}
1773
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001774static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1775{
1776 int i;
1777 BUG_ON(num_bytes > 4);
1778 for (i = 0; i < num_bytes; i++)
1779 reg_pair[i] = (value >> (8 * i)) & 0xff;
1780}
1781
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001782static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1783 struct drm_display_mode *m)
1784{
1785 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1786 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1787 unsigned int val;
1788
1789 hdata->mode_conf.cea_video_id =
1790 drm_match_cea_mode((struct drm_display_mode *)m);
1791 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301792 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001793
1794 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1795 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1796
1797 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1798 hdmi_set_reg(core->vsync_pol, 1, val);
1799
1800 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1801 hdmi_set_reg(core->int_pro_mode, 1, val);
1802
1803 val = (m->hsync_start - m->hdisplay - 2);
1804 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1805 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1806 hdmi_set_reg(core->h_sync_gen, 3, val);
1807
1808 /*
1809 * Quirk requirement for exynos HDMI IP design,
1810 * 2 pixels less than the actual calculation for hsync_start
1811 * and end.
1812 */
1813
1814 /* Following values & calculations differ for different type of modes */
1815 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1816 /* Interlaced Mode */
1817 val = ((m->vsync_end - m->vdisplay) / 2);
1818 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1819 hdmi_set_reg(core->v_sync_gen1, 3, val);
1820
1821 val = m->vtotal / 2;
1822 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1823 hdmi_set_reg(core->v_blank, 3, val);
1824
1825 val = (m->vtotal +
1826 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1827 val |= m->vtotal << 11;
1828 hdmi_set_reg(core->v_blank_f, 3, val);
1829
1830 val = ((m->vtotal / 2) + 7);
1831 val |= ((m->vtotal / 2) + 2) << 12;
1832 hdmi_set_reg(core->v_sync_gen2, 3, val);
1833
1834 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1835 val |= ((m->htotal / 2) +
1836 (m->hsync_start - m->hdisplay)) << 12;
1837 hdmi_set_reg(core->v_sync_gen3, 3, val);
1838
1839 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1840 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1841
1842 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1843 } else {
1844 /* Progressive Mode */
1845
1846 val = m->vtotal;
1847 val |= (m->vtotal - m->vdisplay) << 11;
1848 hdmi_set_reg(core->v_blank, 3, val);
1849
1850 hdmi_set_reg(core->v_blank_f, 3, 0);
1851
1852 val = (m->vsync_end - m->vdisplay);
1853 val |= ((m->vsync_start - m->vdisplay) << 12);
1854 hdmi_set_reg(core->v_sync_gen1, 3, val);
1855
1856 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1857 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1858 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1859 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1860 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1861 }
1862
1863 /* Timing generator registers */
1864 hdmi_set_reg(tg->cmd, 1, 0x0);
1865 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1866 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1867 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1868 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1869 hdmi_set_reg(tg->vsync, 2, 0x1);
1870 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1871 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1872 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1873 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1874 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1875 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1876 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1877}
1878
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001879static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1880 struct drm_display_mode *m)
1881{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001882 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1883 struct hdmi_v14_core_regs *core =
1884 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001885
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001886 hdata->mode_conf.cea_video_id =
1887 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001888 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301889 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001890
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001891 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1892 hdmi_set_reg(core->v_line, 2, m->vtotal);
1893 hdmi_set_reg(core->h_line, 2, m->htotal);
1894 hdmi_set_reg(core->hsync_pol, 1,
1895 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1896 hdmi_set_reg(core->vsync_pol, 1,
1897 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1898 hdmi_set_reg(core->int_pro_mode, 1,
1899 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1900
1901 /*
1902 * Quirk requirement for exynos 5 HDMI IP design,
1903 * 2 pixels less than the actual calculation for hsync_start
1904 * and end.
1905 */
1906
1907 /* Following values & calculations differ for different type of modes */
1908 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1909 /* Interlaced Mode */
1910 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1911 (m->vsync_end - m->vdisplay) / 2);
1912 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1913 (m->vsync_start - m->vdisplay) / 2);
1914 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1915 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301916 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001917 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1918 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1919 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1920 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1921 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1922 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1923 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1924 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1925 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301926 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1927 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1928 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1929 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001930 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1931 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1932 } else {
1933 /* Progressive Mode */
1934 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1935 m->vsync_end - m->vdisplay);
1936 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1937 m->vsync_start - m->vdisplay);
1938 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1939 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1940 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1941 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1942 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1943 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1944 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1945 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1946 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1947 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1948 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1949 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1950 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301951 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1952 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1953 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001954 }
1955
1956 /* Following values & calculations are same irrespective of mode type */
1957 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1958 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1959 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1960 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1961 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1962 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1963 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1964 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1965 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1966 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1967 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1968 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1969 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1970 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1971 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1972 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1973 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1974 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1975 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1976 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1977
1978 /* Timing generator registers */
1979 hdmi_set_reg(tg->cmd, 1, 0x0);
1980 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1981 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1982 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1983 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1984 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001985 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1986 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001987 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001988 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001989}
1990
Sean Paulf041b252014-01-30 16:19:15 -05001991static void hdmi_mode_set(struct exynos_drm_display *display,
1992 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001993{
Sean Paulf041b252014-01-30 16:19:15 -05001994 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001995 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001996
YoungJun Chocbc4c332013-06-12 10:44:40 +09001997 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1998 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001999 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
2000 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002001
Rahul Sharmabfa48422014-04-03 20:41:04 +05302002 /* preserve mode information for later use. */
2003 drm_mode_copy(&hdata->current_mode, mode);
2004
Sachin Kamat5f46c332013-04-26 11:29:00 +05302005 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002006 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302007 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002008 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002009}
2010
Sean Paulf041b252014-01-30 16:19:15 -05002011static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002012{
Sean Paulf041b252014-01-30 16:19:15 -05002013 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002014
Shirish Sdda90122013-01-23 22:03:18 -05002015 mutex_lock(&hdata->hdmi_mutex);
2016 if (!hdata->powered) {
2017 mutex_unlock(&hdata->hdmi_mutex);
2018 return;
2019 }
2020 mutex_unlock(&hdata->hdmi_mutex);
2021
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002022 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002023}
2024
Sean Paulf041b252014-01-30 16:19:15 -05002025static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002026{
Sean Paulf041b252014-01-30 16:19:15 -05002027 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002028 struct hdmi_resources *res = &hdata->res;
2029
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002030 mutex_lock(&hdata->hdmi_mutex);
2031 if (hdata->powered) {
2032 mutex_unlock(&hdata->hdmi_mutex);
2033 return;
2034 }
2035
2036 hdata->powered = true;
2037
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002038 mutex_unlock(&hdata->hdmi_mutex);
2039
Sean Paulaf65c802014-01-30 16:19:27 -05002040 pm_runtime_get_sync(hdata->dev);
2041
Seung-Woo Kimad079452013-06-05 14:34:38 +09002042 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2043 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2044
Rahul Sharma049d34e2014-05-20 10:36:05 +05302045 /* set pmu hdmiphy control bit to enable hdmiphy */
2046 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2047 PMU_HDMI_PHY_ENABLE_BIT, 1);
2048
Sean Paul0bfb1f82013-06-11 12:24:02 +05302049 clk_prepare_enable(res->hdmi);
2050 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302051
2052 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05002053 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002054}
2055
Sean Paulf041b252014-01-30 16:19:15 -05002056static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002057{
Sean Paulf041b252014-01-30 16:19:15 -05002058 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002059 struct hdmi_resources *res = &hdata->res;
2060
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002061 mutex_lock(&hdata->hdmi_mutex);
2062 if (!hdata->powered)
2063 goto out;
2064 mutex_unlock(&hdata->hdmi_mutex);
2065
Rahul Sharmabfa48422014-04-03 20:41:04 +05302066 /* HDMI System Disable */
2067 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2068
Rahul Sharmaa5562252012-11-28 11:30:25 +05302069 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002070
Sean Paul724fd142014-05-09 15:05:10 +09002071 cancel_delayed_work(&hdata->hotplug_work);
2072
Sean Paul0bfb1f82013-06-11 12:24:02 +05302073 clk_disable_unprepare(res->sclk_hdmi);
2074 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302075
2076 /* reset pmu hdmiphy control bit to disable hdmiphy */
2077 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2078 PMU_HDMI_PHY_ENABLE_BIT, 0);
2079
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002080 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2081
Sean Paulaf65c802014-01-30 16:19:27 -05002082 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002083
Sean Paulaf65c802014-01-30 16:19:27 -05002084 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002085 hdata->powered = false;
2086
2087out:
2088 mutex_unlock(&hdata->hdmi_mutex);
2089}
2090
Sean Paulf041b252014-01-30 16:19:15 -05002091static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002092{
Inki Dae245f98f2014-06-13 17:44:40 +09002093 struct hdmi_context *hdata = display->ctx;
2094 struct drm_encoder *encoder = hdata->encoder;
2095 struct drm_crtc *crtc = encoder->crtc;
2096 struct drm_crtc_helper_funcs *funcs = NULL;
2097
YoungJun Chocbc4c332013-06-12 10:44:40 +09002098 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002099
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002100 switch (mode) {
2101 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05002102 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002103 break;
2104 case DRM_MODE_DPMS_STANDBY:
2105 case DRM_MODE_DPMS_SUSPEND:
2106 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002107 /*
2108 * The SFRs of VP and Mixer are updated by Vertical Sync of
2109 * Timing generator which is a part of HDMI so the sequence
2110 * to disable TV Subsystem should be as following,
2111 * VP -> Mixer -> HDMI
2112 *
2113 * Below codes will try to disable Mixer and VP(if used)
2114 * prior to disabling HDMI.
2115 */
2116 if (crtc)
2117 funcs = crtc->helper_private;
2118 if (funcs && funcs->dpms)
2119 (*funcs->dpms)(crtc, mode);
2120
Sean Paulaf65c802014-01-30 16:19:27 -05002121 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002122 break;
2123 default:
2124 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2125 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002126 }
2127}
2128
Sean Paulf041b252014-01-30 16:19:15 -05002129static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002130 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002131 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002132 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002133 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002134 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002135};
2136
Sean Paulf041b252014-01-30 16:19:15 -05002137static struct exynos_drm_display hdmi_display = {
2138 .type = EXYNOS_DISPLAY_TYPE_HDMI,
2139 .ops = &hdmi_display_ops,
2140};
2141
Sean Paul724fd142014-05-09 15:05:10 +09002142static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002143{
Sean Paul724fd142014-05-09 15:05:10 +09002144 struct hdmi_context *hdata;
2145
2146 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002147
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002148 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302149 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002150 mutex_unlock(&hdata->hdmi_mutex);
2151
Sean Paul45517892014-01-30 16:19:05 -05002152 if (hdata->drm_dev)
2153 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002154}
2155
2156static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2157{
2158 struct hdmi_context *hdata = arg;
2159
2160 mod_delayed_work(system_wq, &hdata->hotplug_work,
2161 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002162
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002163 return IRQ_HANDLED;
2164}
2165
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002166static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002167{
2168 struct device *dev = hdata->dev;
2169 struct hdmi_resources *res = &hdata->res;
2170 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002171 "vdd",
2172 "vdd_osc",
2173 "vdd_pll",
2174 };
2175 int i, ret;
2176
2177 DRM_DEBUG_KMS("HDMI resource init\n");
2178
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002179 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302180 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302181 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002182 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002183 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002184 goto fail;
2185 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302186 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302187 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002188 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002189 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002190 goto fail;
2191 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302192 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302193 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002195 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196 goto fail;
2197 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302198 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302199 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002200 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002201 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002202 goto fail;
2203 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302204 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2205 if (IS_ERR(res->mout_hdmi)) {
2206 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002207 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302208 goto fail;
2209 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002210
Rahul Sharma59956d32013-06-11 12:24:03 +05302211 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002212
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302213 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302214 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002215 if (!res->regul_bulk) {
2216 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002217 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002218 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002219 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2220 res->regul_bulk[i].supply = supply[i];
2221 res->regul_bulk[i].consumer = NULL;
2222 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302223 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002224 if (ret) {
2225 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002226 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002227 }
2228 res->regul_count = ARRAY_SIZE(supply);
2229
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002230 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2231 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2232 DRM_ERROR("failed to get hdmi-en regulator\n");
2233 return PTR_ERR(res->reg_hdmi_en);
2234 }
2235 if (!IS_ERR(res->reg_hdmi_en)) {
2236 ret = regulator_enable(res->reg_hdmi_en);
2237 if (ret) {
2238 DRM_ERROR("failed to enable hdmi-en regulator\n");
2239 return ret;
2240 }
2241 } else
2242 res->reg_hdmi_en = NULL;
2243
Inki Daedf5225b2014-05-29 18:28:02 +09002244 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002245fail:
2246 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002247 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002248}
2249
Rahul Sharma22c4f422012-10-04 20:48:55 +05302250static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2251 (struct device *dev)
2252{
2253 struct device_node *np = dev->of_node;
2254 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302255 u32 value;
2256
2257 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002258 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302259 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302260
2261 if (!of_find_property(np, "hpd-gpio", &value)) {
2262 DRM_ERROR("no hpd gpio property found\n");
2263 goto err_data;
2264 }
2265
Rahul Sharma5f916e22013-06-11 19:41:29 +05302266 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302267
2268 return pd;
2269
2270err_data:
2271 return NULL;
2272}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302273
Rahul Sharma22c4f422012-10-04 20:48:55 +05302274static struct of_device_id hdmi_match_types[] = {
2275 {
2276 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002277 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302278 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302279 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002280 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302281 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302282 .compatible = "samsung,exynos5420-hdmi",
2283 .data = &exynos5420_hdmi_driver_data,
2284 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302285 /* end node */
2286 }
2287};
2288
Inki Daef37cd5e2014-05-09 14:25:20 +09002289static int hdmi_bind(struct device *dev, struct device *master, void *data)
2290{
2291 struct drm_device *drm_dev = data;
2292 struct hdmi_context *hdata;
2293
2294 hdata = hdmi_display.ctx;
2295 hdata->drm_dev = drm_dev;
2296
2297 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2298}
2299
2300static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2301{
2302 struct exynos_drm_display *display = get_hdmi_display(dev);
2303 struct drm_encoder *encoder = display->encoder;
2304 struct hdmi_context *hdata = display->ctx;
2305
2306 encoder->funcs->destroy(encoder);
2307 drm_connector_cleanup(&hdata->connector);
2308}
2309
2310static const struct component_ops hdmi_component_ops = {
2311 .bind = hdmi_bind,
2312 .unbind = hdmi_unbind,
2313};
2314
Inki Daee2a562d2014-05-09 16:46:10 +09002315static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2316{
2317 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2318 struct device_node *np;
2319
2320 np = of_find_compatible_node(NULL, NULL, compatible_str);
2321 if (np)
2322 return of_get_next_parent(np);
2323
2324 return NULL;
2325}
2326
2327static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2328{
2329 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2330
2331 return of_find_compatible_node(NULL, NULL, compatible_str);
2332}
2333
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002334static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002335{
Inki Daef37cd5e2014-05-09 14:25:20 +09002336 struct device_node *ddc_node, *phy_node;
2337 struct s5p_hdmi_platform_data *pdata;
2338 struct hdmi_driver_data *drv_data;
2339 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002340 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002341 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002342 struct resource *res;
2343 int ret;
2344
Inki Daedf5225b2014-05-29 18:28:02 +09002345 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
2346 hdmi_display.type);
2347 if (ret)
2348 return ret;
2349
2350 if (!dev->of_node) {
2351 ret = -ENODEV;
2352 goto err_del_component;
2353 }
Rahul Sharma22c4f422012-10-04 20:48:55 +05302354
Sachin Kamat88c49812013-08-28 10:47:57 +05302355 pdata = drm_hdmi_dt_parse_pdata(dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002356 if (!pdata) {
2357 ret = -EINVAL;
2358 goto err_del_component;
2359 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002360
Sachin Kamat88c49812013-08-28 10:47:57 +05302361 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002362 if (!hdata) {
2363 ret = -ENOMEM;
2364 goto err_del_component;
2365 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002366
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002367 mutex_init(&hdata->hdmi_mutex);
2368
Sean Paulf041b252014-01-30 16:19:15 -05002369 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002370
Sachin Kamat88c49812013-08-28 10:47:57 +05302371 match = of_match_node(hdmi_match_types, dev->of_node);
Inki Daedf5225b2014-05-29 18:28:02 +09002372 if (!match) {
2373 ret = -ENODEV;
2374 goto err_del_component;
2375 }
Inki Daebfe4e842014-03-06 14:18:17 +09002376
2377 drv_data = (struct hdmi_driver_data *)match->data;
2378 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002379 hdata->phy_confs = drv_data->phy_confs;
2380 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302381
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302382 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002383 hdata->dev = dev;
2384
2385 ret = hdmi_resources_init(hdata);
2386 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302387 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002388 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002389 }
2390
2391 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002392 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002393 if (IS_ERR(hdata->regs)) {
2394 ret = PTR_ERR(hdata->regs);
2395 goto err_del_component;
2396 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002397
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002398 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302399 if (ret) {
2400 DRM_ERROR("failed to request HPD gpio\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002401 goto err_del_component;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302402 }
2403
Inki Daee2a562d2014-05-09 16:46:10 +09002404 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2405 if (ddc_node)
2406 goto out_get_ddc_adpt;
2407
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002408 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002409 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2410 if (!ddc_node) {
2411 DRM_ERROR("Failed to find ddc node in device tree\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002412 ret = -ENODEV;
2413 goto err_del_component;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002414 }
Inki Daee2a562d2014-05-09 16:46:10 +09002415
2416out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002417 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2418 if (!hdata->ddc_adpt) {
2419 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002420 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002421 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002422
Inki Daee2a562d2014-05-09 16:46:10 +09002423 phy_node = hdmi_legacy_phy_dt_binding(dev);
2424 if (phy_node)
2425 goto out_get_phy_port;
2426
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002427 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002428 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2429 if (!phy_node) {
2430 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2431 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002432 goto err_ddc;
2433 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002434
Inki Daee2a562d2014-05-09 16:46:10 +09002435out_get_phy_port:
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002436 if (drv_data->is_apb_phy) {
2437 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2438 if (!hdata->regs_hdmiphy) {
2439 DRM_ERROR("failed to ioremap hdmi phy\n");
2440 ret = -ENOMEM;
2441 goto err_ddc;
2442 }
2443 } else {
2444 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2445 if (!hdata->hdmiphy_port) {
2446 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002447 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002448 goto err_ddc;
2449 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002450 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002451
Sean Paul77006a72013-01-16 10:17:20 -05002452 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2453 if (hdata->irq < 0) {
2454 DRM_ERROR("failed to get GPIO irq\n");
2455 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002456 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002457 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002458
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302459 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2460
Sean Paul724fd142014-05-09 15:05:10 +09002461 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2462
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002463 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002464 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002465 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002466 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002467 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002468 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002469 goto err_hdmiphy;
2470 }
2471
Rahul Sharma049d34e2014-05-20 10:36:05 +05302472 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2473 "samsung,syscon-phandle");
2474 if (IS_ERR(hdata->pmureg)) {
2475 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002476 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302477 goto err_hdmiphy;
2478 }
2479
Sean Paulaf65c802014-01-30 16:19:27 -05002480 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002481 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002482
Inki Daedf5225b2014-05-29 18:28:02 +09002483 ret = component_add(&pdev->dev, &hdmi_component_ops);
2484 if (ret)
2485 goto err_disable_pm_runtime;
2486
2487 return ret;
2488
2489err_disable_pm_runtime:
2490 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002491
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002492err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002493 if (hdata->hdmiphy_port)
2494 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002495err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002496 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002497
2498err_del_component:
2499 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
2500
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002501 return ret;
2502}
2503
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002504static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002505{
Inki Daef37cd5e2014-05-09 14:25:20 +09002506 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002507
Sean Paul724fd142014-05-09 15:05:10 +09002508 cancel_delayed_work_sync(&hdata->hotplug_work);
2509
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002510 if (hdata->res.reg_hdmi_en)
2511 regulator_disable(hdata->res.reg_hdmi_en);
2512
Daniel Kurtz2b768132014-02-24 18:52:51 +09002513 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002514 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002515
Sean Paulaf65c802014-01-30 16:19:27 -05002516 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002517 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002518
Inki Daedf5225b2014-05-29 18:28:02 +09002519 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002520 return 0;
2521}
2522
2523struct platform_driver hdmi_driver = {
2524 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002525 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002526 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302527 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002528 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302529 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002530 },
2531};