blob: 3cf09bb995a39c26720014d80725a6c43894ce53 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
25#include <linux/spinlock.h>
26#include <linux/wait.h>
27#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090028#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/irq.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/clk.h>
34#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053036#include <linux/of.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090037#include <linux/of_address.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053038#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053039#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090040#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053041#include <linux/mfd/syscon.h>
42#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090043
44#include <drm/exynos_drm.h>
45
46#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090047#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050048#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090049
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053050#include <linux/gpio.h>
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053051
Sean Pauld9716ee2014-01-30 16:19:29 -050052#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090053
Sean Paul724fd142014-05-09 15:05:10 +090054#define HOTPLUG_DEBOUNCE_MS 1100
55
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053056/* AVI header and aspect ratio */
57#define HDMI_AVI_VERSION 0x02
58#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053059
60/* AUI header info */
61#define HDMI_AUI_VERSION 0x01
62#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053063#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
64#define AVI_4_3_CENTER_RATIO 0x9
65#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053066
Rahul Sharma5a325072012-10-04 20:48:54 +053067enum hdmi_type {
68 HDMI_TYPE13,
69 HDMI_TYPE14,
70};
71
Inki Daebfe4e842014-03-06 14:18:17 +090072struct hdmi_driver_data {
73 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090074 const struct hdmiphy_config *phy_confs;
75 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090076 unsigned int is_apb_phy:1;
77};
78
Joonyoung Shim590f4182012-03-16 18:47:14 +090079struct hdmi_resources {
80 struct clk *hdmi;
81 struct clk *sclk_hdmi;
82 struct clk *sclk_pixel;
83 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053084 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090085 struct regulator_bulk_data *regul_bulk;
Marek Szyprowski05fdf982014-07-01 10:10:06 +020086 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +090087 int regul_count;
88};
89
Sean Paul2f7e2ed2013-01-15 08:11:08 -050090struct hdmi_tg_regs {
91 u8 cmd[1];
92 u8 h_fsz[2];
93 u8 hact_st[2];
94 u8 hact_sz[2];
95 u8 v_fsz[2];
96 u8 vsync[2];
97 u8 vsync2[2];
98 u8 vact_st[2];
99 u8 vact_sz[2];
100 u8 field_chg[2];
101 u8 vact_st2[2];
102 u8 vact_st3[2];
103 u8 vact_st4[2];
104 u8 vsync_top_hdmi[2];
105 u8 vsync_bot_hdmi[2];
106 u8 field_top_hdmi[2];
107 u8 field_bot_hdmi[2];
108 u8 tg_3d[1];
109};
110
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900111struct hdmi_v13_core_regs {
112 u8 h_blank[2];
113 u8 v_blank[3];
114 u8 h_v_line[3];
115 u8 vsync_pol[1];
116 u8 int_pro_mode[1];
117 u8 v_blank_f[3];
118 u8 h_sync_gen[3];
119 u8 v_sync_gen1[3];
120 u8 v_sync_gen2[3];
121 u8 v_sync_gen3[3];
122};
123
124struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500125 u8 h_blank[2];
126 u8 v2_blank[2];
127 u8 v1_blank[2];
128 u8 v_line[2];
129 u8 h_line[2];
130 u8 hsync_pol[1];
131 u8 vsync_pol[1];
132 u8 int_pro_mode[1];
133 u8 v_blank_f0[2];
134 u8 v_blank_f1[2];
135 u8 h_sync_start[2];
136 u8 h_sync_end[2];
137 u8 v_sync_line_bef_2[2];
138 u8 v_sync_line_bef_1[2];
139 u8 v_sync_line_aft_2[2];
140 u8 v_sync_line_aft_1[2];
141 u8 v_sync_line_aft_pxl_2[2];
142 u8 v_sync_line_aft_pxl_1[2];
143 u8 v_blank_f2[2]; /* for 3D mode */
144 u8 v_blank_f3[2]; /* for 3D mode */
145 u8 v_blank_f4[2]; /* for 3D mode */
146 u8 v_blank_f5[2]; /* for 3D mode */
147 u8 v_sync_line_aft_3[2];
148 u8 v_sync_line_aft_4[2];
149 u8 v_sync_line_aft_5[2];
150 u8 v_sync_line_aft_6[2];
151 u8 v_sync_line_aft_pxl_3[2];
152 u8 v_sync_line_aft_pxl_4[2];
153 u8 v_sync_line_aft_pxl_5[2];
154 u8 v_sync_line_aft_pxl_6[2];
155 u8 vact_space_1[2];
156 u8 vact_space_2[2];
157 u8 vact_space_3[2];
158 u8 vact_space_4[2];
159 u8 vact_space_5[2];
160 u8 vact_space_6[2];
161};
162
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163struct hdmi_v13_conf {
164 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500165 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166};
167
168struct hdmi_v14_conf {
169 struct hdmi_v14_core_regs core;
170 struct hdmi_tg_regs tg;
171};
172
173struct hdmi_conf_regs {
174 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500175 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530176 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900177 union {
178 struct hdmi_v13_conf v13_conf;
179 struct hdmi_v14_conf v14_conf;
180 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500181};
182
Joonyoung Shim590f4182012-03-16 18:47:14 +0900183struct hdmi_context {
Andrzej Hajda930865f2014-11-17 09:54:20 +0100184 struct exynos_drm_display display;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900185 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
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100216static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
217{
218 return container_of(d, struct hdmi_context, display);
219}
220
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500221struct hdmiphy_config {
222 int pixel_clock;
223 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900224};
225
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900226/* list of phy config settings */
227static const struct hdmiphy_config hdmiphy_v13_configs[] = {
228 {
229 .pixel_clock = 27000000,
230 .conf = {
231 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
232 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
233 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
234 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
235 },
236 },
237 {
238 .pixel_clock = 27027000,
239 .conf = {
240 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
241 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
242 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
243 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
244 },
245 },
246 {
247 .pixel_clock = 74176000,
248 .conf = {
249 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
250 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
251 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
252 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
253 },
254 },
255 {
256 .pixel_clock = 74250000,
257 .conf = {
258 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
259 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
260 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
261 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
262 },
263 },
264 {
265 .pixel_clock = 148500000,
266 .conf = {
267 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
268 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
269 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
270 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
271 },
272 },
273};
274
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500275static const struct hdmiphy_config hdmiphy_v14_configs[] = {
276 {
277 .pixel_clock = 25200000,
278 .conf = {
279 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
280 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
281 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
282 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
283 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900284 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500285 {
286 .pixel_clock = 27000000,
287 .conf = {
288 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
289 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
290 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
291 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
292 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900293 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500294 {
295 .pixel_clock = 27027000,
296 .conf = {
297 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
298 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
299 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
300 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
301 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900302 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500303 {
304 .pixel_clock = 36000000,
305 .conf = {
306 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
307 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
308 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
309 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
310 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900311 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500312 {
313 .pixel_clock = 40000000,
314 .conf = {
315 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
316 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
317 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
318 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
319 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900320 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500321 {
322 .pixel_clock = 65000000,
323 .conf = {
324 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
325 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
326 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
327 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
328 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900329 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500330 {
Shirish Se1d883c2014-03-13 14:28:27 +0900331 .pixel_clock = 71000000,
332 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530333 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
334 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
335 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900336 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
337 },
338 },
339 {
340 .pixel_clock = 73250000,
341 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530342 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
343 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
344 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900345 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
346 },
347 },
348 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500349 .pixel_clock = 74176000,
350 .conf = {
351 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
352 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
353 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
354 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
355 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900356 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500357 {
358 .pixel_clock = 74250000,
359 .conf = {
360 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
361 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
362 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
363 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
364 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900365 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500366 {
367 .pixel_clock = 83500000,
368 .conf = {
369 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
370 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
371 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
372 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
373 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900374 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500375 {
376 .pixel_clock = 106500000,
377 .conf = {
378 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
379 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
380 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
381 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
382 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900383 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500384 {
385 .pixel_clock = 108000000,
386 .conf = {
387 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
388 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
389 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
390 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
391 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900392 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500393 {
Shirish Se1d883c2014-03-13 14:28:27 +0900394 .pixel_clock = 115500000,
395 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530396 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
397 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
398 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900399 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
400 },
401 },
402 {
403 .pixel_clock = 119000000,
404 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530405 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
406 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
407 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900408 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
409 },
410 },
411 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500412 .pixel_clock = 146250000,
413 .conf = {
414 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
415 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
416 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
417 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
418 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900419 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500420 {
421 .pixel_clock = 148500000,
422 .conf = {
423 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
424 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
425 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
426 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
427 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900428 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900429};
430
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530431static const struct hdmiphy_config hdmiphy_5420_configs[] = {
432 {
433 .pixel_clock = 25200000,
434 .conf = {
435 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
436 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
437 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
438 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
439 },
440 },
441 {
442 .pixel_clock = 27000000,
443 .conf = {
444 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
445 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
446 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
447 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
448 },
449 },
450 {
451 .pixel_clock = 27027000,
452 .conf = {
453 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
454 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
455 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
456 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
457 },
458 },
459 {
460 .pixel_clock = 36000000,
461 .conf = {
462 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
463 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
464 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
465 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
466 },
467 },
468 {
469 .pixel_clock = 40000000,
470 .conf = {
471 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
472 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
473 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
474 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
475 },
476 },
477 {
478 .pixel_clock = 65000000,
479 .conf = {
480 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
481 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
482 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
483 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
484 },
485 },
486 {
487 .pixel_clock = 71000000,
488 .conf = {
489 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
490 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
491 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
492 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
493 },
494 },
495 {
496 .pixel_clock = 73250000,
497 .conf = {
498 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
499 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
500 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
501 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
502 },
503 },
504 {
505 .pixel_clock = 74176000,
506 .conf = {
507 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
508 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
509 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
510 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
511 },
512 },
513 {
514 .pixel_clock = 74250000,
515 .conf = {
516 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
517 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
518 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
519 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
520 },
521 },
522 {
523 .pixel_clock = 83500000,
524 .conf = {
525 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
526 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
527 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
528 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
529 },
530 },
531 {
532 .pixel_clock = 88750000,
533 .conf = {
534 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
535 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
536 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
537 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
538 },
539 },
540 {
541 .pixel_clock = 106500000,
542 .conf = {
543 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
544 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
545 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
546 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
547 },
548 },
549 {
550 .pixel_clock = 108000000,
551 .conf = {
552 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
553 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
554 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
555 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
556 },
557 },
558 {
559 .pixel_clock = 115500000,
560 .conf = {
561 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
562 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
563 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
564 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
565 },
566 },
567 {
568 .pixel_clock = 146250000,
569 .conf = {
570 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
571 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
572 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
573 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
574 },
575 },
576 {
577 .pixel_clock = 148500000,
578 .conf = {
579 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
580 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
581 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
582 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
583 },
584 },
585};
586
Sachin Kamat16337072014-05-22 10:32:56 +0530587static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530588 .type = HDMI_TYPE14,
589 .phy_confs = hdmiphy_5420_configs,
590 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
591 .is_apb_phy = 1,
592};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900593
Sachin Kamat16337072014-05-22 10:32:56 +0530594static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900595 .type = HDMI_TYPE14,
596 .phy_confs = hdmiphy_v14_configs,
597 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
598 .is_apb_phy = 0,
599};
600
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200601static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
602 .type = HDMI_TYPE13,
603 .phy_confs = hdmiphy_v13_configs,
604 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
605 .is_apb_phy = 0,
606};
607
Sachin Kamat16337072014-05-22 10:32:56 +0530608static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900609 .type = HDMI_TYPE14,
610 .phy_confs = hdmiphy_v13_configs,
611 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
612 .is_apb_phy = 0,
613};
614
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900615static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
616{
617 return readl(hdata->regs + reg_id);
618}
619
620static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
621 u32 reg_id, u8 value)
622{
623 writeb(value, hdata->regs + reg_id);
624}
625
626static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
627 u32 reg_id, u32 value, u32 mask)
628{
629 u32 old = readl(hdata->regs + reg_id);
630 value = (value & mask) | (old & ~mask);
631 writel(value, hdata->regs + reg_id);
632}
633
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900634static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
635 u32 reg_offset, u8 value)
636{
637 if (hdata->hdmiphy_port) {
638 u8 buffer[2];
639 int ret;
640
641 buffer[0] = reg_offset;
642 buffer[1] = value;
643
644 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
645 if (ret == 2)
646 return 0;
647 return ret;
648 } else {
649 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
650 return 0;
651 }
652}
653
654static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
655 u32 reg_offset, const u8 *buf, u32 len)
656{
657 if ((reg_offset + len) > 32)
658 return -EINVAL;
659
660 if (hdata->hdmiphy_port) {
661 int ret;
662
663 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
664 if (ret == len)
665 return 0;
666 return ret;
667 } else {
668 int i;
669 for (i = 0; i < len; i++)
670 writeb(buf[i], hdata->regs_hdmiphy +
671 ((reg_offset + i)<<2));
672 return 0;
673 }
674}
675
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900676static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900677{
678#define DUMPREG(reg_id) \
679 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
680 readl(hdata->regs + reg_id))
681 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
682 DUMPREG(HDMI_INTC_FLAG);
683 DUMPREG(HDMI_INTC_CON);
684 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900685 DUMPREG(HDMI_V13_PHY_RSTOUT);
686 DUMPREG(HDMI_V13_PHY_VPLL);
687 DUMPREG(HDMI_V13_PHY_CMU);
688 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900689
690 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
691 DUMPREG(HDMI_CON_0);
692 DUMPREG(HDMI_CON_1);
693 DUMPREG(HDMI_CON_2);
694 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900695 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900696 DUMPREG(HDMI_STATUS_EN);
697 DUMPREG(HDMI_HPD);
698 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900699 DUMPREG(HDMI_V13_HPD_GEN);
700 DUMPREG(HDMI_V13_DC_CONTROL);
701 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900702
703 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
704 DUMPREG(HDMI_H_BLANK_0);
705 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900706 DUMPREG(HDMI_V13_V_BLANK_0);
707 DUMPREG(HDMI_V13_V_BLANK_1);
708 DUMPREG(HDMI_V13_V_BLANK_2);
709 DUMPREG(HDMI_V13_H_V_LINE_0);
710 DUMPREG(HDMI_V13_H_V_LINE_1);
711 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900712 DUMPREG(HDMI_VSYNC_POL);
713 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900714 DUMPREG(HDMI_V13_V_BLANK_F_0);
715 DUMPREG(HDMI_V13_V_BLANK_F_1);
716 DUMPREG(HDMI_V13_V_BLANK_F_2);
717 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
718 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
719 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
720 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
721 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
722 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
723 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
724 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
725 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
726 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
727 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
728 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900729
730 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
731 DUMPREG(HDMI_TG_CMD);
732 DUMPREG(HDMI_TG_H_FSZ_L);
733 DUMPREG(HDMI_TG_H_FSZ_H);
734 DUMPREG(HDMI_TG_HACT_ST_L);
735 DUMPREG(HDMI_TG_HACT_ST_H);
736 DUMPREG(HDMI_TG_HACT_SZ_L);
737 DUMPREG(HDMI_TG_HACT_SZ_H);
738 DUMPREG(HDMI_TG_V_FSZ_L);
739 DUMPREG(HDMI_TG_V_FSZ_H);
740 DUMPREG(HDMI_TG_VSYNC_L);
741 DUMPREG(HDMI_TG_VSYNC_H);
742 DUMPREG(HDMI_TG_VSYNC2_L);
743 DUMPREG(HDMI_TG_VSYNC2_H);
744 DUMPREG(HDMI_TG_VACT_ST_L);
745 DUMPREG(HDMI_TG_VACT_ST_H);
746 DUMPREG(HDMI_TG_VACT_SZ_L);
747 DUMPREG(HDMI_TG_VACT_SZ_H);
748 DUMPREG(HDMI_TG_FIELD_CHG_L);
749 DUMPREG(HDMI_TG_FIELD_CHG_H);
750 DUMPREG(HDMI_TG_VACT_ST2_L);
751 DUMPREG(HDMI_TG_VACT_ST2_H);
752 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
753 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
754 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
755 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
756 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
757 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
758 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
759 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
760#undef DUMPREG
761}
762
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900763static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
764{
765 int i;
766
767#define DUMPREG(reg_id) \
768 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
769 readl(hdata->regs + reg_id))
770
771 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
772 DUMPREG(HDMI_INTC_CON);
773 DUMPREG(HDMI_INTC_FLAG);
774 DUMPREG(HDMI_HPD_STATUS);
775 DUMPREG(HDMI_INTC_CON_1);
776 DUMPREG(HDMI_INTC_FLAG_1);
777 DUMPREG(HDMI_PHY_STATUS_0);
778 DUMPREG(HDMI_PHY_STATUS_PLL);
779 DUMPREG(HDMI_PHY_CON_0);
780 DUMPREG(HDMI_PHY_RSTOUT);
781 DUMPREG(HDMI_PHY_VPLL);
782 DUMPREG(HDMI_PHY_CMU);
783 DUMPREG(HDMI_CORE_RSTOUT);
784
785 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
786 DUMPREG(HDMI_CON_0);
787 DUMPREG(HDMI_CON_1);
788 DUMPREG(HDMI_CON_2);
789 DUMPREG(HDMI_SYS_STATUS);
790 DUMPREG(HDMI_PHY_STATUS_0);
791 DUMPREG(HDMI_STATUS_EN);
792 DUMPREG(HDMI_HPD);
793 DUMPREG(HDMI_MODE_SEL);
794 DUMPREG(HDMI_ENC_EN);
795 DUMPREG(HDMI_DC_CONTROL);
796 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
797
798 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
799 DUMPREG(HDMI_H_BLANK_0);
800 DUMPREG(HDMI_H_BLANK_1);
801 DUMPREG(HDMI_V2_BLANK_0);
802 DUMPREG(HDMI_V2_BLANK_1);
803 DUMPREG(HDMI_V1_BLANK_0);
804 DUMPREG(HDMI_V1_BLANK_1);
805 DUMPREG(HDMI_V_LINE_0);
806 DUMPREG(HDMI_V_LINE_1);
807 DUMPREG(HDMI_H_LINE_0);
808 DUMPREG(HDMI_H_LINE_1);
809 DUMPREG(HDMI_HSYNC_POL);
810
811 DUMPREG(HDMI_VSYNC_POL);
812 DUMPREG(HDMI_INT_PRO_MODE);
813 DUMPREG(HDMI_V_BLANK_F0_0);
814 DUMPREG(HDMI_V_BLANK_F0_1);
815 DUMPREG(HDMI_V_BLANK_F1_0);
816 DUMPREG(HDMI_V_BLANK_F1_1);
817
818 DUMPREG(HDMI_H_SYNC_START_0);
819 DUMPREG(HDMI_H_SYNC_START_1);
820 DUMPREG(HDMI_H_SYNC_END_0);
821 DUMPREG(HDMI_H_SYNC_END_1);
822
823 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
824 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
825 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
826 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
827
828 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
829 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
830 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
831 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
832
833 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
834 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
835 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
836 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
837
838 DUMPREG(HDMI_V_BLANK_F2_0);
839 DUMPREG(HDMI_V_BLANK_F2_1);
840 DUMPREG(HDMI_V_BLANK_F3_0);
841 DUMPREG(HDMI_V_BLANK_F3_1);
842 DUMPREG(HDMI_V_BLANK_F4_0);
843 DUMPREG(HDMI_V_BLANK_F4_1);
844 DUMPREG(HDMI_V_BLANK_F5_0);
845 DUMPREG(HDMI_V_BLANK_F5_1);
846
847 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
848 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
849 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
850 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
851 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
852 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
853 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
854 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
855
856 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
857 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
858 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
859 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
860 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
861 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
862 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
863 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
864
865 DUMPREG(HDMI_VACT_SPACE_1_0);
866 DUMPREG(HDMI_VACT_SPACE_1_1);
867 DUMPREG(HDMI_VACT_SPACE_2_0);
868 DUMPREG(HDMI_VACT_SPACE_2_1);
869 DUMPREG(HDMI_VACT_SPACE_3_0);
870 DUMPREG(HDMI_VACT_SPACE_3_1);
871 DUMPREG(HDMI_VACT_SPACE_4_0);
872 DUMPREG(HDMI_VACT_SPACE_4_1);
873 DUMPREG(HDMI_VACT_SPACE_5_0);
874 DUMPREG(HDMI_VACT_SPACE_5_1);
875 DUMPREG(HDMI_VACT_SPACE_6_0);
876 DUMPREG(HDMI_VACT_SPACE_6_1);
877
878 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
879 DUMPREG(HDMI_TG_CMD);
880 DUMPREG(HDMI_TG_H_FSZ_L);
881 DUMPREG(HDMI_TG_H_FSZ_H);
882 DUMPREG(HDMI_TG_HACT_ST_L);
883 DUMPREG(HDMI_TG_HACT_ST_H);
884 DUMPREG(HDMI_TG_HACT_SZ_L);
885 DUMPREG(HDMI_TG_HACT_SZ_H);
886 DUMPREG(HDMI_TG_V_FSZ_L);
887 DUMPREG(HDMI_TG_V_FSZ_H);
888 DUMPREG(HDMI_TG_VSYNC_L);
889 DUMPREG(HDMI_TG_VSYNC_H);
890 DUMPREG(HDMI_TG_VSYNC2_L);
891 DUMPREG(HDMI_TG_VSYNC2_H);
892 DUMPREG(HDMI_TG_VACT_ST_L);
893 DUMPREG(HDMI_TG_VACT_ST_H);
894 DUMPREG(HDMI_TG_VACT_SZ_L);
895 DUMPREG(HDMI_TG_VACT_SZ_H);
896 DUMPREG(HDMI_TG_FIELD_CHG_L);
897 DUMPREG(HDMI_TG_FIELD_CHG_H);
898 DUMPREG(HDMI_TG_VACT_ST2_L);
899 DUMPREG(HDMI_TG_VACT_ST2_H);
900 DUMPREG(HDMI_TG_VACT_ST3_L);
901 DUMPREG(HDMI_TG_VACT_ST3_H);
902 DUMPREG(HDMI_TG_VACT_ST4_L);
903 DUMPREG(HDMI_TG_VACT_ST4_H);
904 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
905 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
906 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
907 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
908 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
909 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
910 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
911 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
912 DUMPREG(HDMI_TG_3D);
913
914 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
915 DUMPREG(HDMI_AVI_CON);
916 DUMPREG(HDMI_AVI_HEADER0);
917 DUMPREG(HDMI_AVI_HEADER1);
918 DUMPREG(HDMI_AVI_HEADER2);
919 DUMPREG(HDMI_AVI_CHECK_SUM);
920 DUMPREG(HDMI_VSI_CON);
921 DUMPREG(HDMI_VSI_HEADER0);
922 DUMPREG(HDMI_VSI_HEADER1);
923 DUMPREG(HDMI_VSI_HEADER2);
924 for (i = 0; i < 7; ++i)
925 DUMPREG(HDMI_VSI_DATA(i));
926
927#undef DUMPREG
928}
929
930static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
931{
Rahul Sharma5a325072012-10-04 20:48:54 +0530932 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900933 hdmi_v13_regs_dump(hdata, prefix);
934 else
935 hdmi_v14_regs_dump(hdata, prefix);
936}
937
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530938static u8 hdmi_chksum(struct hdmi_context *hdata,
939 u32 start, u8 len, u32 hdr_sum)
940{
941 int i;
942
943 /* hdr_sum : header0 + header1 + header2
944 * start : start address of packet byte1
945 * len : packet bytes - 1 */
946 for (i = 0; i < len; ++i)
947 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
948
949 /* return 2's complement of 8 bit hdr_sum */
950 return (u8)(~(hdr_sum & 0xff) + 1);
951}
952
953static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530954 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530955{
956 u32 hdr_sum;
957 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530958 u32 mod;
959 u32 vic;
960
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530961 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
962 if (hdata->dvi_mode) {
963 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
964 HDMI_VSI_CON_DO_NOT_TRANSMIT);
965 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
966 HDMI_AVI_CON_DO_NOT_TRANSMIT);
967 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
968 return;
969 }
970
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530971 switch (infoframe->any.type) {
972 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530973 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530974 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
975 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
976 infoframe->any.version);
977 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
978 hdr_sum = infoframe->any.type + infoframe->any.version +
979 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530980
981 /* Output format zero hardcoded ,RGB YBCR selection */
982 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
983 AVI_ACTIVE_FORMAT_VALID |
984 AVI_UNDERSCANNED_DISPLAY_VALID);
985
Shirish S46154152014-03-13 10:58:28 +0530986 /*
987 * Set the aspect ratio as per the mode, mentioned in
988 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
989 */
990 switch (hdata->mode_conf.aspect_ratio) {
991 case HDMI_PICTURE_ASPECT_4_3:
992 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
993 hdata->mode_conf.aspect_ratio |
994 AVI_4_3_CENTER_RATIO);
995 break;
996 case HDMI_PICTURE_ASPECT_16_9:
997 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
998 hdata->mode_conf.aspect_ratio |
999 AVI_16_9_CENTER_RATIO);
1000 break;
1001 case HDMI_PICTURE_ASPECT_NONE:
1002 default:
1003 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
1004 hdata->mode_conf.aspect_ratio |
1005 AVI_SAME_AS_PIC_ASPECT_RATIO);
1006 break;
1007 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301008
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001009 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301010 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
1011
1012 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301013 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301014 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1015 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1016 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301017 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301018 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301019 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1020 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1021 infoframe->any.version);
1022 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1023 hdr_sum = infoframe->any.type + infoframe->any.version +
1024 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301025 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301026 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301027 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1028 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1029 break;
1030 default:
1031 break;
1032 }
1033}
1034
Sean Pauld9716ee2014-01-30 16:19:29 -05001035static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1036 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001037{
Sean Pauld9716ee2014-01-30 16:19:29 -05001038 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -05001039
Sean Paul5137c8c2014-04-03 20:41:03 +05301040 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1041
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 return hdata->hpd ? connector_status_connected :
1043 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001044}
1045
Sean Pauld9716ee2014-01-30 16:19:29 -05001046static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001047{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001048 drm_connector_unregister(connector);
1049 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001050}
1051
Sean Pauld9716ee2014-01-30 16:19:29 -05001052static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001053 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001054 .fill_modes = drm_helper_probe_single_connector_modes,
1055 .detect = hdmi_detect,
1056 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001057 .reset = drm_atomic_helper_connector_reset,
1058 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1059 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001060};
1061
1062static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001063{
Sean Pauld9716ee2014-01-30 16:19:29 -05001064 struct hdmi_context *hdata = ctx_from_connector(connector);
1065 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001066 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001067
Inki Dae8fa04aa2014-03-13 16:38:31 +09001068 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001069 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001070
Inki Dae8fa04aa2014-03-13 16:38:31 +09001071 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001072 if (!edid)
1073 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001074
Sean Pauld9716ee2014-01-30 16:19:29 -05001075 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001076 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1077 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001078 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001079
Sean Pauld9716ee2014-01-30 16:19:29 -05001080 drm_mode_connector_update_edid_property(connector, edid);
1081
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001082 ret = drm_add_edid_modes(connector, edid);
1083
1084 kfree(edid);
1085
1086 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001087}
1088
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001089static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001090{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001091 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001092
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001093 for (i = 0; i < hdata->phy_conf_count; i++)
1094 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001095 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001096
1097 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1098 return -EINVAL;
1099}
1100
Sean Pauld9716ee2014-01-30 16:19:29 -05001101static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001102 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001103{
Sean Pauld9716ee2014-01-30 16:19:29 -05001104 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001105 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001106
Rahul Sharma16844fb2013-06-10 14:50:00 +05301107 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1108 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1109 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1110 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001111
Sean Paulf041b252014-01-30 16:19:15 -05001112 ret = mixer_check_mode(mode);
1113 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001114 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001115
Rahul Sharma16844fb2013-06-10 14:50:00 +05301116 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001117 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001118 return MODE_BAD;
1119
1120 return MODE_OK;
1121}
1122
1123static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1124{
1125 struct hdmi_context *hdata = ctx_from_connector(connector);
1126
1127 return hdata->encoder;
1128}
1129
1130static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1131 .get_modes = hdmi_get_modes,
1132 .mode_valid = hdmi_mode_valid,
1133 .best_encoder = hdmi_best_encoder,
1134};
1135
1136static int hdmi_create_connector(struct exynos_drm_display *display,
1137 struct drm_encoder *encoder)
1138{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01001139 struct hdmi_context *hdata = display_to_hdmi(display);
Sean Pauld9716ee2014-01-30 16:19:29 -05001140 struct drm_connector *connector = &hdata->connector;
1141 int ret;
1142
1143 hdata->encoder = encoder;
1144 connector->interlace_allowed = true;
1145 connector->polled = DRM_CONNECTOR_POLL_HPD;
1146
1147 ret = drm_connector_init(hdata->drm_dev, connector,
1148 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1149 if (ret) {
1150 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001151 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001152 }
1153
1154 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001155 drm_connector_register(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001156 drm_mode_connector_attach_encoder(connector, encoder);
1157
1158 return 0;
1159}
1160
Sean Paulf041b252014-01-30 16:19:15 -05001161static void hdmi_mode_fixup(struct exynos_drm_display *display,
1162 struct drm_connector *connector,
1163 const struct drm_display_mode *mode,
1164 struct drm_display_mode *adjusted_mode)
1165{
1166 struct drm_display_mode *m;
1167 int mode_ok;
1168
1169 DRM_DEBUG_KMS("%s\n", __FILE__);
1170
1171 drm_mode_set_crtcinfo(adjusted_mode, 0);
1172
Sean Pauld9716ee2014-01-30 16:19:29 -05001173 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001174
1175 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001176 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001177 return;
1178
1179 /*
1180 * otherwise, find the most suitable mode among modes and change it
1181 * to adjusted_mode.
1182 */
1183 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001184 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001185
Sean Pauld9716ee2014-01-30 16:19:29 -05001186 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001187 DRM_INFO("desired mode doesn't exist so\n");
1188 DRM_INFO("use the most suitable mode among modes.\n");
1189
1190 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1191 m->hdisplay, m->vdisplay, m->vrefresh);
1192
Sean Paul75626852014-01-30 16:19:16 -05001193 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001194 break;
1195 }
1196 }
1197}
1198
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001199static void hdmi_set_acr(u32 freq, u8 *acr)
1200{
1201 u32 n, cts;
1202
1203 switch (freq) {
1204 case 32000:
1205 n = 4096;
1206 cts = 27000;
1207 break;
1208 case 44100:
1209 n = 6272;
1210 cts = 30000;
1211 break;
1212 case 88200:
1213 n = 12544;
1214 cts = 30000;
1215 break;
1216 case 176400:
1217 n = 25088;
1218 cts = 30000;
1219 break;
1220 case 48000:
1221 n = 6144;
1222 cts = 27000;
1223 break;
1224 case 96000:
1225 n = 12288;
1226 cts = 27000;
1227 break;
1228 case 192000:
1229 n = 24576;
1230 cts = 27000;
1231 break;
1232 default:
1233 n = 0;
1234 cts = 0;
1235 break;
1236 }
1237
1238 acr[1] = cts >> 16;
1239 acr[2] = cts >> 8 & 0xff;
1240 acr[3] = cts & 0xff;
1241
1242 acr[4] = n >> 16;
1243 acr[5] = n >> 8 & 0xff;
1244 acr[6] = n & 0xff;
1245}
1246
1247static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1248{
1249 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1250 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1251 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1252 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1253 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1254 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1255 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1256 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1257 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1258
Rahul Sharma5a325072012-10-04 20:48:54 +05301259 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001260 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1261 else
1262 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1263}
1264
1265static void hdmi_audio_init(struct hdmi_context *hdata)
1266{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301267 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001268 u32 data_num, bit_ch, sample_frq;
1269 u32 val;
1270 u8 acr[7];
1271
1272 sample_rate = 44100;
1273 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001274
1275 switch (bits_per_sample) {
1276 case 20:
1277 data_num = 2;
1278 bit_ch = 1;
1279 break;
1280 case 24:
1281 data_num = 3;
1282 bit_ch = 1;
1283 break;
1284 default:
1285 data_num = 1;
1286 bit_ch = 0;
1287 break;
1288 }
1289
1290 hdmi_set_acr(sample_rate, acr);
1291 hdmi_reg_acr(hdata, acr);
1292
1293 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1294 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1295 | HDMI_I2S_MUX_ENABLE);
1296
1297 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1298 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1299
1300 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1301
1302 sample_frq = (sample_rate == 44100) ? 0 :
1303 (sample_rate == 48000) ? 2 :
1304 (sample_rate == 32000) ? 3 :
1305 (sample_rate == 96000) ? 0xa : 0x0;
1306
1307 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1308 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1309
1310 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1311 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1312
1313 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1314 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1315 | HDMI_I2S_SEL_LRCK(6));
1316 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1317 | HDMI_I2S_SEL_SDATA2(4));
1318 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1319 | HDMI_I2S_SEL_SDATA2(2));
1320 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1321
1322 /* I2S_CON_1 & 2 */
1323 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1324 | HDMI_I2S_L_CH_LOW_POL);
1325 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1326 | HDMI_I2S_SET_BIT_CH(bit_ch)
1327 | HDMI_I2S_SET_SDATA_BIT(data_num)
1328 | HDMI_I2S_BASIC_FORMAT);
1329
1330 /* Configure register related to CUV information */
1331 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1332 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1333 | HDMI_I2S_COPYRIGHT
1334 | HDMI_I2S_LINEAR_PCM
1335 | HDMI_I2S_CONSUMER_FORMAT);
1336 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1337 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1338 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1339 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1340 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1341 HDMI_I2S_ORG_SMP_FREQ_44_1
1342 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1343 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1344
1345 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1346}
1347
1348static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1349{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001350 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001351 return;
1352
1353 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1354 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1355 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1356}
1357
Rahul Sharmabfa48422014-04-03 20:41:04 +05301358static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001359{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301360 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001361
Rahul Sharmabfa48422014-04-03 20:41:04 +05301362 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1363 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001364
Rahul Sharmabfa48422014-04-03 20:41:04 +05301365 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1366 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001367}
1368
1369static void hdmi_conf_init(struct hdmi_context *hdata)
1370{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301371 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301372
Sean Paul77006a72013-01-16 10:17:20 -05001373 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001374 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1375 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001376
1377 /* choose HDMI mode */
1378 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1379 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301380 /* Apply Video preable and Guard band in HDMI mode only */
1381 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001382 /* disable bluescreen */
1383 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001384
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001385 if (hdata->dvi_mode) {
1386 /* choose DVI mode */
1387 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1388 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1389 hdmi_reg_writeb(hdata, HDMI_CON_2,
1390 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1391 }
1392
Rahul Sharma5a325072012-10-04 20:48:54 +05301393 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001394 /* choose bluescreen (fecal) color */
1395 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1396 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1397 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1398
1399 /* enable AVI packet every vsync, fixes purple line problem */
1400 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1401 /* force RGB, look to CEA-861-D, table 7 for more detail */
1402 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1403 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1404
1405 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1406 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1407 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1408 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301409 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1410 infoframe.any.version = HDMI_AVI_VERSION;
1411 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301412 hdmi_reg_infoframe(hdata, &infoframe);
1413
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301414 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1415 infoframe.any.version = HDMI_AUI_VERSION;
1416 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301417 hdmi_reg_infoframe(hdata, &infoframe);
1418
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001419 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001420 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1421 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001422}
1423
Rahul Sharma16844fb2013-06-10 14:50:00 +05301424static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001425{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001426 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1427 const struct hdmi_v13_core_regs *core =
1428 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001429 int tries;
1430
1431 /* setting core registers */
1432 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1433 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001434 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1435 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1436 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1437 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1438 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1439 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001440 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1441 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001442 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1443 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1444 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1445 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1446 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1447 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1448 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1449 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1450 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1451 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1452 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1453 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1454 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1455 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1456 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001457 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001458 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1461 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1462 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1463 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1464 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1465 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1466 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1467 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1468 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1469 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1470 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1471 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1472 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1473 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1474 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1475 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1476 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1477 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1478 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1479 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1480 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1481 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1482 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1483 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1484 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1485 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001486
1487 /* waiting for HDMIPHY's PLL to get to steady state */
1488 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001489 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001490 if (val & HDMI_PHY_STATUS_READY)
1491 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001492 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001493 }
1494 /* steady state not achieved */
1495 if (tries == 0) {
1496 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1497 hdmi_regs_dump(hdata, "timing apply");
1498 }
1499
Sean Paul0bfb1f82013-06-11 12:24:02 +05301500 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301501 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301502 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001503
1504 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301505 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001506}
1507
Rahul Sharma16844fb2013-06-10 14:50:00 +05301508static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001509{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001510 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1511 const struct hdmi_v14_core_regs *core =
1512 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001513 int tries;
1514
1515 /* setting core registers */
1516 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1517 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1518 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1519 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1520 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1521 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1522 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1523 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1524 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1525 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1526 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1527 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1528 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1529 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1530 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1531 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1532 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1533 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1534 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1535 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1536 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1537 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1538 core->v_sync_line_bef_2[0]);
1539 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1540 core->v_sync_line_bef_2[1]);
1541 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1542 core->v_sync_line_bef_1[0]);
1543 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1544 core->v_sync_line_bef_1[1]);
1545 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1546 core->v_sync_line_aft_2[0]);
1547 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1548 core->v_sync_line_aft_2[1]);
1549 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1550 core->v_sync_line_aft_1[0]);
1551 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1552 core->v_sync_line_aft_1[1]);
1553 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1554 core->v_sync_line_aft_pxl_2[0]);
1555 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1556 core->v_sync_line_aft_pxl_2[1]);
1557 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1558 core->v_sync_line_aft_pxl_1[0]);
1559 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1560 core->v_sync_line_aft_pxl_1[1]);
1561 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1562 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1563 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1564 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1565 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1566 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1567 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1568 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1569 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1570 core->v_sync_line_aft_3[0]);
1571 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1572 core->v_sync_line_aft_3[1]);
1573 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1574 core->v_sync_line_aft_4[0]);
1575 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1576 core->v_sync_line_aft_4[1]);
1577 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1578 core->v_sync_line_aft_5[0]);
1579 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1580 core->v_sync_line_aft_5[1]);
1581 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1582 core->v_sync_line_aft_6[0]);
1583 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1584 core->v_sync_line_aft_6[1]);
1585 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1586 core->v_sync_line_aft_pxl_3[0]);
1587 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1588 core->v_sync_line_aft_pxl_3[1]);
1589 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1590 core->v_sync_line_aft_pxl_4[0]);
1591 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1592 core->v_sync_line_aft_pxl_4[1]);
1593 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1594 core->v_sync_line_aft_pxl_5[0]);
1595 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1596 core->v_sync_line_aft_pxl_5[1]);
1597 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1598 core->v_sync_line_aft_pxl_6[0]);
1599 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1600 core->v_sync_line_aft_pxl_6[1]);
1601 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1602 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1603 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1604 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1605 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1606 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1607 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1608 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1609 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1610 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1611 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1612 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1613
1614 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001615 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1616 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1617 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1618 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1619 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1620 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1621 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1622 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1623 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1624 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1625 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1626 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1627 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1628 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1629 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1630 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1631 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1632 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1633 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1634 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1635 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1636 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1637 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1638 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1639 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1640 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1641 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1642 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1643 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1644 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1645 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1646 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1647 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001648
1649 /* waiting for HDMIPHY's PLL to get to steady state */
1650 for (tries = 100; tries; --tries) {
1651 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1652 if (val & HDMI_PHY_STATUS_READY)
1653 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001654 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001655 }
1656 /* steady state not achieved */
1657 if (tries == 0) {
1658 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1659 hdmi_regs_dump(hdata, "timing apply");
1660 }
1661
Sean Paul0bfb1f82013-06-11 12:24:02 +05301662 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301663 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301664 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001665
1666 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301667 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001668}
1669
Rahul Sharma16844fb2013-06-10 14:50:00 +05301670static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001671{
Rahul Sharma5a325072012-10-04 20:48:54 +05301672 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301673 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001674 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301675 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001676}
1677
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001678static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1679{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001680 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001681
Sean Paul0bfb1f82013-06-11 12:24:02 +05301682 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301683 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301684 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001685
1686 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001687 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1688 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001689
Rahul Sharma5a325072012-10-04 20:48:54 +05301690 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001691 reg = HDMI_V13_PHY_RSTOUT;
1692 else
1693 reg = HDMI_PHY_RSTOUT;
1694
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001695 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001696 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001697 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001698 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001699 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001700}
1701
Rahul Sharmaa5562252012-11-28 11:30:25 +05301702static void hdmiphy_poweron(struct hdmi_context *hdata)
1703{
Shirish S6a296e22014-04-03 20:41:02 +05301704 if (hdata->type != HDMI_TYPE14)
1705 return;
1706
1707 DRM_DEBUG_KMS("\n");
1708
1709 /* For PHY Mode Setting */
1710 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1711 HDMI_PHY_ENABLE_MODE_SET);
1712 /* Phy Power On */
1713 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1714 HDMI_PHY_POWER_ON);
1715 /* For PHY Mode Setting */
1716 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1717 HDMI_PHY_DISABLE_MODE_SET);
1718 /* PHY SW Reset */
1719 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301720}
1721
1722static void hdmiphy_poweroff(struct hdmi_context *hdata)
1723{
Shirish S6a296e22014-04-03 20:41:02 +05301724 if (hdata->type != HDMI_TYPE14)
1725 return;
1726
1727 DRM_DEBUG_KMS("\n");
1728
1729 /* PHY SW Reset */
1730 hdmiphy_conf_reset(hdata);
1731 /* For PHY Mode Setting */
1732 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1733 HDMI_PHY_ENABLE_MODE_SET);
1734
1735 /* PHY Power Off */
1736 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1737 HDMI_PHY_POWER_OFF);
1738
1739 /* For PHY Mode Setting */
1740 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1741 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301742}
1743
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001744static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1745{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001746 int ret;
1747 int i;
1748
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001749 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001750 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1751 if (i < 0) {
1752 DRM_ERROR("failed to find hdmiphy conf\n");
1753 return;
1754 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001755
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001756 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1757 if (ret) {
1758 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001759 return;
1760 }
1761
Sean Paul09760ea2013-01-14 17:03:20 -05001762 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001763
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001764 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1765 HDMI_PHY_DISABLE_MODE_SET);
1766 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001767 DRM_ERROR("failed to enable hdmiphy\n");
1768 return;
1769 }
1770
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001771}
1772
1773static void hdmi_conf_apply(struct hdmi_context *hdata)
1774{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001775 hdmiphy_conf_reset(hdata);
1776 hdmiphy_conf_apply(hdata);
1777
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001778 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301779 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001780 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001781 mutex_unlock(&hdata->hdmi_mutex);
1782
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001783 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001784
1785 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301786 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001787 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001788
1789 hdmi_regs_dump(hdata, "start");
1790}
1791
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001792static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1793{
1794 int i;
1795 BUG_ON(num_bytes > 4);
1796 for (i = 0; i < num_bytes; i++)
1797 reg_pair[i] = (value >> (8 * i)) & 0xff;
1798}
1799
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001800static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1801 struct drm_display_mode *m)
1802{
1803 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1804 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1805 unsigned int val;
1806
1807 hdata->mode_conf.cea_video_id =
1808 drm_match_cea_mode((struct drm_display_mode *)m);
1809 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301810 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001811
1812 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1813 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1814
1815 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1816 hdmi_set_reg(core->vsync_pol, 1, val);
1817
1818 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1819 hdmi_set_reg(core->int_pro_mode, 1, val);
1820
1821 val = (m->hsync_start - m->hdisplay - 2);
1822 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1823 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1824 hdmi_set_reg(core->h_sync_gen, 3, val);
1825
1826 /*
1827 * Quirk requirement for exynos HDMI IP design,
1828 * 2 pixels less than the actual calculation for hsync_start
1829 * and end.
1830 */
1831
1832 /* Following values & calculations differ for different type of modes */
1833 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1834 /* Interlaced Mode */
1835 val = ((m->vsync_end - m->vdisplay) / 2);
1836 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1837 hdmi_set_reg(core->v_sync_gen1, 3, val);
1838
1839 val = m->vtotal / 2;
1840 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1841 hdmi_set_reg(core->v_blank, 3, val);
1842
1843 val = (m->vtotal +
1844 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1845 val |= m->vtotal << 11;
1846 hdmi_set_reg(core->v_blank_f, 3, val);
1847
1848 val = ((m->vtotal / 2) + 7);
1849 val |= ((m->vtotal / 2) + 2) << 12;
1850 hdmi_set_reg(core->v_sync_gen2, 3, val);
1851
1852 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1853 val |= ((m->htotal / 2) +
1854 (m->hsync_start - m->hdisplay)) << 12;
1855 hdmi_set_reg(core->v_sync_gen3, 3, val);
1856
1857 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1858 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1859
1860 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1861 } else {
1862 /* Progressive Mode */
1863
1864 val = m->vtotal;
1865 val |= (m->vtotal - m->vdisplay) << 11;
1866 hdmi_set_reg(core->v_blank, 3, val);
1867
1868 hdmi_set_reg(core->v_blank_f, 3, 0);
1869
1870 val = (m->vsync_end - m->vdisplay);
1871 val |= ((m->vsync_start - m->vdisplay) << 12);
1872 hdmi_set_reg(core->v_sync_gen1, 3, val);
1873
1874 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1875 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1876 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1877 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1878 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1879 }
1880
1881 /* Timing generator registers */
1882 hdmi_set_reg(tg->cmd, 1, 0x0);
1883 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1884 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1885 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1886 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1887 hdmi_set_reg(tg->vsync, 2, 0x1);
1888 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1889 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1890 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1891 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1892 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1893 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1894 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1895}
1896
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001897static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1898 struct drm_display_mode *m)
1899{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001900 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1901 struct hdmi_v14_core_regs *core =
1902 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001903
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001904 hdata->mode_conf.cea_video_id =
1905 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001906 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301907 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001908
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001909 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1910 hdmi_set_reg(core->v_line, 2, m->vtotal);
1911 hdmi_set_reg(core->h_line, 2, m->htotal);
1912 hdmi_set_reg(core->hsync_pol, 1,
1913 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1914 hdmi_set_reg(core->vsync_pol, 1,
1915 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1916 hdmi_set_reg(core->int_pro_mode, 1,
1917 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1918
1919 /*
1920 * Quirk requirement for exynos 5 HDMI IP design,
1921 * 2 pixels less than the actual calculation for hsync_start
1922 * and end.
1923 */
1924
1925 /* Following values & calculations differ for different type of modes */
1926 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1927 /* Interlaced Mode */
1928 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1929 (m->vsync_end - m->vdisplay) / 2);
1930 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1931 (m->vsync_start - m->vdisplay) / 2);
1932 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1933 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301934 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001935 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1936 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1937 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1938 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1939 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1940 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1941 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1942 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1943 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301944 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1945 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1946 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1947 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001948 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1949 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1950 } else {
1951 /* Progressive Mode */
1952 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1953 m->vsync_end - m->vdisplay);
1954 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1955 m->vsync_start - m->vdisplay);
1956 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1957 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1958 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1959 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1960 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1961 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1962 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1963 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1964 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1965 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1966 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1967 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1968 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301969 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1970 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1971 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001972 }
1973
1974 /* Following values & calculations are same irrespective of mode type */
1975 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1976 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1977 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1978 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1979 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1980 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1981 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1982 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1983 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1984 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1985 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1986 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1987 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1988 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1989 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1990 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1991 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1992 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1993 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1994 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1995
1996 /* Timing generator registers */
1997 hdmi_set_reg(tg->cmd, 1, 0x0);
1998 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1999 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
2000 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
2001 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
2002 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002003 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
2004 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002005 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002006 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002007}
2008
Sean Paulf041b252014-01-30 16:19:15 -05002009static void hdmi_mode_set(struct exynos_drm_display *display,
2010 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002012 struct hdmi_context *hdata = display_to_hdmi(display);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002013 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002014
YoungJun Chocbc4c332013-06-12 10:44:40 +09002015 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
2016 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002017 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02002018 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002019
Rahul Sharmabfa48422014-04-03 20:41:04 +05302020 /* preserve mode information for later use. */
2021 drm_mode_copy(&hdata->current_mode, mode);
2022
Sachin Kamat5f46c332013-04-26 11:29:00 +05302023 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09002024 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05302025 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05002026 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002027}
2028
Sean Paulf041b252014-01-30 16:19:15 -05002029static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002030{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002031 struct hdmi_context *hdata = display_to_hdmi(display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002032
Shirish Sdda90122013-01-23 22:03:18 -05002033 mutex_lock(&hdata->hdmi_mutex);
2034 if (!hdata->powered) {
2035 mutex_unlock(&hdata->hdmi_mutex);
2036 return;
2037 }
2038 mutex_unlock(&hdata->hdmi_mutex);
2039
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002040 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002041}
2042
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002043static void hdmi_poweron(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002044{
2045 struct hdmi_resources *res = &hdata->res;
2046
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002047 mutex_lock(&hdata->hdmi_mutex);
2048 if (hdata->powered) {
2049 mutex_unlock(&hdata->hdmi_mutex);
2050 return;
2051 }
2052
2053 hdata->powered = true;
2054
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002055 mutex_unlock(&hdata->hdmi_mutex);
2056
Sean Paulaf65c802014-01-30 16:19:27 -05002057 pm_runtime_get_sync(hdata->dev);
2058
Seung-Woo Kimad079452013-06-05 14:34:38 +09002059 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
2060 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
2061
Rahul Sharma049d34e2014-05-20 10:36:05 +05302062 /* set pmu hdmiphy control bit to enable hdmiphy */
2063 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2064 PMU_HDMI_PHY_ENABLE_BIT, 1);
2065
Sean Paul0bfb1f82013-06-11 12:24:02 +05302066 clk_prepare_enable(res->hdmi);
2067 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05302068
2069 hdmiphy_poweron(hdata);
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002070 hdmi_commit(&hdata->display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002071}
2072
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002073static void hdmi_poweroff(struct hdmi_context *hdata)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002074{
2075 struct hdmi_resources *res = &hdata->res;
2076
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002077 mutex_lock(&hdata->hdmi_mutex);
2078 if (!hdata->powered)
2079 goto out;
2080 mutex_unlock(&hdata->hdmi_mutex);
2081
Rahul Sharmabfa48422014-04-03 20:41:04 +05302082 /* HDMI System Disable */
2083 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
2084
Rahul Sharmaa5562252012-11-28 11:30:25 +05302085 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002086
Sean Paul724fd142014-05-09 15:05:10 +09002087 cancel_delayed_work(&hdata->hotplug_work);
2088
Sean Paul0bfb1f82013-06-11 12:24:02 +05302089 clk_disable_unprepare(res->sclk_hdmi);
2090 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05302091
2092 /* reset pmu hdmiphy control bit to disable hdmiphy */
2093 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
2094 PMU_HDMI_PHY_ENABLE_BIT, 0);
2095
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002096 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2097
Sean Paulaf65c802014-01-30 16:19:27 -05002098 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002099
Sean Paulaf65c802014-01-30 16:19:27 -05002100 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002101 hdata->powered = false;
2102
2103out:
2104 mutex_unlock(&hdata->hdmi_mutex);
2105}
2106
Sean Paulf041b252014-01-30 16:19:15 -05002107static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002108{
Andrzej Hajda0d8424f82014-11-17 09:54:21 +01002109 struct hdmi_context *hdata = display_to_hdmi(display);
Inki Dae245f98f2014-06-13 17:44:40 +09002110 struct drm_encoder *encoder = hdata->encoder;
2111 struct drm_crtc *crtc = encoder->crtc;
Jani Nikulab0f87782015-03-11 11:50:59 +02002112 const struct drm_crtc_helper_funcs *funcs = NULL;
Inki Dae245f98f2014-06-13 17:44:40 +09002113
YoungJun Chocbc4c332013-06-12 10:44:40 +09002114 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002115
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002116 switch (mode) {
2117 case DRM_MODE_DPMS_ON:
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002118 hdmi_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002119 break;
2120 case DRM_MODE_DPMS_STANDBY:
2121 case DRM_MODE_DPMS_SUSPEND:
2122 case DRM_MODE_DPMS_OFF:
Inki Dae245f98f2014-06-13 17:44:40 +09002123 /*
2124 * The SFRs of VP and Mixer are updated by Vertical Sync of
2125 * Timing generator which is a part of HDMI so the sequence
2126 * to disable TV Subsystem should be as following,
2127 * VP -> Mixer -> HDMI
2128 *
2129 * Below codes will try to disable Mixer and VP(if used)
2130 * prior to disabling HDMI.
2131 */
2132 if (crtc)
2133 funcs = crtc->helper_private;
Gustavo Padovan63498e32015-06-01 12:04:53 -03002134 if (funcs && funcs->disable)
2135 (*funcs->disable)(crtc);
Inki Dae245f98f2014-06-13 17:44:40 +09002136
Joonyoung Shim92dc7a02015-01-30 16:43:02 +09002137 hdmi_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002138 break;
2139 default:
2140 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
2141 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002142 }
2143}
2144
Sean Paulf041b252014-01-30 16:19:15 -05002145static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05002146 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05002147 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002148 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05002149 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002150 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002151};
2152
Sean Paul724fd142014-05-09 15:05:10 +09002153static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002154{
Sean Paul724fd142014-05-09 15:05:10 +09002155 struct hdmi_context *hdata;
2156
2157 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002158
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002159 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302160 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002161 mutex_unlock(&hdata->hdmi_mutex);
2162
Sean Paul45517892014-01-30 16:19:05 -05002163 if (hdata->drm_dev)
2164 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09002165}
2166
2167static irqreturn_t hdmi_irq_thread(int irq, void *arg)
2168{
2169 struct hdmi_context *hdata = arg;
2170
2171 mod_delayed_work(system_wq, &hdata->hotplug_work,
2172 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002173
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002174 return IRQ_HANDLED;
2175}
2176
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002177static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002178{
2179 struct device *dev = hdata->dev;
2180 struct hdmi_resources *res = &hdata->res;
2181 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002182 "vdd",
2183 "vdd_osc",
2184 "vdd_pll",
2185 };
2186 int i, ret;
2187
2188 DRM_DEBUG_KMS("HDMI resource init\n");
2189
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002190 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302191 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302192 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002193 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002194 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002195 goto fail;
2196 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302197 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302198 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002199 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002200 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002201 goto fail;
2202 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302203 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302204 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002205 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002206 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002207 goto fail;
2208 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302209 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05302210 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002211 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002212 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002213 goto fail;
2214 }
Rahul Sharma59956d32013-06-11 12:24:03 +05302215 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
2216 if (IS_ERR(res->mout_hdmi)) {
2217 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002218 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05302219 goto fail;
2220 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002221
Rahul Sharma59956d32013-06-11 12:24:03 +05302222 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002223
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302224 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05302225 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09002226 if (!res->regul_bulk) {
2227 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002228 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09002229 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002230 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2231 res->regul_bulk[i].supply = supply[i];
2232 res->regul_bulk[i].consumer = NULL;
2233 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302234 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002235 if (ret) {
2236 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002237 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002238 }
2239 res->regul_count = ARRAY_SIZE(supply);
2240
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002241 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
2242 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
2243 DRM_ERROR("failed to get hdmi-en regulator\n");
2244 return PTR_ERR(res->reg_hdmi_en);
2245 }
2246 if (!IS_ERR(res->reg_hdmi_en)) {
2247 ret = regulator_enable(res->reg_hdmi_en);
2248 if (ret) {
2249 DRM_ERROR("failed to enable hdmi-en regulator\n");
2250 return ret;
2251 }
2252 } else
2253 res->reg_hdmi_en = NULL;
2254
Inki Daedf5225b2014-05-29 18:28:02 +09002255 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002256fail:
2257 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002258 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002259}
2260
Rahul Sharma22c4f422012-10-04 20:48:55 +05302261static struct of_device_id hdmi_match_types[] = {
2262 {
2263 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002264 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302265 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02002266 .compatible = "samsung,exynos4210-hdmi",
2267 .data = &exynos4210_hdmi_driver_data,
2268 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302269 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002270 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302271 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05302272 .compatible = "samsung,exynos5420-hdmi",
2273 .data = &exynos5420_hdmi_driver_data,
2274 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302275 /* end node */
2276 }
2277};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02002278MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302279
Inki Daef37cd5e2014-05-09 14:25:20 +09002280static int hdmi_bind(struct device *dev, struct device *master, void *data)
2281{
2282 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002283 struct hdmi_context *hdata = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002284
Inki Daef37cd5e2014-05-09 14:25:20 +09002285 hdata->drm_dev = drm_dev;
2286
Andrzej Hajda930865f2014-11-17 09:54:20 +01002287 return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
Inki Daef37cd5e2014-05-09 14:25:20 +09002288}
2289
2290static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2291{
Inki Daef37cd5e2014-05-09 14:25:20 +09002292}
2293
2294static const struct component_ops hdmi_component_ops = {
2295 .bind = hdmi_bind,
2296 .unbind = hdmi_unbind,
2297};
2298
Inki Daee2a562d2014-05-09 16:46:10 +09002299static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
2300{
2301 const char *compatible_str = "samsung,exynos4210-hdmiddc";
2302 struct device_node *np;
2303
2304 np = of_find_compatible_node(NULL, NULL, compatible_str);
2305 if (np)
2306 return of_get_next_parent(np);
2307
2308 return NULL;
2309}
2310
2311static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2312{
2313 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2314
2315 return of_find_compatible_node(NULL, NULL, compatible_str);
2316}
2317
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002318static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002319{
Inki Daef37cd5e2014-05-09 14:25:20 +09002320 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09002321 struct hdmi_driver_data *drv_data;
2322 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002323 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002324 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002325 struct resource *res;
2326 int ret;
2327
Andrzej Hajda930865f2014-11-17 09:54:20 +01002328 if (!dev->of_node)
2329 return -ENODEV;
2330
Andrzej Hajda930865f2014-11-17 09:54:20 +01002331 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2332 if (!hdata)
2333 return -ENOMEM;
2334
2335 hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
2336 hdata->display.ops = &hdmi_display_ops;
2337
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002338 mutex_init(&hdata->hdmi_mutex);
2339
Andrzej Hajda930865f2014-11-17 09:54:20 +01002340 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002341
Sachin Kamat88c49812013-08-28 10:47:57 +05302342 match = of_match_node(hdmi_match_types, dev->of_node);
Andrzej Hajda86650402015-06-11 23:23:37 +09002343 if (!match)
2344 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002345
2346 drv_data = (struct hdmi_driver_data *)match->data;
2347 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002348 hdata->phy_confs = drv_data->phy_confs;
2349 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302350
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002351 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002352 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2353 if (hdata->hpd_gpio < 0) {
2354 DRM_ERROR("cannot get hpd gpio property\n");
2355 return hdata->hpd_gpio;
2356 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002357
2358 ret = hdmi_resources_init(hdata);
2359 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302360 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002361 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002362 }
2363
2364 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002365 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002366 if (IS_ERR(hdata->regs)) {
2367 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002368 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002369 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002370
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002371 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302372 if (ret) {
2373 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002374 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302375 }
2376
Inki Daee2a562d2014-05-09 16:46:10 +09002377 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2378 if (ddc_node)
2379 goto out_get_ddc_adpt;
2380
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002381 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002382 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2383 if (!ddc_node) {
2384 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002385 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002386 }
Inki Daee2a562d2014-05-09 16:46:10 +09002387
2388out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002389 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2390 if (!hdata->ddc_adpt) {
2391 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002392 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002393 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002394
Inki Daee2a562d2014-05-09 16:46:10 +09002395 phy_node = hdmi_legacy_phy_dt_binding(dev);
2396 if (phy_node)
2397 goto out_get_phy_port;
2398
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002399 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002400 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2401 if (!phy_node) {
2402 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2403 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002404 goto err_ddc;
2405 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002406
Inki Daee2a562d2014-05-09 16:46:10 +09002407out_get_phy_port:
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002408 if (drv_data->is_apb_phy) {
2409 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2410 if (!hdata->regs_hdmiphy) {
2411 DRM_ERROR("failed to ioremap hdmi phy\n");
2412 ret = -ENOMEM;
2413 goto err_ddc;
2414 }
2415 } else {
2416 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2417 if (!hdata->hdmiphy_port) {
2418 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002419 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002420 goto err_ddc;
2421 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002422 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002423
Sean Paul77006a72013-01-16 10:17:20 -05002424 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2425 if (hdata->irq < 0) {
2426 DRM_ERROR("failed to get GPIO irq\n");
2427 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002428 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002429 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002430
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302431 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2432
Sean Paul724fd142014-05-09 15:05:10 +09002433 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2434
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002435 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002436 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002437 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002438 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002439 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002440 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002441 goto err_hdmiphy;
2442 }
2443
Rahul Sharma049d34e2014-05-20 10:36:05 +05302444 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2445 "samsung,syscon-phandle");
2446 if (IS_ERR(hdata->pmureg)) {
2447 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002448 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302449 goto err_hdmiphy;
2450 }
2451
Sean Paulaf65c802014-01-30 16:19:27 -05002452 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002453
Inki Daedf5225b2014-05-29 18:28:02 +09002454 ret = component_add(&pdev->dev, &hdmi_component_ops);
2455 if (ret)
2456 goto err_disable_pm_runtime;
2457
2458 return ret;
2459
2460err_disable_pm_runtime:
2461 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002462
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002463err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002464 if (hdata->hdmiphy_port)
2465 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002466err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002467 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002468
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002469 return ret;
2470}
2471
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002472static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002473{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002474 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002475
Sean Paul724fd142014-05-09 15:05:10 +09002476 cancel_delayed_work_sync(&hdata->hotplug_work);
2477
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002478 if (hdata->res.reg_hdmi_en)
2479 regulator_disable(hdata->res.reg_hdmi_en);
2480
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002481 if (hdata->hdmiphy_port)
2482 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002483 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002484
Sean Paulaf65c802014-01-30 16:19:27 -05002485 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002486 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002487
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002488 return 0;
2489}
2490
2491struct platform_driver hdmi_driver = {
2492 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002493 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002494 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302495 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002496 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302497 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002498 },
2499};