blob: c0664d53ce2e03a407670bdd009194ce96572b6d [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
Andrzej Hajda2228b7c2015-09-25 14:48:24 +020033#include <linux/gpio/consumer.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020037#include <linux/of_device.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Sean Pauld9716ee2014-01-30 16:19:29 -050049#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090050
Sean Paul724fd142014-05-09 15:05:10 +090051#define HOTPLUG_DEBOUNCE_MS 1100
52
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053/* AVI header and aspect ratio */
54#define HDMI_AVI_VERSION 0x02
55#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053056
57/* AUI header info */
58#define HDMI_AUI_VERSION 0x01
59#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053060#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
61#define AVI_4_3_CENTER_RATIO 0x9
62#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053063
Rahul Sharma5a325072012-10-04 20:48:54 +053064enum hdmi_type {
65 HDMI_TYPE13,
66 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020067 HDMI_TYPE_COUNT
68};
69
70#define HDMI_MAPPED_BASE 0xffff0000
71
72enum hdmi_mapped_regs {
73 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
74 HDMI_PHY_RSTOUT,
75 HDMI_ACR_CON,
76};
77
78static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
79 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
80 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
81 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Rahul Sharma5a325072012-10-04 20:48:54 +053082};
83
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020084static const char * const supply[] = {
85 "vdd",
86 "vdd_osc",
87 "vdd_pll",
88};
89
Inki Daebfe4e842014-03-06 14:18:17 +090090struct hdmi_driver_data {
91 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090092 const struct hdmiphy_config *phy_confs;
93 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090094 unsigned int is_apb_phy:1;
95};
96
Joonyoung Shim590f4182012-03-16 18:47:14 +090097struct hdmi_resources {
98 struct clk *hdmi;
99 struct clk *sclk_hdmi;
100 struct clk *sclk_pixel;
101 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +0530102 struct clk *mout_hdmi;
Andrzej Hajda1ab739d2015-09-25 14:48:22 +0200103 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
Marek Szyprowski05fdf982014-07-01 10:10:06 +0200104 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900105};
106
107struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300108 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900109 struct device *dev;
110 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500111 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900112 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900113 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900114 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900115
Joonyoung Shim590f4182012-03-16 18:47:14 +0900116 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500117 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900118 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900119
Inki Dae8fa04aa2014-03-13 16:38:31 +0900120 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900121 struct i2c_client *hdmiphy_port;
122
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900123 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530124 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200125 u8 cea_video_id;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900126
127 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200128 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900129
Andrzej Hajda2228b7c2015-09-25 14:48:24 +0200130 struct gpio_desc *hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900131 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530132
Rahul Sharma049d34e2014-05-20 10:36:05 +0530133 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900134};
135
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300136static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100137{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900138 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100139}
140
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500141struct hdmiphy_config {
142 int pixel_clock;
143 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900144};
145
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900146/* list of phy config settings */
147static const struct hdmiphy_config hdmiphy_v13_configs[] = {
148 {
149 .pixel_clock = 27000000,
150 .conf = {
151 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
152 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
153 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200154 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900155 },
156 },
157 {
158 .pixel_clock = 27027000,
159 .conf = {
160 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
161 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
162 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200163 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900164 },
165 },
166 {
167 .pixel_clock = 74176000,
168 .conf = {
169 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
170 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
171 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200172 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900173 },
174 },
175 {
176 .pixel_clock = 74250000,
177 .conf = {
178 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
179 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
180 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200181 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900182 },
183 },
184 {
185 .pixel_clock = 148500000,
186 .conf = {
187 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
188 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
189 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200190 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900191 },
192 },
193};
194
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500195static const struct hdmiphy_config hdmiphy_v14_configs[] = {
196 {
197 .pixel_clock = 25200000,
198 .conf = {
199 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
200 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
201 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
202 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
203 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900204 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500205 {
206 .pixel_clock = 27000000,
207 .conf = {
208 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
209 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
210 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
211 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
212 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900213 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500214 {
215 .pixel_clock = 27027000,
216 .conf = {
217 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
218 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
219 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200220 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500221 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900222 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500223 {
224 .pixel_clock = 36000000,
225 .conf = {
226 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
227 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
228 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
229 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
230 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900231 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500232 {
233 .pixel_clock = 40000000,
234 .conf = {
235 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
236 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
237 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
238 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
239 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900240 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500241 {
242 .pixel_clock = 65000000,
243 .conf = {
244 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
245 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
246 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
247 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
248 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900249 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500250 {
Shirish Se1d883c2014-03-13 14:28:27 +0900251 .pixel_clock = 71000000,
252 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530253 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
254 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
255 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900256 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
257 },
258 },
259 {
260 .pixel_clock = 73250000,
261 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530262 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
263 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
264 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900265 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
266 },
267 },
268 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500269 .pixel_clock = 74176000,
270 .conf = {
271 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
272 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
273 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
274 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
275 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900276 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500277 {
278 .pixel_clock = 74250000,
279 .conf = {
280 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
281 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
282 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200283 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500284 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900285 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500286 {
287 .pixel_clock = 83500000,
288 .conf = {
289 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
290 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
291 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
292 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
293 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900294 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500295 {
296 .pixel_clock = 106500000,
297 .conf = {
298 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
299 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
300 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
301 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
302 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900303 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500304 {
305 .pixel_clock = 108000000,
306 .conf = {
307 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
308 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
309 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
310 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
311 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900312 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500313 {
Shirish Se1d883c2014-03-13 14:28:27 +0900314 .pixel_clock = 115500000,
315 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530316 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
317 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
318 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900319 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
320 },
321 },
322 {
323 .pixel_clock = 119000000,
324 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530325 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
326 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
327 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900328 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
329 },
330 },
331 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500332 .pixel_clock = 146250000,
333 .conf = {
334 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
335 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
336 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
337 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
338 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900339 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500340 {
341 .pixel_clock = 148500000,
342 .conf = {
343 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
344 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
345 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200346 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500347 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900348 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900349};
350
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530351static const struct hdmiphy_config hdmiphy_5420_configs[] = {
352 {
353 .pixel_clock = 25200000,
354 .conf = {
355 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
356 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
357 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
358 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
359 },
360 },
361 {
362 .pixel_clock = 27000000,
363 .conf = {
364 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
365 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
366 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
367 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
368 },
369 },
370 {
371 .pixel_clock = 27027000,
372 .conf = {
373 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
374 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
375 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
376 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
377 },
378 },
379 {
380 .pixel_clock = 36000000,
381 .conf = {
382 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
383 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
384 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
385 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
386 },
387 },
388 {
389 .pixel_clock = 40000000,
390 .conf = {
391 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
392 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
393 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
394 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
395 },
396 },
397 {
398 .pixel_clock = 65000000,
399 .conf = {
400 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
401 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
402 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
403 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
404 },
405 },
406 {
407 .pixel_clock = 71000000,
408 .conf = {
409 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
410 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
411 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
412 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
413 },
414 },
415 {
416 .pixel_clock = 73250000,
417 .conf = {
418 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
419 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
420 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
421 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
422 },
423 },
424 {
425 .pixel_clock = 74176000,
426 .conf = {
427 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
428 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
429 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
430 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
431 },
432 },
433 {
434 .pixel_clock = 74250000,
435 .conf = {
436 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
437 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
438 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
439 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
440 },
441 },
442 {
443 .pixel_clock = 83500000,
444 .conf = {
445 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
446 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
447 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
448 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
449 },
450 },
451 {
452 .pixel_clock = 88750000,
453 .conf = {
454 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
455 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
456 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
457 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
458 },
459 },
460 {
461 .pixel_clock = 106500000,
462 .conf = {
463 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
464 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
465 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
466 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
467 },
468 },
469 {
470 .pixel_clock = 108000000,
471 .conf = {
472 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
473 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
474 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
475 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
476 },
477 },
478 {
479 .pixel_clock = 115500000,
480 .conf = {
481 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
482 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
483 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
484 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
485 },
486 },
487 {
488 .pixel_clock = 146250000,
489 .conf = {
490 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
491 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
492 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
493 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
494 },
495 },
496 {
497 .pixel_clock = 148500000,
498 .conf = {
499 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
500 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
501 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
502 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
503 },
504 },
505};
506
Sachin Kamat16337072014-05-22 10:32:56 +0530507static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530508 .type = HDMI_TYPE14,
509 .phy_confs = hdmiphy_5420_configs,
510 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
511 .is_apb_phy = 1,
512};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900513
Sachin Kamat16337072014-05-22 10:32:56 +0530514static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900515 .type = HDMI_TYPE14,
516 .phy_confs = hdmiphy_v14_configs,
517 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
518 .is_apb_phy = 0,
519};
520
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200521static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
522 .type = HDMI_TYPE13,
523 .phy_confs = hdmiphy_v13_configs,
524 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
525 .is_apb_phy = 0,
526};
527
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200528static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
529{
530 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
531 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
532 return reg_id;
533}
534
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
536{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200537 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538}
539
540static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
541 u32 reg_id, u8 value)
542{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200543 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900544}
545
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200546static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
547 int bytes, u32 val)
548{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200549 reg_id = hdmi_map_reg(hdata, reg_id);
550
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200551 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200552 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200553 val >>= 8;
554 reg_id += 4;
555 }
556}
557
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
559 u32 reg_id, u32 value, u32 mask)
560{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200561 u32 old;
562
563 reg_id = hdmi_map_reg(hdata, reg_id);
564 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565 value = (value & mask) | (old & ~mask);
566 writel(value, hdata->regs + reg_id);
567}
568
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900569static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
570 u32 reg_offset, const u8 *buf, u32 len)
571{
572 if ((reg_offset + len) > 32)
573 return -EINVAL;
574
575 if (hdata->hdmiphy_port) {
576 int ret;
577
578 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
579 if (ret == len)
580 return 0;
581 return ret;
582 } else {
583 int i;
584 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200585 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900586 ((reg_offset + i)<<2));
587 return 0;
588 }
589}
590
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900591static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900592{
593#define DUMPREG(reg_id) \
594 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
595 readl(hdata->regs + reg_id))
596 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
597 DUMPREG(HDMI_INTC_FLAG);
598 DUMPREG(HDMI_INTC_CON);
599 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900600 DUMPREG(HDMI_V13_PHY_RSTOUT);
601 DUMPREG(HDMI_V13_PHY_VPLL);
602 DUMPREG(HDMI_V13_PHY_CMU);
603 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900604
605 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
606 DUMPREG(HDMI_CON_0);
607 DUMPREG(HDMI_CON_1);
608 DUMPREG(HDMI_CON_2);
609 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900610 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900611 DUMPREG(HDMI_STATUS_EN);
612 DUMPREG(HDMI_HPD);
613 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900614 DUMPREG(HDMI_V13_HPD_GEN);
615 DUMPREG(HDMI_V13_DC_CONTROL);
616 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900617
618 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
619 DUMPREG(HDMI_H_BLANK_0);
620 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900621 DUMPREG(HDMI_V13_V_BLANK_0);
622 DUMPREG(HDMI_V13_V_BLANK_1);
623 DUMPREG(HDMI_V13_V_BLANK_2);
624 DUMPREG(HDMI_V13_H_V_LINE_0);
625 DUMPREG(HDMI_V13_H_V_LINE_1);
626 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900627 DUMPREG(HDMI_VSYNC_POL);
628 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900629 DUMPREG(HDMI_V13_V_BLANK_F_0);
630 DUMPREG(HDMI_V13_V_BLANK_F_1);
631 DUMPREG(HDMI_V13_V_BLANK_F_2);
632 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
633 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
634 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
635 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
636 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
637 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
638 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
639 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
640 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
641 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
642 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
643 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900644
645 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
646 DUMPREG(HDMI_TG_CMD);
647 DUMPREG(HDMI_TG_H_FSZ_L);
648 DUMPREG(HDMI_TG_H_FSZ_H);
649 DUMPREG(HDMI_TG_HACT_ST_L);
650 DUMPREG(HDMI_TG_HACT_ST_H);
651 DUMPREG(HDMI_TG_HACT_SZ_L);
652 DUMPREG(HDMI_TG_HACT_SZ_H);
653 DUMPREG(HDMI_TG_V_FSZ_L);
654 DUMPREG(HDMI_TG_V_FSZ_H);
655 DUMPREG(HDMI_TG_VSYNC_L);
656 DUMPREG(HDMI_TG_VSYNC_H);
657 DUMPREG(HDMI_TG_VSYNC2_L);
658 DUMPREG(HDMI_TG_VSYNC2_H);
659 DUMPREG(HDMI_TG_VACT_ST_L);
660 DUMPREG(HDMI_TG_VACT_ST_H);
661 DUMPREG(HDMI_TG_VACT_SZ_L);
662 DUMPREG(HDMI_TG_VACT_SZ_H);
663 DUMPREG(HDMI_TG_FIELD_CHG_L);
664 DUMPREG(HDMI_TG_FIELD_CHG_H);
665 DUMPREG(HDMI_TG_VACT_ST2_L);
666 DUMPREG(HDMI_TG_VACT_ST2_H);
667 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
668 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
669 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
670 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
671 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
672 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
673 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
674 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
675#undef DUMPREG
676}
677
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900678static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
679{
680 int i;
681
682#define DUMPREG(reg_id) \
683 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
684 readl(hdata->regs + reg_id))
685
686 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
687 DUMPREG(HDMI_INTC_CON);
688 DUMPREG(HDMI_INTC_FLAG);
689 DUMPREG(HDMI_HPD_STATUS);
690 DUMPREG(HDMI_INTC_CON_1);
691 DUMPREG(HDMI_INTC_FLAG_1);
692 DUMPREG(HDMI_PHY_STATUS_0);
693 DUMPREG(HDMI_PHY_STATUS_PLL);
694 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200695 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900696 DUMPREG(HDMI_PHY_VPLL);
697 DUMPREG(HDMI_PHY_CMU);
698 DUMPREG(HDMI_CORE_RSTOUT);
699
700 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
701 DUMPREG(HDMI_CON_0);
702 DUMPREG(HDMI_CON_1);
703 DUMPREG(HDMI_CON_2);
704 DUMPREG(HDMI_SYS_STATUS);
705 DUMPREG(HDMI_PHY_STATUS_0);
706 DUMPREG(HDMI_STATUS_EN);
707 DUMPREG(HDMI_HPD);
708 DUMPREG(HDMI_MODE_SEL);
709 DUMPREG(HDMI_ENC_EN);
710 DUMPREG(HDMI_DC_CONTROL);
711 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
712
713 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
714 DUMPREG(HDMI_H_BLANK_0);
715 DUMPREG(HDMI_H_BLANK_1);
716 DUMPREG(HDMI_V2_BLANK_0);
717 DUMPREG(HDMI_V2_BLANK_1);
718 DUMPREG(HDMI_V1_BLANK_0);
719 DUMPREG(HDMI_V1_BLANK_1);
720 DUMPREG(HDMI_V_LINE_0);
721 DUMPREG(HDMI_V_LINE_1);
722 DUMPREG(HDMI_H_LINE_0);
723 DUMPREG(HDMI_H_LINE_1);
724 DUMPREG(HDMI_HSYNC_POL);
725
726 DUMPREG(HDMI_VSYNC_POL);
727 DUMPREG(HDMI_INT_PRO_MODE);
728 DUMPREG(HDMI_V_BLANK_F0_0);
729 DUMPREG(HDMI_V_BLANK_F0_1);
730 DUMPREG(HDMI_V_BLANK_F1_0);
731 DUMPREG(HDMI_V_BLANK_F1_1);
732
733 DUMPREG(HDMI_H_SYNC_START_0);
734 DUMPREG(HDMI_H_SYNC_START_1);
735 DUMPREG(HDMI_H_SYNC_END_0);
736 DUMPREG(HDMI_H_SYNC_END_1);
737
738 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
739 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
740 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
741 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
742
743 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
744 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
745 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
746 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
747
748 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
749 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
750 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
751 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
752
753 DUMPREG(HDMI_V_BLANK_F2_0);
754 DUMPREG(HDMI_V_BLANK_F2_1);
755 DUMPREG(HDMI_V_BLANK_F3_0);
756 DUMPREG(HDMI_V_BLANK_F3_1);
757 DUMPREG(HDMI_V_BLANK_F4_0);
758 DUMPREG(HDMI_V_BLANK_F4_1);
759 DUMPREG(HDMI_V_BLANK_F5_0);
760 DUMPREG(HDMI_V_BLANK_F5_1);
761
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
770
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
774 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
775 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
776 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
777 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
778 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
779
780 DUMPREG(HDMI_VACT_SPACE_1_0);
781 DUMPREG(HDMI_VACT_SPACE_1_1);
782 DUMPREG(HDMI_VACT_SPACE_2_0);
783 DUMPREG(HDMI_VACT_SPACE_2_1);
784 DUMPREG(HDMI_VACT_SPACE_3_0);
785 DUMPREG(HDMI_VACT_SPACE_3_1);
786 DUMPREG(HDMI_VACT_SPACE_4_0);
787 DUMPREG(HDMI_VACT_SPACE_4_1);
788 DUMPREG(HDMI_VACT_SPACE_5_0);
789 DUMPREG(HDMI_VACT_SPACE_5_1);
790 DUMPREG(HDMI_VACT_SPACE_6_0);
791 DUMPREG(HDMI_VACT_SPACE_6_1);
792
793 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
794 DUMPREG(HDMI_TG_CMD);
795 DUMPREG(HDMI_TG_H_FSZ_L);
796 DUMPREG(HDMI_TG_H_FSZ_H);
797 DUMPREG(HDMI_TG_HACT_ST_L);
798 DUMPREG(HDMI_TG_HACT_ST_H);
799 DUMPREG(HDMI_TG_HACT_SZ_L);
800 DUMPREG(HDMI_TG_HACT_SZ_H);
801 DUMPREG(HDMI_TG_V_FSZ_L);
802 DUMPREG(HDMI_TG_V_FSZ_H);
803 DUMPREG(HDMI_TG_VSYNC_L);
804 DUMPREG(HDMI_TG_VSYNC_H);
805 DUMPREG(HDMI_TG_VSYNC2_L);
806 DUMPREG(HDMI_TG_VSYNC2_H);
807 DUMPREG(HDMI_TG_VACT_ST_L);
808 DUMPREG(HDMI_TG_VACT_ST_H);
809 DUMPREG(HDMI_TG_VACT_SZ_L);
810 DUMPREG(HDMI_TG_VACT_SZ_H);
811 DUMPREG(HDMI_TG_FIELD_CHG_L);
812 DUMPREG(HDMI_TG_FIELD_CHG_H);
813 DUMPREG(HDMI_TG_VACT_ST2_L);
814 DUMPREG(HDMI_TG_VACT_ST2_H);
815 DUMPREG(HDMI_TG_VACT_ST3_L);
816 DUMPREG(HDMI_TG_VACT_ST3_H);
817 DUMPREG(HDMI_TG_VACT_ST4_L);
818 DUMPREG(HDMI_TG_VACT_ST4_H);
819 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
820 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
821 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
822 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
823 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
824 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
825 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
826 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
827 DUMPREG(HDMI_TG_3D);
828
829 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
830 DUMPREG(HDMI_AVI_CON);
831 DUMPREG(HDMI_AVI_HEADER0);
832 DUMPREG(HDMI_AVI_HEADER1);
833 DUMPREG(HDMI_AVI_HEADER2);
834 DUMPREG(HDMI_AVI_CHECK_SUM);
835 DUMPREG(HDMI_VSI_CON);
836 DUMPREG(HDMI_VSI_HEADER0);
837 DUMPREG(HDMI_VSI_HEADER1);
838 DUMPREG(HDMI_VSI_HEADER2);
839 for (i = 0; i < 7; ++i)
840 DUMPREG(HDMI_VSI_DATA(i));
841
842#undef DUMPREG
843}
844
845static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
846{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200847 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900848 hdmi_v13_regs_dump(hdata, prefix);
849 else
850 hdmi_v14_regs_dump(hdata, prefix);
851}
852
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530853static u8 hdmi_chksum(struct hdmi_context *hdata,
854 u32 start, u8 len, u32 hdr_sum)
855{
856 int i;
857
858 /* hdr_sum : header0 + header1 + header2
859 * start : start address of packet byte1
860 * len : packet bytes - 1 */
861 for (i = 0; i < len; ++i)
862 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
863
864 /* return 2's complement of 8 bit hdr_sum */
865 return (u8)(~(hdr_sum & 0xff) + 1);
866}
867
868static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530869 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530870{
871 u32 hdr_sum;
872 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530873 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200874 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530875
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530876 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
877 if (hdata->dvi_mode) {
878 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
879 HDMI_VSI_CON_DO_NOT_TRANSMIT);
880 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
881 HDMI_AVI_CON_DO_NOT_TRANSMIT);
882 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
883 return;
884 }
885
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530886 switch (infoframe->any.type) {
887 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530888 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530889 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
890 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
891 infoframe->any.version);
892 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
893 hdr_sum = infoframe->any.type + infoframe->any.version +
894 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530895
896 /* Output format zero hardcoded ,RGB YBCR selection */
897 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
898 AVI_ACTIVE_FORMAT_VALID |
899 AVI_UNDERSCANNED_DISPLAY_VALID);
900
Shirish S46154152014-03-13 10:58:28 +0530901 /*
902 * Set the aspect ratio as per the mode, mentioned in
903 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
904 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200905 ar = hdata->current_mode.picture_aspect_ratio;
906 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530907 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200908 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530909 break;
910 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200911 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530912 break;
913 case HDMI_PICTURE_ASPECT_NONE:
914 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200915 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530916 break;
917 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200918 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530919
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200920 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530921
922 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530923 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530924 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
925 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
926 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530927 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530928 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530929 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
930 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
931 infoframe->any.version);
932 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
933 hdr_sum = infoframe->any.type + infoframe->any.version +
934 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530935 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530936 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530937 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
938 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
939 break;
940 default:
941 break;
942 }
943}
944
Sean Pauld9716ee2014-01-30 16:19:29 -0500945static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
946 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500947{
Sean Pauld9716ee2014-01-30 16:19:29 -0500948 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500949
Andrzej Hajda2228b7c2015-09-25 14:48:24 +0200950 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200951 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530952
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200953 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500954}
955
Sean Pauld9716ee2014-01-30 16:19:29 -0500956static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900957{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200958 drm_connector_unregister(connector);
959 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900960}
961
Sean Pauld9716ee2014-01-30 16:19:29 -0500962static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300963 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500964 .fill_modes = drm_helper_probe_single_connector_modes,
965 .detect = hdmi_detect,
966 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300967 .reset = drm_atomic_helper_connector_reset,
968 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
969 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500970};
971
972static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900973{
Sean Pauld9716ee2014-01-30 16:19:29 -0500974 struct hdmi_context *hdata = ctx_from_connector(connector);
975 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200976 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977
Inki Dae8fa04aa2014-03-13 16:38:31 +0900978 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500979 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900980
Inki Dae8fa04aa2014-03-13 16:38:31 +0900981 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500982 if (!edid)
983 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900984
Sean Pauld9716ee2014-01-30 16:19:29 -0500985 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500986 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
987 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500988 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500989
Sean Pauld9716ee2014-01-30 16:19:29 -0500990 drm_mode_connector_update_edid_property(connector, edid);
991
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200992 ret = drm_add_edid_modes(connector, edid);
993
994 kfree(edid);
995
996 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997}
998
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900999static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001000{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001001 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001002
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001003 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1004 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001005 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001006
1007 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1008 return -EINVAL;
1009}
1010
Sean Pauld9716ee2014-01-30 16:19:29 -05001011static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001012 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001013{
Sean Pauld9716ee2014-01-30 16:19:29 -05001014 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001015 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001016
Rahul Sharma16844fb2013-06-10 14:50:00 +05301017 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1018 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1019 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1020 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001021
Sean Paulf041b252014-01-30 16:19:15 -05001022 ret = mixer_check_mode(mode);
1023 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001024 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001025
Rahul Sharma16844fb2013-06-10 14:50:00 +05301026 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001027 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001028 return MODE_BAD;
1029
1030 return MODE_OK;
1031}
1032
1033static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1034{
1035 struct hdmi_context *hdata = ctx_from_connector(connector);
1036
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001037 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001038}
1039
1040static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1041 .get_modes = hdmi_get_modes,
1042 .mode_valid = hdmi_mode_valid,
1043 .best_encoder = hdmi_best_encoder,
1044};
1045
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001046static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001047{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001048 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001049 struct drm_connector *connector = &hdata->connector;
1050 int ret;
1051
Sean Pauld9716ee2014-01-30 16:19:29 -05001052 connector->interlace_allowed = true;
1053 connector->polled = DRM_CONNECTOR_POLL_HPD;
1054
1055 ret = drm_connector_init(hdata->drm_dev, connector,
1056 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1057 if (ret) {
1058 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001059 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001060 }
1061
1062 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001063 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001064 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001065
1066 return 0;
1067}
1068
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001069static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1070 const struct drm_display_mode *mode,
1071 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001072{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001073 struct drm_device *dev = encoder->dev;
1074 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001075 struct drm_display_mode *m;
1076 int mode_ok;
1077
Sean Paulf041b252014-01-30 16:19:15 -05001078 drm_mode_set_crtcinfo(adjusted_mode, 0);
1079
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001080 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1081 if (connector->encoder == encoder)
1082 break;
1083 }
1084
1085 if (connector->encoder != encoder)
1086 return true;
1087
Sean Pauld9716ee2014-01-30 16:19:29 -05001088 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001089
1090 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001091 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001092 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001093
1094 /*
1095 * otherwise, find the most suitable mode among modes and change it
1096 * to adjusted_mode.
1097 */
1098 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001099 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001100
Sean Pauld9716ee2014-01-30 16:19:29 -05001101 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001102 DRM_INFO("desired mode doesn't exist so\n");
1103 DRM_INFO("use the most suitable mode among modes.\n");
1104
1105 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1106 m->hdisplay, m->vdisplay, m->vrefresh);
1107
Sean Paul75626852014-01-30 16:19:16 -05001108 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001109 break;
1110 }
1111 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001112
1113 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001114}
1115
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001116static void hdmi_set_acr(u32 freq, u8 *acr)
1117{
1118 u32 n, cts;
1119
1120 switch (freq) {
1121 case 32000:
1122 n = 4096;
1123 cts = 27000;
1124 break;
1125 case 44100:
1126 n = 6272;
1127 cts = 30000;
1128 break;
1129 case 88200:
1130 n = 12544;
1131 cts = 30000;
1132 break;
1133 case 176400:
1134 n = 25088;
1135 cts = 30000;
1136 break;
1137 case 48000:
1138 n = 6144;
1139 cts = 27000;
1140 break;
1141 case 96000:
1142 n = 12288;
1143 cts = 27000;
1144 break;
1145 case 192000:
1146 n = 24576;
1147 cts = 27000;
1148 break;
1149 default:
1150 n = 0;
1151 cts = 0;
1152 break;
1153 }
1154
1155 acr[1] = cts >> 16;
1156 acr[2] = cts >> 8 & 0xff;
1157 acr[3] = cts & 0xff;
1158
1159 acr[4] = n >> 16;
1160 acr[5] = n >> 8 & 0xff;
1161 acr[6] = n & 0xff;
1162}
1163
1164static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1165{
1166 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1167 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1168 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1169 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1170 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1171 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1172 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1173 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1174 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001175 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001176}
1177
1178static void hdmi_audio_init(struct hdmi_context *hdata)
1179{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301180 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001181 u32 data_num, bit_ch, sample_frq;
1182 u32 val;
1183 u8 acr[7];
1184
1185 sample_rate = 44100;
1186 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001187
1188 switch (bits_per_sample) {
1189 case 20:
1190 data_num = 2;
1191 bit_ch = 1;
1192 break;
1193 case 24:
1194 data_num = 3;
1195 bit_ch = 1;
1196 break;
1197 default:
1198 data_num = 1;
1199 bit_ch = 0;
1200 break;
1201 }
1202
1203 hdmi_set_acr(sample_rate, acr);
1204 hdmi_reg_acr(hdata, acr);
1205
1206 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1207 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1208 | HDMI_I2S_MUX_ENABLE);
1209
1210 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1211 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1212
1213 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1214
1215 sample_frq = (sample_rate == 44100) ? 0 :
1216 (sample_rate == 48000) ? 2 :
1217 (sample_rate == 32000) ? 3 :
1218 (sample_rate == 96000) ? 0xa : 0x0;
1219
1220 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1221 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1222
1223 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1224 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1225
1226 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1227 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1228 | HDMI_I2S_SEL_LRCK(6));
1229 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1230 | HDMI_I2S_SEL_SDATA2(4));
1231 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1232 | HDMI_I2S_SEL_SDATA2(2));
1233 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1234
1235 /* I2S_CON_1 & 2 */
1236 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1237 | HDMI_I2S_L_CH_LOW_POL);
1238 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1239 | HDMI_I2S_SET_BIT_CH(bit_ch)
1240 | HDMI_I2S_SET_SDATA_BIT(data_num)
1241 | HDMI_I2S_BASIC_FORMAT);
1242
1243 /* Configure register related to CUV information */
1244 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1245 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1246 | HDMI_I2S_COPYRIGHT
1247 | HDMI_I2S_LINEAR_PCM
1248 | HDMI_I2S_CONSUMER_FORMAT);
1249 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1250 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1251 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1252 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1253 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1254 HDMI_I2S_ORG_SMP_FREQ_44_1
1255 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1256 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1257
1258 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1259}
1260
1261static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1262{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001263 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001264 return;
1265
1266 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1267 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1268 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1269}
1270
Rahul Sharmabfa48422014-04-03 20:41:04 +05301271static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001272{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301273 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001274
Rahul Sharmabfa48422014-04-03 20:41:04 +05301275 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1276 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001277
Rahul Sharmabfa48422014-04-03 20:41:04 +05301278 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1279 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001280}
1281
1282static void hdmi_conf_init(struct hdmi_context *hdata)
1283{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301284 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301285
Sean Paul77006a72013-01-16 10:17:20 -05001286 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001287 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1288 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289
1290 /* choose HDMI mode */
1291 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1292 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301293 /* Apply Video preable and Guard band in HDMI mode only */
1294 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001295 /* disable bluescreen */
1296 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001298 if (hdata->dvi_mode) {
1299 /* choose DVI mode */
1300 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1301 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1302 hdmi_reg_writeb(hdata, HDMI_CON_2,
1303 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1304 }
1305
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001306 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001307 /* choose bluescreen (fecal) color */
1308 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1309 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1310 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1311
1312 /* enable AVI packet every vsync, fixes purple line problem */
1313 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1314 /* force RGB, look to CEA-861-D, table 7 for more detail */
1315 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1316 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1317
1318 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1319 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1320 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1321 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301322 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1323 infoframe.any.version = HDMI_AVI_VERSION;
1324 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301325 hdmi_reg_infoframe(hdata, &infoframe);
1326
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301327 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1328 infoframe.any.version = HDMI_AUI_VERSION;
1329 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301330 hdmi_reg_infoframe(hdata, &infoframe);
1331
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001332 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001333 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1334 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001335}
1336
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001337static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1338{
1339 int tries;
1340
1341 for (tries = 0; tries < 10; ++tries) {
1342 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1343
1344 if (val & HDMI_PHY_STATUS_READY) {
1345 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1346 return;
1347 }
1348 usleep_range(10, 20);
1349 }
1350
1351 DRM_ERROR("PLL could not reach steady state\n");
1352}
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
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001359 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1360 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1361 (m->htotal << 12) | m->vtotal);
1362
1363 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1364 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1365
1366 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1367 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1368
1369 val = (m->hsync_start - m->hdisplay - 2);
1370 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1371 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1372 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1373
1374 /*
1375 * Quirk requirement for exynos HDMI IP design,
1376 * 2 pixels less than the actual calculation for hsync_start
1377 * and end.
1378 */
1379
1380 /* Following values & calculations differ for different type of modes */
1381 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1382 /* Interlaced Mode */
1383 val = ((m->vsync_end - m->vdisplay) / 2);
1384 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1385 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1386
1387 val = m->vtotal / 2;
1388 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1389 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1390
1391 val = (m->vtotal +
1392 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1393 val |= m->vtotal << 11;
1394 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1395
1396 val = ((m->vtotal / 2) + 7);
1397 val |= ((m->vtotal / 2) + 2) << 12;
1398 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1399
1400 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1401 val |= ((m->htotal / 2) +
1402 (m->hsync_start - m->hdisplay)) << 12;
1403 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1404
1405 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1406 (m->vtotal - m->vdisplay) / 2);
1407 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1408
1409 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1410 } else {
1411 /* Progressive Mode */
1412
1413 val = m->vtotal;
1414 val |= (m->vtotal - m->vdisplay) << 11;
1415 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1416
1417 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1418
1419 val = (m->vsync_end - m->vdisplay);
1420 val |= ((m->vsync_start - m->vdisplay) << 12);
1421 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1422
1423 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1424 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1425 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1426 m->vtotal - m->vdisplay);
1427 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1428 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1429 }
1430
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001431 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001432 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1433 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1434 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1435 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1436 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1437 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1438 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1439 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1440 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1441 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1442 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001443}
1444
Rahul Sharma16844fb2013-06-10 14:50:00 +05301445static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001446{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001447 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001448
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001449 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1450 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1451 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1452 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1453 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1454 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1455 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1456 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1457 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1458
1459 /*
1460 * Quirk requirement for exynos 5 HDMI IP design,
1461 * 2 pixels less than the actual calculation for hsync_start
1462 * and end.
1463 */
1464
1465 /* Following values & calculations differ for different type of modes */
1466 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1467 /* Interlaced Mode */
1468 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1469 (m->vsync_end - m->vdisplay) / 2);
1470 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1471 (m->vsync_start - m->vdisplay) / 2);
1472 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1473 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1474 (m->vtotal - m->vdisplay) / 2);
1475 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1476 m->vtotal - m->vdisplay / 2);
1477 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1478 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1479 (m->vtotal / 2) + 7);
1480 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1481 (m->vtotal / 2) + 2);
1482 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1483 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1484 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1485 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1486 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1487 (m->vtotal - m->vdisplay) / 2);
1488 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1489 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1490 m->vtotal - m->vdisplay / 2);
1491 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1492 (m->vtotal / 2) + 1);
1493 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1494 (m->vtotal / 2) + 1);
1495 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1496 (m->vtotal / 2) + 1);
1497 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1498 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1499 } else {
1500 /* Progressive Mode */
1501 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1502 m->vsync_end - m->vdisplay);
1503 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1504 m->vsync_start - m->vdisplay);
1505 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1506 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1507 m->vtotal - m->vdisplay);
1508 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1509 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1510 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1511 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1512 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1513 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1514 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1515 m->vtotal - m->vdisplay);
1516 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1517 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1518 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1519 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1520 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1521 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1522 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1523 }
1524
1525 /* Following values & calculations are same irrespective of mode type */
1526 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1527 m->hsync_start - m->hdisplay - 2);
1528 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1529 m->hsync_end - m->hdisplay - 2);
1530 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1538 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1539 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1540 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1541 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1542 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1543 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1544 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1546 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1547 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001548
1549 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001550 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1551 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1552 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1553 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1554 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1555 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1556 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1557 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1558 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001559}
1560
Rahul Sharma16844fb2013-06-10 14:50:00 +05301561static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001562{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001563 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301564 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001565 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301566 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001567
1568 hdmiphy_wait_for_pll(hdata);
1569
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001570 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001571
1572 /* enable HDMI and timing generator */
1573 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001574}
1575
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001576static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1577{
Rahul Sharma59956d32013-06-11 12:24:03 +05301578 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001579
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001580 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001581 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001582 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001583 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001584 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001585}
1586
1587static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1588{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001589 int ret;
1590 int i;
1591
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001592 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001593 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001594 if (i < 0) {
1595 DRM_ERROR("failed to find hdmiphy conf\n");
1596 return;
1597 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001598
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001599 ret = hdmiphy_reg_write_buf(hdata, 0,
1600 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001601 if (ret) {
1602 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001603 return;
1604 }
1605
Sean Paul09760ea2013-01-14 17:03:20 -05001606 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001607}
1608
1609static void hdmi_conf_apply(struct hdmi_context *hdata)
1610{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001611 hdmiphy_conf_reset(hdata);
1612 hdmiphy_conf_apply(hdata);
1613
Rahul Sharmabfa48422014-04-03 20:41:04 +05301614 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001615 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001616
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001617 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001618
1619 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301620 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001621 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001622
1623 hdmi_regs_dump(hdata, "start");
1624}
1625
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001626static void hdmi_mode_set(struct drm_encoder *encoder,
1627 struct drm_display_mode *mode,
1628 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001629{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001630 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001631 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001632
YoungJun Chocbc4c332013-06-12 10:44:40 +09001633 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1634 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001635 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001636 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001637
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001638 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001639 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001640}
1641
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001642static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001643{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001644 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001645 struct hdmi_resources *res = &hdata->res;
1646
Andrzej Hajda882a0642015-07-09 16:28:08 +02001647 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001648 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001649
1650 hdata->powered = true;
1651
Sean Paulaf65c802014-01-30 16:19:27 -05001652 pm_runtime_get_sync(hdata->dev);
1653
Andrzej Hajda1ab739d2015-09-25 14:48:22 +02001654 if (regulator_bulk_enable(ARRAY_SIZE(supply), res->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001655 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1656
Rahul Sharma049d34e2014-05-20 10:36:05 +05301657 /* set pmu hdmiphy control bit to enable hdmiphy */
1658 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1659 PMU_HDMI_PHY_ENABLE_BIT, 1);
1660
Sean Paul0bfb1f82013-06-11 12:24:02 +05301661 clk_prepare_enable(res->hdmi);
1662 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301663
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001664 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001665}
1666
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001667static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001668{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001669 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001670 struct hdmi_resources *res = &hdata->res;
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001671 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001672 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001673
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001674 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001675 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001676
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001677 /*
1678 * The SFRs of VP and Mixer are updated by Vertical Sync of
1679 * Timing generator which is a part of HDMI so the sequence
1680 * to disable TV Subsystem should be as following,
1681 * VP -> Mixer -> HDMI
1682 *
1683 * Below codes will try to disable Mixer and VP(if used)
1684 * prior to disabling HDMI.
1685 */
1686 if (crtc)
1687 funcs = crtc->helper_private;
1688 if (funcs && funcs->disable)
1689 (*funcs->disable)(crtc);
1690
Rahul Sharmabfa48422014-04-03 20:41:04 +05301691 /* HDMI System Disable */
1692 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1693
Sean Paul724fd142014-05-09 15:05:10 +09001694 cancel_delayed_work(&hdata->hotplug_work);
1695
Sean Paul0bfb1f82013-06-11 12:24:02 +05301696 clk_disable_unprepare(res->sclk_hdmi);
1697 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301698
1699 /* reset pmu hdmiphy control bit to disable hdmiphy */
1700 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1701 PMU_HDMI_PHY_ENABLE_BIT, 0);
1702
Andrzej Hajda1ab739d2015-09-25 14:48:22 +02001703 regulator_bulk_disable(ARRAY_SIZE(supply), res->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001704
Sean Paulaf65c802014-01-30 16:19:27 -05001705 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001706
1707 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001708}
1709
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001710static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001711 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001712 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001713 .enable = hdmi_enable,
1714 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001715};
1716
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001717static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1718 .destroy = drm_encoder_cleanup,
1719};
1720
Sean Paul724fd142014-05-09 15:05:10 +09001721static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001722{
Sean Paul724fd142014-05-09 15:05:10 +09001723 struct hdmi_context *hdata;
1724
1725 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001726
Sean Paul45517892014-01-30 16:19:05 -05001727 if (hdata->drm_dev)
1728 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001729}
1730
1731static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1732{
1733 struct hdmi_context *hdata = arg;
1734
1735 mod_delayed_work(system_wq, &hdata->hotplug_work,
1736 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001737
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001738 return IRQ_HANDLED;
1739}
1740
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001741static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001742{
1743 struct device *dev = hdata->dev;
1744 struct hdmi_resources *res = &hdata->res;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001745 int i, ret;
1746
1747 DRM_DEBUG_KMS("HDMI resource init\n");
1748
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001749 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1750 if (IS_ERR(hdata->hpd_gpio)) {
1751 DRM_ERROR("cannot get hpd gpio property\n");
1752 return PTR_ERR(hdata->hpd_gpio);
1753 }
1754
1755 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1756 if (hdata->irq < 0) {
1757 DRM_ERROR("failed to get GPIO irq\n");
1758 return hdata->irq;
1759 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001760 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301761 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301762 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001763 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001764 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001765 goto fail;
1766 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301767 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301768 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001769 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001770 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001771 goto fail;
1772 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301773 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301774 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001775 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001776 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001777 goto fail;
1778 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301779 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301780 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001781 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001782 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001783 goto fail;
1784 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301785 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1786 if (IS_ERR(res->mout_hdmi)) {
1787 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001788 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301789 goto fail;
1790 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001791
Rahul Sharma59956d32013-06-11 12:24:03 +05301792 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001793
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001794 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1795 res->regul_bulk[i].supply = supply[i];
1796 res->regul_bulk[i].consumer = NULL;
1797 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301798 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001799 if (ret) {
1800 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001801 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001802 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001803
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001804 res->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
1805
1806 if (PTR_ERR(res->reg_hdmi_en) == -ENODEV)
1807 return 0;
1808
1809 if (IS_ERR(res->reg_hdmi_en))
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001810 return PTR_ERR(res->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001811
1812 ret = regulator_enable(res->reg_hdmi_en);
1813 if (ret)
1814 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001815
Inki Daedf5225b2014-05-29 18:28:02 +09001816 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001817fail:
1818 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001819 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001820}
1821
Rahul Sharma22c4f422012-10-04 20:48:55 +05301822static struct of_device_id hdmi_match_types[] = {
1823 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001824 .compatible = "samsung,exynos4210-hdmi",
1825 .data = &exynos4210_hdmi_driver_data,
1826 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301827 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001828 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301829 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301830 .compatible = "samsung,exynos5420-hdmi",
1831 .data = &exynos5420_hdmi_driver_data,
1832 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301833 /* end node */
1834 }
1835};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001836MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301837
Inki Daef37cd5e2014-05-09 14:25:20 +09001838static int hdmi_bind(struct device *dev, struct device *master, void *data)
1839{
1840 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001841 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001842 struct drm_encoder *encoder = &hdata->encoder;
1843 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001844
Inki Daef37cd5e2014-05-09 14:25:20 +09001845 hdata->drm_dev = drm_dev;
1846
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001847 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1848 EXYNOS_DISPLAY_TYPE_HDMI);
1849 if (pipe < 0)
1850 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001851
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001852 encoder->possible_crtcs = 1 << pipe;
1853
1854 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1855
1856 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1857 DRM_MODE_ENCODER_TMDS);
1858
1859 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1860
1861 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001862 if (ret) {
1863 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001864 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001865 return ret;
1866 }
1867
1868 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001869}
1870
1871static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1872{
Inki Daef37cd5e2014-05-09 14:25:20 +09001873}
1874
1875static const struct component_ops hdmi_component_ops = {
1876 .bind = hdmi_bind,
1877 .unbind = hdmi_unbind,
1878};
1879
Inki Daee2a562d2014-05-09 16:46:10 +09001880static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1881{
1882 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1883 struct device_node *np;
1884
1885 np = of_find_compatible_node(NULL, NULL, compatible_str);
1886 if (np)
1887 return of_get_next_parent(np);
1888
1889 return NULL;
1890}
1891
1892static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1893{
1894 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1895
1896 return of_find_compatible_node(NULL, NULL, compatible_str);
1897}
1898
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001899static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001900{
Inki Daef37cd5e2014-05-09 14:25:20 +09001901 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001902 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001903 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001904 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001905 struct resource *res;
1906 int ret;
1907
Andrzej Hajda930865f2014-11-17 09:54:20 +01001908 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1909 if (!hdata)
1910 return -ENOMEM;
1911
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001912 match = of_match_device(hdmi_match_types, dev);
1913 if (!match)
1914 return -ENODEV;
1915
1916 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001917
Andrzej Hajda930865f2014-11-17 09:54:20 +01001918 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001919
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001920 hdata->dev = dev;
1921
1922 ret = hdmi_resources_init(hdata);
1923 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301924 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001925 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001926 }
1927
1928 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001929 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001930 if (IS_ERR(hdata->regs)) {
1931 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001932 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001933 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001934
Inki Daee2a562d2014-05-09 16:46:10 +09001935 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1936 if (ddc_node)
1937 goto out_get_ddc_adpt;
1938
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001939 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001940 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1941 if (!ddc_node) {
1942 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001943 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001944 }
Inki Daee2a562d2014-05-09 16:46:10 +09001945
1946out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001947 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1948 if (!hdata->ddc_adpt) {
1949 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001950 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001951 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952
Inki Daee2a562d2014-05-09 16:46:10 +09001953 phy_node = hdmi_legacy_phy_dt_binding(dev);
1954 if (phy_node)
1955 goto out_get_phy_port;
1956
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001957 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001958 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1959 if (!phy_node) {
1960 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1961 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001962 goto err_ddc;
1963 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001964
Inki Daee2a562d2014-05-09 16:46:10 +09001965out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001966 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001967 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1968 if (!hdata->regs_hdmiphy) {
1969 DRM_ERROR("failed to ioremap hdmi phy\n");
1970 ret = -ENOMEM;
1971 goto err_ddc;
1972 }
1973 } else {
1974 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1975 if (!hdata->hdmiphy_port) {
1976 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001977 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001978 goto err_ddc;
1979 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001980 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001981
Sean Paul724fd142014-05-09 15:05:10 +09001982 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1983
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001984 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001985 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001986 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001987 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001988 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001989 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001990 goto err_hdmiphy;
1991 }
1992
Rahul Sharma049d34e2014-05-20 10:36:05 +05301993 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
1994 "samsung,syscon-phandle");
1995 if (IS_ERR(hdata->pmureg)) {
1996 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001997 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05301998 goto err_hdmiphy;
1999 }
2000
Sean Paulaf65c802014-01-30 16:19:27 -05002001 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002002
Inki Daedf5225b2014-05-29 18:28:02 +09002003 ret = component_add(&pdev->dev, &hdmi_component_ops);
2004 if (ret)
2005 goto err_disable_pm_runtime;
2006
2007 return ret;
2008
2009err_disable_pm_runtime:
2010 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002012err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002013 if (hdata->hdmiphy_port)
2014 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002015err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002016 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002017
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002018 return ret;
2019}
2020
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002021static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002022{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002023 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002024
Sean Paul724fd142014-05-09 15:05:10 +09002025 cancel_delayed_work_sync(&hdata->hotplug_work);
2026
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002027 component_del(&pdev->dev, &hdmi_component_ops);
2028
2029 pm_runtime_disable(&pdev->dev);
2030
Andrzej Hajda498d5a32015-09-25 14:48:21 +02002031 if (!IS_ERR(hdata->res.reg_hdmi_en))
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002032 regulator_disable(hdata->res.reg_hdmi_en);
2033
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002034 if (hdata->hdmiphy_port)
2035 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002036
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002037 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002038
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002039 return 0;
2040}
2041
2042struct platform_driver hdmi_driver = {
2043 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002044 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002045 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302046 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002047 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302048 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002049 },
2050};