blob: 622180317aca2d65ab65160cb35135b24ce6cf11 [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"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053049#include <linux/gpio.h>
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053050
Sean Pauld9716ee2014-01-30 16:19:29 -050051#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090052
Sean Paul724fd142014-05-09 15:05:10 +090053#define HOTPLUG_DEBOUNCE_MS 1100
54
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053055/* AVI header and aspect ratio */
56#define HDMI_AVI_VERSION 0x02
57#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053058
59/* AUI header info */
60#define HDMI_AUI_VERSION 0x01
61#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053062#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
63#define AVI_4_3_CENTER_RATIO 0x9
64#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053065
Rahul Sharma5a325072012-10-04 20:48:54 +053066enum hdmi_type {
67 HDMI_TYPE13,
68 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020069 HDMI_TYPE_COUNT
70};
71
72#define HDMI_MAPPED_BASE 0xffff0000
73
74enum hdmi_mapped_regs {
75 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
76 HDMI_PHY_RSTOUT,
77 HDMI_ACR_CON,
78};
79
80static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
81 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
82 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
83 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Rahul Sharma5a325072012-10-04 20:48:54 +053084};
85
Inki Daebfe4e842014-03-06 14:18:17 +090086struct hdmi_driver_data {
87 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090088 const struct hdmiphy_config *phy_confs;
89 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090090 unsigned int is_apb_phy:1;
91};
92
Joonyoung Shim590f4182012-03-16 18:47:14 +090093struct hdmi_resources {
94 struct clk *hdmi;
95 struct clk *sclk_hdmi;
96 struct clk *sclk_pixel;
97 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053098 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090099 struct regulator_bulk_data *regul_bulk;
Marek Szyprowski05fdf982014-07-01 10:10:06 +0200100 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900101 int regul_count;
102};
103
104struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300105 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900106 struct device *dev;
107 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500108 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900109 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900110 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900111 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900112
Joonyoung Shim590f4182012-03-16 18:47:14 +0900113 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500114 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900115 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900116
Inki Dae8fa04aa2014-03-13 16:38:31 +0900117 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900118 struct i2c_client *hdmiphy_port;
119
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900120 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530121 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200122 u8 cea_video_id;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900123
124 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200125 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900126
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530127 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900128 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530129
Rahul Sharma049d34e2014-05-20 10:36:05 +0530130 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900131};
132
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300133static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100134{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900135 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100136}
137
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500138struct hdmiphy_config {
139 int pixel_clock;
140 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900141};
142
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900143/* list of phy config settings */
144static const struct hdmiphy_config hdmiphy_v13_configs[] = {
145 {
146 .pixel_clock = 27000000,
147 .conf = {
148 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
149 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
150 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
151 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
152 },
153 },
154 {
155 .pixel_clock = 27027000,
156 .conf = {
157 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
158 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
159 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
160 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
161 },
162 },
163 {
164 .pixel_clock = 74176000,
165 .conf = {
166 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
167 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
168 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
169 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
170 },
171 },
172 {
173 .pixel_clock = 74250000,
174 .conf = {
175 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
176 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
177 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
178 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
179 },
180 },
181 {
182 .pixel_clock = 148500000,
183 .conf = {
184 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
185 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
186 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
187 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
188 },
189 },
190};
191
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500192static const struct hdmiphy_config hdmiphy_v14_configs[] = {
193 {
194 .pixel_clock = 25200000,
195 .conf = {
196 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
197 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
198 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
199 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
200 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900201 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500202 {
203 .pixel_clock = 27000000,
204 .conf = {
205 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
206 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
207 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
208 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
209 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900210 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500211 {
212 .pixel_clock = 27027000,
213 .conf = {
214 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
215 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
216 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
217 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
218 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900219 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500220 {
221 .pixel_clock = 36000000,
222 .conf = {
223 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
224 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
225 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
226 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
227 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900228 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500229 {
230 .pixel_clock = 40000000,
231 .conf = {
232 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
233 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
234 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
235 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
236 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900237 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500238 {
239 .pixel_clock = 65000000,
240 .conf = {
241 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
242 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
243 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
244 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
245 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900246 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500247 {
Shirish Se1d883c2014-03-13 14:28:27 +0900248 .pixel_clock = 71000000,
249 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530250 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
251 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
252 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900253 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
254 },
255 },
256 {
257 .pixel_clock = 73250000,
258 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530259 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
260 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
261 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900262 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
263 },
264 },
265 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500266 .pixel_clock = 74176000,
267 .conf = {
268 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
269 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
270 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
271 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
272 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900273 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500274 {
275 .pixel_clock = 74250000,
276 .conf = {
277 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
278 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
279 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
280 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
281 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900282 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500283 {
284 .pixel_clock = 83500000,
285 .conf = {
286 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
287 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
288 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
289 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
290 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900291 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500292 {
293 .pixel_clock = 106500000,
294 .conf = {
295 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
296 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
297 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
298 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
299 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900300 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500301 {
302 .pixel_clock = 108000000,
303 .conf = {
304 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
305 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
306 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
307 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
308 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900309 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500310 {
Shirish Se1d883c2014-03-13 14:28:27 +0900311 .pixel_clock = 115500000,
312 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530313 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
314 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
315 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900316 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
317 },
318 },
319 {
320 .pixel_clock = 119000000,
321 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530322 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
323 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
324 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900325 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
326 },
327 },
328 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500329 .pixel_clock = 146250000,
330 .conf = {
331 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
332 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
333 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
334 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
335 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900336 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500337 {
338 .pixel_clock = 148500000,
339 .conf = {
340 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
341 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
342 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
343 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
344 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900345 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900346};
347
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530348static const struct hdmiphy_config hdmiphy_5420_configs[] = {
349 {
350 .pixel_clock = 25200000,
351 .conf = {
352 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
353 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
354 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
355 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
356 },
357 },
358 {
359 .pixel_clock = 27000000,
360 .conf = {
361 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
362 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
363 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
364 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
365 },
366 },
367 {
368 .pixel_clock = 27027000,
369 .conf = {
370 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
371 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
372 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
373 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
374 },
375 },
376 {
377 .pixel_clock = 36000000,
378 .conf = {
379 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
380 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
381 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
382 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
383 },
384 },
385 {
386 .pixel_clock = 40000000,
387 .conf = {
388 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
389 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
390 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
391 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
392 },
393 },
394 {
395 .pixel_clock = 65000000,
396 .conf = {
397 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
398 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
399 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
400 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
401 },
402 },
403 {
404 .pixel_clock = 71000000,
405 .conf = {
406 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
407 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
408 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
409 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
410 },
411 },
412 {
413 .pixel_clock = 73250000,
414 .conf = {
415 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
416 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
417 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
418 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
419 },
420 },
421 {
422 .pixel_clock = 74176000,
423 .conf = {
424 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
425 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
426 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
427 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
428 },
429 },
430 {
431 .pixel_clock = 74250000,
432 .conf = {
433 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
434 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
435 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
436 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
437 },
438 },
439 {
440 .pixel_clock = 83500000,
441 .conf = {
442 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
443 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
444 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
445 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
446 },
447 },
448 {
449 .pixel_clock = 88750000,
450 .conf = {
451 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
452 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
453 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
454 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
455 },
456 },
457 {
458 .pixel_clock = 106500000,
459 .conf = {
460 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
461 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
462 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
463 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
464 },
465 },
466 {
467 .pixel_clock = 108000000,
468 .conf = {
469 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
470 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
471 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
472 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
473 },
474 },
475 {
476 .pixel_clock = 115500000,
477 .conf = {
478 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
479 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
480 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
481 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
482 },
483 },
484 {
485 .pixel_clock = 146250000,
486 .conf = {
487 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
488 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
489 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
490 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
491 },
492 },
493 {
494 .pixel_clock = 148500000,
495 .conf = {
496 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
497 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
498 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
499 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
500 },
501 },
502};
503
Sachin Kamat16337072014-05-22 10:32:56 +0530504static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530505 .type = HDMI_TYPE14,
506 .phy_confs = hdmiphy_5420_configs,
507 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
508 .is_apb_phy = 1,
509};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900510
Sachin Kamat16337072014-05-22 10:32:56 +0530511static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900512 .type = HDMI_TYPE14,
513 .phy_confs = hdmiphy_v14_configs,
514 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
515 .is_apb_phy = 0,
516};
517
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200518static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
519 .type = HDMI_TYPE13,
520 .phy_confs = hdmiphy_v13_configs,
521 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
522 .is_apb_phy = 0,
523};
524
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200525static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
526{
527 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
528 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
529 return reg_id;
530}
531
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900532static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
533{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200534 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535}
536
537static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
538 u32 reg_id, u8 value)
539{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200540 writeb(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900541}
542
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200543static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
544 int bytes, u32 val)
545{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200546 reg_id = hdmi_map_reg(hdata, reg_id);
547
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200548 while (--bytes >= 0) {
549 writeb(val & 0xff, hdata->regs + reg_id);
550 val >>= 8;
551 reg_id += 4;
552 }
553}
554
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900555static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
556 u32 reg_id, u32 value, u32 mask)
557{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200558 u32 old;
559
560 reg_id = hdmi_map_reg(hdata, reg_id);
561 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562 value = (value & mask) | (old & ~mask);
563 writel(value, hdata->regs + reg_id);
564}
565
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900566static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
567 u32 reg_offset, u8 value)
568{
569 if (hdata->hdmiphy_port) {
570 u8 buffer[2];
571 int ret;
572
573 buffer[0] = reg_offset;
574 buffer[1] = value;
575
576 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
577 if (ret == 2)
578 return 0;
579 return ret;
580 } else {
581 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
582 return 0;
583 }
584}
585
586static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
587 u32 reg_offset, const u8 *buf, u32 len)
588{
589 if ((reg_offset + len) > 32)
590 return -EINVAL;
591
592 if (hdata->hdmiphy_port) {
593 int ret;
594
595 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
596 if (ret == len)
597 return 0;
598 return ret;
599 } else {
600 int i;
601 for (i = 0; i < len; i++)
602 writeb(buf[i], hdata->regs_hdmiphy +
603 ((reg_offset + i)<<2));
604 return 0;
605 }
606}
607
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900608static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900609{
610#define DUMPREG(reg_id) \
611 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
612 readl(hdata->regs + reg_id))
613 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
614 DUMPREG(HDMI_INTC_FLAG);
615 DUMPREG(HDMI_INTC_CON);
616 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900617 DUMPREG(HDMI_V13_PHY_RSTOUT);
618 DUMPREG(HDMI_V13_PHY_VPLL);
619 DUMPREG(HDMI_V13_PHY_CMU);
620 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900621
622 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
623 DUMPREG(HDMI_CON_0);
624 DUMPREG(HDMI_CON_1);
625 DUMPREG(HDMI_CON_2);
626 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900627 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900628 DUMPREG(HDMI_STATUS_EN);
629 DUMPREG(HDMI_HPD);
630 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900631 DUMPREG(HDMI_V13_HPD_GEN);
632 DUMPREG(HDMI_V13_DC_CONTROL);
633 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
635 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
636 DUMPREG(HDMI_H_BLANK_0);
637 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900638 DUMPREG(HDMI_V13_V_BLANK_0);
639 DUMPREG(HDMI_V13_V_BLANK_1);
640 DUMPREG(HDMI_V13_V_BLANK_2);
641 DUMPREG(HDMI_V13_H_V_LINE_0);
642 DUMPREG(HDMI_V13_H_V_LINE_1);
643 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900644 DUMPREG(HDMI_VSYNC_POL);
645 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900646 DUMPREG(HDMI_V13_V_BLANK_F_0);
647 DUMPREG(HDMI_V13_V_BLANK_F_1);
648 DUMPREG(HDMI_V13_V_BLANK_F_2);
649 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
650 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
651 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
652 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
653 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
654 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
655 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
656 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
657 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
658 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
659 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
660 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900661
662 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
663 DUMPREG(HDMI_TG_CMD);
664 DUMPREG(HDMI_TG_H_FSZ_L);
665 DUMPREG(HDMI_TG_H_FSZ_H);
666 DUMPREG(HDMI_TG_HACT_ST_L);
667 DUMPREG(HDMI_TG_HACT_ST_H);
668 DUMPREG(HDMI_TG_HACT_SZ_L);
669 DUMPREG(HDMI_TG_HACT_SZ_H);
670 DUMPREG(HDMI_TG_V_FSZ_L);
671 DUMPREG(HDMI_TG_V_FSZ_H);
672 DUMPREG(HDMI_TG_VSYNC_L);
673 DUMPREG(HDMI_TG_VSYNC_H);
674 DUMPREG(HDMI_TG_VSYNC2_L);
675 DUMPREG(HDMI_TG_VSYNC2_H);
676 DUMPREG(HDMI_TG_VACT_ST_L);
677 DUMPREG(HDMI_TG_VACT_ST_H);
678 DUMPREG(HDMI_TG_VACT_SZ_L);
679 DUMPREG(HDMI_TG_VACT_SZ_H);
680 DUMPREG(HDMI_TG_FIELD_CHG_L);
681 DUMPREG(HDMI_TG_FIELD_CHG_H);
682 DUMPREG(HDMI_TG_VACT_ST2_L);
683 DUMPREG(HDMI_TG_VACT_ST2_H);
684 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
685 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
686 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
687 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
688 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
689 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
690 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
691 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
692#undef DUMPREG
693}
694
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900695static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
696{
697 int i;
698
699#define DUMPREG(reg_id) \
700 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
701 readl(hdata->regs + reg_id))
702
703 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
704 DUMPREG(HDMI_INTC_CON);
705 DUMPREG(HDMI_INTC_FLAG);
706 DUMPREG(HDMI_HPD_STATUS);
707 DUMPREG(HDMI_INTC_CON_1);
708 DUMPREG(HDMI_INTC_FLAG_1);
709 DUMPREG(HDMI_PHY_STATUS_0);
710 DUMPREG(HDMI_PHY_STATUS_PLL);
711 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200712 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900713 DUMPREG(HDMI_PHY_VPLL);
714 DUMPREG(HDMI_PHY_CMU);
715 DUMPREG(HDMI_CORE_RSTOUT);
716
717 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
718 DUMPREG(HDMI_CON_0);
719 DUMPREG(HDMI_CON_1);
720 DUMPREG(HDMI_CON_2);
721 DUMPREG(HDMI_SYS_STATUS);
722 DUMPREG(HDMI_PHY_STATUS_0);
723 DUMPREG(HDMI_STATUS_EN);
724 DUMPREG(HDMI_HPD);
725 DUMPREG(HDMI_MODE_SEL);
726 DUMPREG(HDMI_ENC_EN);
727 DUMPREG(HDMI_DC_CONTROL);
728 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
729
730 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
731 DUMPREG(HDMI_H_BLANK_0);
732 DUMPREG(HDMI_H_BLANK_1);
733 DUMPREG(HDMI_V2_BLANK_0);
734 DUMPREG(HDMI_V2_BLANK_1);
735 DUMPREG(HDMI_V1_BLANK_0);
736 DUMPREG(HDMI_V1_BLANK_1);
737 DUMPREG(HDMI_V_LINE_0);
738 DUMPREG(HDMI_V_LINE_1);
739 DUMPREG(HDMI_H_LINE_0);
740 DUMPREG(HDMI_H_LINE_1);
741 DUMPREG(HDMI_HSYNC_POL);
742
743 DUMPREG(HDMI_VSYNC_POL);
744 DUMPREG(HDMI_INT_PRO_MODE);
745 DUMPREG(HDMI_V_BLANK_F0_0);
746 DUMPREG(HDMI_V_BLANK_F0_1);
747 DUMPREG(HDMI_V_BLANK_F1_0);
748 DUMPREG(HDMI_V_BLANK_F1_1);
749
750 DUMPREG(HDMI_H_SYNC_START_0);
751 DUMPREG(HDMI_H_SYNC_START_1);
752 DUMPREG(HDMI_H_SYNC_END_0);
753 DUMPREG(HDMI_H_SYNC_END_1);
754
755 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
756 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
757 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
758 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
759
760 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
764
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
769
770 DUMPREG(HDMI_V_BLANK_F2_0);
771 DUMPREG(HDMI_V_BLANK_F2_1);
772 DUMPREG(HDMI_V_BLANK_F3_0);
773 DUMPREG(HDMI_V_BLANK_F3_1);
774 DUMPREG(HDMI_V_BLANK_F4_0);
775 DUMPREG(HDMI_V_BLANK_F4_1);
776 DUMPREG(HDMI_V_BLANK_F5_0);
777 DUMPREG(HDMI_V_BLANK_F5_1);
778
779 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
780 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
781 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
782 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
783 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
784 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
785 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
786 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
787
788 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
789 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
790 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
791 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
792 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
793 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
794 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
795 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
796
797 DUMPREG(HDMI_VACT_SPACE_1_0);
798 DUMPREG(HDMI_VACT_SPACE_1_1);
799 DUMPREG(HDMI_VACT_SPACE_2_0);
800 DUMPREG(HDMI_VACT_SPACE_2_1);
801 DUMPREG(HDMI_VACT_SPACE_3_0);
802 DUMPREG(HDMI_VACT_SPACE_3_1);
803 DUMPREG(HDMI_VACT_SPACE_4_0);
804 DUMPREG(HDMI_VACT_SPACE_4_1);
805 DUMPREG(HDMI_VACT_SPACE_5_0);
806 DUMPREG(HDMI_VACT_SPACE_5_1);
807 DUMPREG(HDMI_VACT_SPACE_6_0);
808 DUMPREG(HDMI_VACT_SPACE_6_1);
809
810 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
811 DUMPREG(HDMI_TG_CMD);
812 DUMPREG(HDMI_TG_H_FSZ_L);
813 DUMPREG(HDMI_TG_H_FSZ_H);
814 DUMPREG(HDMI_TG_HACT_ST_L);
815 DUMPREG(HDMI_TG_HACT_ST_H);
816 DUMPREG(HDMI_TG_HACT_SZ_L);
817 DUMPREG(HDMI_TG_HACT_SZ_H);
818 DUMPREG(HDMI_TG_V_FSZ_L);
819 DUMPREG(HDMI_TG_V_FSZ_H);
820 DUMPREG(HDMI_TG_VSYNC_L);
821 DUMPREG(HDMI_TG_VSYNC_H);
822 DUMPREG(HDMI_TG_VSYNC2_L);
823 DUMPREG(HDMI_TG_VSYNC2_H);
824 DUMPREG(HDMI_TG_VACT_ST_L);
825 DUMPREG(HDMI_TG_VACT_ST_H);
826 DUMPREG(HDMI_TG_VACT_SZ_L);
827 DUMPREG(HDMI_TG_VACT_SZ_H);
828 DUMPREG(HDMI_TG_FIELD_CHG_L);
829 DUMPREG(HDMI_TG_FIELD_CHG_H);
830 DUMPREG(HDMI_TG_VACT_ST2_L);
831 DUMPREG(HDMI_TG_VACT_ST2_H);
832 DUMPREG(HDMI_TG_VACT_ST3_L);
833 DUMPREG(HDMI_TG_VACT_ST3_H);
834 DUMPREG(HDMI_TG_VACT_ST4_L);
835 DUMPREG(HDMI_TG_VACT_ST4_H);
836 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
837 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
838 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
839 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
840 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
841 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
842 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
843 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
844 DUMPREG(HDMI_TG_3D);
845
846 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
847 DUMPREG(HDMI_AVI_CON);
848 DUMPREG(HDMI_AVI_HEADER0);
849 DUMPREG(HDMI_AVI_HEADER1);
850 DUMPREG(HDMI_AVI_HEADER2);
851 DUMPREG(HDMI_AVI_CHECK_SUM);
852 DUMPREG(HDMI_VSI_CON);
853 DUMPREG(HDMI_VSI_HEADER0);
854 DUMPREG(HDMI_VSI_HEADER1);
855 DUMPREG(HDMI_VSI_HEADER2);
856 for (i = 0; i < 7; ++i)
857 DUMPREG(HDMI_VSI_DATA(i));
858
859#undef DUMPREG
860}
861
862static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
863{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200864 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900865 hdmi_v13_regs_dump(hdata, prefix);
866 else
867 hdmi_v14_regs_dump(hdata, prefix);
868}
869
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530870static u8 hdmi_chksum(struct hdmi_context *hdata,
871 u32 start, u8 len, u32 hdr_sum)
872{
873 int i;
874
875 /* hdr_sum : header0 + header1 + header2
876 * start : start address of packet byte1
877 * len : packet bytes - 1 */
878 for (i = 0; i < len; ++i)
879 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
880
881 /* return 2's complement of 8 bit hdr_sum */
882 return (u8)(~(hdr_sum & 0xff) + 1);
883}
884
885static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530886 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530887{
888 u32 hdr_sum;
889 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530890 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200891 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530892
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530893 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
894 if (hdata->dvi_mode) {
895 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
896 HDMI_VSI_CON_DO_NOT_TRANSMIT);
897 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
898 HDMI_AVI_CON_DO_NOT_TRANSMIT);
899 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
900 return;
901 }
902
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530903 switch (infoframe->any.type) {
904 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530905 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530906 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
907 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
908 infoframe->any.version);
909 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
910 hdr_sum = infoframe->any.type + infoframe->any.version +
911 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530912
913 /* Output format zero hardcoded ,RGB YBCR selection */
914 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
915 AVI_ACTIVE_FORMAT_VALID |
916 AVI_UNDERSCANNED_DISPLAY_VALID);
917
Shirish S46154152014-03-13 10:58:28 +0530918 /*
919 * Set the aspect ratio as per the mode, mentioned in
920 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
921 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200922 ar = hdata->current_mode.picture_aspect_ratio;
923 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530924 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200925 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530926 break;
927 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200928 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530929 break;
930 case HDMI_PICTURE_ASPECT_NONE:
931 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200932 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530933 break;
934 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200935 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530936
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200937 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530938
939 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530940 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530941 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
942 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
943 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530944 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530945 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530946 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
947 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
948 infoframe->any.version);
949 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
950 hdr_sum = infoframe->any.type + infoframe->any.version +
951 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530952 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530953 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530954 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
955 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
956 break;
957 default:
958 break;
959 }
960}
961
Sean Pauld9716ee2014-01-30 16:19:29 -0500962static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
963 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500964{
Sean Pauld9716ee2014-01-30 16:19:29 -0500965 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500966
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200967 if (gpio_get_value(hdata->hpd_gpio))
968 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530969
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200970 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500971}
972
Sean Pauld9716ee2014-01-30 16:19:29 -0500973static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200975 drm_connector_unregister(connector);
976 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977}
978
Sean Pauld9716ee2014-01-30 16:19:29 -0500979static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300980 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500981 .fill_modes = drm_helper_probe_single_connector_modes,
982 .detect = hdmi_detect,
983 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300984 .reset = drm_atomic_helper_connector_reset,
985 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
986 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500987};
988
989static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990{
Sean Pauld9716ee2014-01-30 16:19:29 -0500991 struct hdmi_context *hdata = ctx_from_connector(connector);
992 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200993 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994
Inki Dae8fa04aa2014-03-13 16:38:31 +0900995 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500996 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997
Inki Dae8fa04aa2014-03-13 16:38:31 +0900998 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500999 if (!edid)
1000 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001001
Sean Pauld9716ee2014-01-30 16:19:29 -05001002 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001003 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1004 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001005 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001006
Sean Pauld9716ee2014-01-30 16:19:29 -05001007 drm_mode_connector_update_edid_property(connector, edid);
1008
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001009 ret = drm_add_edid_modes(connector, edid);
1010
1011 kfree(edid);
1012
1013 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001014}
1015
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001016static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001017{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001018 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001019
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001020 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1021 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001022 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001023
1024 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1025 return -EINVAL;
1026}
1027
Sean Pauld9716ee2014-01-30 16:19:29 -05001028static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001029 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001030{
Sean Pauld9716ee2014-01-30 16:19:29 -05001031 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001032 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001033
Rahul Sharma16844fb2013-06-10 14:50:00 +05301034 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1035 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1036 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1037 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001038
Sean Paulf041b252014-01-30 16:19:15 -05001039 ret = mixer_check_mode(mode);
1040 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001041 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001042
Rahul Sharma16844fb2013-06-10 14:50:00 +05301043 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001044 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001045 return MODE_BAD;
1046
1047 return MODE_OK;
1048}
1049
1050static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1051{
1052 struct hdmi_context *hdata = ctx_from_connector(connector);
1053
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001054 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001055}
1056
1057static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1058 .get_modes = hdmi_get_modes,
1059 .mode_valid = hdmi_mode_valid,
1060 .best_encoder = hdmi_best_encoder,
1061};
1062
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001063static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001064{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001065 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001066 struct drm_connector *connector = &hdata->connector;
1067 int ret;
1068
Sean Pauld9716ee2014-01-30 16:19:29 -05001069 connector->interlace_allowed = true;
1070 connector->polled = DRM_CONNECTOR_POLL_HPD;
1071
1072 ret = drm_connector_init(hdata->drm_dev, connector,
1073 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1074 if (ret) {
1075 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001076 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001077 }
1078
1079 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001080 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001081 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001082
1083 return 0;
1084}
1085
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001086static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1087 const struct drm_display_mode *mode,
1088 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001089{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001090 struct drm_device *dev = encoder->dev;
1091 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001092 struct drm_display_mode *m;
1093 int mode_ok;
1094
Sean Paulf041b252014-01-30 16:19:15 -05001095 drm_mode_set_crtcinfo(adjusted_mode, 0);
1096
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001097 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1098 if (connector->encoder == encoder)
1099 break;
1100 }
1101
1102 if (connector->encoder != encoder)
1103 return true;
1104
Sean Pauld9716ee2014-01-30 16:19:29 -05001105 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001106
1107 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001108 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001109 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001110
1111 /*
1112 * otherwise, find the most suitable mode among modes and change it
1113 * to adjusted_mode.
1114 */
1115 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001116 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001117
Sean Pauld9716ee2014-01-30 16:19:29 -05001118 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001119 DRM_INFO("desired mode doesn't exist so\n");
1120 DRM_INFO("use the most suitable mode among modes.\n");
1121
1122 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1123 m->hdisplay, m->vdisplay, m->vrefresh);
1124
Sean Paul75626852014-01-30 16:19:16 -05001125 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001126 break;
1127 }
1128 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001129
1130 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001131}
1132
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001133static void hdmi_set_acr(u32 freq, u8 *acr)
1134{
1135 u32 n, cts;
1136
1137 switch (freq) {
1138 case 32000:
1139 n = 4096;
1140 cts = 27000;
1141 break;
1142 case 44100:
1143 n = 6272;
1144 cts = 30000;
1145 break;
1146 case 88200:
1147 n = 12544;
1148 cts = 30000;
1149 break;
1150 case 176400:
1151 n = 25088;
1152 cts = 30000;
1153 break;
1154 case 48000:
1155 n = 6144;
1156 cts = 27000;
1157 break;
1158 case 96000:
1159 n = 12288;
1160 cts = 27000;
1161 break;
1162 case 192000:
1163 n = 24576;
1164 cts = 27000;
1165 break;
1166 default:
1167 n = 0;
1168 cts = 0;
1169 break;
1170 }
1171
1172 acr[1] = cts >> 16;
1173 acr[2] = cts >> 8 & 0xff;
1174 acr[3] = cts & 0xff;
1175
1176 acr[4] = n >> 16;
1177 acr[5] = n >> 8 & 0xff;
1178 acr[6] = n & 0xff;
1179}
1180
1181static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1182{
1183 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1184 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1185 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1186 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1187 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1188 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1189 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1190 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1191 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001192 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001193}
1194
1195static void hdmi_audio_init(struct hdmi_context *hdata)
1196{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301197 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001198 u32 data_num, bit_ch, sample_frq;
1199 u32 val;
1200 u8 acr[7];
1201
1202 sample_rate = 44100;
1203 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001204
1205 switch (bits_per_sample) {
1206 case 20:
1207 data_num = 2;
1208 bit_ch = 1;
1209 break;
1210 case 24:
1211 data_num = 3;
1212 bit_ch = 1;
1213 break;
1214 default:
1215 data_num = 1;
1216 bit_ch = 0;
1217 break;
1218 }
1219
1220 hdmi_set_acr(sample_rate, acr);
1221 hdmi_reg_acr(hdata, acr);
1222
1223 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1224 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1225 | HDMI_I2S_MUX_ENABLE);
1226
1227 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1228 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1229
1230 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1231
1232 sample_frq = (sample_rate == 44100) ? 0 :
1233 (sample_rate == 48000) ? 2 :
1234 (sample_rate == 32000) ? 3 :
1235 (sample_rate == 96000) ? 0xa : 0x0;
1236
1237 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1238 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1239
1240 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1241 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1242
1243 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1244 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1245 | HDMI_I2S_SEL_LRCK(6));
1246 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1247 | HDMI_I2S_SEL_SDATA2(4));
1248 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1249 | HDMI_I2S_SEL_SDATA2(2));
1250 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1251
1252 /* I2S_CON_1 & 2 */
1253 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1254 | HDMI_I2S_L_CH_LOW_POL);
1255 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1256 | HDMI_I2S_SET_BIT_CH(bit_ch)
1257 | HDMI_I2S_SET_SDATA_BIT(data_num)
1258 | HDMI_I2S_BASIC_FORMAT);
1259
1260 /* Configure register related to CUV information */
1261 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1262 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1263 | HDMI_I2S_COPYRIGHT
1264 | HDMI_I2S_LINEAR_PCM
1265 | HDMI_I2S_CONSUMER_FORMAT);
1266 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1267 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1268 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1269 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1270 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1271 HDMI_I2S_ORG_SMP_FREQ_44_1
1272 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1273 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1274
1275 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1276}
1277
1278static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1279{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001280 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001281 return;
1282
1283 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1284 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1285 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1286}
1287
Rahul Sharmabfa48422014-04-03 20:41:04 +05301288static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301290 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001291
Rahul Sharmabfa48422014-04-03 20:41:04 +05301292 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1293 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001294
Rahul Sharmabfa48422014-04-03 20:41:04 +05301295 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1296 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297}
1298
1299static void hdmi_conf_init(struct hdmi_context *hdata)
1300{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301301 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301302
Sean Paul77006a72013-01-16 10:17:20 -05001303 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001304 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1305 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001306
1307 /* choose HDMI mode */
1308 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1309 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301310 /* Apply Video preable and Guard band in HDMI mode only */
1311 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001312 /* disable bluescreen */
1313 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001314
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001315 if (hdata->dvi_mode) {
1316 /* choose DVI mode */
1317 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1318 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1319 hdmi_reg_writeb(hdata, HDMI_CON_2,
1320 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1321 }
1322
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001323 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001324 /* choose bluescreen (fecal) color */
1325 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1326 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1327 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1328
1329 /* enable AVI packet every vsync, fixes purple line problem */
1330 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1331 /* force RGB, look to CEA-861-D, table 7 for more detail */
1332 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1333 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1334
1335 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1336 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1337 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1338 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301339 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1340 infoframe.any.version = HDMI_AVI_VERSION;
1341 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301342 hdmi_reg_infoframe(hdata, &infoframe);
1343
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301344 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1345 infoframe.any.version = HDMI_AUI_VERSION;
1346 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301347 hdmi_reg_infoframe(hdata, &infoframe);
1348
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001349 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001350 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1351 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001352}
1353
Rahul Sharma16844fb2013-06-10 14:50:00 +05301354static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001355{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001356 struct drm_display_mode *m = &hdata->current_mode;
1357 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001358 int tries;
1359
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001360 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1361 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1362 (m->htotal << 12) | m->vtotal);
1363
1364 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1365 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1366
1367 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1368 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1369
1370 val = (m->hsync_start - m->hdisplay - 2);
1371 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1372 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1373 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1374
1375 /*
1376 * Quirk requirement for exynos HDMI IP design,
1377 * 2 pixels less than the actual calculation for hsync_start
1378 * and end.
1379 */
1380
1381 /* Following values & calculations differ for different type of modes */
1382 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1383 /* Interlaced Mode */
1384 val = ((m->vsync_end - m->vdisplay) / 2);
1385 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1386 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1387
1388 val = m->vtotal / 2;
1389 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1390 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1391
1392 val = (m->vtotal +
1393 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1394 val |= m->vtotal << 11;
1395 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1396
1397 val = ((m->vtotal / 2) + 7);
1398 val |= ((m->vtotal / 2) + 2) << 12;
1399 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1400
1401 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1402 val |= ((m->htotal / 2) +
1403 (m->hsync_start - m->hdisplay)) << 12;
1404 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1405
1406 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1407 (m->vtotal - m->vdisplay) / 2);
1408 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1409
1410 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1411 } else {
1412 /* Progressive Mode */
1413
1414 val = m->vtotal;
1415 val |= (m->vtotal - m->vdisplay) << 11;
1416 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1417
1418 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1419
1420 val = (m->vsync_end - m->vdisplay);
1421 val |= ((m->vsync_start - m->vdisplay) << 12);
1422 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1423
1424 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1425 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1426 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1427 m->vtotal - m->vdisplay);
1428 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1429 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1430 }
1431
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001432 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001433 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1434 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1435 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1436 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1437 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1438 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1439 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1440 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1441 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1442 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1443 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001444
1445 /* waiting for HDMIPHY's PLL to get to steady state */
1446 for (tries = 100; tries; --tries) {
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001447 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001448 if (val & HDMI_PHY_STATUS_READY)
1449 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001450 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001451 }
1452 /* steady state not achieved */
1453 if (tries == 0) {
1454 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1455 hdmi_regs_dump(hdata, "timing apply");
1456 }
1457
Sean Paul0bfb1f82013-06-11 12:24:02 +05301458 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301459 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301460 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001461
1462 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301463 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001464}
1465
Rahul Sharma16844fb2013-06-10 14:50:00 +05301466static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001467{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001468 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001469 int tries;
1470
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001471 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1472 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1473 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1474 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1475 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1476 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1477 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1478 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1479 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1480
1481 /*
1482 * Quirk requirement for exynos 5 HDMI IP design,
1483 * 2 pixels less than the actual calculation for hsync_start
1484 * and end.
1485 */
1486
1487 /* Following values & calculations differ for different type of modes */
1488 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1489 /* Interlaced Mode */
1490 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1491 (m->vsync_end - m->vdisplay) / 2);
1492 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1493 (m->vsync_start - m->vdisplay) / 2);
1494 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1495 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1496 (m->vtotal - m->vdisplay) / 2);
1497 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1498 m->vtotal - m->vdisplay / 2);
1499 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1500 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1501 (m->vtotal / 2) + 7);
1502 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1503 (m->vtotal / 2) + 2);
1504 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1505 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1506 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1507 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1508 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1509 (m->vtotal - m->vdisplay) / 2);
1510 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1511 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1512 m->vtotal - m->vdisplay / 2);
1513 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1514 (m->vtotal / 2) + 1);
1515 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1516 (m->vtotal / 2) + 1);
1517 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1518 (m->vtotal / 2) + 1);
1519 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1520 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1521 } else {
1522 /* Progressive Mode */
1523 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1524 m->vsync_end - m->vdisplay);
1525 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1526 m->vsync_start - m->vdisplay);
1527 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1528 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1529 m->vtotal - m->vdisplay);
1530 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1537 m->vtotal - m->vdisplay);
1538 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1539 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1540 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1541 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1542 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1543 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1544 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1545 }
1546
1547 /* Following values & calculations are same irrespective of mode type */
1548 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1549 m->hsync_start - m->hdisplay - 2);
1550 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1551 m->hsync_end - m->hdisplay - 2);
1552 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1553 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1554 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1555 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1556 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1557 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1558 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1559 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1560 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1561 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1562 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1563 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1564 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1565 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1566 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1567 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1568 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1569 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001570
1571 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001572 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1573 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1574 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1575 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1576 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1577 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1578 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1579 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1580 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001581
1582 /* waiting for HDMIPHY's PLL to get to steady state */
1583 for (tries = 100; tries; --tries) {
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001584 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001585 if (val & HDMI_PHY_STATUS_READY)
1586 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001587 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001588 }
1589 /* steady state not achieved */
1590 if (tries == 0) {
1591 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1592 hdmi_regs_dump(hdata, "timing apply");
1593 }
1594
Sean Paul0bfb1f82013-06-11 12:24:02 +05301595 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301596 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301597 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001598
1599 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301600 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001601}
1602
Rahul Sharma16844fb2013-06-10 14:50:00 +05301603static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001604{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001605 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301606 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001607 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301608 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001609}
1610
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001611static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1612{
Sean Paul0bfb1f82013-06-11 12:24:02 +05301613 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301614 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301615 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001616
1617 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001618 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1619 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001620
1621 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001622 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001623 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001624 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001625 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001626}
1627
Rahul Sharmaa5562252012-11-28 11:30:25 +05301628static void hdmiphy_poweron(struct hdmi_context *hdata)
1629{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001630 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301631 return;
1632
1633 DRM_DEBUG_KMS("\n");
1634
1635 /* For PHY Mode Setting */
1636 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1637 HDMI_PHY_ENABLE_MODE_SET);
1638 /* Phy Power On */
1639 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1640 HDMI_PHY_POWER_ON);
1641 /* For PHY Mode Setting */
1642 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1643 HDMI_PHY_DISABLE_MODE_SET);
1644 /* PHY SW Reset */
1645 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301646}
1647
1648static void hdmiphy_poweroff(struct hdmi_context *hdata)
1649{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001650 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301651 return;
1652
1653 DRM_DEBUG_KMS("\n");
1654
1655 /* PHY SW Reset */
1656 hdmiphy_conf_reset(hdata);
1657 /* For PHY Mode Setting */
1658 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1659 HDMI_PHY_ENABLE_MODE_SET);
1660
1661 /* PHY Power Off */
1662 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1663 HDMI_PHY_POWER_OFF);
1664
1665 /* For PHY Mode Setting */
1666 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1667 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301668}
1669
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001670static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1671{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001672 int ret;
1673 int i;
1674
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001675 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001676 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001677 if (i < 0) {
1678 DRM_ERROR("failed to find hdmiphy conf\n");
1679 return;
1680 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001681
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001682 ret = hdmiphy_reg_write_buf(hdata, 0,
1683 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001684 if (ret) {
1685 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001686 return;
1687 }
1688
Sean Paul09760ea2013-01-14 17:03:20 -05001689 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001690
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001691 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1692 HDMI_PHY_DISABLE_MODE_SET);
1693 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001694 DRM_ERROR("failed to enable hdmiphy\n");
1695 return;
1696 }
1697
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001698}
1699
1700static void hdmi_conf_apply(struct hdmi_context *hdata)
1701{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001702 hdmiphy_conf_reset(hdata);
1703 hdmiphy_conf_apply(hdata);
1704
Rahul Sharmabfa48422014-04-03 20:41:04 +05301705 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001706 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001707
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001708 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001709
1710 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301711 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001712 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001713
1714 hdmi_regs_dump(hdata, "start");
1715}
1716
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001717static void hdmi_mode_set(struct drm_encoder *encoder,
1718 struct drm_display_mode *mode,
1719 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001720{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001721 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001722 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001723
YoungJun Chocbc4c332013-06-12 10:44:40 +09001724 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1725 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001726 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001727 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001728
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001729 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001730 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001731}
1732
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001733static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001734{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001735 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001736 struct hdmi_resources *res = &hdata->res;
1737
Andrzej Hajda882a0642015-07-09 16:28:08 +02001738 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001739 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001740
1741 hdata->powered = true;
1742
Sean Paulaf65c802014-01-30 16:19:27 -05001743 pm_runtime_get_sync(hdata->dev);
1744
Seung-Woo Kimad079452013-06-05 14:34:38 +09001745 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1746 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1747
Rahul Sharma049d34e2014-05-20 10:36:05 +05301748 /* set pmu hdmiphy control bit to enable hdmiphy */
1749 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1750 PMU_HDMI_PHY_ENABLE_BIT, 1);
1751
Sean Paul0bfb1f82013-06-11 12:24:02 +05301752 clk_prepare_enable(res->hdmi);
1753 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301754
1755 hdmiphy_poweron(hdata);
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001756 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001757}
1758
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001759static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001760{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001761 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001762 struct hdmi_resources *res = &hdata->res;
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001763 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001764 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001765
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001766 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001767 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001768
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001769 /*
1770 * The SFRs of VP and Mixer are updated by Vertical Sync of
1771 * Timing generator which is a part of HDMI so the sequence
1772 * to disable TV Subsystem should be as following,
1773 * VP -> Mixer -> HDMI
1774 *
1775 * Below codes will try to disable Mixer and VP(if used)
1776 * prior to disabling HDMI.
1777 */
1778 if (crtc)
1779 funcs = crtc->helper_private;
1780 if (funcs && funcs->disable)
1781 (*funcs->disable)(crtc);
1782
Rahul Sharmabfa48422014-04-03 20:41:04 +05301783 /* HDMI System Disable */
1784 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1785
Rahul Sharmaa5562252012-11-28 11:30:25 +05301786 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001787
Sean Paul724fd142014-05-09 15:05:10 +09001788 cancel_delayed_work(&hdata->hotplug_work);
1789
Sean Paul0bfb1f82013-06-11 12:24:02 +05301790 clk_disable_unprepare(res->sclk_hdmi);
1791 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301792
1793 /* reset pmu hdmiphy control bit to disable hdmiphy */
1794 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1795 PMU_HDMI_PHY_ENABLE_BIT, 0);
1796
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001797 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1798
Sean Paulaf65c802014-01-30 16:19:27 -05001799 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001800
1801 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001802}
1803
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001804static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001805 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001806 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001807 .enable = hdmi_enable,
1808 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001809};
1810
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001811static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1812 .destroy = drm_encoder_cleanup,
1813};
1814
Sean Paul724fd142014-05-09 15:05:10 +09001815static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001816{
Sean Paul724fd142014-05-09 15:05:10 +09001817 struct hdmi_context *hdata;
1818
1819 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001820
Sean Paul45517892014-01-30 16:19:05 -05001821 if (hdata->drm_dev)
1822 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001823}
1824
1825static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1826{
1827 struct hdmi_context *hdata = arg;
1828
1829 mod_delayed_work(system_wq, &hdata->hotplug_work,
1830 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001831
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001832 return IRQ_HANDLED;
1833}
1834
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001835static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001836{
1837 struct device *dev = hdata->dev;
1838 struct hdmi_resources *res = &hdata->res;
1839 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001840 "vdd",
1841 "vdd_osc",
1842 "vdd_pll",
1843 };
1844 int i, ret;
1845
1846 DRM_DEBUG_KMS("HDMI resource init\n");
1847
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001848 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301849 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301850 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001851 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001852 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001853 goto fail;
1854 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301855 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301856 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001857 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001858 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001859 goto fail;
1860 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301861 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301862 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001863 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001864 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001865 goto fail;
1866 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301867 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301868 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001869 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001870 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001871 goto fail;
1872 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301873 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1874 if (IS_ERR(res->mout_hdmi)) {
1875 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001876 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301877 goto fail;
1878 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001879
Rahul Sharma59956d32013-06-11 12:24:03 +05301880 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001881
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301882 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301883 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09001884 if (!res->regul_bulk) {
1885 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001886 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09001887 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001888 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1889 res->regul_bulk[i].supply = supply[i];
1890 res->regul_bulk[i].consumer = NULL;
1891 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301892 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001893 if (ret) {
1894 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001895 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001896 }
1897 res->regul_count = ARRAY_SIZE(supply);
1898
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001899 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
1900 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
1901 DRM_ERROR("failed to get hdmi-en regulator\n");
1902 return PTR_ERR(res->reg_hdmi_en);
1903 }
1904 if (!IS_ERR(res->reg_hdmi_en)) {
1905 ret = regulator_enable(res->reg_hdmi_en);
1906 if (ret) {
1907 DRM_ERROR("failed to enable hdmi-en regulator\n");
1908 return ret;
1909 }
1910 } else
1911 res->reg_hdmi_en = NULL;
1912
Inki Daedf5225b2014-05-29 18:28:02 +09001913 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001914fail:
1915 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001916 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001917}
1918
Rahul Sharma22c4f422012-10-04 20:48:55 +05301919static struct of_device_id hdmi_match_types[] = {
1920 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001921 .compatible = "samsung,exynos4210-hdmi",
1922 .data = &exynos4210_hdmi_driver_data,
1923 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301924 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001925 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301926 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301927 .compatible = "samsung,exynos5420-hdmi",
1928 .data = &exynos5420_hdmi_driver_data,
1929 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301930 /* end node */
1931 }
1932};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001933MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301934
Inki Daef37cd5e2014-05-09 14:25:20 +09001935static int hdmi_bind(struct device *dev, struct device *master, void *data)
1936{
1937 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001938 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001939 struct drm_encoder *encoder = &hdata->encoder;
1940 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001941
Inki Daef37cd5e2014-05-09 14:25:20 +09001942 hdata->drm_dev = drm_dev;
1943
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001944 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1945 EXYNOS_DISPLAY_TYPE_HDMI);
1946 if (pipe < 0)
1947 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001948
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001949 encoder->possible_crtcs = 1 << pipe;
1950
1951 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1952
1953 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1954 DRM_MODE_ENCODER_TMDS);
1955
1956 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1957
1958 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001959 if (ret) {
1960 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001961 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001962 return ret;
1963 }
1964
1965 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001966}
1967
1968static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1969{
Inki Daef37cd5e2014-05-09 14:25:20 +09001970}
1971
1972static const struct component_ops hdmi_component_ops = {
1973 .bind = hdmi_bind,
1974 .unbind = hdmi_unbind,
1975};
1976
Inki Daee2a562d2014-05-09 16:46:10 +09001977static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1978{
1979 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1980 struct device_node *np;
1981
1982 np = of_find_compatible_node(NULL, NULL, compatible_str);
1983 if (np)
1984 return of_get_next_parent(np);
1985
1986 return NULL;
1987}
1988
1989static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1990{
1991 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1992
1993 return of_find_compatible_node(NULL, NULL, compatible_str);
1994}
1995
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001996static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001997{
Inki Daef37cd5e2014-05-09 14:25:20 +09001998 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001999 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002000 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002001 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002002 struct resource *res;
2003 int ret;
2004
Andrzej Hajda930865f2014-11-17 09:54:20 +01002005 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2006 if (!hdata)
2007 return -ENOMEM;
2008
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002009 match = of_match_device(hdmi_match_types, dev);
2010 if (!match)
2011 return -ENODEV;
2012
2013 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002014
Andrzej Hajda930865f2014-11-17 09:54:20 +01002015 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002016
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002017 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002018 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2019 if (hdata->hpd_gpio < 0) {
2020 DRM_ERROR("cannot get hpd gpio property\n");
2021 return hdata->hpd_gpio;
2022 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002023
2024 ret = hdmi_resources_init(hdata);
2025 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302026 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002027 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002028 }
2029
2030 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002031 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002032 if (IS_ERR(hdata->regs)) {
2033 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002034 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002035 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002036
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002037 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302038 if (ret) {
2039 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002040 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302041 }
2042
Inki Daee2a562d2014-05-09 16:46:10 +09002043 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2044 if (ddc_node)
2045 goto out_get_ddc_adpt;
2046
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002047 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002048 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2049 if (!ddc_node) {
2050 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002051 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002052 }
Inki Daee2a562d2014-05-09 16:46:10 +09002053
2054out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002055 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2056 if (!hdata->ddc_adpt) {
2057 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002058 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002059 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002060
Inki Daee2a562d2014-05-09 16:46:10 +09002061 phy_node = hdmi_legacy_phy_dt_binding(dev);
2062 if (phy_node)
2063 goto out_get_phy_port;
2064
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002065 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002066 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2067 if (!phy_node) {
2068 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2069 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002070 goto err_ddc;
2071 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002072
Inki Daee2a562d2014-05-09 16:46:10 +09002073out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002074 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002075 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2076 if (!hdata->regs_hdmiphy) {
2077 DRM_ERROR("failed to ioremap hdmi phy\n");
2078 ret = -ENOMEM;
2079 goto err_ddc;
2080 }
2081 } else {
2082 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2083 if (!hdata->hdmiphy_port) {
2084 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002085 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002086 goto err_ddc;
2087 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002088 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002089
Sean Paul77006a72013-01-16 10:17:20 -05002090 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2091 if (hdata->irq < 0) {
2092 DRM_ERROR("failed to get GPIO irq\n");
2093 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002094 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002095 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002096
Sean Paul724fd142014-05-09 15:05:10 +09002097 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2098
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002099 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002100 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002101 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002102 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002103 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002104 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002105 goto err_hdmiphy;
2106 }
2107
Rahul Sharma049d34e2014-05-20 10:36:05 +05302108 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2109 "samsung,syscon-phandle");
2110 if (IS_ERR(hdata->pmureg)) {
2111 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002112 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302113 goto err_hdmiphy;
2114 }
2115
Sean Paulaf65c802014-01-30 16:19:27 -05002116 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002117
Inki Daedf5225b2014-05-29 18:28:02 +09002118 ret = component_add(&pdev->dev, &hdmi_component_ops);
2119 if (ret)
2120 goto err_disable_pm_runtime;
2121
2122 return ret;
2123
2124err_disable_pm_runtime:
2125 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002126
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002127err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002128 if (hdata->hdmiphy_port)
2129 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002130err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002131 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002132
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133 return ret;
2134}
2135
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002136static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002137{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002138 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002139
Sean Paul724fd142014-05-09 15:05:10 +09002140 cancel_delayed_work_sync(&hdata->hotplug_work);
2141
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002142 if (hdata->res.reg_hdmi_en)
2143 regulator_disable(hdata->res.reg_hdmi_en);
2144
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002145 if (hdata->hdmiphy_port)
2146 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002147 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002148
Sean Paulaf65c802014-01-30 16:19:27 -05002149 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002150 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002151
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002152 return 0;
2153}
2154
2155struct platform_driver hdmi_driver = {
2156 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002157 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002158 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302159 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002160 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302161 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002162 },
2163};