blob: 0d538d3cc38edf2015b5980567afbb170dfb7e1f [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>
Andrzej Hajda2228b7c2015-09-25 14:48:24 +020033#include <linux/gpio/consumer.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020037#include <linux/of_device.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Sean Pauld9716ee2014-01-30 16:19:29 -050049#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090050
Sean Paul724fd142014-05-09 15:05:10 +090051#define HOTPLUG_DEBOUNCE_MS 1100
52
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053/* AVI header and aspect ratio */
54#define HDMI_AVI_VERSION 0x02
55#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053056
57/* AUI header info */
58#define HDMI_AUI_VERSION 0x01
59#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053060#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
61#define AVI_4_3_CENTER_RATIO 0x9
62#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053063
Rahul Sharma5a325072012-10-04 20:48:54 +053064enum hdmi_type {
65 HDMI_TYPE13,
66 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020067 HDMI_TYPE_COUNT
68};
69
70#define HDMI_MAPPED_BASE 0xffff0000
71
72enum hdmi_mapped_regs {
73 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
74 HDMI_PHY_RSTOUT,
75 HDMI_ACR_CON,
76};
77
78static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
79 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
80 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
81 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Rahul Sharma5a325072012-10-04 20:48:54 +053082};
83
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020084static const char * const supply[] = {
85 "vdd",
86 "vdd_osc",
87 "vdd_pll",
88};
89
Inki Daebfe4e842014-03-06 14:18:17 +090090struct hdmi_driver_data {
91 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090092 const struct hdmiphy_config *phy_confs;
93 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090094 unsigned int is_apb_phy:1;
95};
96
Joonyoung Shim590f4182012-03-16 18:47:14 +090097struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -030098 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +090099 struct device *dev;
100 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500101 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900102 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900103 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900104 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900105 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530106 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200107 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200108 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900109
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200110 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900111 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200112 struct i2c_client *hdmiphy_port;
113 struct i2c_adapter *ddc_adpt;
114 struct gpio_desc *hpd_gpio;
115 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530116 struct regmap *pmureg;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200117 struct clk *hdmi;
118 struct clk *sclk_hdmi;
119 struct clk *sclk_pixel;
120 struct clk *sclk_hdmiphy;
121 struct clk *mout_hdmi;
122 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
123 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900124};
125
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300126static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100127{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900128 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100129}
130
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500131struct hdmiphy_config {
132 int pixel_clock;
133 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900134};
135
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900136/* list of phy config settings */
137static const struct hdmiphy_config hdmiphy_v13_configs[] = {
138 {
139 .pixel_clock = 27000000,
140 .conf = {
141 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
142 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
143 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200144 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900145 },
146 },
147 {
148 .pixel_clock = 27027000,
149 .conf = {
150 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
151 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
152 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200153 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900154 },
155 },
156 {
157 .pixel_clock = 74176000,
158 .conf = {
159 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
160 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
161 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200162 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163 },
164 },
165 {
166 .pixel_clock = 74250000,
167 .conf = {
168 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
169 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
170 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200171 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900172 },
173 },
174 {
175 .pixel_clock = 148500000,
176 .conf = {
177 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
178 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
179 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200180 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900181 },
182 },
183};
184
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500185static const struct hdmiphy_config hdmiphy_v14_configs[] = {
186 {
187 .pixel_clock = 25200000,
188 .conf = {
189 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
190 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
191 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
192 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
193 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900194 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500195 {
196 .pixel_clock = 27000000,
197 .conf = {
198 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
199 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
200 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
201 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
202 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900203 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500204 {
205 .pixel_clock = 27027000,
206 .conf = {
207 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
208 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
209 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200210 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500211 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900212 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500213 {
214 .pixel_clock = 36000000,
215 .conf = {
216 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
217 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
218 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
219 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
220 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900221 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500222 {
223 .pixel_clock = 40000000,
224 .conf = {
225 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
226 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
227 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
228 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
229 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900230 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500231 {
232 .pixel_clock = 65000000,
233 .conf = {
234 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
235 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
236 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
237 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
238 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900239 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500240 {
Shirish Se1d883c2014-03-13 14:28:27 +0900241 .pixel_clock = 71000000,
242 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530243 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
244 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
245 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900246 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
247 },
248 },
249 {
250 .pixel_clock = 73250000,
251 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530252 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
253 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
254 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900255 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
256 },
257 },
258 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500259 .pixel_clock = 74176000,
260 .conf = {
261 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
262 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
263 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
264 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
265 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900266 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500267 {
268 .pixel_clock = 74250000,
269 .conf = {
270 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
271 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
272 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200273 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500274 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900275 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500276 {
277 .pixel_clock = 83500000,
278 .conf = {
279 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
280 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
281 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
282 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
283 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900284 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500285 {
286 .pixel_clock = 106500000,
287 .conf = {
288 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
289 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
290 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
291 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
292 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900293 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500294 {
295 .pixel_clock = 108000000,
296 .conf = {
297 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
298 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
299 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
300 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
301 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900302 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500303 {
Shirish Se1d883c2014-03-13 14:28:27 +0900304 .pixel_clock = 115500000,
305 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530306 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
307 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
308 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900309 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
310 },
311 },
312 {
313 .pixel_clock = 119000000,
314 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530315 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
316 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
317 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900318 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
319 },
320 },
321 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500322 .pixel_clock = 146250000,
323 .conf = {
324 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
325 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
326 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
327 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
328 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900329 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500330 {
331 .pixel_clock = 148500000,
332 .conf = {
333 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
334 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
335 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200336 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500337 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900338 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900339};
340
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530341static const struct hdmiphy_config hdmiphy_5420_configs[] = {
342 {
343 .pixel_clock = 25200000,
344 .conf = {
345 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
346 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
347 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
348 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
349 },
350 },
351 {
352 .pixel_clock = 27000000,
353 .conf = {
354 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
355 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
356 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
357 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
358 },
359 },
360 {
361 .pixel_clock = 27027000,
362 .conf = {
363 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
364 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
365 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
366 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
367 },
368 },
369 {
370 .pixel_clock = 36000000,
371 .conf = {
372 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
373 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
374 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
375 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
376 },
377 },
378 {
379 .pixel_clock = 40000000,
380 .conf = {
381 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
382 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
383 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
384 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
385 },
386 },
387 {
388 .pixel_clock = 65000000,
389 .conf = {
390 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
391 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
392 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
393 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
394 },
395 },
396 {
397 .pixel_clock = 71000000,
398 .conf = {
399 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
400 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
401 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
402 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
403 },
404 },
405 {
406 .pixel_clock = 73250000,
407 .conf = {
408 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
409 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
410 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
411 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
412 },
413 },
414 {
415 .pixel_clock = 74176000,
416 .conf = {
417 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
418 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
419 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
420 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
421 },
422 },
423 {
424 .pixel_clock = 74250000,
425 .conf = {
426 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
427 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
428 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
429 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
430 },
431 },
432 {
433 .pixel_clock = 83500000,
434 .conf = {
435 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
436 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
437 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
438 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
439 },
440 },
441 {
442 .pixel_clock = 88750000,
443 .conf = {
444 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
445 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
446 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
447 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
448 },
449 },
450 {
451 .pixel_clock = 106500000,
452 .conf = {
453 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
454 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
455 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
456 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
457 },
458 },
459 {
460 .pixel_clock = 108000000,
461 .conf = {
462 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
463 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
464 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
465 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
466 },
467 },
468 {
469 .pixel_clock = 115500000,
470 .conf = {
471 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
472 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
473 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
474 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
475 },
476 },
477 {
478 .pixel_clock = 146250000,
479 .conf = {
480 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
481 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
482 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
483 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
484 },
485 },
486 {
487 .pixel_clock = 148500000,
488 .conf = {
489 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
490 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
491 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
492 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
493 },
494 },
495};
496
Sachin Kamat16337072014-05-22 10:32:56 +0530497static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530498 .type = HDMI_TYPE14,
499 .phy_confs = hdmiphy_5420_configs,
500 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
501 .is_apb_phy = 1,
502};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900503
Sachin Kamat16337072014-05-22 10:32:56 +0530504static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900505 .type = HDMI_TYPE14,
506 .phy_confs = hdmiphy_v14_configs,
507 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
508 .is_apb_phy = 0,
509};
510
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200511static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
512 .type = HDMI_TYPE13,
513 .phy_confs = hdmiphy_v13_configs,
514 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
515 .is_apb_phy = 0,
516};
517
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200518static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
519{
520 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
521 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
522 return reg_id;
523}
524
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900525static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
526{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200527 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900528}
529
530static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
531 u32 reg_id, u8 value)
532{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200533 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534}
535
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200536static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
537 int bytes, u32 val)
538{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200539 reg_id = hdmi_map_reg(hdata, reg_id);
540
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200541 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200542 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200543 val >>= 8;
544 reg_id += 4;
545 }
546}
547
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900548static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
549 u32 reg_id, u32 value, u32 mask)
550{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200551 u32 old;
552
553 reg_id = hdmi_map_reg(hdata, reg_id);
554 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900555 value = (value & mask) | (old & ~mask);
556 writel(value, hdata->regs + reg_id);
557}
558
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900559static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
560 u32 reg_offset, const u8 *buf, u32 len)
561{
562 if ((reg_offset + len) > 32)
563 return -EINVAL;
564
565 if (hdata->hdmiphy_port) {
566 int ret;
567
568 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
569 if (ret == len)
570 return 0;
571 return ret;
572 } else {
573 int i;
574 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200575 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900576 ((reg_offset + i)<<2));
577 return 0;
578 }
579}
580
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900581static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900582{
583#define DUMPREG(reg_id) \
584 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
585 readl(hdata->regs + reg_id))
586 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
587 DUMPREG(HDMI_INTC_FLAG);
588 DUMPREG(HDMI_INTC_CON);
589 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900590 DUMPREG(HDMI_V13_PHY_RSTOUT);
591 DUMPREG(HDMI_V13_PHY_VPLL);
592 DUMPREG(HDMI_V13_PHY_CMU);
593 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594
595 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
596 DUMPREG(HDMI_CON_0);
597 DUMPREG(HDMI_CON_1);
598 DUMPREG(HDMI_CON_2);
599 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900600 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900601 DUMPREG(HDMI_STATUS_EN);
602 DUMPREG(HDMI_HPD);
603 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900604 DUMPREG(HDMI_V13_HPD_GEN);
605 DUMPREG(HDMI_V13_DC_CONTROL);
606 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900607
608 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
609 DUMPREG(HDMI_H_BLANK_0);
610 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900611 DUMPREG(HDMI_V13_V_BLANK_0);
612 DUMPREG(HDMI_V13_V_BLANK_1);
613 DUMPREG(HDMI_V13_V_BLANK_2);
614 DUMPREG(HDMI_V13_H_V_LINE_0);
615 DUMPREG(HDMI_V13_H_V_LINE_1);
616 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900617 DUMPREG(HDMI_VSYNC_POL);
618 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900619 DUMPREG(HDMI_V13_V_BLANK_F_0);
620 DUMPREG(HDMI_V13_V_BLANK_F_1);
621 DUMPREG(HDMI_V13_V_BLANK_F_2);
622 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
623 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
624 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
625 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
626 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
627 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
628 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
629 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
630 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
631 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
632 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
633 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
635 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
636 DUMPREG(HDMI_TG_CMD);
637 DUMPREG(HDMI_TG_H_FSZ_L);
638 DUMPREG(HDMI_TG_H_FSZ_H);
639 DUMPREG(HDMI_TG_HACT_ST_L);
640 DUMPREG(HDMI_TG_HACT_ST_H);
641 DUMPREG(HDMI_TG_HACT_SZ_L);
642 DUMPREG(HDMI_TG_HACT_SZ_H);
643 DUMPREG(HDMI_TG_V_FSZ_L);
644 DUMPREG(HDMI_TG_V_FSZ_H);
645 DUMPREG(HDMI_TG_VSYNC_L);
646 DUMPREG(HDMI_TG_VSYNC_H);
647 DUMPREG(HDMI_TG_VSYNC2_L);
648 DUMPREG(HDMI_TG_VSYNC2_H);
649 DUMPREG(HDMI_TG_VACT_ST_L);
650 DUMPREG(HDMI_TG_VACT_ST_H);
651 DUMPREG(HDMI_TG_VACT_SZ_L);
652 DUMPREG(HDMI_TG_VACT_SZ_H);
653 DUMPREG(HDMI_TG_FIELD_CHG_L);
654 DUMPREG(HDMI_TG_FIELD_CHG_H);
655 DUMPREG(HDMI_TG_VACT_ST2_L);
656 DUMPREG(HDMI_TG_VACT_ST2_H);
657 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
658 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
659 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
660 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
661 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
662 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
663 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
664 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
665#undef DUMPREG
666}
667
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900668static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
669{
670 int i;
671
672#define DUMPREG(reg_id) \
673 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
674 readl(hdata->regs + reg_id))
675
676 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
677 DUMPREG(HDMI_INTC_CON);
678 DUMPREG(HDMI_INTC_FLAG);
679 DUMPREG(HDMI_HPD_STATUS);
680 DUMPREG(HDMI_INTC_CON_1);
681 DUMPREG(HDMI_INTC_FLAG_1);
682 DUMPREG(HDMI_PHY_STATUS_0);
683 DUMPREG(HDMI_PHY_STATUS_PLL);
684 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200685 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900686 DUMPREG(HDMI_PHY_VPLL);
687 DUMPREG(HDMI_PHY_CMU);
688 DUMPREG(HDMI_CORE_RSTOUT);
689
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);
695 DUMPREG(HDMI_PHY_STATUS_0);
696 DUMPREG(HDMI_STATUS_EN);
697 DUMPREG(HDMI_HPD);
698 DUMPREG(HDMI_MODE_SEL);
699 DUMPREG(HDMI_ENC_EN);
700 DUMPREG(HDMI_DC_CONTROL);
701 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
702
703 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
704 DUMPREG(HDMI_H_BLANK_0);
705 DUMPREG(HDMI_H_BLANK_1);
706 DUMPREG(HDMI_V2_BLANK_0);
707 DUMPREG(HDMI_V2_BLANK_1);
708 DUMPREG(HDMI_V1_BLANK_0);
709 DUMPREG(HDMI_V1_BLANK_1);
710 DUMPREG(HDMI_V_LINE_0);
711 DUMPREG(HDMI_V_LINE_1);
712 DUMPREG(HDMI_H_LINE_0);
713 DUMPREG(HDMI_H_LINE_1);
714 DUMPREG(HDMI_HSYNC_POL);
715
716 DUMPREG(HDMI_VSYNC_POL);
717 DUMPREG(HDMI_INT_PRO_MODE);
718 DUMPREG(HDMI_V_BLANK_F0_0);
719 DUMPREG(HDMI_V_BLANK_F0_1);
720 DUMPREG(HDMI_V_BLANK_F1_0);
721 DUMPREG(HDMI_V_BLANK_F1_1);
722
723 DUMPREG(HDMI_H_SYNC_START_0);
724 DUMPREG(HDMI_H_SYNC_START_1);
725 DUMPREG(HDMI_H_SYNC_END_0);
726 DUMPREG(HDMI_H_SYNC_END_1);
727
728 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
729 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
730 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
731 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
732
733 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
734 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
735 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
736 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
737
738 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
739 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
740 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
741 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
742
743 DUMPREG(HDMI_V_BLANK_F2_0);
744 DUMPREG(HDMI_V_BLANK_F2_1);
745 DUMPREG(HDMI_V_BLANK_F3_0);
746 DUMPREG(HDMI_V_BLANK_F3_1);
747 DUMPREG(HDMI_V_BLANK_F4_0);
748 DUMPREG(HDMI_V_BLANK_F4_1);
749 DUMPREG(HDMI_V_BLANK_F5_0);
750 DUMPREG(HDMI_V_BLANK_F5_1);
751
752 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
753 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
754 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
755 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
756 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
757 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
758 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
759 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
760
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
769
770 DUMPREG(HDMI_VACT_SPACE_1_0);
771 DUMPREG(HDMI_VACT_SPACE_1_1);
772 DUMPREG(HDMI_VACT_SPACE_2_0);
773 DUMPREG(HDMI_VACT_SPACE_2_1);
774 DUMPREG(HDMI_VACT_SPACE_3_0);
775 DUMPREG(HDMI_VACT_SPACE_3_1);
776 DUMPREG(HDMI_VACT_SPACE_4_0);
777 DUMPREG(HDMI_VACT_SPACE_4_1);
778 DUMPREG(HDMI_VACT_SPACE_5_0);
779 DUMPREG(HDMI_VACT_SPACE_5_1);
780 DUMPREG(HDMI_VACT_SPACE_6_0);
781 DUMPREG(HDMI_VACT_SPACE_6_1);
782
783 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
784 DUMPREG(HDMI_TG_CMD);
785 DUMPREG(HDMI_TG_H_FSZ_L);
786 DUMPREG(HDMI_TG_H_FSZ_H);
787 DUMPREG(HDMI_TG_HACT_ST_L);
788 DUMPREG(HDMI_TG_HACT_ST_H);
789 DUMPREG(HDMI_TG_HACT_SZ_L);
790 DUMPREG(HDMI_TG_HACT_SZ_H);
791 DUMPREG(HDMI_TG_V_FSZ_L);
792 DUMPREG(HDMI_TG_V_FSZ_H);
793 DUMPREG(HDMI_TG_VSYNC_L);
794 DUMPREG(HDMI_TG_VSYNC_H);
795 DUMPREG(HDMI_TG_VSYNC2_L);
796 DUMPREG(HDMI_TG_VSYNC2_H);
797 DUMPREG(HDMI_TG_VACT_ST_L);
798 DUMPREG(HDMI_TG_VACT_ST_H);
799 DUMPREG(HDMI_TG_VACT_SZ_L);
800 DUMPREG(HDMI_TG_VACT_SZ_H);
801 DUMPREG(HDMI_TG_FIELD_CHG_L);
802 DUMPREG(HDMI_TG_FIELD_CHG_H);
803 DUMPREG(HDMI_TG_VACT_ST2_L);
804 DUMPREG(HDMI_TG_VACT_ST2_H);
805 DUMPREG(HDMI_TG_VACT_ST3_L);
806 DUMPREG(HDMI_TG_VACT_ST3_H);
807 DUMPREG(HDMI_TG_VACT_ST4_L);
808 DUMPREG(HDMI_TG_VACT_ST4_H);
809 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
810 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
811 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
812 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
813 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
814 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
815 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
816 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
817 DUMPREG(HDMI_TG_3D);
818
819 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
820 DUMPREG(HDMI_AVI_CON);
821 DUMPREG(HDMI_AVI_HEADER0);
822 DUMPREG(HDMI_AVI_HEADER1);
823 DUMPREG(HDMI_AVI_HEADER2);
824 DUMPREG(HDMI_AVI_CHECK_SUM);
825 DUMPREG(HDMI_VSI_CON);
826 DUMPREG(HDMI_VSI_HEADER0);
827 DUMPREG(HDMI_VSI_HEADER1);
828 DUMPREG(HDMI_VSI_HEADER2);
829 for (i = 0; i < 7; ++i)
830 DUMPREG(HDMI_VSI_DATA(i));
831
832#undef DUMPREG
833}
834
835static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
836{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200837 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900838 hdmi_v13_regs_dump(hdata, prefix);
839 else
840 hdmi_v14_regs_dump(hdata, prefix);
841}
842
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530843static u8 hdmi_chksum(struct hdmi_context *hdata,
844 u32 start, u8 len, u32 hdr_sum)
845{
846 int i;
847
848 /* hdr_sum : header0 + header1 + header2
849 * start : start address of packet byte1
850 * len : packet bytes - 1 */
851 for (i = 0; i < len; ++i)
852 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
853
854 /* return 2's complement of 8 bit hdr_sum */
855 return (u8)(~(hdr_sum & 0xff) + 1);
856}
857
858static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530859 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530860{
861 u32 hdr_sum;
862 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530863 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200864 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530865
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530866 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
867 if (hdata->dvi_mode) {
868 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
869 HDMI_VSI_CON_DO_NOT_TRANSMIT);
870 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
871 HDMI_AVI_CON_DO_NOT_TRANSMIT);
872 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
873 return;
874 }
875
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530876 switch (infoframe->any.type) {
877 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530878 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530879 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
880 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
881 infoframe->any.version);
882 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
883 hdr_sum = infoframe->any.type + infoframe->any.version +
884 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530885
886 /* Output format zero hardcoded ,RGB YBCR selection */
887 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
888 AVI_ACTIVE_FORMAT_VALID |
889 AVI_UNDERSCANNED_DISPLAY_VALID);
890
Shirish S46154152014-03-13 10:58:28 +0530891 /*
892 * Set the aspect ratio as per the mode, mentioned in
893 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
894 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200895 ar = hdata->current_mode.picture_aspect_ratio;
896 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530897 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200898 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530899 break;
900 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200901 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530902 break;
903 case HDMI_PICTURE_ASPECT_NONE:
904 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200905 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530906 break;
907 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200908 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530909
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200910 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530911
912 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530913 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530914 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
915 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
916 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530917 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530918 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530919 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
920 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
921 infoframe->any.version);
922 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
923 hdr_sum = infoframe->any.type + infoframe->any.version +
924 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530925 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530926 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530927 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
928 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
929 break;
930 default:
931 break;
932 }
933}
934
Sean Pauld9716ee2014-01-30 16:19:29 -0500935static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
936 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500937{
Sean Pauld9716ee2014-01-30 16:19:29 -0500938 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500939
Andrzej Hajda2228b7c2015-09-25 14:48:24 +0200940 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200941 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530942
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200943 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500944}
945
Sean Pauld9716ee2014-01-30 16:19:29 -0500946static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900947{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200948 drm_connector_unregister(connector);
949 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950}
951
Sean Pauld9716ee2014-01-30 16:19:29 -0500952static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300953 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500954 .fill_modes = drm_helper_probe_single_connector_modes,
955 .detect = hdmi_detect,
956 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300957 .reset = drm_atomic_helper_connector_reset,
958 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
959 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500960};
961
962static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900963{
Sean Pauld9716ee2014-01-30 16:19:29 -0500964 struct hdmi_context *hdata = ctx_from_connector(connector);
965 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200966 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900967
Inki Dae8fa04aa2014-03-13 16:38:31 +0900968 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500969 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970
Inki Dae8fa04aa2014-03-13 16:38:31 +0900971 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500972 if (!edid)
973 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974
Sean Pauld9716ee2014-01-30 16:19:29 -0500975 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500976 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
977 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500978 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500979
Sean Pauld9716ee2014-01-30 16:19:29 -0500980 drm_mode_connector_update_edid_property(connector, edid);
981
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200982 ret = drm_add_edid_modes(connector, edid);
983
984 kfree(edid);
985
986 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900987}
988
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900989static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900991 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900992
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200993 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
994 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500995 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500996
997 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
998 return -EINVAL;
999}
1000
Sean Pauld9716ee2014-01-30 16:19:29 -05001001static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001002 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001003{
Sean Pauld9716ee2014-01-30 16:19:29 -05001004 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001005 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001006
Rahul Sharma16844fb2013-06-10 14:50:00 +05301007 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1008 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1009 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1010 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001011
Sean Paulf041b252014-01-30 16:19:15 -05001012 ret = mixer_check_mode(mode);
1013 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001014 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001015
Rahul Sharma16844fb2013-06-10 14:50:00 +05301016 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001017 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001018 return MODE_BAD;
1019
1020 return MODE_OK;
1021}
1022
1023static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1024{
1025 struct hdmi_context *hdata = ctx_from_connector(connector);
1026
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001027 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001028}
1029
1030static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1031 .get_modes = hdmi_get_modes,
1032 .mode_valid = hdmi_mode_valid,
1033 .best_encoder = hdmi_best_encoder,
1034};
1035
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001036static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001037{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001038 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001039 struct drm_connector *connector = &hdata->connector;
1040 int ret;
1041
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 connector->interlace_allowed = true;
1043 connector->polled = DRM_CONNECTOR_POLL_HPD;
1044
1045 ret = drm_connector_init(hdata->drm_dev, connector,
1046 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1047 if (ret) {
1048 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001049 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001050 }
1051
1052 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001053 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001054 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001055
1056 return 0;
1057}
1058
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001059static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1060 const struct drm_display_mode *mode,
1061 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001062{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001063 struct drm_device *dev = encoder->dev;
1064 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001065 struct drm_display_mode *m;
1066 int mode_ok;
1067
Sean Paulf041b252014-01-30 16:19:15 -05001068 drm_mode_set_crtcinfo(adjusted_mode, 0);
1069
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001070 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1071 if (connector->encoder == encoder)
1072 break;
1073 }
1074
1075 if (connector->encoder != encoder)
1076 return true;
1077
Sean Pauld9716ee2014-01-30 16:19:29 -05001078 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001079
1080 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001081 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001082 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001083
1084 /*
1085 * otherwise, find the most suitable mode among modes and change it
1086 * to adjusted_mode.
1087 */
1088 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001089 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001090
Sean Pauld9716ee2014-01-30 16:19:29 -05001091 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001092 DRM_INFO("desired mode doesn't exist so\n");
1093 DRM_INFO("use the most suitable mode among modes.\n");
1094
1095 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1096 m->hdisplay, m->vdisplay, m->vrefresh);
1097
Sean Paul75626852014-01-30 16:19:16 -05001098 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001099 break;
1100 }
1101 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001102
1103 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001104}
1105
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001106static void hdmi_set_acr(u32 freq, u8 *acr)
1107{
1108 u32 n, cts;
1109
1110 switch (freq) {
1111 case 32000:
1112 n = 4096;
1113 cts = 27000;
1114 break;
1115 case 44100:
1116 n = 6272;
1117 cts = 30000;
1118 break;
1119 case 88200:
1120 n = 12544;
1121 cts = 30000;
1122 break;
1123 case 176400:
1124 n = 25088;
1125 cts = 30000;
1126 break;
1127 case 48000:
1128 n = 6144;
1129 cts = 27000;
1130 break;
1131 case 96000:
1132 n = 12288;
1133 cts = 27000;
1134 break;
1135 case 192000:
1136 n = 24576;
1137 cts = 27000;
1138 break;
1139 default:
1140 n = 0;
1141 cts = 0;
1142 break;
1143 }
1144
1145 acr[1] = cts >> 16;
1146 acr[2] = cts >> 8 & 0xff;
1147 acr[3] = cts & 0xff;
1148
1149 acr[4] = n >> 16;
1150 acr[5] = n >> 8 & 0xff;
1151 acr[6] = n & 0xff;
1152}
1153
1154static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1155{
1156 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1157 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1158 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1159 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1160 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1161 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1162 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1163 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1164 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001165 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001166}
1167
1168static void hdmi_audio_init(struct hdmi_context *hdata)
1169{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301170 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001171 u32 data_num, bit_ch, sample_frq;
1172 u32 val;
1173 u8 acr[7];
1174
1175 sample_rate = 44100;
1176 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001177
1178 switch (bits_per_sample) {
1179 case 20:
1180 data_num = 2;
1181 bit_ch = 1;
1182 break;
1183 case 24:
1184 data_num = 3;
1185 bit_ch = 1;
1186 break;
1187 default:
1188 data_num = 1;
1189 bit_ch = 0;
1190 break;
1191 }
1192
1193 hdmi_set_acr(sample_rate, acr);
1194 hdmi_reg_acr(hdata, acr);
1195
1196 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1197 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1198 | HDMI_I2S_MUX_ENABLE);
1199
1200 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1201 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1202
1203 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1204
1205 sample_frq = (sample_rate == 44100) ? 0 :
1206 (sample_rate == 48000) ? 2 :
1207 (sample_rate == 32000) ? 3 :
1208 (sample_rate == 96000) ? 0xa : 0x0;
1209
1210 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1211 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1212
1213 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1214 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1215
1216 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1217 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1218 | HDMI_I2S_SEL_LRCK(6));
1219 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1220 | HDMI_I2S_SEL_SDATA2(4));
1221 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1222 | HDMI_I2S_SEL_SDATA2(2));
1223 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1224
1225 /* I2S_CON_1 & 2 */
1226 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1227 | HDMI_I2S_L_CH_LOW_POL);
1228 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1229 | HDMI_I2S_SET_BIT_CH(bit_ch)
1230 | HDMI_I2S_SET_SDATA_BIT(data_num)
1231 | HDMI_I2S_BASIC_FORMAT);
1232
1233 /* Configure register related to CUV information */
1234 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1235 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1236 | HDMI_I2S_COPYRIGHT
1237 | HDMI_I2S_LINEAR_PCM
1238 | HDMI_I2S_CONSUMER_FORMAT);
1239 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1240 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1241 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1242 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1243 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1244 HDMI_I2S_ORG_SMP_FREQ_44_1
1245 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1246 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1247
1248 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1249}
1250
1251static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1252{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001253 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001254 return;
1255
1256 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1257 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1258 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1259}
1260
Rahul Sharmabfa48422014-04-03 20:41:04 +05301261static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001262{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301263 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001264
Rahul Sharmabfa48422014-04-03 20:41:04 +05301265 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1266 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001267
Rahul Sharmabfa48422014-04-03 20:41:04 +05301268 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1269 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001270}
1271
1272static void hdmi_conf_init(struct hdmi_context *hdata)
1273{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301274 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301275
Sean Paul77006a72013-01-16 10:17:20 -05001276 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001277 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1278 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001279
1280 /* choose HDMI mode */
1281 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1282 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301283 /* Apply Video preable and Guard band in HDMI mode only */
1284 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001285 /* disable bluescreen */
1286 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001287
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001288 if (hdata->dvi_mode) {
1289 /* choose DVI mode */
1290 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1291 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1292 hdmi_reg_writeb(hdata, HDMI_CON_2,
1293 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1294 }
1295
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001296 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001297 /* choose bluescreen (fecal) color */
1298 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1299 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1300 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1301
1302 /* enable AVI packet every vsync, fixes purple line problem */
1303 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1304 /* force RGB, look to CEA-861-D, table 7 for more detail */
1305 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1306 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1307
1308 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1309 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1310 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1311 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301312 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1313 infoframe.any.version = HDMI_AVI_VERSION;
1314 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301315 hdmi_reg_infoframe(hdata, &infoframe);
1316
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301317 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1318 infoframe.any.version = HDMI_AUI_VERSION;
1319 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301320 hdmi_reg_infoframe(hdata, &infoframe);
1321
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001322 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001323 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1324 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001325}
1326
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001327static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1328{
1329 int tries;
1330
1331 for (tries = 0; tries < 10; ++tries) {
1332 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1333
1334 if (val & HDMI_PHY_STATUS_READY) {
1335 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1336 return;
1337 }
1338 usleep_range(10, 20);
1339 }
1340
1341 DRM_ERROR("PLL could not reach steady state\n");
1342}
1343
Rahul Sharma16844fb2013-06-10 14:50:00 +05301344static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001345{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001346 struct drm_display_mode *m = &hdata->current_mode;
1347 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001348
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001349 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1350 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1351 (m->htotal << 12) | m->vtotal);
1352
1353 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1354 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1355
1356 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1357 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1358
1359 val = (m->hsync_start - m->hdisplay - 2);
1360 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1361 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1362 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1363
1364 /*
1365 * Quirk requirement for exynos HDMI IP design,
1366 * 2 pixels less than the actual calculation for hsync_start
1367 * and end.
1368 */
1369
1370 /* Following values & calculations differ for different type of modes */
1371 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1372 /* Interlaced Mode */
1373 val = ((m->vsync_end - m->vdisplay) / 2);
1374 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1375 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1376
1377 val = m->vtotal / 2;
1378 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1379 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1380
1381 val = (m->vtotal +
1382 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1383 val |= m->vtotal << 11;
1384 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1385
1386 val = ((m->vtotal / 2) + 7);
1387 val |= ((m->vtotal / 2) + 2) << 12;
1388 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1389
1390 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1391 val |= ((m->htotal / 2) +
1392 (m->hsync_start - m->hdisplay)) << 12;
1393 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1394
1395 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1396 (m->vtotal - m->vdisplay) / 2);
1397 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1398
1399 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1400 } else {
1401 /* Progressive Mode */
1402
1403 val = m->vtotal;
1404 val |= (m->vtotal - m->vdisplay) << 11;
1405 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1406
1407 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1408
1409 val = (m->vsync_end - m->vdisplay);
1410 val |= ((m->vsync_start - m->vdisplay) << 12);
1411 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1412
1413 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1414 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1415 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1416 m->vtotal - m->vdisplay);
1417 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1418 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1419 }
1420
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001421 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001422 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1423 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1424 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1425 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1426 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1427 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1428 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1429 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1430 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1431 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1432 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001433}
1434
Rahul Sharma16844fb2013-06-10 14:50:00 +05301435static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001436{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001437 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001438
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001439 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1440 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1441 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1442 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1443 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1444 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1445 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1446 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1447 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1448
1449 /*
1450 * Quirk requirement for exynos 5 HDMI IP design,
1451 * 2 pixels less than the actual calculation for hsync_start
1452 * and end.
1453 */
1454
1455 /* Following values & calculations differ for different type of modes */
1456 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1457 /* Interlaced Mode */
1458 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1459 (m->vsync_end - m->vdisplay) / 2);
1460 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1461 (m->vsync_start - m->vdisplay) / 2);
1462 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1463 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1464 (m->vtotal - m->vdisplay) / 2);
1465 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1466 m->vtotal - m->vdisplay / 2);
1467 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1468 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1469 (m->vtotal / 2) + 7);
1470 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1471 (m->vtotal / 2) + 2);
1472 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1473 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1474 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1475 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1476 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1477 (m->vtotal - m->vdisplay) / 2);
1478 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1479 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1480 m->vtotal - m->vdisplay / 2);
1481 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1482 (m->vtotal / 2) + 1);
1483 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1484 (m->vtotal / 2) + 1);
1485 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1486 (m->vtotal / 2) + 1);
1487 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1488 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1489 } else {
1490 /* Progressive Mode */
1491 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1492 m->vsync_end - m->vdisplay);
1493 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1494 m->vsync_start - m->vdisplay);
1495 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1496 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1497 m->vtotal - m->vdisplay);
1498 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1499 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1500 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1501 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1502 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1503 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1504 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1505 m->vtotal - m->vdisplay);
1506 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1507 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1508 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1509 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1510 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1511 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1512 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1513 }
1514
1515 /* Following values & calculations are same irrespective of mode type */
1516 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1517 m->hsync_start - m->hdisplay - 2);
1518 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1519 m->hsync_end - m->hdisplay - 2);
1520 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1521 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1522 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1523 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1524 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1525 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1526 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1527 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1528 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1529 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1530 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001538
1539 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001540 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1541 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1542 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1543 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1544 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1545 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1546 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1547 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1548 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001549}
1550
Rahul Sharma16844fb2013-06-10 14:50:00 +05301551static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001552{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001553 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301554 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001555 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301556 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001557
1558 hdmiphy_wait_for_pll(hdata);
1559
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001560 clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001561
1562 /* enable HDMI and timing generator */
1563 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001564}
1565
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001566static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1567{
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001568 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001569
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001570 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001571 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001572 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001573 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001574 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001575}
1576
1577static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1578{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001579 int ret;
1580 int i;
1581
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001582 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001583 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001584 if (i < 0) {
1585 DRM_ERROR("failed to find hdmiphy conf\n");
1586 return;
1587 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001588
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001589 ret = hdmiphy_reg_write_buf(hdata, 0,
1590 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001591 if (ret) {
1592 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001593 return;
1594 }
1595
Sean Paul09760ea2013-01-14 17:03:20 -05001596 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001597}
1598
1599static void hdmi_conf_apply(struct hdmi_context *hdata)
1600{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001601 hdmiphy_conf_reset(hdata);
1602 hdmiphy_conf_apply(hdata);
1603
Rahul Sharmabfa48422014-04-03 20:41:04 +05301604 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001605 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001606
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001607 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001608
1609 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301610 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001611 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001612
1613 hdmi_regs_dump(hdata, "start");
1614}
1615
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001616static void hdmi_mode_set(struct drm_encoder *encoder,
1617 struct drm_display_mode *mode,
1618 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001619{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001620 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001621 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001622
YoungJun Chocbc4c332013-06-12 10:44:40 +09001623 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1624 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001625 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001626 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001627
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001628 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001629 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001630}
1631
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001632static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001633{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001634 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001635
Andrzej Hajda882a0642015-07-09 16:28:08 +02001636 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001637 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001638
1639 hdata->powered = true;
1640
Sean Paulaf65c802014-01-30 16:19:27 -05001641 pm_runtime_get_sync(hdata->dev);
1642
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001643 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001644 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1645
Rahul Sharma049d34e2014-05-20 10:36:05 +05301646 /* set pmu hdmiphy control bit to enable hdmiphy */
1647 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1648 PMU_HDMI_PHY_ENABLE_BIT, 1);
1649
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001650 clk_prepare_enable(hdata->hdmi);
1651 clk_prepare_enable(hdata->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301652
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001653 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001654}
1655
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001656static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001657{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001658 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001659 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001660 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001661
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001662 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001663 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001664
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001665 /*
1666 * The SFRs of VP and Mixer are updated by Vertical Sync of
1667 * Timing generator which is a part of HDMI so the sequence
1668 * to disable TV Subsystem should be as following,
1669 * VP -> Mixer -> HDMI
1670 *
1671 * Below codes will try to disable Mixer and VP(if used)
1672 * prior to disabling HDMI.
1673 */
1674 if (crtc)
1675 funcs = crtc->helper_private;
1676 if (funcs && funcs->disable)
1677 (*funcs->disable)(crtc);
1678
Rahul Sharmabfa48422014-04-03 20:41:04 +05301679 /* HDMI System Disable */
1680 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1681
Sean Paul724fd142014-05-09 15:05:10 +09001682 cancel_delayed_work(&hdata->hotplug_work);
1683
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001684 clk_disable_unprepare(hdata->sclk_hdmi);
1685 clk_disable_unprepare(hdata->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301686
1687 /* reset pmu hdmiphy control bit to disable hdmiphy */
1688 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1689 PMU_HDMI_PHY_ENABLE_BIT, 0);
1690
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001691 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001692
Sean Paulaf65c802014-01-30 16:19:27 -05001693 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001694
1695 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001696}
1697
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001698static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001699 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001700 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001701 .enable = hdmi_enable,
1702 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001703};
1704
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001705static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1706 .destroy = drm_encoder_cleanup,
1707};
1708
Sean Paul724fd142014-05-09 15:05:10 +09001709static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001710{
Sean Paul724fd142014-05-09 15:05:10 +09001711 struct hdmi_context *hdata;
1712
1713 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001714
Sean Paul45517892014-01-30 16:19:05 -05001715 if (hdata->drm_dev)
1716 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001717}
1718
1719static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1720{
1721 struct hdmi_context *hdata = arg;
1722
1723 mod_delayed_work(system_wq, &hdata->hotplug_work,
1724 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001725
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001726 return IRQ_HANDLED;
1727}
1728
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001729static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001730{
1731 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001732 int i, ret;
1733
1734 DRM_DEBUG_KMS("HDMI resource init\n");
1735
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001736 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1737 if (IS_ERR(hdata->hpd_gpio)) {
1738 DRM_ERROR("cannot get hpd gpio property\n");
1739 return PTR_ERR(hdata->hpd_gpio);
1740 }
1741
1742 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1743 if (hdata->irq < 0) {
1744 DRM_ERROR("failed to get GPIO irq\n");
1745 return hdata->irq;
1746 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001747 /* get clocks, power */
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001748 hdata->hdmi = devm_clk_get(dev, "hdmi");
1749 if (IS_ERR(hdata->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001750 DRM_ERROR("failed to get clock 'hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001751 ret = PTR_ERR(hdata->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001752 goto fail;
1753 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001754 hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
1755 if (IS_ERR(hdata->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001756 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001757 ret = PTR_ERR(hdata->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001758 goto fail;
1759 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001760 hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
1761 if (IS_ERR(hdata->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001762 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001763 ret = PTR_ERR(hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001764 goto fail;
1765 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001766 hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
1767 if (IS_ERR(hdata->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001768 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001769 ret = PTR_ERR(hdata->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001770 goto fail;
1771 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001772 hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1773 if (IS_ERR(hdata->mout_hdmi)) {
Rahul Sharma59956d32013-06-11 12:24:03 +05301774 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001775 ret = PTR_ERR(hdata->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301776 goto fail;
1777 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001778
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001779 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001780
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001781 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001782 hdata->regul_bulk[i].supply = supply[i];
1783 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001784 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001785 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001786 if (ret) {
1787 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001788 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001789 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001790
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001791 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001792
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001793 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001794 return 0;
1795
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001796 if (IS_ERR(hdata->reg_hdmi_en))
1797 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001798
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001799 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001800 if (ret)
1801 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001802
Inki Daedf5225b2014-05-29 18:28:02 +09001803 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001804fail:
1805 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001806 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001807}
1808
Rahul Sharma22c4f422012-10-04 20:48:55 +05301809static struct of_device_id hdmi_match_types[] = {
1810 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001811 .compatible = "samsung,exynos4210-hdmi",
1812 .data = &exynos4210_hdmi_driver_data,
1813 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301814 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001815 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301816 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301817 .compatible = "samsung,exynos5420-hdmi",
1818 .data = &exynos5420_hdmi_driver_data,
1819 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301820 /* end node */
1821 }
1822};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001823MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301824
Inki Daef37cd5e2014-05-09 14:25:20 +09001825static int hdmi_bind(struct device *dev, struct device *master, void *data)
1826{
1827 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001828 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001829 struct drm_encoder *encoder = &hdata->encoder;
1830 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001831
Inki Daef37cd5e2014-05-09 14:25:20 +09001832 hdata->drm_dev = drm_dev;
1833
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001834 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1835 EXYNOS_DISPLAY_TYPE_HDMI);
1836 if (pipe < 0)
1837 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001838
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001839 encoder->possible_crtcs = 1 << pipe;
1840
1841 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1842
1843 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1844 DRM_MODE_ENCODER_TMDS);
1845
1846 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1847
1848 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001849 if (ret) {
1850 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001851 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001852 return ret;
1853 }
1854
1855 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001856}
1857
1858static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1859{
Inki Daef37cd5e2014-05-09 14:25:20 +09001860}
1861
1862static const struct component_ops hdmi_component_ops = {
1863 .bind = hdmi_bind,
1864 .unbind = hdmi_unbind,
1865};
1866
Inki Daee2a562d2014-05-09 16:46:10 +09001867static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1868{
1869 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1870 struct device_node *np;
1871
1872 np = of_find_compatible_node(NULL, NULL, compatible_str);
1873 if (np)
1874 return of_get_next_parent(np);
1875
1876 return NULL;
1877}
1878
1879static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1880{
1881 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1882
1883 return of_find_compatible_node(NULL, NULL, compatible_str);
1884}
1885
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001886static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001887{
Inki Daef37cd5e2014-05-09 14:25:20 +09001888 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001889 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001890 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001891 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001892 struct resource *res;
1893 int ret;
1894
Andrzej Hajda930865f2014-11-17 09:54:20 +01001895 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1896 if (!hdata)
1897 return -ENOMEM;
1898
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001899 match = of_match_device(hdmi_match_types, dev);
1900 if (!match)
1901 return -ENODEV;
1902
1903 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001904
Andrzej Hajda930865f2014-11-17 09:54:20 +01001905 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001906
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001907 hdata->dev = dev;
1908
1909 ret = hdmi_resources_init(hdata);
1910 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301911 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001912 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001913 }
1914
1915 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001916 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001917 if (IS_ERR(hdata->regs)) {
1918 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001919 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001920 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001921
Inki Daee2a562d2014-05-09 16:46:10 +09001922 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1923 if (ddc_node)
1924 goto out_get_ddc_adpt;
1925
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001926 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001927 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1928 if (!ddc_node) {
1929 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001930 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001931 }
Inki Daee2a562d2014-05-09 16:46:10 +09001932
1933out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001934 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1935 if (!hdata->ddc_adpt) {
1936 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001937 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001938 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001939
Inki Daee2a562d2014-05-09 16:46:10 +09001940 phy_node = hdmi_legacy_phy_dt_binding(dev);
1941 if (phy_node)
1942 goto out_get_phy_port;
1943
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001944 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001945 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1946 if (!phy_node) {
1947 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1948 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001949 goto err_ddc;
1950 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001951
Inki Daee2a562d2014-05-09 16:46:10 +09001952out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001953 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001954 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1955 if (!hdata->regs_hdmiphy) {
1956 DRM_ERROR("failed to ioremap hdmi phy\n");
1957 ret = -ENOMEM;
1958 goto err_ddc;
1959 }
1960 } else {
1961 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1962 if (!hdata->hdmiphy_port) {
1963 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001964 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001965 goto err_ddc;
1966 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001967 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001968
Sean Paul724fd142014-05-09 15:05:10 +09001969 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1970
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001971 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001972 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001973 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001974 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001975 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001976 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001977 goto err_hdmiphy;
1978 }
1979
Rahul Sharma049d34e2014-05-20 10:36:05 +05301980 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
1981 "samsung,syscon-phandle");
1982 if (IS_ERR(hdata->pmureg)) {
1983 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001984 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05301985 goto err_hdmiphy;
1986 }
1987
Sean Paulaf65c802014-01-30 16:19:27 -05001988 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001989
Inki Daedf5225b2014-05-29 18:28:02 +09001990 ret = component_add(&pdev->dev, &hdmi_component_ops);
1991 if (ret)
1992 goto err_disable_pm_runtime;
1993
1994 return ret;
1995
1996err_disable_pm_runtime:
1997 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001998
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001999err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002000 if (hdata->hdmiphy_port)
2001 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002002err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002003 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002004
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002005 return ret;
2006}
2007
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002008static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002009{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002010 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011
Sean Paul724fd142014-05-09 15:05:10 +09002012 cancel_delayed_work_sync(&hdata->hotplug_work);
2013
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002014 component_del(&pdev->dev, &hdmi_component_ops);
2015
2016 pm_runtime_disable(&pdev->dev);
2017
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02002018 if (!IS_ERR(hdata->reg_hdmi_en))
2019 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002020
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002021 if (hdata->hdmiphy_port)
2022 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002023
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002024 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002025
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002026 return 0;
2027}
2028
2029struct platform_driver hdmi_driver = {
2030 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002031 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002032 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302033 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002034 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302035 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002036 },
2037};