blob: 148e42fe1a516140872e5b23ea1c64db0ccda420 [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>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053034#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090035#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020036#include <linux/of_device.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053037#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Gustavo Padovana2986e82015-08-05 20:24:20 -030047#include "exynos_drm_encoder.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
90struct hdmi_context {
Gustavo Padovancf67cc92015-08-11 17:38:06 +090091 struct exynos_drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +090092 struct device *dev;
93 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -050094 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +090095 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090096 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +090097 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +090098
Joonyoung Shim590f4182012-03-16 18:47:14 +090099 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500100 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900101 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900102
Inki Dae8fa04aa2014-03-13 16:38:31 +0900103 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900104 struct i2c_client *hdmiphy_port;
105
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900106 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530107 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200108 u8 cea_video_id;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900109
110 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200111 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900112
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530113 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900114 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530115
Rahul Sharma049d34e2014-05-20 10:36:05 +0530116 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900117};
118
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900119static inline struct hdmi_context *encoder_to_hdmi(struct exynos_drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100120{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900121 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100122}
123
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500124struct hdmiphy_config {
125 int pixel_clock;
126 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900127};
128
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900129/* list of phy config settings */
130static const struct hdmiphy_config hdmiphy_v13_configs[] = {
131 {
132 .pixel_clock = 27000000,
133 .conf = {
134 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
135 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
136 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
137 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
138 },
139 },
140 {
141 .pixel_clock = 27027000,
142 .conf = {
143 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
144 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
145 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
146 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
147 },
148 },
149 {
150 .pixel_clock = 74176000,
151 .conf = {
152 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
153 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
154 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
155 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
156 },
157 },
158 {
159 .pixel_clock = 74250000,
160 .conf = {
161 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
162 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
163 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
164 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
165 },
166 },
167 {
168 .pixel_clock = 148500000,
169 .conf = {
170 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
171 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
172 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
173 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
174 },
175 },
176};
177
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500178static const struct hdmiphy_config hdmiphy_v14_configs[] = {
179 {
180 .pixel_clock = 25200000,
181 .conf = {
182 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
183 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
184 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
185 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
186 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900187 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500188 {
189 .pixel_clock = 27000000,
190 .conf = {
191 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
192 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
193 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
194 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
195 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900196 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500197 {
198 .pixel_clock = 27027000,
199 .conf = {
200 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
201 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
202 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
203 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
204 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900205 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500206 {
207 .pixel_clock = 36000000,
208 .conf = {
209 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
210 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
211 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
212 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
213 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900214 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500215 {
216 .pixel_clock = 40000000,
217 .conf = {
218 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
219 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
220 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
221 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
222 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900223 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500224 {
225 .pixel_clock = 65000000,
226 .conf = {
227 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
228 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
229 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
230 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
231 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900232 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500233 {
Shirish Se1d883c2014-03-13 14:28:27 +0900234 .pixel_clock = 71000000,
235 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530236 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
237 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
238 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900239 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
240 },
241 },
242 {
243 .pixel_clock = 73250000,
244 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530245 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
246 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
247 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900248 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
249 },
250 },
251 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500252 .pixel_clock = 74176000,
253 .conf = {
254 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
255 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
256 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
257 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
258 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900259 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500260 {
261 .pixel_clock = 74250000,
262 .conf = {
263 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
264 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
265 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
266 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
267 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900268 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500269 {
270 .pixel_clock = 83500000,
271 .conf = {
272 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
273 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
274 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
275 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
276 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900277 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500278 {
279 .pixel_clock = 106500000,
280 .conf = {
281 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
282 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
283 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
284 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
285 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900286 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500287 {
288 .pixel_clock = 108000000,
289 .conf = {
290 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
291 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
292 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
293 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
294 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900295 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500296 {
Shirish Se1d883c2014-03-13 14:28:27 +0900297 .pixel_clock = 115500000,
298 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530299 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
300 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
301 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900302 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
303 },
304 },
305 {
306 .pixel_clock = 119000000,
307 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530308 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
309 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
310 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900311 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
312 },
313 },
314 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500315 .pixel_clock = 146250000,
316 .conf = {
317 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
318 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
319 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
320 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
321 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900322 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500323 {
324 .pixel_clock = 148500000,
325 .conf = {
326 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
327 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
328 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
329 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
330 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900331 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900332};
333
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530334static const struct hdmiphy_config hdmiphy_5420_configs[] = {
335 {
336 .pixel_clock = 25200000,
337 .conf = {
338 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
339 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
340 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
341 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
342 },
343 },
344 {
345 .pixel_clock = 27000000,
346 .conf = {
347 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
348 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
349 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
350 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
351 },
352 },
353 {
354 .pixel_clock = 27027000,
355 .conf = {
356 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
357 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
358 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
359 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
360 },
361 },
362 {
363 .pixel_clock = 36000000,
364 .conf = {
365 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
366 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
367 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
368 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
369 },
370 },
371 {
372 .pixel_clock = 40000000,
373 .conf = {
374 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
375 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
376 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
377 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
378 },
379 },
380 {
381 .pixel_clock = 65000000,
382 .conf = {
383 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
384 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
385 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
386 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
387 },
388 },
389 {
390 .pixel_clock = 71000000,
391 .conf = {
392 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
393 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
394 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
395 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
396 },
397 },
398 {
399 .pixel_clock = 73250000,
400 .conf = {
401 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
402 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
403 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
404 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
405 },
406 },
407 {
408 .pixel_clock = 74176000,
409 .conf = {
410 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
411 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
412 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
413 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
414 },
415 },
416 {
417 .pixel_clock = 74250000,
418 .conf = {
419 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
420 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
421 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
422 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
423 },
424 },
425 {
426 .pixel_clock = 83500000,
427 .conf = {
428 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
429 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
430 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
431 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
432 },
433 },
434 {
435 .pixel_clock = 88750000,
436 .conf = {
437 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
438 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
439 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
440 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
441 },
442 },
443 {
444 .pixel_clock = 106500000,
445 .conf = {
446 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
447 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
448 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
449 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
450 },
451 },
452 {
453 .pixel_clock = 108000000,
454 .conf = {
455 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
456 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
457 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
458 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
459 },
460 },
461 {
462 .pixel_clock = 115500000,
463 .conf = {
464 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
465 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
466 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
467 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
468 },
469 },
470 {
471 .pixel_clock = 146250000,
472 .conf = {
473 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
474 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
475 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
476 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
477 },
478 },
479 {
480 .pixel_clock = 148500000,
481 .conf = {
482 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
483 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
484 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
485 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
486 },
487 },
488};
489
Sachin Kamat16337072014-05-22 10:32:56 +0530490static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530491 .type = HDMI_TYPE14,
492 .phy_confs = hdmiphy_5420_configs,
493 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
494 .is_apb_phy = 1,
495};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900496
Sachin Kamat16337072014-05-22 10:32:56 +0530497static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900498 .type = HDMI_TYPE14,
499 .phy_confs = hdmiphy_v14_configs,
500 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
501 .is_apb_phy = 0,
502};
503
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200504static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
505 .type = HDMI_TYPE13,
506 .phy_confs = hdmiphy_v13_configs,
507 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
508 .is_apb_phy = 0,
509};
510
Sachin Kamat16337072014-05-22 10:32:56 +0530511static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900512 .type = HDMI_TYPE14,
513 .phy_confs = hdmiphy_v13_configs,
514 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
515 .is_apb_phy = 0,
516};
517
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900518static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
519{
520 return readl(hdata->regs + reg_id);
521}
522
523static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
524 u32 reg_id, u8 value)
525{
526 writeb(value, hdata->regs + reg_id);
527}
528
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200529static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
530 int bytes, u32 val)
531{
532 while (--bytes >= 0) {
533 writeb(val & 0xff, hdata->regs + reg_id);
534 val >>= 8;
535 reg_id += 4;
536 }
537}
538
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900539static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
540 u32 reg_id, u32 value, u32 mask)
541{
542 u32 old = readl(hdata->regs + reg_id);
543 value = (value & mask) | (old & ~mask);
544 writel(value, hdata->regs + reg_id);
545}
546
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900547static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
548 u32 reg_offset, u8 value)
549{
550 if (hdata->hdmiphy_port) {
551 u8 buffer[2];
552 int ret;
553
554 buffer[0] = reg_offset;
555 buffer[1] = value;
556
557 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
558 if (ret == 2)
559 return 0;
560 return ret;
561 } else {
562 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
563 return 0;
564 }
565}
566
567static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
568 u32 reg_offset, const u8 *buf, u32 len)
569{
570 if ((reg_offset + len) > 32)
571 return -EINVAL;
572
573 if (hdata->hdmiphy_port) {
574 int ret;
575
576 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
577 if (ret == len)
578 return 0;
579 return ret;
580 } else {
581 int i;
582 for (i = 0; i < len; i++)
583 writeb(buf[i], hdata->regs_hdmiphy +
584 ((reg_offset + i)<<2));
585 return 0;
586 }
587}
588
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900589static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900590{
591#define DUMPREG(reg_id) \
592 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
593 readl(hdata->regs + reg_id))
594 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
595 DUMPREG(HDMI_INTC_FLAG);
596 DUMPREG(HDMI_INTC_CON);
597 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900598 DUMPREG(HDMI_V13_PHY_RSTOUT);
599 DUMPREG(HDMI_V13_PHY_VPLL);
600 DUMPREG(HDMI_V13_PHY_CMU);
601 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900602
603 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
604 DUMPREG(HDMI_CON_0);
605 DUMPREG(HDMI_CON_1);
606 DUMPREG(HDMI_CON_2);
607 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900608 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900609 DUMPREG(HDMI_STATUS_EN);
610 DUMPREG(HDMI_HPD);
611 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900612 DUMPREG(HDMI_V13_HPD_GEN);
613 DUMPREG(HDMI_V13_DC_CONTROL);
614 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900615
616 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
617 DUMPREG(HDMI_H_BLANK_0);
618 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900619 DUMPREG(HDMI_V13_V_BLANK_0);
620 DUMPREG(HDMI_V13_V_BLANK_1);
621 DUMPREG(HDMI_V13_V_BLANK_2);
622 DUMPREG(HDMI_V13_H_V_LINE_0);
623 DUMPREG(HDMI_V13_H_V_LINE_1);
624 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900625 DUMPREG(HDMI_VSYNC_POL);
626 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900627 DUMPREG(HDMI_V13_V_BLANK_F_0);
628 DUMPREG(HDMI_V13_V_BLANK_F_1);
629 DUMPREG(HDMI_V13_V_BLANK_F_2);
630 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
631 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
632 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
633 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
634 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
635 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
636 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
637 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
638 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
639 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
640 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
641 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900642
643 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
644 DUMPREG(HDMI_TG_CMD);
645 DUMPREG(HDMI_TG_H_FSZ_L);
646 DUMPREG(HDMI_TG_H_FSZ_H);
647 DUMPREG(HDMI_TG_HACT_ST_L);
648 DUMPREG(HDMI_TG_HACT_ST_H);
649 DUMPREG(HDMI_TG_HACT_SZ_L);
650 DUMPREG(HDMI_TG_HACT_SZ_H);
651 DUMPREG(HDMI_TG_V_FSZ_L);
652 DUMPREG(HDMI_TG_V_FSZ_H);
653 DUMPREG(HDMI_TG_VSYNC_L);
654 DUMPREG(HDMI_TG_VSYNC_H);
655 DUMPREG(HDMI_TG_VSYNC2_L);
656 DUMPREG(HDMI_TG_VSYNC2_H);
657 DUMPREG(HDMI_TG_VACT_ST_L);
658 DUMPREG(HDMI_TG_VACT_ST_H);
659 DUMPREG(HDMI_TG_VACT_SZ_L);
660 DUMPREG(HDMI_TG_VACT_SZ_H);
661 DUMPREG(HDMI_TG_FIELD_CHG_L);
662 DUMPREG(HDMI_TG_FIELD_CHG_H);
663 DUMPREG(HDMI_TG_VACT_ST2_L);
664 DUMPREG(HDMI_TG_VACT_ST2_H);
665 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
666 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
667 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
668 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
669 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
670 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
671 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
672 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
673#undef DUMPREG
674}
675
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900676static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
677{
678 int i;
679
680#define DUMPREG(reg_id) \
681 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
682 readl(hdata->regs + reg_id))
683
684 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
685 DUMPREG(HDMI_INTC_CON);
686 DUMPREG(HDMI_INTC_FLAG);
687 DUMPREG(HDMI_HPD_STATUS);
688 DUMPREG(HDMI_INTC_CON_1);
689 DUMPREG(HDMI_INTC_FLAG_1);
690 DUMPREG(HDMI_PHY_STATUS_0);
691 DUMPREG(HDMI_PHY_STATUS_PLL);
692 DUMPREG(HDMI_PHY_CON_0);
693 DUMPREG(HDMI_PHY_RSTOUT);
694 DUMPREG(HDMI_PHY_VPLL);
695 DUMPREG(HDMI_PHY_CMU);
696 DUMPREG(HDMI_CORE_RSTOUT);
697
698 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
699 DUMPREG(HDMI_CON_0);
700 DUMPREG(HDMI_CON_1);
701 DUMPREG(HDMI_CON_2);
702 DUMPREG(HDMI_SYS_STATUS);
703 DUMPREG(HDMI_PHY_STATUS_0);
704 DUMPREG(HDMI_STATUS_EN);
705 DUMPREG(HDMI_HPD);
706 DUMPREG(HDMI_MODE_SEL);
707 DUMPREG(HDMI_ENC_EN);
708 DUMPREG(HDMI_DC_CONTROL);
709 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
710
711 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
712 DUMPREG(HDMI_H_BLANK_0);
713 DUMPREG(HDMI_H_BLANK_1);
714 DUMPREG(HDMI_V2_BLANK_0);
715 DUMPREG(HDMI_V2_BLANK_1);
716 DUMPREG(HDMI_V1_BLANK_0);
717 DUMPREG(HDMI_V1_BLANK_1);
718 DUMPREG(HDMI_V_LINE_0);
719 DUMPREG(HDMI_V_LINE_1);
720 DUMPREG(HDMI_H_LINE_0);
721 DUMPREG(HDMI_H_LINE_1);
722 DUMPREG(HDMI_HSYNC_POL);
723
724 DUMPREG(HDMI_VSYNC_POL);
725 DUMPREG(HDMI_INT_PRO_MODE);
726 DUMPREG(HDMI_V_BLANK_F0_0);
727 DUMPREG(HDMI_V_BLANK_F0_1);
728 DUMPREG(HDMI_V_BLANK_F1_0);
729 DUMPREG(HDMI_V_BLANK_F1_1);
730
731 DUMPREG(HDMI_H_SYNC_START_0);
732 DUMPREG(HDMI_H_SYNC_START_1);
733 DUMPREG(HDMI_H_SYNC_END_0);
734 DUMPREG(HDMI_H_SYNC_END_1);
735
736 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
737 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
738 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
739 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
740
741 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
742 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
743 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
744 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
745
746 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
747 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
748 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
749 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
750
751 DUMPREG(HDMI_V_BLANK_F2_0);
752 DUMPREG(HDMI_V_BLANK_F2_1);
753 DUMPREG(HDMI_V_BLANK_F3_0);
754 DUMPREG(HDMI_V_BLANK_F3_1);
755 DUMPREG(HDMI_V_BLANK_F4_0);
756 DUMPREG(HDMI_V_BLANK_F4_1);
757 DUMPREG(HDMI_V_BLANK_F5_0);
758 DUMPREG(HDMI_V_BLANK_F5_1);
759
760 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
768
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
774 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
775 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
776 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
777
778 DUMPREG(HDMI_VACT_SPACE_1_0);
779 DUMPREG(HDMI_VACT_SPACE_1_1);
780 DUMPREG(HDMI_VACT_SPACE_2_0);
781 DUMPREG(HDMI_VACT_SPACE_2_1);
782 DUMPREG(HDMI_VACT_SPACE_3_0);
783 DUMPREG(HDMI_VACT_SPACE_3_1);
784 DUMPREG(HDMI_VACT_SPACE_4_0);
785 DUMPREG(HDMI_VACT_SPACE_4_1);
786 DUMPREG(HDMI_VACT_SPACE_5_0);
787 DUMPREG(HDMI_VACT_SPACE_5_1);
788 DUMPREG(HDMI_VACT_SPACE_6_0);
789 DUMPREG(HDMI_VACT_SPACE_6_1);
790
791 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
792 DUMPREG(HDMI_TG_CMD);
793 DUMPREG(HDMI_TG_H_FSZ_L);
794 DUMPREG(HDMI_TG_H_FSZ_H);
795 DUMPREG(HDMI_TG_HACT_ST_L);
796 DUMPREG(HDMI_TG_HACT_ST_H);
797 DUMPREG(HDMI_TG_HACT_SZ_L);
798 DUMPREG(HDMI_TG_HACT_SZ_H);
799 DUMPREG(HDMI_TG_V_FSZ_L);
800 DUMPREG(HDMI_TG_V_FSZ_H);
801 DUMPREG(HDMI_TG_VSYNC_L);
802 DUMPREG(HDMI_TG_VSYNC_H);
803 DUMPREG(HDMI_TG_VSYNC2_L);
804 DUMPREG(HDMI_TG_VSYNC2_H);
805 DUMPREG(HDMI_TG_VACT_ST_L);
806 DUMPREG(HDMI_TG_VACT_ST_H);
807 DUMPREG(HDMI_TG_VACT_SZ_L);
808 DUMPREG(HDMI_TG_VACT_SZ_H);
809 DUMPREG(HDMI_TG_FIELD_CHG_L);
810 DUMPREG(HDMI_TG_FIELD_CHG_H);
811 DUMPREG(HDMI_TG_VACT_ST2_L);
812 DUMPREG(HDMI_TG_VACT_ST2_H);
813 DUMPREG(HDMI_TG_VACT_ST3_L);
814 DUMPREG(HDMI_TG_VACT_ST3_H);
815 DUMPREG(HDMI_TG_VACT_ST4_L);
816 DUMPREG(HDMI_TG_VACT_ST4_H);
817 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
818 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
819 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
820 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
821 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
822 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
823 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
824 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
825 DUMPREG(HDMI_TG_3D);
826
827 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
828 DUMPREG(HDMI_AVI_CON);
829 DUMPREG(HDMI_AVI_HEADER0);
830 DUMPREG(HDMI_AVI_HEADER1);
831 DUMPREG(HDMI_AVI_HEADER2);
832 DUMPREG(HDMI_AVI_CHECK_SUM);
833 DUMPREG(HDMI_VSI_CON);
834 DUMPREG(HDMI_VSI_HEADER0);
835 DUMPREG(HDMI_VSI_HEADER1);
836 DUMPREG(HDMI_VSI_HEADER2);
837 for (i = 0; i < 7; ++i)
838 DUMPREG(HDMI_VSI_DATA(i));
839
840#undef DUMPREG
841}
842
843static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
844{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200845 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900846 hdmi_v13_regs_dump(hdata, prefix);
847 else
848 hdmi_v14_regs_dump(hdata, prefix);
849}
850
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530851static u8 hdmi_chksum(struct hdmi_context *hdata,
852 u32 start, u8 len, u32 hdr_sum)
853{
854 int i;
855
856 /* hdr_sum : header0 + header1 + header2
857 * start : start address of packet byte1
858 * len : packet bytes - 1 */
859 for (i = 0; i < len; ++i)
860 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
861
862 /* return 2's complement of 8 bit hdr_sum */
863 return (u8)(~(hdr_sum & 0xff) + 1);
864}
865
866static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530867 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530868{
869 u32 hdr_sum;
870 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530871 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200872 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530873
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530874 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
875 if (hdata->dvi_mode) {
876 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
877 HDMI_VSI_CON_DO_NOT_TRANSMIT);
878 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
879 HDMI_AVI_CON_DO_NOT_TRANSMIT);
880 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
881 return;
882 }
883
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530884 switch (infoframe->any.type) {
885 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530886 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530887 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
888 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
889 infoframe->any.version);
890 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
891 hdr_sum = infoframe->any.type + infoframe->any.version +
892 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530893
894 /* Output format zero hardcoded ,RGB YBCR selection */
895 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
896 AVI_ACTIVE_FORMAT_VALID |
897 AVI_UNDERSCANNED_DISPLAY_VALID);
898
Shirish S46154152014-03-13 10:58:28 +0530899 /*
900 * Set the aspect ratio as per the mode, mentioned in
901 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
902 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200903 ar = hdata->current_mode.picture_aspect_ratio;
904 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530905 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200906 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530907 break;
908 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200909 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530910 break;
911 case HDMI_PICTURE_ASPECT_NONE:
912 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200913 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530914 break;
915 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200916 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530917
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200918 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530919
920 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530921 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530922 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
923 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
924 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530925 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530926 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530927 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
928 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
929 infoframe->any.version);
930 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
931 hdr_sum = infoframe->any.type + infoframe->any.version +
932 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530933 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530934 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530935 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
936 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
937 break;
938 default:
939 break;
940 }
941}
942
Sean Pauld9716ee2014-01-30 16:19:29 -0500943static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
944 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500945{
Sean Pauld9716ee2014-01-30 16:19:29 -0500946 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500947
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200948 if (gpio_get_value(hdata->hpd_gpio))
949 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530950
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200951 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500952}
953
Sean Pauld9716ee2014-01-30 16:19:29 -0500954static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900955{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200956 drm_connector_unregister(connector);
957 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900958}
959
Sean Pauld9716ee2014-01-30 16:19:29 -0500960static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300961 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500962 .fill_modes = drm_helper_probe_single_connector_modes,
963 .detect = hdmi_detect,
964 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300965 .reset = drm_atomic_helper_connector_reset,
966 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
967 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500968};
969
970static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900971{
Sean Pauld9716ee2014-01-30 16:19:29 -0500972 struct hdmi_context *hdata = ctx_from_connector(connector);
973 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200974 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900975
Inki Dae8fa04aa2014-03-13 16:38:31 +0900976 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500977 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900978
Inki Dae8fa04aa2014-03-13 16:38:31 +0900979 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500980 if (!edid)
981 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900982
Sean Pauld9716ee2014-01-30 16:19:29 -0500983 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500984 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
985 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500986 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500987
Sean Pauld9716ee2014-01-30 16:19:29 -0500988 drm_mode_connector_update_edid_property(connector, edid);
989
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200990 ret = drm_add_edid_modes(connector, edid);
991
992 kfree(edid);
993
994 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995}
996
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900997static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900998{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900999 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001000
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001001 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1002 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001003 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001004
1005 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1006 return -EINVAL;
1007}
1008
Sean Pauld9716ee2014-01-30 16:19:29 -05001009static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001010 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001011{
Sean Pauld9716ee2014-01-30 16:19:29 -05001012 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001013 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001014
Rahul Sharma16844fb2013-06-10 14:50:00 +05301015 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1016 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1017 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1018 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001019
Sean Paulf041b252014-01-30 16:19:15 -05001020 ret = mixer_check_mode(mode);
1021 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001022 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001023
Rahul Sharma16844fb2013-06-10 14:50:00 +05301024 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001025 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001026 return MODE_BAD;
1027
1028 return MODE_OK;
1029}
1030
1031static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1032{
1033 struct hdmi_context *hdata = ctx_from_connector(connector);
1034
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001035 return &hdata->encoder.base;
Sean Pauld9716ee2014-01-30 16:19:29 -05001036}
1037
1038static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1039 .get_modes = hdmi_get_modes,
1040 .mode_valid = hdmi_mode_valid,
1041 .best_encoder = hdmi_best_encoder,
1042};
1043
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001044static int hdmi_create_connector(struct exynos_drm_encoder *exynos_encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001045{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001046 struct hdmi_context *hdata = encoder_to_hdmi(exynos_encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001047 struct drm_connector *connector = &hdata->connector;
1048 int ret;
1049
Sean Pauld9716ee2014-01-30 16:19:29 -05001050 connector->interlace_allowed = true;
1051 connector->polled = DRM_CONNECTOR_POLL_HPD;
1052
1053 ret = drm_connector_init(hdata->drm_dev, connector,
1054 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1055 if (ret) {
1056 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001057 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001058 }
1059
1060 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001061 drm_connector_register(connector);
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001062 drm_mode_connector_attach_encoder(connector, &exynos_encoder->base);
Sean Pauld9716ee2014-01-30 16:19:29 -05001063
1064 return 0;
1065}
1066
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001067static void hdmi_mode_fixup(struct exynos_drm_encoder *encoder,
Sean Paulf041b252014-01-30 16:19:15 -05001068 struct drm_connector *connector,
1069 const struct drm_display_mode *mode,
1070 struct drm_display_mode *adjusted_mode)
1071{
1072 struct drm_display_mode *m;
1073 int mode_ok;
1074
1075 DRM_DEBUG_KMS("%s\n", __FILE__);
1076
1077 drm_mode_set_crtcinfo(adjusted_mode, 0);
1078
Sean Pauld9716ee2014-01-30 16:19:29 -05001079 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001080
1081 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001082 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -05001083 return;
1084
1085 /*
1086 * otherwise, find the most suitable mode among modes and change it
1087 * to adjusted_mode.
1088 */
1089 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001090 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001091
Sean Pauld9716ee2014-01-30 16:19:29 -05001092 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001093 DRM_INFO("desired mode doesn't exist so\n");
1094 DRM_INFO("use the most suitable mode among modes.\n");
1095
1096 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1097 m->hdisplay, m->vdisplay, m->vrefresh);
1098
Sean Paul75626852014-01-30 16:19:16 -05001099 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001100 break;
1101 }
1102 }
1103}
1104
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001105static void hdmi_set_acr(u32 freq, u8 *acr)
1106{
1107 u32 n, cts;
1108
1109 switch (freq) {
1110 case 32000:
1111 n = 4096;
1112 cts = 27000;
1113 break;
1114 case 44100:
1115 n = 6272;
1116 cts = 30000;
1117 break;
1118 case 88200:
1119 n = 12544;
1120 cts = 30000;
1121 break;
1122 case 176400:
1123 n = 25088;
1124 cts = 30000;
1125 break;
1126 case 48000:
1127 n = 6144;
1128 cts = 27000;
1129 break;
1130 case 96000:
1131 n = 12288;
1132 cts = 27000;
1133 break;
1134 case 192000:
1135 n = 24576;
1136 cts = 27000;
1137 break;
1138 default:
1139 n = 0;
1140 cts = 0;
1141 break;
1142 }
1143
1144 acr[1] = cts >> 16;
1145 acr[2] = cts >> 8 & 0xff;
1146 acr[3] = cts & 0xff;
1147
1148 acr[4] = n >> 16;
1149 acr[5] = n >> 8 & 0xff;
1150 acr[6] = n & 0xff;
1151}
1152
1153static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1154{
1155 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1156 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1157 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1158 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1159 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1160 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1161 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1162 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1163 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1164
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001165 if (hdata->drv_data->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001166 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1167 else
1168 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1169}
1170
1171static void hdmi_audio_init(struct hdmi_context *hdata)
1172{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301173 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001174 u32 data_num, bit_ch, sample_frq;
1175 u32 val;
1176 u8 acr[7];
1177
1178 sample_rate = 44100;
1179 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001180
1181 switch (bits_per_sample) {
1182 case 20:
1183 data_num = 2;
1184 bit_ch = 1;
1185 break;
1186 case 24:
1187 data_num = 3;
1188 bit_ch = 1;
1189 break;
1190 default:
1191 data_num = 1;
1192 bit_ch = 0;
1193 break;
1194 }
1195
1196 hdmi_set_acr(sample_rate, acr);
1197 hdmi_reg_acr(hdata, acr);
1198
1199 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1200 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1201 | HDMI_I2S_MUX_ENABLE);
1202
1203 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1204 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1205
1206 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1207
1208 sample_frq = (sample_rate == 44100) ? 0 :
1209 (sample_rate == 48000) ? 2 :
1210 (sample_rate == 32000) ? 3 :
1211 (sample_rate == 96000) ? 0xa : 0x0;
1212
1213 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1214 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1215
1216 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1217 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1218
1219 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1220 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1221 | HDMI_I2S_SEL_LRCK(6));
1222 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1223 | HDMI_I2S_SEL_SDATA2(4));
1224 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1225 | HDMI_I2S_SEL_SDATA2(2));
1226 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1227
1228 /* I2S_CON_1 & 2 */
1229 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1230 | HDMI_I2S_L_CH_LOW_POL);
1231 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1232 | HDMI_I2S_SET_BIT_CH(bit_ch)
1233 | HDMI_I2S_SET_SDATA_BIT(data_num)
1234 | HDMI_I2S_BASIC_FORMAT);
1235
1236 /* Configure register related to CUV information */
1237 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1238 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1239 | HDMI_I2S_COPYRIGHT
1240 | HDMI_I2S_LINEAR_PCM
1241 | HDMI_I2S_CONSUMER_FORMAT);
1242 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1243 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1244 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1245 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1246 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1247 HDMI_I2S_ORG_SMP_FREQ_44_1
1248 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1249 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1250
1251 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1252}
1253
1254static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1255{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001256 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001257 return;
1258
1259 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1260 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1261 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1262}
1263
Rahul Sharmabfa48422014-04-03 20:41:04 +05301264static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001265{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301266 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001267
Rahul Sharmabfa48422014-04-03 20:41:04 +05301268 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1269 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001270
Rahul Sharmabfa48422014-04-03 20:41:04 +05301271 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1272 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001273}
1274
1275static void hdmi_conf_init(struct hdmi_context *hdata)
1276{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301277 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301278
Sean Paul77006a72013-01-16 10:17:20 -05001279 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001280 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1281 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001282
1283 /* choose HDMI mode */
1284 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1285 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301286 /* Apply Video preable and Guard band in HDMI mode only */
1287 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001288 /* disable bluescreen */
1289 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001290
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001291 if (hdata->dvi_mode) {
1292 /* choose DVI mode */
1293 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1294 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1295 hdmi_reg_writeb(hdata, HDMI_CON_2,
1296 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1297 }
1298
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001299 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001300 /* choose bluescreen (fecal) color */
1301 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1302 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1303 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1304
1305 /* enable AVI packet every vsync, fixes purple line problem */
1306 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1307 /* force RGB, look to CEA-861-D, table 7 for more detail */
1308 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1309 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1310
1311 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1312 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1313 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1314 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301315 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1316 infoframe.any.version = HDMI_AVI_VERSION;
1317 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301318 hdmi_reg_infoframe(hdata, &infoframe);
1319
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301320 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1321 infoframe.any.version = HDMI_AUI_VERSION;
1322 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301323 hdmi_reg_infoframe(hdata, &infoframe);
1324
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001325 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001326 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1327 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001328}
1329
Rahul Sharma16844fb2013-06-10 14:50:00 +05301330static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001331{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001332 struct drm_display_mode *m = &hdata->current_mode;
1333 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001334 int tries;
1335
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001336 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1337 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1338 (m->htotal << 12) | m->vtotal);
1339
1340 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1341 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1342
1343 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1344 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1345
1346 val = (m->hsync_start - m->hdisplay - 2);
1347 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1348 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1349 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1350
1351 /*
1352 * Quirk requirement for exynos HDMI IP design,
1353 * 2 pixels less than the actual calculation for hsync_start
1354 * and end.
1355 */
1356
1357 /* Following values & calculations differ for different type of modes */
1358 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1359 /* Interlaced Mode */
1360 val = ((m->vsync_end - m->vdisplay) / 2);
1361 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1362 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1363
1364 val = m->vtotal / 2;
1365 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1366 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1367
1368 val = (m->vtotal +
1369 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1370 val |= m->vtotal << 11;
1371 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1372
1373 val = ((m->vtotal / 2) + 7);
1374 val |= ((m->vtotal / 2) + 2) << 12;
1375 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1376
1377 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1378 val |= ((m->htotal / 2) +
1379 (m->hsync_start - m->hdisplay)) << 12;
1380 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1381
1382 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1383 (m->vtotal - m->vdisplay) / 2);
1384 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1385
1386 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1387 } else {
1388 /* Progressive Mode */
1389
1390 val = m->vtotal;
1391 val |= (m->vtotal - m->vdisplay) << 11;
1392 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1393
1394 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1395
1396 val = (m->vsync_end - m->vdisplay);
1397 val |= ((m->vsync_start - m->vdisplay) << 12);
1398 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1399
1400 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1401 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1402 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1403 m->vtotal - m->vdisplay);
1404 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1405 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1406 }
1407
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001408 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001409 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1410 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1411 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1412 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1413 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1414 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1415 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1416 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1417 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1418 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1419 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001420
1421 /* waiting for HDMIPHY's PLL to get to steady state */
1422 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001423 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001424 if (val & HDMI_PHY_STATUS_READY)
1425 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001426 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001427 }
1428 /* steady state not achieved */
1429 if (tries == 0) {
1430 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1431 hdmi_regs_dump(hdata, "timing apply");
1432 }
1433
Sean Paul0bfb1f82013-06-11 12:24:02 +05301434 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301435 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301436 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001437
1438 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301439 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001440}
1441
Rahul Sharma16844fb2013-06-10 14:50:00 +05301442static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001443{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001444 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001445 int tries;
1446
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001447 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1448 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1449 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1450 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1451 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1452 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1453 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1454 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1455 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1456
1457 /*
1458 * Quirk requirement for exynos 5 HDMI IP design,
1459 * 2 pixels less than the actual calculation for hsync_start
1460 * and end.
1461 */
1462
1463 /* Following values & calculations differ for different type of modes */
1464 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1465 /* Interlaced Mode */
1466 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1467 (m->vsync_end - m->vdisplay) / 2);
1468 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1469 (m->vsync_start - m->vdisplay) / 2);
1470 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1471 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1472 (m->vtotal - m->vdisplay) / 2);
1473 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1474 m->vtotal - m->vdisplay / 2);
1475 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1476 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1477 (m->vtotal / 2) + 7);
1478 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1479 (m->vtotal / 2) + 2);
1480 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1481 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1482 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1483 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1484 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1485 (m->vtotal - m->vdisplay) / 2);
1486 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1487 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1488 m->vtotal - m->vdisplay / 2);
1489 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1490 (m->vtotal / 2) + 1);
1491 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1492 (m->vtotal / 2) + 1);
1493 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1494 (m->vtotal / 2) + 1);
1495 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1496 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1497 } else {
1498 /* Progressive Mode */
1499 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1500 m->vsync_end - m->vdisplay);
1501 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1502 m->vsync_start - m->vdisplay);
1503 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1504 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1505 m->vtotal - m->vdisplay);
1506 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1507 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1508 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1509 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1510 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1511 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1512 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1513 m->vtotal - m->vdisplay);
1514 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1515 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1516 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1517 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1518 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1519 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1520 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1521 }
1522
1523 /* Following values & calculations are same irrespective of mode type */
1524 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1525 m->hsync_start - m->hdisplay - 2);
1526 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1527 m->hsync_end - m->hdisplay - 2);
1528 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1529 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1530 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1538 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1539 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1540 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1541 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1542 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1543 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1544 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001546
1547 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001548 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1549 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1550 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1551 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1552 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1553 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1554 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1555 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1556 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001557
1558 /* waiting for HDMIPHY's PLL to get to steady state */
1559 for (tries = 100; tries; --tries) {
1560 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1561 if (val & HDMI_PHY_STATUS_READY)
1562 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001563 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001564 }
1565 /* steady state not achieved */
1566 if (tries == 0) {
1567 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1568 hdmi_regs_dump(hdata, "timing apply");
1569 }
1570
Sean Paul0bfb1f82013-06-11 12:24:02 +05301571 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301572 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301573 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001574
1575 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301576 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001577}
1578
Rahul Sharma16844fb2013-06-10 14:50:00 +05301579static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001580{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001581 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301582 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001583 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301584 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001585}
1586
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001587static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1588{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001589 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001590
Sean Paul0bfb1f82013-06-11 12:24:02 +05301591 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301592 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301593 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001594
1595 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001596 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1597 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001598
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001599 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001600 reg = HDMI_V13_PHY_RSTOUT;
1601 else
1602 reg = HDMI_PHY_RSTOUT;
1603
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001604 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001605 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001606 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001607 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001608 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001609}
1610
Rahul Sharmaa5562252012-11-28 11:30:25 +05301611static void hdmiphy_poweron(struct hdmi_context *hdata)
1612{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001613 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301614 return;
1615
1616 DRM_DEBUG_KMS("\n");
1617
1618 /* For PHY Mode Setting */
1619 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1620 HDMI_PHY_ENABLE_MODE_SET);
1621 /* Phy Power On */
1622 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1623 HDMI_PHY_POWER_ON);
1624 /* For PHY Mode Setting */
1625 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1626 HDMI_PHY_DISABLE_MODE_SET);
1627 /* PHY SW Reset */
1628 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301629}
1630
1631static void hdmiphy_poweroff(struct hdmi_context *hdata)
1632{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001633 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301634 return;
1635
1636 DRM_DEBUG_KMS("\n");
1637
1638 /* PHY SW Reset */
1639 hdmiphy_conf_reset(hdata);
1640 /* For PHY Mode Setting */
1641 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1642 HDMI_PHY_ENABLE_MODE_SET);
1643
1644 /* PHY Power Off */
1645 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1646 HDMI_PHY_POWER_OFF);
1647
1648 /* For PHY Mode Setting */
1649 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1650 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301651}
1652
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001653static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1654{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001655 int ret;
1656 int i;
1657
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001658 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001659 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001660 if (i < 0) {
1661 DRM_ERROR("failed to find hdmiphy conf\n");
1662 return;
1663 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001664
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001665 ret = hdmiphy_reg_write_buf(hdata, 0,
1666 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001667 if (ret) {
1668 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001669 return;
1670 }
1671
Sean Paul09760ea2013-01-14 17:03:20 -05001672 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001673
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001674 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1675 HDMI_PHY_DISABLE_MODE_SET);
1676 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001677 DRM_ERROR("failed to enable hdmiphy\n");
1678 return;
1679 }
1680
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001681}
1682
1683static void hdmi_conf_apply(struct hdmi_context *hdata)
1684{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001685 hdmiphy_conf_reset(hdata);
1686 hdmiphy_conf_apply(hdata);
1687
Rahul Sharmabfa48422014-04-03 20:41:04 +05301688 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001689 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001690
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001691 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001692
1693 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301694 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001695 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001696
1697 hdmi_regs_dump(hdata, "start");
1698}
1699
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001700static void hdmi_mode_set(struct exynos_drm_encoder *encoder,
Sean Paulf041b252014-01-30 16:19:15 -05001701 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001702{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001703 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001704 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001705
YoungJun Chocbc4c332013-06-12 10:44:40 +09001706 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1707 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001708 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001709 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001710
Rahul Sharmabfa48422014-04-03 20:41:04 +05301711 drm_mode_copy(&hdata->current_mode, mode);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001712 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001713}
1714
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001715static void hdmi_enable(struct exynos_drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001716{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001717 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001718 struct hdmi_resources *res = &hdata->res;
1719
Andrzej Hajda882a0642015-07-09 16:28:08 +02001720 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001721 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001722
1723 hdata->powered = true;
1724
Sean Paulaf65c802014-01-30 16:19:27 -05001725 pm_runtime_get_sync(hdata->dev);
1726
Seung-Woo Kimad079452013-06-05 14:34:38 +09001727 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1728 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1729
Rahul Sharma049d34e2014-05-20 10:36:05 +05301730 /* set pmu hdmiphy control bit to enable hdmiphy */
1731 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1732 PMU_HDMI_PHY_ENABLE_BIT, 1);
1733
Sean Paul0bfb1f82013-06-11 12:24:02 +05301734 clk_prepare_enable(res->hdmi);
1735 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301736
1737 hdmiphy_poweron(hdata);
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001738 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001739}
1740
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001741static void hdmi_disable(struct exynos_drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001742{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001743 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001744 struct hdmi_resources *res = &hdata->res;
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001745 struct drm_crtc *crtc = hdata->encoder.base.crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001746 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001747
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001748 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001749 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001750
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001751 /*
1752 * The SFRs of VP and Mixer are updated by Vertical Sync of
1753 * Timing generator which is a part of HDMI so the sequence
1754 * to disable TV Subsystem should be as following,
1755 * VP -> Mixer -> HDMI
1756 *
1757 * Below codes will try to disable Mixer and VP(if used)
1758 * prior to disabling HDMI.
1759 */
1760 if (crtc)
1761 funcs = crtc->helper_private;
1762 if (funcs && funcs->disable)
1763 (*funcs->disable)(crtc);
1764
Rahul Sharmabfa48422014-04-03 20:41:04 +05301765 /* HDMI System Disable */
1766 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1767
Rahul Sharmaa5562252012-11-28 11:30:25 +05301768 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001769
Sean Paul724fd142014-05-09 15:05:10 +09001770 cancel_delayed_work(&hdata->hotplug_work);
1771
Sean Paul0bfb1f82013-06-11 12:24:02 +05301772 clk_disable_unprepare(res->sclk_hdmi);
1773 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301774
1775 /* reset pmu hdmiphy control bit to disable hdmiphy */
1776 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1777 PMU_HDMI_PHY_ENABLE_BIT, 0);
1778
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001779 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1780
Sean Paulaf65c802014-01-30 16:19:27 -05001781 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001782
1783 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001784}
1785
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001786static struct exynos_drm_encoder_ops hdmi_encoder_ops = {
Sean Paulf041b252014-01-30 16:19:15 -05001787 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001788 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001789 .enable = hdmi_enable,
1790 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001791};
1792
Sean Paul724fd142014-05-09 15:05:10 +09001793static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001794{
Sean Paul724fd142014-05-09 15:05:10 +09001795 struct hdmi_context *hdata;
1796
1797 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001798
Sean Paul45517892014-01-30 16:19:05 -05001799 if (hdata->drm_dev)
1800 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001801}
1802
1803static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1804{
1805 struct hdmi_context *hdata = arg;
1806
1807 mod_delayed_work(system_wq, &hdata->hotplug_work,
1808 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001809
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001810 return IRQ_HANDLED;
1811}
1812
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001813static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001814{
1815 struct device *dev = hdata->dev;
1816 struct hdmi_resources *res = &hdata->res;
1817 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001818 "vdd",
1819 "vdd_osc",
1820 "vdd_pll",
1821 };
1822 int i, ret;
1823
1824 DRM_DEBUG_KMS("HDMI resource init\n");
1825
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001826 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301827 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301828 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001829 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001830 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001831 goto fail;
1832 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301833 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301834 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001835 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001836 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001837 goto fail;
1838 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301839 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301840 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001841 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001842 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001843 goto fail;
1844 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301845 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301846 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001847 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001848 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001849 goto fail;
1850 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301851 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1852 if (IS_ERR(res->mout_hdmi)) {
1853 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001854 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301855 goto fail;
1856 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001857
Rahul Sharma59956d32013-06-11 12:24:03 +05301858 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001859
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301860 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301861 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09001862 if (!res->regul_bulk) {
1863 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001864 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09001865 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001866 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1867 res->regul_bulk[i].supply = supply[i];
1868 res->regul_bulk[i].consumer = NULL;
1869 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301870 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001871 if (ret) {
1872 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001873 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001874 }
1875 res->regul_count = ARRAY_SIZE(supply);
1876
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001877 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
1878 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
1879 DRM_ERROR("failed to get hdmi-en regulator\n");
1880 return PTR_ERR(res->reg_hdmi_en);
1881 }
1882 if (!IS_ERR(res->reg_hdmi_en)) {
1883 ret = regulator_enable(res->reg_hdmi_en);
1884 if (ret) {
1885 DRM_ERROR("failed to enable hdmi-en regulator\n");
1886 return ret;
1887 }
1888 } else
1889 res->reg_hdmi_en = NULL;
1890
Inki Daedf5225b2014-05-29 18:28:02 +09001891 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001892fail:
1893 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001894 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001895}
1896
Rahul Sharma22c4f422012-10-04 20:48:55 +05301897static struct of_device_id hdmi_match_types[] = {
1898 {
1899 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001900 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301901 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001902 .compatible = "samsung,exynos4210-hdmi",
1903 .data = &exynos4210_hdmi_driver_data,
1904 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301905 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001906 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301907 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301908 .compatible = "samsung,exynos5420-hdmi",
1909 .data = &exynos5420_hdmi_driver_data,
1910 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301911 /* end node */
1912 }
1913};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001914MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301915
Inki Daef37cd5e2014-05-09 14:25:20 +09001916static int hdmi_bind(struct device *dev, struct device *master, void *data)
1917{
1918 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001919 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001920 struct exynos_drm_encoder *exynos_encoder = &hdata->encoder;
1921 int ret;
Inki Daef37cd5e2014-05-09 14:25:20 +09001922
Inki Daef37cd5e2014-05-09 14:25:20 +09001923 hdata->drm_dev = drm_dev;
1924
Gustavo Padovana2986e82015-08-05 20:24:20 -03001925 ret = exynos_drm_encoder_create(drm_dev, exynos_encoder,
1926 EXYNOS_DISPLAY_TYPE_HDMI);
1927 if (ret) {
1928 DRM_ERROR("failed to create encoder\n");
1929 return ret;
1930 }
1931
1932 ret = hdmi_create_connector(exynos_encoder);
1933 if (ret) {
1934 DRM_ERROR("failed to create connector ret = %d\n", ret);
1935 drm_encoder_cleanup(&exynos_encoder->base);
1936 return ret;
1937 }
1938
1939 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001940}
1941
1942static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1943{
Inki Daef37cd5e2014-05-09 14:25:20 +09001944}
1945
1946static const struct component_ops hdmi_component_ops = {
1947 .bind = hdmi_bind,
1948 .unbind = hdmi_unbind,
1949};
1950
Inki Daee2a562d2014-05-09 16:46:10 +09001951static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1952{
1953 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1954 struct device_node *np;
1955
1956 np = of_find_compatible_node(NULL, NULL, compatible_str);
1957 if (np)
1958 return of_get_next_parent(np);
1959
1960 return NULL;
1961}
1962
1963static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1964{
1965 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1966
1967 return of_find_compatible_node(NULL, NULL, compatible_str);
1968}
1969
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001970static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001971{
Inki Daef37cd5e2014-05-09 14:25:20 +09001972 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001973 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001974 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001975 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001976 struct resource *res;
1977 int ret;
1978
Andrzej Hajda930865f2014-11-17 09:54:20 +01001979 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1980 if (!hdata)
1981 return -ENOMEM;
1982
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001983 match = of_match_device(hdmi_match_types, dev);
1984 if (!match)
1985 return -ENODEV;
1986
1987 hdata->drv_data = match->data;
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001988 hdata->encoder.ops = &hdmi_encoder_ops;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001989
Andrzej Hajda930865f2014-11-17 09:54:20 +01001990 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001991
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001992 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02001993 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
1994 if (hdata->hpd_gpio < 0) {
1995 DRM_ERROR("cannot get hpd gpio property\n");
1996 return hdata->hpd_gpio;
1997 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001998
1999 ret = hdmi_resources_init(hdata);
2000 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302001 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002002 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002003 }
2004
2005 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002006 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002007 if (IS_ERR(hdata->regs)) {
2008 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002009 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002010 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002012 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302013 if (ret) {
2014 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002015 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302016 }
2017
Inki Daee2a562d2014-05-09 16:46:10 +09002018 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2019 if (ddc_node)
2020 goto out_get_ddc_adpt;
2021
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002022 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002023 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2024 if (!ddc_node) {
2025 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002026 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002027 }
Inki Daee2a562d2014-05-09 16:46:10 +09002028
2029out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002030 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2031 if (!hdata->ddc_adpt) {
2032 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002033 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002034 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002035
Inki Daee2a562d2014-05-09 16:46:10 +09002036 phy_node = hdmi_legacy_phy_dt_binding(dev);
2037 if (phy_node)
2038 goto out_get_phy_port;
2039
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002040 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002041 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2042 if (!phy_node) {
2043 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2044 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002045 goto err_ddc;
2046 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002047
Inki Daee2a562d2014-05-09 16:46:10 +09002048out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002049 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002050 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2051 if (!hdata->regs_hdmiphy) {
2052 DRM_ERROR("failed to ioremap hdmi phy\n");
2053 ret = -ENOMEM;
2054 goto err_ddc;
2055 }
2056 } else {
2057 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2058 if (!hdata->hdmiphy_port) {
2059 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002060 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002061 goto err_ddc;
2062 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002063 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002064
Sean Paul77006a72013-01-16 10:17:20 -05002065 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2066 if (hdata->irq < 0) {
2067 DRM_ERROR("failed to get GPIO irq\n");
2068 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002069 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002070 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002071
Sean Paul724fd142014-05-09 15:05:10 +09002072 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2073
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002074 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002075 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002076 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002077 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002078 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002079 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002080 goto err_hdmiphy;
2081 }
2082
Rahul Sharma049d34e2014-05-20 10:36:05 +05302083 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2084 "samsung,syscon-phandle");
2085 if (IS_ERR(hdata->pmureg)) {
2086 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002087 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302088 goto err_hdmiphy;
2089 }
2090
Sean Paulaf65c802014-01-30 16:19:27 -05002091 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002092
Inki Daedf5225b2014-05-29 18:28:02 +09002093 ret = component_add(&pdev->dev, &hdmi_component_ops);
2094 if (ret)
2095 goto err_disable_pm_runtime;
2096
2097 return ret;
2098
2099err_disable_pm_runtime:
2100 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002101
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002102err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002103 if (hdata->hdmiphy_port)
2104 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002105err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002106 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002107
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002108 return ret;
2109}
2110
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002111static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002112{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002113 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002114
Sean Paul724fd142014-05-09 15:05:10 +09002115 cancel_delayed_work_sync(&hdata->hotplug_work);
2116
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002117 if (hdata->res.reg_hdmi_en)
2118 regulator_disable(hdata->res.reg_hdmi_en);
2119
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002120 if (hdata->hdmiphy_port)
2121 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002122 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002123
Sean Paulaf65c802014-01-30 16:19:27 -05002124 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002125 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002126
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002127 return 0;
2128}
2129
2130struct platform_driver hdmi_driver = {
2131 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002132 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302134 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002135 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302136 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002137 },
2138};