blob: 475341f3f9e0204dd2ff7ec0e6fc17477fb78a53 [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
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020086static const char * const supply[] = {
87 "vdd",
88 "vdd_osc",
89 "vdd_pll",
90};
91
Inki Daebfe4e842014-03-06 14:18:17 +090092struct hdmi_driver_data {
93 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090094 const struct hdmiphy_config *phy_confs;
95 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090096 unsigned int is_apb_phy:1;
97};
98
Joonyoung Shim590f4182012-03-16 18:47:14 +090099struct hdmi_resources {
100 struct clk *hdmi;
101 struct clk *sclk_hdmi;
102 struct clk *sclk_pixel;
103 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +0530104 struct clk *mout_hdmi;
Andrzej Hajda1ab739d2015-09-25 14:48:22 +0200105 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
Marek Szyprowski05fdf982014-07-01 10:10:06 +0200106 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900107};
108
109struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300110 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900111 struct device *dev;
112 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500113 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900114 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900115 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900116 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900117
Joonyoung Shim590f4182012-03-16 18:47:14 +0900118 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500119 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900120 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900121
Inki Dae8fa04aa2014-03-13 16:38:31 +0900122 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900123 struct i2c_client *hdmiphy_port;
124
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900125 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530126 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200127 u8 cea_video_id;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900128
129 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200130 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900131
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530132 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900133 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530134
Rahul Sharma049d34e2014-05-20 10:36:05 +0530135 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900136};
137
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300138static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100139{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900140 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100141}
142
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500143struct hdmiphy_config {
144 int pixel_clock;
145 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900146};
147
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900148/* list of phy config settings */
149static const struct hdmiphy_config hdmiphy_v13_configs[] = {
150 {
151 .pixel_clock = 27000000,
152 .conf = {
153 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
154 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
155 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200156 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900157 },
158 },
159 {
160 .pixel_clock = 27027000,
161 .conf = {
162 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
163 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
164 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200165 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166 },
167 },
168 {
169 .pixel_clock = 74176000,
170 .conf = {
171 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
172 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
173 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200174 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900175 },
176 },
177 {
178 .pixel_clock = 74250000,
179 .conf = {
180 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
181 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
182 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200183 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900184 },
185 },
186 {
187 .pixel_clock = 148500000,
188 .conf = {
189 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
190 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
191 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200192 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900193 },
194 },
195};
196
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500197static const struct hdmiphy_config hdmiphy_v14_configs[] = {
198 {
199 .pixel_clock = 25200000,
200 .conf = {
201 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
202 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
203 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
204 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
205 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900206 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500207 {
208 .pixel_clock = 27000000,
209 .conf = {
210 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
211 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
212 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
213 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
214 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900215 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500216 {
217 .pixel_clock = 27027000,
218 .conf = {
219 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
220 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
221 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200222 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500223 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900224 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500225 {
226 .pixel_clock = 36000000,
227 .conf = {
228 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
229 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
230 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
231 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
232 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900233 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500234 {
235 .pixel_clock = 40000000,
236 .conf = {
237 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
238 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
239 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
240 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
241 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900242 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500243 {
244 .pixel_clock = 65000000,
245 .conf = {
246 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
247 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
248 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
249 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
250 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900251 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500252 {
Shirish Se1d883c2014-03-13 14:28:27 +0900253 .pixel_clock = 71000000,
254 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530255 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
256 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
257 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900258 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
259 },
260 },
261 {
262 .pixel_clock = 73250000,
263 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530264 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
265 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
266 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900267 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
268 },
269 },
270 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500271 .pixel_clock = 74176000,
272 .conf = {
273 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
274 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
275 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
276 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
277 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900278 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500279 {
280 .pixel_clock = 74250000,
281 .conf = {
282 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
283 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
284 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200285 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500286 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900287 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500288 {
289 .pixel_clock = 83500000,
290 .conf = {
291 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
292 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
293 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
294 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
295 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900296 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500297 {
298 .pixel_clock = 106500000,
299 .conf = {
300 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
301 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
302 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
303 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
304 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900305 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500306 {
307 .pixel_clock = 108000000,
308 .conf = {
309 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
310 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
311 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
312 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
313 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900314 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500315 {
Shirish Se1d883c2014-03-13 14:28:27 +0900316 .pixel_clock = 115500000,
317 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530318 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
319 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
320 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900321 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
322 },
323 },
324 {
325 .pixel_clock = 119000000,
326 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530327 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
328 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
329 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900330 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
331 },
332 },
333 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500334 .pixel_clock = 146250000,
335 .conf = {
336 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
337 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
338 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
339 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
340 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900341 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500342 {
343 .pixel_clock = 148500000,
344 .conf = {
345 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
346 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
347 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200348 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500349 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900350 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900351};
352
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530353static const struct hdmiphy_config hdmiphy_5420_configs[] = {
354 {
355 .pixel_clock = 25200000,
356 .conf = {
357 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
358 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
359 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
360 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
361 },
362 },
363 {
364 .pixel_clock = 27000000,
365 .conf = {
366 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
367 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
368 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
369 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
370 },
371 },
372 {
373 .pixel_clock = 27027000,
374 .conf = {
375 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
376 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
377 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
378 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
379 },
380 },
381 {
382 .pixel_clock = 36000000,
383 .conf = {
384 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
385 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
386 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
387 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
388 },
389 },
390 {
391 .pixel_clock = 40000000,
392 .conf = {
393 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
394 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
395 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
396 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
397 },
398 },
399 {
400 .pixel_clock = 65000000,
401 .conf = {
402 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
403 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
404 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
405 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
406 },
407 },
408 {
409 .pixel_clock = 71000000,
410 .conf = {
411 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
412 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
413 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
414 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
415 },
416 },
417 {
418 .pixel_clock = 73250000,
419 .conf = {
420 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
421 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
422 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
423 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
424 },
425 },
426 {
427 .pixel_clock = 74176000,
428 .conf = {
429 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
430 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
431 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
432 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
433 },
434 },
435 {
436 .pixel_clock = 74250000,
437 .conf = {
438 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
439 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
440 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
441 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
442 },
443 },
444 {
445 .pixel_clock = 83500000,
446 .conf = {
447 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
448 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
449 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
450 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
451 },
452 },
453 {
454 .pixel_clock = 88750000,
455 .conf = {
456 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
457 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
458 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
459 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
460 },
461 },
462 {
463 .pixel_clock = 106500000,
464 .conf = {
465 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
466 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
467 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
468 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
469 },
470 },
471 {
472 .pixel_clock = 108000000,
473 .conf = {
474 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
475 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
476 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
477 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
478 },
479 },
480 {
481 .pixel_clock = 115500000,
482 .conf = {
483 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
484 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
485 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
486 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
487 },
488 },
489 {
490 .pixel_clock = 146250000,
491 .conf = {
492 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
493 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
494 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
495 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
496 },
497 },
498 {
499 .pixel_clock = 148500000,
500 .conf = {
501 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
502 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
503 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
504 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
505 },
506 },
507};
508
Sachin Kamat16337072014-05-22 10:32:56 +0530509static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530510 .type = HDMI_TYPE14,
511 .phy_confs = hdmiphy_5420_configs,
512 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
513 .is_apb_phy = 1,
514};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900515
Sachin Kamat16337072014-05-22 10:32:56 +0530516static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900517 .type = HDMI_TYPE14,
518 .phy_confs = hdmiphy_v14_configs,
519 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
520 .is_apb_phy = 0,
521};
522
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200523static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
524 .type = HDMI_TYPE13,
525 .phy_confs = hdmiphy_v13_configs,
526 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
527 .is_apb_phy = 0,
528};
529
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200530static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
531{
532 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
533 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
534 return reg_id;
535}
536
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900537static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
538{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200539 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900540}
541
542static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
543 u32 reg_id, u8 value)
544{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200545 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900546}
547
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200548static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
549 int bytes, u32 val)
550{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200551 reg_id = hdmi_map_reg(hdata, reg_id);
552
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200553 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200554 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200555 val >>= 8;
556 reg_id += 4;
557 }
558}
559
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900560static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
561 u32 reg_id, u32 value, u32 mask)
562{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200563 u32 old;
564
565 reg_id = hdmi_map_reg(hdata, reg_id);
566 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900567 value = (value & mask) | (old & ~mask);
568 writel(value, hdata->regs + reg_id);
569}
570
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900571static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
572 u32 reg_offset, const u8 *buf, u32 len)
573{
574 if ((reg_offset + len) > 32)
575 return -EINVAL;
576
577 if (hdata->hdmiphy_port) {
578 int ret;
579
580 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
581 if (ret == len)
582 return 0;
583 return ret;
584 } else {
585 int i;
586 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200587 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900588 ((reg_offset + i)<<2));
589 return 0;
590 }
591}
592
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900593static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594{
595#define DUMPREG(reg_id) \
596 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
597 readl(hdata->regs + reg_id))
598 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
599 DUMPREG(HDMI_INTC_FLAG);
600 DUMPREG(HDMI_INTC_CON);
601 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900602 DUMPREG(HDMI_V13_PHY_RSTOUT);
603 DUMPREG(HDMI_V13_PHY_VPLL);
604 DUMPREG(HDMI_V13_PHY_CMU);
605 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900606
607 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
608 DUMPREG(HDMI_CON_0);
609 DUMPREG(HDMI_CON_1);
610 DUMPREG(HDMI_CON_2);
611 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900612 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900613 DUMPREG(HDMI_STATUS_EN);
614 DUMPREG(HDMI_HPD);
615 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900616 DUMPREG(HDMI_V13_HPD_GEN);
617 DUMPREG(HDMI_V13_DC_CONTROL);
618 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900619
620 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
621 DUMPREG(HDMI_H_BLANK_0);
622 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900623 DUMPREG(HDMI_V13_V_BLANK_0);
624 DUMPREG(HDMI_V13_V_BLANK_1);
625 DUMPREG(HDMI_V13_V_BLANK_2);
626 DUMPREG(HDMI_V13_H_V_LINE_0);
627 DUMPREG(HDMI_V13_H_V_LINE_1);
628 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900629 DUMPREG(HDMI_VSYNC_POL);
630 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900631 DUMPREG(HDMI_V13_V_BLANK_F_0);
632 DUMPREG(HDMI_V13_V_BLANK_F_1);
633 DUMPREG(HDMI_V13_V_BLANK_F_2);
634 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
635 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
636 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
637 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
638 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
639 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
640 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
641 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
642 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
643 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
644 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
645 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900646
647 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
648 DUMPREG(HDMI_TG_CMD);
649 DUMPREG(HDMI_TG_H_FSZ_L);
650 DUMPREG(HDMI_TG_H_FSZ_H);
651 DUMPREG(HDMI_TG_HACT_ST_L);
652 DUMPREG(HDMI_TG_HACT_ST_H);
653 DUMPREG(HDMI_TG_HACT_SZ_L);
654 DUMPREG(HDMI_TG_HACT_SZ_H);
655 DUMPREG(HDMI_TG_V_FSZ_L);
656 DUMPREG(HDMI_TG_V_FSZ_H);
657 DUMPREG(HDMI_TG_VSYNC_L);
658 DUMPREG(HDMI_TG_VSYNC_H);
659 DUMPREG(HDMI_TG_VSYNC2_L);
660 DUMPREG(HDMI_TG_VSYNC2_H);
661 DUMPREG(HDMI_TG_VACT_ST_L);
662 DUMPREG(HDMI_TG_VACT_ST_H);
663 DUMPREG(HDMI_TG_VACT_SZ_L);
664 DUMPREG(HDMI_TG_VACT_SZ_H);
665 DUMPREG(HDMI_TG_FIELD_CHG_L);
666 DUMPREG(HDMI_TG_FIELD_CHG_H);
667 DUMPREG(HDMI_TG_VACT_ST2_L);
668 DUMPREG(HDMI_TG_VACT_ST2_H);
669 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
670 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
671 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
672 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
673 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
674 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
675 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
676 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
677#undef DUMPREG
678}
679
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900680static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
681{
682 int i;
683
684#define DUMPREG(reg_id) \
685 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
686 readl(hdata->regs + reg_id))
687
688 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
689 DUMPREG(HDMI_INTC_CON);
690 DUMPREG(HDMI_INTC_FLAG);
691 DUMPREG(HDMI_HPD_STATUS);
692 DUMPREG(HDMI_INTC_CON_1);
693 DUMPREG(HDMI_INTC_FLAG_1);
694 DUMPREG(HDMI_PHY_STATUS_0);
695 DUMPREG(HDMI_PHY_STATUS_PLL);
696 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200697 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900698 DUMPREG(HDMI_PHY_VPLL);
699 DUMPREG(HDMI_PHY_CMU);
700 DUMPREG(HDMI_CORE_RSTOUT);
701
702 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
703 DUMPREG(HDMI_CON_0);
704 DUMPREG(HDMI_CON_1);
705 DUMPREG(HDMI_CON_2);
706 DUMPREG(HDMI_SYS_STATUS);
707 DUMPREG(HDMI_PHY_STATUS_0);
708 DUMPREG(HDMI_STATUS_EN);
709 DUMPREG(HDMI_HPD);
710 DUMPREG(HDMI_MODE_SEL);
711 DUMPREG(HDMI_ENC_EN);
712 DUMPREG(HDMI_DC_CONTROL);
713 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
714
715 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
716 DUMPREG(HDMI_H_BLANK_0);
717 DUMPREG(HDMI_H_BLANK_1);
718 DUMPREG(HDMI_V2_BLANK_0);
719 DUMPREG(HDMI_V2_BLANK_1);
720 DUMPREG(HDMI_V1_BLANK_0);
721 DUMPREG(HDMI_V1_BLANK_1);
722 DUMPREG(HDMI_V_LINE_0);
723 DUMPREG(HDMI_V_LINE_1);
724 DUMPREG(HDMI_H_LINE_0);
725 DUMPREG(HDMI_H_LINE_1);
726 DUMPREG(HDMI_HSYNC_POL);
727
728 DUMPREG(HDMI_VSYNC_POL);
729 DUMPREG(HDMI_INT_PRO_MODE);
730 DUMPREG(HDMI_V_BLANK_F0_0);
731 DUMPREG(HDMI_V_BLANK_F0_1);
732 DUMPREG(HDMI_V_BLANK_F1_0);
733 DUMPREG(HDMI_V_BLANK_F1_1);
734
735 DUMPREG(HDMI_H_SYNC_START_0);
736 DUMPREG(HDMI_H_SYNC_START_1);
737 DUMPREG(HDMI_H_SYNC_END_0);
738 DUMPREG(HDMI_H_SYNC_END_1);
739
740 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
741 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
742 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
743 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
744
745 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
746 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
747 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
748 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
749
750 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
751 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
752 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
753 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
754
755 DUMPREG(HDMI_V_BLANK_F2_0);
756 DUMPREG(HDMI_V_BLANK_F2_1);
757 DUMPREG(HDMI_V_BLANK_F3_0);
758 DUMPREG(HDMI_V_BLANK_F3_1);
759 DUMPREG(HDMI_V_BLANK_F4_0);
760 DUMPREG(HDMI_V_BLANK_F4_1);
761 DUMPREG(HDMI_V_BLANK_F5_0);
762 DUMPREG(HDMI_V_BLANK_F5_1);
763
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
772
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
774 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
775 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
776 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
777 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
778 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
779 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
780 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
781
782 DUMPREG(HDMI_VACT_SPACE_1_0);
783 DUMPREG(HDMI_VACT_SPACE_1_1);
784 DUMPREG(HDMI_VACT_SPACE_2_0);
785 DUMPREG(HDMI_VACT_SPACE_2_1);
786 DUMPREG(HDMI_VACT_SPACE_3_0);
787 DUMPREG(HDMI_VACT_SPACE_3_1);
788 DUMPREG(HDMI_VACT_SPACE_4_0);
789 DUMPREG(HDMI_VACT_SPACE_4_1);
790 DUMPREG(HDMI_VACT_SPACE_5_0);
791 DUMPREG(HDMI_VACT_SPACE_5_1);
792 DUMPREG(HDMI_VACT_SPACE_6_0);
793 DUMPREG(HDMI_VACT_SPACE_6_1);
794
795 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
796 DUMPREG(HDMI_TG_CMD);
797 DUMPREG(HDMI_TG_H_FSZ_L);
798 DUMPREG(HDMI_TG_H_FSZ_H);
799 DUMPREG(HDMI_TG_HACT_ST_L);
800 DUMPREG(HDMI_TG_HACT_ST_H);
801 DUMPREG(HDMI_TG_HACT_SZ_L);
802 DUMPREG(HDMI_TG_HACT_SZ_H);
803 DUMPREG(HDMI_TG_V_FSZ_L);
804 DUMPREG(HDMI_TG_V_FSZ_H);
805 DUMPREG(HDMI_TG_VSYNC_L);
806 DUMPREG(HDMI_TG_VSYNC_H);
807 DUMPREG(HDMI_TG_VSYNC2_L);
808 DUMPREG(HDMI_TG_VSYNC2_H);
809 DUMPREG(HDMI_TG_VACT_ST_L);
810 DUMPREG(HDMI_TG_VACT_ST_H);
811 DUMPREG(HDMI_TG_VACT_SZ_L);
812 DUMPREG(HDMI_TG_VACT_SZ_H);
813 DUMPREG(HDMI_TG_FIELD_CHG_L);
814 DUMPREG(HDMI_TG_FIELD_CHG_H);
815 DUMPREG(HDMI_TG_VACT_ST2_L);
816 DUMPREG(HDMI_TG_VACT_ST2_H);
817 DUMPREG(HDMI_TG_VACT_ST3_L);
818 DUMPREG(HDMI_TG_VACT_ST3_H);
819 DUMPREG(HDMI_TG_VACT_ST4_L);
820 DUMPREG(HDMI_TG_VACT_ST4_H);
821 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
822 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
823 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
824 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
825 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
826 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
827 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
828 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
829 DUMPREG(HDMI_TG_3D);
830
831 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
832 DUMPREG(HDMI_AVI_CON);
833 DUMPREG(HDMI_AVI_HEADER0);
834 DUMPREG(HDMI_AVI_HEADER1);
835 DUMPREG(HDMI_AVI_HEADER2);
836 DUMPREG(HDMI_AVI_CHECK_SUM);
837 DUMPREG(HDMI_VSI_CON);
838 DUMPREG(HDMI_VSI_HEADER0);
839 DUMPREG(HDMI_VSI_HEADER1);
840 DUMPREG(HDMI_VSI_HEADER2);
841 for (i = 0; i < 7; ++i)
842 DUMPREG(HDMI_VSI_DATA(i));
843
844#undef DUMPREG
845}
846
847static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
848{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200849 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900850 hdmi_v13_regs_dump(hdata, prefix);
851 else
852 hdmi_v14_regs_dump(hdata, prefix);
853}
854
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530855static u8 hdmi_chksum(struct hdmi_context *hdata,
856 u32 start, u8 len, u32 hdr_sum)
857{
858 int i;
859
860 /* hdr_sum : header0 + header1 + header2
861 * start : start address of packet byte1
862 * len : packet bytes - 1 */
863 for (i = 0; i < len; ++i)
864 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
865
866 /* return 2's complement of 8 bit hdr_sum */
867 return (u8)(~(hdr_sum & 0xff) + 1);
868}
869
870static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530871 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530872{
873 u32 hdr_sum;
874 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530875 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200876 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530877
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530878 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
879 if (hdata->dvi_mode) {
880 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
881 HDMI_VSI_CON_DO_NOT_TRANSMIT);
882 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
883 HDMI_AVI_CON_DO_NOT_TRANSMIT);
884 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
885 return;
886 }
887
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530888 switch (infoframe->any.type) {
889 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530890 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530891 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
892 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
893 infoframe->any.version);
894 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
895 hdr_sum = infoframe->any.type + infoframe->any.version +
896 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530897
898 /* Output format zero hardcoded ,RGB YBCR selection */
899 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
900 AVI_ACTIVE_FORMAT_VALID |
901 AVI_UNDERSCANNED_DISPLAY_VALID);
902
Shirish S46154152014-03-13 10:58:28 +0530903 /*
904 * Set the aspect ratio as per the mode, mentioned in
905 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
906 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200907 ar = hdata->current_mode.picture_aspect_ratio;
908 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530909 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200910 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530911 break;
912 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200913 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530914 break;
915 case HDMI_PICTURE_ASPECT_NONE:
916 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200917 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530918 break;
919 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200920 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530921
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200922 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530923
924 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530925 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530926 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
927 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
928 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530929 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530930 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530931 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
932 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
933 infoframe->any.version);
934 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
935 hdr_sum = infoframe->any.type + infoframe->any.version +
936 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530937 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530938 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530939 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
940 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
941 break;
942 default:
943 break;
944 }
945}
946
Sean Pauld9716ee2014-01-30 16:19:29 -0500947static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
948 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500949{
Sean Pauld9716ee2014-01-30 16:19:29 -0500950 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500951
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200952 if (gpio_get_value(hdata->hpd_gpio))
953 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530954
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200955 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500956}
957
Sean Pauld9716ee2014-01-30 16:19:29 -0500958static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900959{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200960 drm_connector_unregister(connector);
961 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900962}
963
Sean Pauld9716ee2014-01-30 16:19:29 -0500964static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300965 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500966 .fill_modes = drm_helper_probe_single_connector_modes,
967 .detect = hdmi_detect,
968 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300969 .reset = drm_atomic_helper_connector_reset,
970 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
971 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500972};
973
974static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900975{
Sean Pauld9716ee2014-01-30 16:19:29 -0500976 struct hdmi_context *hdata = ctx_from_connector(connector);
977 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200978 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900979
Inki Dae8fa04aa2014-03-13 16:38:31 +0900980 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500981 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900982
Inki Dae8fa04aa2014-03-13 16:38:31 +0900983 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500984 if (!edid)
985 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900986
Sean Pauld9716ee2014-01-30 16:19:29 -0500987 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500988 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
989 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500990 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500991
Sean Pauld9716ee2014-01-30 16:19:29 -0500992 drm_mode_connector_update_edid_property(connector, edid);
993
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200994 ret = drm_add_edid_modes(connector, edid);
995
996 kfree(edid);
997
998 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999}
1000
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001001static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001002{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001003 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001004
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001005 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1006 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001007 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001008
1009 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1010 return -EINVAL;
1011}
1012
Sean Pauld9716ee2014-01-30 16:19:29 -05001013static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001014 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001015{
Sean Pauld9716ee2014-01-30 16:19:29 -05001016 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001017 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001018
Rahul Sharma16844fb2013-06-10 14:50:00 +05301019 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1020 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1021 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1022 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001023
Sean Paulf041b252014-01-30 16:19:15 -05001024 ret = mixer_check_mode(mode);
1025 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001026 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001027
Rahul Sharma16844fb2013-06-10 14:50:00 +05301028 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001029 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001030 return MODE_BAD;
1031
1032 return MODE_OK;
1033}
1034
1035static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1036{
1037 struct hdmi_context *hdata = ctx_from_connector(connector);
1038
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001039 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001040}
1041
1042static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1043 .get_modes = hdmi_get_modes,
1044 .mode_valid = hdmi_mode_valid,
1045 .best_encoder = hdmi_best_encoder,
1046};
1047
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001048static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001049{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001050 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001051 struct drm_connector *connector = &hdata->connector;
1052 int ret;
1053
Sean Pauld9716ee2014-01-30 16:19:29 -05001054 connector->interlace_allowed = true;
1055 connector->polled = DRM_CONNECTOR_POLL_HPD;
1056
1057 ret = drm_connector_init(hdata->drm_dev, connector,
1058 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1059 if (ret) {
1060 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001061 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001062 }
1063
1064 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001065 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001066 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001067
1068 return 0;
1069}
1070
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001071static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1072 const struct drm_display_mode *mode,
1073 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001074{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001075 struct drm_device *dev = encoder->dev;
1076 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001077 struct drm_display_mode *m;
1078 int mode_ok;
1079
Sean Paulf041b252014-01-30 16:19:15 -05001080 drm_mode_set_crtcinfo(adjusted_mode, 0);
1081
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001082 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1083 if (connector->encoder == encoder)
1084 break;
1085 }
1086
1087 if (connector->encoder != encoder)
1088 return true;
1089
Sean Pauld9716ee2014-01-30 16:19:29 -05001090 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001091
1092 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001093 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001094 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001095
1096 /*
1097 * otherwise, find the most suitable mode among modes and change it
1098 * to adjusted_mode.
1099 */
1100 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001101 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001102
Sean Pauld9716ee2014-01-30 16:19:29 -05001103 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001104 DRM_INFO("desired mode doesn't exist so\n");
1105 DRM_INFO("use the most suitable mode among modes.\n");
1106
1107 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1108 m->hdisplay, m->vdisplay, m->vrefresh);
1109
Sean Paul75626852014-01-30 16:19:16 -05001110 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001111 break;
1112 }
1113 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001114
1115 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001116}
1117
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001118static void hdmi_set_acr(u32 freq, u8 *acr)
1119{
1120 u32 n, cts;
1121
1122 switch (freq) {
1123 case 32000:
1124 n = 4096;
1125 cts = 27000;
1126 break;
1127 case 44100:
1128 n = 6272;
1129 cts = 30000;
1130 break;
1131 case 88200:
1132 n = 12544;
1133 cts = 30000;
1134 break;
1135 case 176400:
1136 n = 25088;
1137 cts = 30000;
1138 break;
1139 case 48000:
1140 n = 6144;
1141 cts = 27000;
1142 break;
1143 case 96000:
1144 n = 12288;
1145 cts = 27000;
1146 break;
1147 case 192000:
1148 n = 24576;
1149 cts = 27000;
1150 break;
1151 default:
1152 n = 0;
1153 cts = 0;
1154 break;
1155 }
1156
1157 acr[1] = cts >> 16;
1158 acr[2] = cts >> 8 & 0xff;
1159 acr[3] = cts & 0xff;
1160
1161 acr[4] = n >> 16;
1162 acr[5] = n >> 8 & 0xff;
1163 acr[6] = n & 0xff;
1164}
1165
1166static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1167{
1168 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1169 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1170 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1171 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1172 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1173 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1174 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1175 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1176 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001177 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001178}
1179
1180static void hdmi_audio_init(struct hdmi_context *hdata)
1181{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301182 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001183 u32 data_num, bit_ch, sample_frq;
1184 u32 val;
1185 u8 acr[7];
1186
1187 sample_rate = 44100;
1188 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001189
1190 switch (bits_per_sample) {
1191 case 20:
1192 data_num = 2;
1193 bit_ch = 1;
1194 break;
1195 case 24:
1196 data_num = 3;
1197 bit_ch = 1;
1198 break;
1199 default:
1200 data_num = 1;
1201 bit_ch = 0;
1202 break;
1203 }
1204
1205 hdmi_set_acr(sample_rate, acr);
1206 hdmi_reg_acr(hdata, acr);
1207
1208 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1209 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1210 | HDMI_I2S_MUX_ENABLE);
1211
1212 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1213 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1214
1215 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1216
1217 sample_frq = (sample_rate == 44100) ? 0 :
1218 (sample_rate == 48000) ? 2 :
1219 (sample_rate == 32000) ? 3 :
1220 (sample_rate == 96000) ? 0xa : 0x0;
1221
1222 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1223 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1224
1225 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1226 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1227
1228 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1229 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1230 | HDMI_I2S_SEL_LRCK(6));
1231 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1232 | HDMI_I2S_SEL_SDATA2(4));
1233 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1234 | HDMI_I2S_SEL_SDATA2(2));
1235 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1236
1237 /* I2S_CON_1 & 2 */
1238 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1239 | HDMI_I2S_L_CH_LOW_POL);
1240 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1241 | HDMI_I2S_SET_BIT_CH(bit_ch)
1242 | HDMI_I2S_SET_SDATA_BIT(data_num)
1243 | HDMI_I2S_BASIC_FORMAT);
1244
1245 /* Configure register related to CUV information */
1246 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1247 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1248 | HDMI_I2S_COPYRIGHT
1249 | HDMI_I2S_LINEAR_PCM
1250 | HDMI_I2S_CONSUMER_FORMAT);
1251 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1252 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1253 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1254 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1255 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1256 HDMI_I2S_ORG_SMP_FREQ_44_1
1257 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1258 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1259
1260 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1261}
1262
1263static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1264{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001265 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001266 return;
1267
1268 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1269 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1270 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1271}
1272
Rahul Sharmabfa48422014-04-03 20:41:04 +05301273static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001274{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301275 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001276
Rahul Sharmabfa48422014-04-03 20:41:04 +05301277 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1278 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001279
Rahul Sharmabfa48422014-04-03 20:41:04 +05301280 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1281 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001282}
1283
1284static void hdmi_conf_init(struct hdmi_context *hdata)
1285{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301286 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301287
Sean Paul77006a72013-01-16 10:17:20 -05001288 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1290 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001291
1292 /* choose HDMI mode */
1293 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1294 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301295 /* Apply Video preable and Guard band in HDMI mode only */
1296 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297 /* disable bluescreen */
1298 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001299
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001300 if (hdata->dvi_mode) {
1301 /* choose DVI mode */
1302 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1303 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1304 hdmi_reg_writeb(hdata, HDMI_CON_2,
1305 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1306 }
1307
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001308 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001309 /* choose bluescreen (fecal) color */
1310 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1311 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1312 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1313
1314 /* enable AVI packet every vsync, fixes purple line problem */
1315 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1316 /* force RGB, look to CEA-861-D, table 7 for more detail */
1317 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1318 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1319
1320 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1321 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1322 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1323 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301324 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1325 infoframe.any.version = HDMI_AVI_VERSION;
1326 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301327 hdmi_reg_infoframe(hdata, &infoframe);
1328
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301329 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1330 infoframe.any.version = HDMI_AUI_VERSION;
1331 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301332 hdmi_reg_infoframe(hdata, &infoframe);
1333
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001334 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001335 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1336 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001337}
1338
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001339static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1340{
1341 int tries;
1342
1343 for (tries = 0; tries < 10; ++tries) {
1344 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1345
1346 if (val & HDMI_PHY_STATUS_READY) {
1347 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1348 return;
1349 }
1350 usleep_range(10, 20);
1351 }
1352
1353 DRM_ERROR("PLL could not reach steady state\n");
1354}
1355
Rahul Sharma16844fb2013-06-10 14:50:00 +05301356static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001357{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001358 struct drm_display_mode *m = &hdata->current_mode;
1359 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001360
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001361 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1362 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1363 (m->htotal << 12) | m->vtotal);
1364
1365 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1366 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1367
1368 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1369 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1370
1371 val = (m->hsync_start - m->hdisplay - 2);
1372 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1373 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1374 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1375
1376 /*
1377 * Quirk requirement for exynos HDMI IP design,
1378 * 2 pixels less than the actual calculation for hsync_start
1379 * and end.
1380 */
1381
1382 /* Following values & calculations differ for different type of modes */
1383 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1384 /* Interlaced Mode */
1385 val = ((m->vsync_end - m->vdisplay) / 2);
1386 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1387 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1388
1389 val = m->vtotal / 2;
1390 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1391 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1392
1393 val = (m->vtotal +
1394 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1395 val |= m->vtotal << 11;
1396 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1397
1398 val = ((m->vtotal / 2) + 7);
1399 val |= ((m->vtotal / 2) + 2) << 12;
1400 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1401
1402 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1403 val |= ((m->htotal / 2) +
1404 (m->hsync_start - m->hdisplay)) << 12;
1405 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1406
1407 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1408 (m->vtotal - m->vdisplay) / 2);
1409 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1410
1411 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1412 } else {
1413 /* Progressive Mode */
1414
1415 val = m->vtotal;
1416 val |= (m->vtotal - m->vdisplay) << 11;
1417 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1418
1419 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1420
1421 val = (m->vsync_end - m->vdisplay);
1422 val |= ((m->vsync_start - m->vdisplay) << 12);
1423 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1424
1425 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1426 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1427 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1428 m->vtotal - m->vdisplay);
1429 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1430 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1431 }
1432
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001433 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001434 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1435 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1436 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1437 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1438 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1439 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1440 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1441 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1442 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1443 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1444 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001445}
1446
Rahul Sharma16844fb2013-06-10 14:50:00 +05301447static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001448{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001449 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001450
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001451 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1452 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1453 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1454 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1455 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1456 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1457 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1458 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1459 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1460
1461 /*
1462 * Quirk requirement for exynos 5 HDMI IP design,
1463 * 2 pixels less than the actual calculation for hsync_start
1464 * and end.
1465 */
1466
1467 /* Following values & calculations differ for different type of modes */
1468 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1469 /* Interlaced Mode */
1470 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1471 (m->vsync_end - m->vdisplay) / 2);
1472 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1473 (m->vsync_start - m->vdisplay) / 2);
1474 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1475 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1476 (m->vtotal - m->vdisplay) / 2);
1477 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1478 m->vtotal - m->vdisplay / 2);
1479 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1480 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1481 (m->vtotal / 2) + 7);
1482 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1483 (m->vtotal / 2) + 2);
1484 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1485 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1486 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1487 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1488 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1489 (m->vtotal - m->vdisplay) / 2);
1490 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1491 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1492 m->vtotal - m->vdisplay / 2);
1493 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1494 (m->vtotal / 2) + 1);
1495 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1496 (m->vtotal / 2) + 1);
1497 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1498 (m->vtotal / 2) + 1);
1499 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1500 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1501 } else {
1502 /* Progressive Mode */
1503 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1504 m->vsync_end - m->vdisplay);
1505 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1506 m->vsync_start - m->vdisplay);
1507 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1508 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1509 m->vtotal - m->vdisplay);
1510 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1511 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1512 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1513 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1514 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1515 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1516 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1517 m->vtotal - m->vdisplay);
1518 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1519 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1520 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1521 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1522 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1523 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1524 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1525 }
1526
1527 /* Following values & calculations are same irrespective of mode type */
1528 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1529 m->hsync_start - m->hdisplay - 2);
1530 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1531 m->hsync_end - m->hdisplay - 2);
1532 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1538 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1539 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1540 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1541 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1542 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1543 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1544 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1546 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1547 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1548 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1549 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001550
1551 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001552 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1553 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1554 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1555 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1556 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1557 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1558 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1559 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1560 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001561}
1562
Rahul Sharma16844fb2013-06-10 14:50:00 +05301563static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001564{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001565 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301566 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001567 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301568 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001569
1570 hdmiphy_wait_for_pll(hdata);
1571
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001572 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001573
1574 /* enable HDMI and timing generator */
1575 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001576}
1577
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001578static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1579{
Rahul Sharma59956d32013-06-11 12:24:03 +05301580 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001581
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001582 /* reset hdmiphy */
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);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001585 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001586 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001587}
1588
1589static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1590{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001591 int ret;
1592 int i;
1593
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001594 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001595 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001596 if (i < 0) {
1597 DRM_ERROR("failed to find hdmiphy conf\n");
1598 return;
1599 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001600
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001601 ret = hdmiphy_reg_write_buf(hdata, 0,
1602 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001603 if (ret) {
1604 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001605 return;
1606 }
1607
Sean Paul09760ea2013-01-14 17:03:20 -05001608 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001609}
1610
1611static void hdmi_conf_apply(struct hdmi_context *hdata)
1612{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001613 hdmiphy_conf_reset(hdata);
1614 hdmiphy_conf_apply(hdata);
1615
Rahul Sharmabfa48422014-04-03 20:41:04 +05301616 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001617 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001618
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001619 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001620
1621 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301622 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001623 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001624
1625 hdmi_regs_dump(hdata, "start");
1626}
1627
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001628static void hdmi_mode_set(struct drm_encoder *encoder,
1629 struct drm_display_mode *mode,
1630 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001631{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001632 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001633 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001634
YoungJun Chocbc4c332013-06-12 10:44:40 +09001635 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1636 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001637 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001638 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001639
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001640 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001641 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001642}
1643
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001644static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001645{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001646 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001647 struct hdmi_resources *res = &hdata->res;
1648
Andrzej Hajda882a0642015-07-09 16:28:08 +02001649 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001650 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001651
1652 hdata->powered = true;
1653
Sean Paulaf65c802014-01-30 16:19:27 -05001654 pm_runtime_get_sync(hdata->dev);
1655
Andrzej Hajda1ab739d2015-09-25 14:48:22 +02001656 if (regulator_bulk_enable(ARRAY_SIZE(supply), res->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001657 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1658
Rahul Sharma049d34e2014-05-20 10:36:05 +05301659 /* set pmu hdmiphy control bit to enable hdmiphy */
1660 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1661 PMU_HDMI_PHY_ENABLE_BIT, 1);
1662
Sean Paul0bfb1f82013-06-11 12:24:02 +05301663 clk_prepare_enable(res->hdmi);
1664 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301665
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001666 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001667}
1668
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001669static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001670{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001671 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001672 struct hdmi_resources *res = &hdata->res;
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001673 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001674 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001675
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001676 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001677 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001678
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001679 /*
1680 * The SFRs of VP and Mixer are updated by Vertical Sync of
1681 * Timing generator which is a part of HDMI so the sequence
1682 * to disable TV Subsystem should be as following,
1683 * VP -> Mixer -> HDMI
1684 *
1685 * Below codes will try to disable Mixer and VP(if used)
1686 * prior to disabling HDMI.
1687 */
1688 if (crtc)
1689 funcs = crtc->helper_private;
1690 if (funcs && funcs->disable)
1691 (*funcs->disable)(crtc);
1692
Rahul Sharmabfa48422014-04-03 20:41:04 +05301693 /* HDMI System Disable */
1694 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1695
Sean Paul724fd142014-05-09 15:05:10 +09001696 cancel_delayed_work(&hdata->hotplug_work);
1697
Sean Paul0bfb1f82013-06-11 12:24:02 +05301698 clk_disable_unprepare(res->sclk_hdmi);
1699 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301700
1701 /* reset pmu hdmiphy control bit to disable hdmiphy */
1702 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1703 PMU_HDMI_PHY_ENABLE_BIT, 0);
1704
Andrzej Hajda1ab739d2015-09-25 14:48:22 +02001705 regulator_bulk_disable(ARRAY_SIZE(supply), res->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001706
Sean Paulaf65c802014-01-30 16:19:27 -05001707 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001708
1709 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001710}
1711
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001712static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001713 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001714 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001715 .enable = hdmi_enable,
1716 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001717};
1718
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001719static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1720 .destroy = drm_encoder_cleanup,
1721};
1722
Sean Paul724fd142014-05-09 15:05:10 +09001723static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001724{
Sean Paul724fd142014-05-09 15:05:10 +09001725 struct hdmi_context *hdata;
1726
1727 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001728
Sean Paul45517892014-01-30 16:19:05 -05001729 if (hdata->drm_dev)
1730 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001731}
1732
1733static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1734{
1735 struct hdmi_context *hdata = arg;
1736
1737 mod_delayed_work(system_wq, &hdata->hotplug_work,
1738 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001739
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001740 return IRQ_HANDLED;
1741}
1742
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001743static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001744{
1745 struct device *dev = hdata->dev;
1746 struct hdmi_resources *res = &hdata->res;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001747 int i, ret;
1748
1749 DRM_DEBUG_KMS("HDMI resource init\n");
1750
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001751 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301752 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301753 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001754 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001755 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001756 goto fail;
1757 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301758 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301759 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001760 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001761 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001762 goto fail;
1763 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301764 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301765 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001766 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001767 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001768 goto fail;
1769 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301770 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301771 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001772 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001773 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001774 goto fail;
1775 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301776 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1777 if (IS_ERR(res->mout_hdmi)) {
1778 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001779 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301780 goto fail;
1781 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001782
Rahul Sharma59956d32013-06-11 12:24:03 +05301783 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001784
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001785 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1786 res->regul_bulk[i].supply = supply[i];
1787 res->regul_bulk[i].consumer = NULL;
1788 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301789 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001790 if (ret) {
1791 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001792 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001793 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001794
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001795 res->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
1796
1797 if (PTR_ERR(res->reg_hdmi_en) == -ENODEV)
1798 return 0;
1799
1800 if (IS_ERR(res->reg_hdmi_en))
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001801 return PTR_ERR(res->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001802
1803 ret = regulator_enable(res->reg_hdmi_en);
1804 if (ret)
1805 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001806
Inki Daedf5225b2014-05-29 18:28:02 +09001807 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001808fail:
1809 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001810 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001811}
1812
Rahul Sharma22c4f422012-10-04 20:48:55 +05301813static struct of_device_id hdmi_match_types[] = {
1814 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001815 .compatible = "samsung,exynos4210-hdmi",
1816 .data = &exynos4210_hdmi_driver_data,
1817 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301818 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001819 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301820 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301821 .compatible = "samsung,exynos5420-hdmi",
1822 .data = &exynos5420_hdmi_driver_data,
1823 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301824 /* end node */
1825 }
1826};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001827MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301828
Inki Daef37cd5e2014-05-09 14:25:20 +09001829static int hdmi_bind(struct device *dev, struct device *master, void *data)
1830{
1831 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001832 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001833 struct drm_encoder *encoder = &hdata->encoder;
1834 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001835
Inki Daef37cd5e2014-05-09 14:25:20 +09001836 hdata->drm_dev = drm_dev;
1837
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001838 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1839 EXYNOS_DISPLAY_TYPE_HDMI);
1840 if (pipe < 0)
1841 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001842
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001843 encoder->possible_crtcs = 1 << pipe;
1844
1845 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1846
1847 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1848 DRM_MODE_ENCODER_TMDS);
1849
1850 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1851
1852 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001853 if (ret) {
1854 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001855 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001856 return ret;
1857 }
1858
1859 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001860}
1861
1862static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1863{
Inki Daef37cd5e2014-05-09 14:25:20 +09001864}
1865
1866static const struct component_ops hdmi_component_ops = {
1867 .bind = hdmi_bind,
1868 .unbind = hdmi_unbind,
1869};
1870
Inki Daee2a562d2014-05-09 16:46:10 +09001871static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1872{
1873 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1874 struct device_node *np;
1875
1876 np = of_find_compatible_node(NULL, NULL, compatible_str);
1877 if (np)
1878 return of_get_next_parent(np);
1879
1880 return NULL;
1881}
1882
1883static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1884{
1885 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1886
1887 return of_find_compatible_node(NULL, NULL, compatible_str);
1888}
1889
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001890static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001891{
Inki Daef37cd5e2014-05-09 14:25:20 +09001892 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001893 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001894 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001895 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001896 struct resource *res;
1897 int ret;
1898
Andrzej Hajda930865f2014-11-17 09:54:20 +01001899 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1900 if (!hdata)
1901 return -ENOMEM;
1902
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001903 match = of_match_device(hdmi_match_types, dev);
1904 if (!match)
1905 return -ENODEV;
1906
1907 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001908
Andrzej Hajda930865f2014-11-17 09:54:20 +01001909 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001910
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001911 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02001912 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
1913 if (hdata->hpd_gpio < 0) {
1914 DRM_ERROR("cannot get hpd gpio property\n");
1915 return hdata->hpd_gpio;
1916 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001917
1918 ret = hdmi_resources_init(hdata);
1919 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301920 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001921 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001922 }
1923
1924 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001925 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001926 if (IS_ERR(hdata->regs)) {
1927 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001928 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001929 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001930
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001931 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301932 if (ret) {
1933 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001934 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301935 }
1936
Inki Daee2a562d2014-05-09 16:46:10 +09001937 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1938 if (ddc_node)
1939 goto out_get_ddc_adpt;
1940
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001941 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001942 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1943 if (!ddc_node) {
1944 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001945 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001946 }
Inki Daee2a562d2014-05-09 16:46:10 +09001947
1948out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001949 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1950 if (!hdata->ddc_adpt) {
1951 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001952 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001953 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001954
Inki Daee2a562d2014-05-09 16:46:10 +09001955 phy_node = hdmi_legacy_phy_dt_binding(dev);
1956 if (phy_node)
1957 goto out_get_phy_port;
1958
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001959 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001960 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1961 if (!phy_node) {
1962 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1963 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001964 goto err_ddc;
1965 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001966
Inki Daee2a562d2014-05-09 16:46:10 +09001967out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001968 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001969 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1970 if (!hdata->regs_hdmiphy) {
1971 DRM_ERROR("failed to ioremap hdmi phy\n");
1972 ret = -ENOMEM;
1973 goto err_ddc;
1974 }
1975 } else {
1976 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1977 if (!hdata->hdmiphy_port) {
1978 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001979 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001980 goto err_ddc;
1981 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001982 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001983
Sean Paul77006a72013-01-16 10:17:20 -05001984 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
1985 if (hdata->irq < 0) {
1986 DRM_ERROR("failed to get GPIO irq\n");
1987 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09001988 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001989 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001990
Sean Paul724fd142014-05-09 15:05:10 +09001991 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1992
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001993 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001994 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001995 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001996 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001997 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001998 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001999 goto err_hdmiphy;
2000 }
2001
Rahul Sharma049d34e2014-05-20 10:36:05 +05302002 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2003 "samsung,syscon-phandle");
2004 if (IS_ERR(hdata->pmureg)) {
2005 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002006 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302007 goto err_hdmiphy;
2008 }
2009
Sean Paulaf65c802014-01-30 16:19:27 -05002010 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011
Inki Daedf5225b2014-05-29 18:28:02 +09002012 ret = component_add(&pdev->dev, &hdmi_component_ops);
2013 if (ret)
2014 goto err_disable_pm_runtime;
2015
2016 return ret;
2017
2018err_disable_pm_runtime:
2019 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002021err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002022 if (hdata->hdmiphy_port)
2023 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002024err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002025 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002026
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002027 return ret;
2028}
2029
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002030static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002031{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002032 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002033
Sean Paul724fd142014-05-09 15:05:10 +09002034 cancel_delayed_work_sync(&hdata->hotplug_work);
2035
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002036 component_del(&pdev->dev, &hdmi_component_ops);
2037
2038 pm_runtime_disable(&pdev->dev);
2039
Andrzej Hajda498d5a32015-09-25 14:48:21 +02002040 if (!IS_ERR(hdata->res.reg_hdmi_en))
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002041 regulator_disable(hdata->res.reg_hdmi_en);
2042
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002043 if (hdata->hdmiphy_port)
2044 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002045
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002046 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002047
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002048 return 0;
2049}
2050
2051struct platform_driver hdmi_driver = {
2052 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002053 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302055 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002056 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302057 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002058 },
2059};