blob: 932f7fa240f83cface947f21fb30dd3684f8d7c8 [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,
69};
70
Inki Daebfe4e842014-03-06 14:18:17 +090071struct hdmi_driver_data {
72 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090073 const struct hdmiphy_config *phy_confs;
74 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090075 unsigned int is_apb_phy:1;
76};
77
Joonyoung Shim590f4182012-03-16 18:47:14 +090078struct hdmi_resources {
79 struct clk *hdmi;
80 struct clk *sclk_hdmi;
81 struct clk *sclk_pixel;
82 struct clk *sclk_hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053083 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090084 struct regulator_bulk_data *regul_bulk;
Marek Szyprowski05fdf982014-07-01 10:10:06 +020085 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +090086 int regul_count;
87};
88
89struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -030090 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +090091 struct device *dev;
92 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -050093 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +090094 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +090095 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +090096 bool dvi_mode;
Joonyoung Shim590f4182012-03-16 18:47:14 +090097
Joonyoung Shim590f4182012-03-16 18:47:14 +090098 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -050099 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900100 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900101
Inki Dae8fa04aa2014-03-13 16:38:31 +0900102 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900103 struct i2c_client *hdmiphy_port;
104
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900105 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530106 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200107 u8 cea_video_id;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900108
109 struct hdmi_resources res;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200110 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900111
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530112 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900113 void __iomem *regs_hdmiphy;
Rahul Sharma5a325072012-10-04 20:48:54 +0530114
Rahul Sharma049d34e2014-05-20 10:36:05 +0530115 struct regmap *pmureg;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900116};
117
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300118static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100119{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900120 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100121}
122
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500123struct hdmiphy_config {
124 int pixel_clock;
125 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900126};
127
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900128/* list of phy config settings */
129static const struct hdmiphy_config hdmiphy_v13_configs[] = {
130 {
131 .pixel_clock = 27000000,
132 .conf = {
133 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
134 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
135 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
136 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
137 },
138 },
139 {
140 .pixel_clock = 27027000,
141 .conf = {
142 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
143 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
144 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
145 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
146 },
147 },
148 {
149 .pixel_clock = 74176000,
150 .conf = {
151 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
152 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
153 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
154 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
155 },
156 },
157 {
158 .pixel_clock = 74250000,
159 .conf = {
160 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
161 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
162 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
163 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
164 },
165 },
166 {
167 .pixel_clock = 148500000,
168 .conf = {
169 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
170 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
171 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
172 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
173 },
174 },
175};
176
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500177static const struct hdmiphy_config hdmiphy_v14_configs[] = {
178 {
179 .pixel_clock = 25200000,
180 .conf = {
181 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
182 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
183 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
184 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
185 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900186 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500187 {
188 .pixel_clock = 27000000,
189 .conf = {
190 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
191 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
192 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
193 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
194 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900195 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500196 {
197 .pixel_clock = 27027000,
198 .conf = {
199 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
200 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
201 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
202 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
203 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900204 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500205 {
206 .pixel_clock = 36000000,
207 .conf = {
208 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
209 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
210 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
211 0x54, 0xab, 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 = 40000000,
216 .conf = {
217 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
218 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
219 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
220 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
221 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900222 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500223 {
224 .pixel_clock = 65000000,
225 .conf = {
226 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
227 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
228 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
229 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
230 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900231 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500232 {
Shirish Se1d883c2014-03-13 14:28:27 +0900233 .pixel_clock = 71000000,
234 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530235 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
236 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
237 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900238 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
239 },
240 },
241 {
242 .pixel_clock = 73250000,
243 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530244 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
245 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
246 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900247 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
248 },
249 },
250 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500251 .pixel_clock = 74176000,
252 .conf = {
253 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
254 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
255 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
256 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
257 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900258 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500259 {
260 .pixel_clock = 74250000,
261 .conf = {
262 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
263 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
264 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
265 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
266 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900267 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500268 {
269 .pixel_clock = 83500000,
270 .conf = {
271 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
272 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
273 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
274 0x54, 0x93, 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 = 106500000,
279 .conf = {
280 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
281 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
282 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
283 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
284 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900285 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500286 {
287 .pixel_clock = 108000000,
288 .conf = {
289 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
290 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
291 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
292 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
293 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900294 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500295 {
Shirish Se1d883c2014-03-13 14:28:27 +0900296 .pixel_clock = 115500000,
297 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530298 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
299 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
300 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900301 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
302 },
303 },
304 {
305 .pixel_clock = 119000000,
306 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530307 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
308 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
309 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900310 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
311 },
312 },
313 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500314 .pixel_clock = 146250000,
315 .conf = {
316 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
317 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
318 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
319 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
320 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900321 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500322 {
323 .pixel_clock = 148500000,
324 .conf = {
325 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
326 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
327 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
328 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
329 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900330 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900331};
332
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530333static const struct hdmiphy_config hdmiphy_5420_configs[] = {
334 {
335 .pixel_clock = 25200000,
336 .conf = {
337 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
338 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
339 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
340 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
341 },
342 },
343 {
344 .pixel_clock = 27000000,
345 .conf = {
346 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
347 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
348 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
349 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
350 },
351 },
352 {
353 .pixel_clock = 27027000,
354 .conf = {
355 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
356 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
357 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
358 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
359 },
360 },
361 {
362 .pixel_clock = 36000000,
363 .conf = {
364 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
365 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
366 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
367 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
368 },
369 },
370 {
371 .pixel_clock = 40000000,
372 .conf = {
373 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
374 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
375 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
376 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
377 },
378 },
379 {
380 .pixel_clock = 65000000,
381 .conf = {
382 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
383 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
384 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
385 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
386 },
387 },
388 {
389 .pixel_clock = 71000000,
390 .conf = {
391 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
392 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
393 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
394 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
395 },
396 },
397 {
398 .pixel_clock = 73250000,
399 .conf = {
400 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
401 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
402 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
403 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
404 },
405 },
406 {
407 .pixel_clock = 74176000,
408 .conf = {
409 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
410 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
411 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
412 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
413 },
414 },
415 {
416 .pixel_clock = 74250000,
417 .conf = {
418 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
419 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
420 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
421 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
422 },
423 },
424 {
425 .pixel_clock = 83500000,
426 .conf = {
427 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
428 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
429 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
430 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
431 },
432 },
433 {
434 .pixel_clock = 88750000,
435 .conf = {
436 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
437 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
438 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
439 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
440 },
441 },
442 {
443 .pixel_clock = 106500000,
444 .conf = {
445 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
446 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
447 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
448 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
449 },
450 },
451 {
452 .pixel_clock = 108000000,
453 .conf = {
454 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
455 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
456 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
457 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
458 },
459 },
460 {
461 .pixel_clock = 115500000,
462 .conf = {
463 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
464 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
465 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
466 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
467 },
468 },
469 {
470 .pixel_clock = 146250000,
471 .conf = {
472 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
473 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
474 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
475 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
476 },
477 },
478 {
479 .pixel_clock = 148500000,
480 .conf = {
481 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
482 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
483 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
484 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
485 },
486 },
487};
488
Sachin Kamat16337072014-05-22 10:32:56 +0530489static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530490 .type = HDMI_TYPE14,
491 .phy_confs = hdmiphy_5420_configs,
492 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
493 .is_apb_phy = 1,
494};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900495
Sachin Kamat16337072014-05-22 10:32:56 +0530496static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900497 .type = HDMI_TYPE14,
498 .phy_confs = hdmiphy_v14_configs,
499 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
500 .is_apb_phy = 0,
501};
502
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200503static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
504 .type = HDMI_TYPE13,
505 .phy_confs = hdmiphy_v13_configs,
506 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
507 .is_apb_phy = 0,
508};
509
Sachin Kamat16337072014-05-22 10:32:56 +0530510static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900511 .type = HDMI_TYPE14,
512 .phy_confs = hdmiphy_v13_configs,
513 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
514 .is_apb_phy = 0,
515};
516
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900517static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
518{
519 return readl(hdata->regs + reg_id);
520}
521
522static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
523 u32 reg_id, u8 value)
524{
525 writeb(value, hdata->regs + reg_id);
526}
527
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200528static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
529 int bytes, u32 val)
530{
531 while (--bytes >= 0) {
532 writeb(val & 0xff, hdata->regs + reg_id);
533 val >>= 8;
534 reg_id += 4;
535 }
536}
537
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900538static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
539 u32 reg_id, u32 value, u32 mask)
540{
541 u32 old = readl(hdata->regs + reg_id);
542 value = (value & mask) | (old & ~mask);
543 writel(value, hdata->regs + reg_id);
544}
545
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900546static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
547 u32 reg_offset, u8 value)
548{
549 if (hdata->hdmiphy_port) {
550 u8 buffer[2];
551 int ret;
552
553 buffer[0] = reg_offset;
554 buffer[1] = value;
555
556 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
557 if (ret == 2)
558 return 0;
559 return ret;
560 } else {
561 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
562 return 0;
563 }
564}
565
566static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
567 u32 reg_offset, const u8 *buf, u32 len)
568{
569 if ((reg_offset + len) > 32)
570 return -EINVAL;
571
572 if (hdata->hdmiphy_port) {
573 int ret;
574
575 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
576 if (ret == len)
577 return 0;
578 return ret;
579 } else {
580 int i;
581 for (i = 0; i < len; i++)
582 writeb(buf[i], hdata->regs_hdmiphy +
583 ((reg_offset + i)<<2));
584 return 0;
585 }
586}
587
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900588static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900589{
590#define DUMPREG(reg_id) \
591 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
592 readl(hdata->regs + reg_id))
593 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
594 DUMPREG(HDMI_INTC_FLAG);
595 DUMPREG(HDMI_INTC_CON);
596 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900597 DUMPREG(HDMI_V13_PHY_RSTOUT);
598 DUMPREG(HDMI_V13_PHY_VPLL);
599 DUMPREG(HDMI_V13_PHY_CMU);
600 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900601
602 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
603 DUMPREG(HDMI_CON_0);
604 DUMPREG(HDMI_CON_1);
605 DUMPREG(HDMI_CON_2);
606 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900607 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900608 DUMPREG(HDMI_STATUS_EN);
609 DUMPREG(HDMI_HPD);
610 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900611 DUMPREG(HDMI_V13_HPD_GEN);
612 DUMPREG(HDMI_V13_DC_CONTROL);
613 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614
615 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
616 DUMPREG(HDMI_H_BLANK_0);
617 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900618 DUMPREG(HDMI_V13_V_BLANK_0);
619 DUMPREG(HDMI_V13_V_BLANK_1);
620 DUMPREG(HDMI_V13_V_BLANK_2);
621 DUMPREG(HDMI_V13_H_V_LINE_0);
622 DUMPREG(HDMI_V13_H_V_LINE_1);
623 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900624 DUMPREG(HDMI_VSYNC_POL);
625 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900626 DUMPREG(HDMI_V13_V_BLANK_F_0);
627 DUMPREG(HDMI_V13_V_BLANK_F_1);
628 DUMPREG(HDMI_V13_V_BLANK_F_2);
629 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
630 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
631 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
632 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
633 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
634 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
635 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
636 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
637 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
638 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
639 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
640 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900641
642 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
643 DUMPREG(HDMI_TG_CMD);
644 DUMPREG(HDMI_TG_H_FSZ_L);
645 DUMPREG(HDMI_TG_H_FSZ_H);
646 DUMPREG(HDMI_TG_HACT_ST_L);
647 DUMPREG(HDMI_TG_HACT_ST_H);
648 DUMPREG(HDMI_TG_HACT_SZ_L);
649 DUMPREG(HDMI_TG_HACT_SZ_H);
650 DUMPREG(HDMI_TG_V_FSZ_L);
651 DUMPREG(HDMI_TG_V_FSZ_H);
652 DUMPREG(HDMI_TG_VSYNC_L);
653 DUMPREG(HDMI_TG_VSYNC_H);
654 DUMPREG(HDMI_TG_VSYNC2_L);
655 DUMPREG(HDMI_TG_VSYNC2_H);
656 DUMPREG(HDMI_TG_VACT_ST_L);
657 DUMPREG(HDMI_TG_VACT_ST_H);
658 DUMPREG(HDMI_TG_VACT_SZ_L);
659 DUMPREG(HDMI_TG_VACT_SZ_H);
660 DUMPREG(HDMI_TG_FIELD_CHG_L);
661 DUMPREG(HDMI_TG_FIELD_CHG_H);
662 DUMPREG(HDMI_TG_VACT_ST2_L);
663 DUMPREG(HDMI_TG_VACT_ST2_H);
664 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
665 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
666 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
667 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
668 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
669 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
670 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
671 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
672#undef DUMPREG
673}
674
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900675static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
676{
677 int i;
678
679#define DUMPREG(reg_id) \
680 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
681 readl(hdata->regs + reg_id))
682
683 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
684 DUMPREG(HDMI_INTC_CON);
685 DUMPREG(HDMI_INTC_FLAG);
686 DUMPREG(HDMI_HPD_STATUS);
687 DUMPREG(HDMI_INTC_CON_1);
688 DUMPREG(HDMI_INTC_FLAG_1);
689 DUMPREG(HDMI_PHY_STATUS_0);
690 DUMPREG(HDMI_PHY_STATUS_PLL);
691 DUMPREG(HDMI_PHY_CON_0);
692 DUMPREG(HDMI_PHY_RSTOUT);
693 DUMPREG(HDMI_PHY_VPLL);
694 DUMPREG(HDMI_PHY_CMU);
695 DUMPREG(HDMI_CORE_RSTOUT);
696
697 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
698 DUMPREG(HDMI_CON_0);
699 DUMPREG(HDMI_CON_1);
700 DUMPREG(HDMI_CON_2);
701 DUMPREG(HDMI_SYS_STATUS);
702 DUMPREG(HDMI_PHY_STATUS_0);
703 DUMPREG(HDMI_STATUS_EN);
704 DUMPREG(HDMI_HPD);
705 DUMPREG(HDMI_MODE_SEL);
706 DUMPREG(HDMI_ENC_EN);
707 DUMPREG(HDMI_DC_CONTROL);
708 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
709
710 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
711 DUMPREG(HDMI_H_BLANK_0);
712 DUMPREG(HDMI_H_BLANK_1);
713 DUMPREG(HDMI_V2_BLANK_0);
714 DUMPREG(HDMI_V2_BLANK_1);
715 DUMPREG(HDMI_V1_BLANK_0);
716 DUMPREG(HDMI_V1_BLANK_1);
717 DUMPREG(HDMI_V_LINE_0);
718 DUMPREG(HDMI_V_LINE_1);
719 DUMPREG(HDMI_H_LINE_0);
720 DUMPREG(HDMI_H_LINE_1);
721 DUMPREG(HDMI_HSYNC_POL);
722
723 DUMPREG(HDMI_VSYNC_POL);
724 DUMPREG(HDMI_INT_PRO_MODE);
725 DUMPREG(HDMI_V_BLANK_F0_0);
726 DUMPREG(HDMI_V_BLANK_F0_1);
727 DUMPREG(HDMI_V_BLANK_F1_0);
728 DUMPREG(HDMI_V_BLANK_F1_1);
729
730 DUMPREG(HDMI_H_SYNC_START_0);
731 DUMPREG(HDMI_H_SYNC_START_1);
732 DUMPREG(HDMI_H_SYNC_END_0);
733 DUMPREG(HDMI_H_SYNC_END_1);
734
735 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
736 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
737 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
738 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
739
740 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
741 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
742 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
743 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
744
745 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
746 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
747 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
748 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
749
750 DUMPREG(HDMI_V_BLANK_F2_0);
751 DUMPREG(HDMI_V_BLANK_F2_1);
752 DUMPREG(HDMI_V_BLANK_F3_0);
753 DUMPREG(HDMI_V_BLANK_F3_1);
754 DUMPREG(HDMI_V_BLANK_F4_0);
755 DUMPREG(HDMI_V_BLANK_F4_1);
756 DUMPREG(HDMI_V_BLANK_F5_0);
757 DUMPREG(HDMI_V_BLANK_F5_1);
758
759 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
760 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
767
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
774 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
775 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
776
777 DUMPREG(HDMI_VACT_SPACE_1_0);
778 DUMPREG(HDMI_VACT_SPACE_1_1);
779 DUMPREG(HDMI_VACT_SPACE_2_0);
780 DUMPREG(HDMI_VACT_SPACE_2_1);
781 DUMPREG(HDMI_VACT_SPACE_3_0);
782 DUMPREG(HDMI_VACT_SPACE_3_1);
783 DUMPREG(HDMI_VACT_SPACE_4_0);
784 DUMPREG(HDMI_VACT_SPACE_4_1);
785 DUMPREG(HDMI_VACT_SPACE_5_0);
786 DUMPREG(HDMI_VACT_SPACE_5_1);
787 DUMPREG(HDMI_VACT_SPACE_6_0);
788 DUMPREG(HDMI_VACT_SPACE_6_1);
789
790 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
791 DUMPREG(HDMI_TG_CMD);
792 DUMPREG(HDMI_TG_H_FSZ_L);
793 DUMPREG(HDMI_TG_H_FSZ_H);
794 DUMPREG(HDMI_TG_HACT_ST_L);
795 DUMPREG(HDMI_TG_HACT_ST_H);
796 DUMPREG(HDMI_TG_HACT_SZ_L);
797 DUMPREG(HDMI_TG_HACT_SZ_H);
798 DUMPREG(HDMI_TG_V_FSZ_L);
799 DUMPREG(HDMI_TG_V_FSZ_H);
800 DUMPREG(HDMI_TG_VSYNC_L);
801 DUMPREG(HDMI_TG_VSYNC_H);
802 DUMPREG(HDMI_TG_VSYNC2_L);
803 DUMPREG(HDMI_TG_VSYNC2_H);
804 DUMPREG(HDMI_TG_VACT_ST_L);
805 DUMPREG(HDMI_TG_VACT_ST_H);
806 DUMPREG(HDMI_TG_VACT_SZ_L);
807 DUMPREG(HDMI_TG_VACT_SZ_H);
808 DUMPREG(HDMI_TG_FIELD_CHG_L);
809 DUMPREG(HDMI_TG_FIELD_CHG_H);
810 DUMPREG(HDMI_TG_VACT_ST2_L);
811 DUMPREG(HDMI_TG_VACT_ST2_H);
812 DUMPREG(HDMI_TG_VACT_ST3_L);
813 DUMPREG(HDMI_TG_VACT_ST3_H);
814 DUMPREG(HDMI_TG_VACT_ST4_L);
815 DUMPREG(HDMI_TG_VACT_ST4_H);
816 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
817 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
818 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
819 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
820 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
821 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
822 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
823 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
824 DUMPREG(HDMI_TG_3D);
825
826 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
827 DUMPREG(HDMI_AVI_CON);
828 DUMPREG(HDMI_AVI_HEADER0);
829 DUMPREG(HDMI_AVI_HEADER1);
830 DUMPREG(HDMI_AVI_HEADER2);
831 DUMPREG(HDMI_AVI_CHECK_SUM);
832 DUMPREG(HDMI_VSI_CON);
833 DUMPREG(HDMI_VSI_HEADER0);
834 DUMPREG(HDMI_VSI_HEADER1);
835 DUMPREG(HDMI_VSI_HEADER2);
836 for (i = 0; i < 7; ++i)
837 DUMPREG(HDMI_VSI_DATA(i));
838
839#undef DUMPREG
840}
841
842static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
843{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200844 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900845 hdmi_v13_regs_dump(hdata, prefix);
846 else
847 hdmi_v14_regs_dump(hdata, prefix);
848}
849
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530850static u8 hdmi_chksum(struct hdmi_context *hdata,
851 u32 start, u8 len, u32 hdr_sum)
852{
853 int i;
854
855 /* hdr_sum : header0 + header1 + header2
856 * start : start address of packet byte1
857 * len : packet bytes - 1 */
858 for (i = 0; i < len; ++i)
859 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
860
861 /* return 2's complement of 8 bit hdr_sum */
862 return (u8)(~(hdr_sum & 0xff) + 1);
863}
864
865static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530866 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530867{
868 u32 hdr_sum;
869 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530870 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200871 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530872
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530873 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
874 if (hdata->dvi_mode) {
875 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
876 HDMI_VSI_CON_DO_NOT_TRANSMIT);
877 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
878 HDMI_AVI_CON_DO_NOT_TRANSMIT);
879 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
880 return;
881 }
882
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530883 switch (infoframe->any.type) {
884 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530885 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530886 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
887 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
888 infoframe->any.version);
889 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
890 hdr_sum = infoframe->any.type + infoframe->any.version +
891 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530892
893 /* Output format zero hardcoded ,RGB YBCR selection */
894 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
895 AVI_ACTIVE_FORMAT_VALID |
896 AVI_UNDERSCANNED_DISPLAY_VALID);
897
Shirish S46154152014-03-13 10:58:28 +0530898 /*
899 * Set the aspect ratio as per the mode, mentioned in
900 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
901 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200902 ar = hdata->current_mode.picture_aspect_ratio;
903 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530904 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200905 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530906 break;
907 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200908 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530909 break;
910 case HDMI_PICTURE_ASPECT_NONE:
911 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200912 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530913 break;
914 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200915 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530916
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200917 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530918
919 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530920 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530921 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
922 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
923 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530924 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530925 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530926 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
927 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
928 infoframe->any.version);
929 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
930 hdr_sum = infoframe->any.type + infoframe->any.version +
931 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530932 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530933 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530934 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
935 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
936 break;
937 default:
938 break;
939 }
940}
941
Sean Pauld9716ee2014-01-30 16:19:29 -0500942static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
943 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500944{
Sean Pauld9716ee2014-01-30 16:19:29 -0500945 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500946
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200947 if (gpio_get_value(hdata->hpd_gpio))
948 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530949
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200950 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500951}
952
Sean Pauld9716ee2014-01-30 16:19:29 -0500953static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900954{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200955 drm_connector_unregister(connector);
956 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900957}
958
Sean Pauld9716ee2014-01-30 16:19:29 -0500959static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300960 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500961 .fill_modes = drm_helper_probe_single_connector_modes,
962 .detect = hdmi_detect,
963 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300964 .reset = drm_atomic_helper_connector_reset,
965 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
966 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500967};
968
969static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970{
Sean Pauld9716ee2014-01-30 16:19:29 -0500971 struct hdmi_context *hdata = ctx_from_connector(connector);
972 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200973 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974
Inki Dae8fa04aa2014-03-13 16:38:31 +0900975 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500976 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977
Inki Dae8fa04aa2014-03-13 16:38:31 +0900978 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500979 if (!edid)
980 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900981
Sean Pauld9716ee2014-01-30 16:19:29 -0500982 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500983 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
984 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500985 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500986
Sean Pauld9716ee2014-01-30 16:19:29 -0500987 drm_mode_connector_update_edid_property(connector, edid);
988
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200989 ret = drm_add_edid_modes(connector, edid);
990
991 kfree(edid);
992
993 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994}
995
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900996static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900998 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001000 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1001 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001002 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001003
1004 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1005 return -EINVAL;
1006}
1007
Sean Pauld9716ee2014-01-30 16:19:29 -05001008static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001009 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001010{
Sean Pauld9716ee2014-01-30 16:19:29 -05001011 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001012 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001013
Rahul Sharma16844fb2013-06-10 14:50:00 +05301014 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1015 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1016 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1017 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001018
Sean Paulf041b252014-01-30 16:19:15 -05001019 ret = mixer_check_mode(mode);
1020 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001021 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001022
Rahul Sharma16844fb2013-06-10 14:50:00 +05301023 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001024 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001025 return MODE_BAD;
1026
1027 return MODE_OK;
1028}
1029
1030static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1031{
1032 struct hdmi_context *hdata = ctx_from_connector(connector);
1033
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001034 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001035}
1036
1037static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1038 .get_modes = hdmi_get_modes,
1039 .mode_valid = hdmi_mode_valid,
1040 .best_encoder = hdmi_best_encoder,
1041};
1042
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001043static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001044{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001045 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001046 struct drm_connector *connector = &hdata->connector;
1047 int ret;
1048
Sean Pauld9716ee2014-01-30 16:19:29 -05001049 connector->interlace_allowed = true;
1050 connector->polled = DRM_CONNECTOR_POLL_HPD;
1051
1052 ret = drm_connector_init(hdata->drm_dev, connector,
1053 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1054 if (ret) {
1055 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001056 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001057 }
1058
1059 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001060 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001061 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001062
1063 return 0;
1064}
1065
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001066static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1067 const struct drm_display_mode *mode,
1068 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001069{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001070 struct drm_device *dev = encoder->dev;
1071 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001072 struct drm_display_mode *m;
1073 int mode_ok;
1074
Sean Paulf041b252014-01-30 16:19:15 -05001075 drm_mode_set_crtcinfo(adjusted_mode, 0);
1076
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001077 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1078 if (connector->encoder == encoder)
1079 break;
1080 }
1081
1082 if (connector->encoder != encoder)
1083 return true;
1084
Sean Pauld9716ee2014-01-30 16:19:29 -05001085 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001086
1087 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001088 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001089 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001090
1091 /*
1092 * otherwise, find the most suitable mode among modes and change it
1093 * to adjusted_mode.
1094 */
1095 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001096 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001097
Sean Pauld9716ee2014-01-30 16:19:29 -05001098 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001099 DRM_INFO("desired mode doesn't exist so\n");
1100 DRM_INFO("use the most suitable mode among modes.\n");
1101
1102 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1103 m->hdisplay, m->vdisplay, m->vrefresh);
1104
Sean Paul75626852014-01-30 16:19:16 -05001105 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001106 break;
1107 }
1108 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001109
1110 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001111}
1112
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001113static void hdmi_set_acr(u32 freq, u8 *acr)
1114{
1115 u32 n, cts;
1116
1117 switch (freq) {
1118 case 32000:
1119 n = 4096;
1120 cts = 27000;
1121 break;
1122 case 44100:
1123 n = 6272;
1124 cts = 30000;
1125 break;
1126 case 88200:
1127 n = 12544;
1128 cts = 30000;
1129 break;
1130 case 176400:
1131 n = 25088;
1132 cts = 30000;
1133 break;
1134 case 48000:
1135 n = 6144;
1136 cts = 27000;
1137 break;
1138 case 96000:
1139 n = 12288;
1140 cts = 27000;
1141 break;
1142 case 192000:
1143 n = 24576;
1144 cts = 27000;
1145 break;
1146 default:
1147 n = 0;
1148 cts = 0;
1149 break;
1150 }
1151
1152 acr[1] = cts >> 16;
1153 acr[2] = cts >> 8 & 0xff;
1154 acr[3] = cts & 0xff;
1155
1156 acr[4] = n >> 16;
1157 acr[5] = n >> 8 & 0xff;
1158 acr[6] = n & 0xff;
1159}
1160
1161static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1162{
1163 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1164 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1165 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1166 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1167 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1168 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1169 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1170 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1171 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1172
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001173 if (hdata->drv_data->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001174 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1175 else
1176 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1177}
1178
1179static void hdmi_audio_init(struct hdmi_context *hdata)
1180{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301181 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001182 u32 data_num, bit_ch, sample_frq;
1183 u32 val;
1184 u8 acr[7];
1185
1186 sample_rate = 44100;
1187 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001188
1189 switch (bits_per_sample) {
1190 case 20:
1191 data_num = 2;
1192 bit_ch = 1;
1193 break;
1194 case 24:
1195 data_num = 3;
1196 bit_ch = 1;
1197 break;
1198 default:
1199 data_num = 1;
1200 bit_ch = 0;
1201 break;
1202 }
1203
1204 hdmi_set_acr(sample_rate, acr);
1205 hdmi_reg_acr(hdata, acr);
1206
1207 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1208 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1209 | HDMI_I2S_MUX_ENABLE);
1210
1211 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1212 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1213
1214 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1215
1216 sample_frq = (sample_rate == 44100) ? 0 :
1217 (sample_rate == 48000) ? 2 :
1218 (sample_rate == 32000) ? 3 :
1219 (sample_rate == 96000) ? 0xa : 0x0;
1220
1221 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1222 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1223
1224 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1225 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1226
1227 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1228 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1229 | HDMI_I2S_SEL_LRCK(6));
1230 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1231 | HDMI_I2S_SEL_SDATA2(4));
1232 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1233 | HDMI_I2S_SEL_SDATA2(2));
1234 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1235
1236 /* I2S_CON_1 & 2 */
1237 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1238 | HDMI_I2S_L_CH_LOW_POL);
1239 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1240 | HDMI_I2S_SET_BIT_CH(bit_ch)
1241 | HDMI_I2S_SET_SDATA_BIT(data_num)
1242 | HDMI_I2S_BASIC_FORMAT);
1243
1244 /* Configure register related to CUV information */
1245 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1246 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1247 | HDMI_I2S_COPYRIGHT
1248 | HDMI_I2S_LINEAR_PCM
1249 | HDMI_I2S_CONSUMER_FORMAT);
1250 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1251 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1252 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1253 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1254 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1255 HDMI_I2S_ORG_SMP_FREQ_44_1
1256 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1257 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1258
1259 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1260}
1261
1262static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1263{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001264 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001265 return;
1266
1267 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1268 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1269 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1270}
1271
Rahul Sharmabfa48422014-04-03 20:41:04 +05301272static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001273{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301274 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001275
Rahul Sharmabfa48422014-04-03 20:41:04 +05301276 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1277 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001278
Rahul Sharmabfa48422014-04-03 20:41:04 +05301279 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1280 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001281}
1282
1283static void hdmi_conf_init(struct hdmi_context *hdata)
1284{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301285 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301286
Sean Paul77006a72013-01-16 10:17:20 -05001287 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001288 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1289 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001290
1291 /* choose HDMI mode */
1292 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1293 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301294 /* Apply Video preable and Guard band in HDMI mode only */
1295 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001296 /* disable bluescreen */
1297 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001298
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001299 if (hdata->dvi_mode) {
1300 /* choose DVI mode */
1301 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1302 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1303 hdmi_reg_writeb(hdata, HDMI_CON_2,
1304 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1305 }
1306
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001307 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001308 /* choose bluescreen (fecal) color */
1309 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1310 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1311 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1312
1313 /* enable AVI packet every vsync, fixes purple line problem */
1314 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1315 /* force RGB, look to CEA-861-D, table 7 for more detail */
1316 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1317 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1318
1319 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1320 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1321 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1322 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301323 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1324 infoframe.any.version = HDMI_AVI_VERSION;
1325 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301326 hdmi_reg_infoframe(hdata, &infoframe);
1327
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301328 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1329 infoframe.any.version = HDMI_AUI_VERSION;
1330 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301331 hdmi_reg_infoframe(hdata, &infoframe);
1332
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001333 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001334 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1335 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001336}
1337
Rahul Sharma16844fb2013-06-10 14:50:00 +05301338static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001339{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001340 struct drm_display_mode *m = &hdata->current_mode;
1341 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001342 int tries;
1343
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001344 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1345 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1346 (m->htotal << 12) | m->vtotal);
1347
1348 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1349 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1350
1351 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1352 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1353
1354 val = (m->hsync_start - m->hdisplay - 2);
1355 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1356 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1357 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1358
1359 /*
1360 * Quirk requirement for exynos HDMI IP design,
1361 * 2 pixels less than the actual calculation for hsync_start
1362 * and end.
1363 */
1364
1365 /* Following values & calculations differ for different type of modes */
1366 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1367 /* Interlaced Mode */
1368 val = ((m->vsync_end - m->vdisplay) / 2);
1369 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1370 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1371
1372 val = m->vtotal / 2;
1373 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1374 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1375
1376 val = (m->vtotal +
1377 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1378 val |= m->vtotal << 11;
1379 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1380
1381 val = ((m->vtotal / 2) + 7);
1382 val |= ((m->vtotal / 2) + 2) << 12;
1383 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1384
1385 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1386 val |= ((m->htotal / 2) +
1387 (m->hsync_start - m->hdisplay)) << 12;
1388 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1389
1390 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1391 (m->vtotal - m->vdisplay) / 2);
1392 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1393
1394 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1395 } else {
1396 /* Progressive Mode */
1397
1398 val = m->vtotal;
1399 val |= (m->vtotal - m->vdisplay) << 11;
1400 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1401
1402 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1403
1404 val = (m->vsync_end - m->vdisplay);
1405 val |= ((m->vsync_start - m->vdisplay) << 12);
1406 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1407
1408 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1409 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1410 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1411 m->vtotal - m->vdisplay);
1412 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1413 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1414 }
1415
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001416 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001417 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1418 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1419 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1420 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1421 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1422 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1423 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1424 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1425 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1426 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1427 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001428
1429 /* waiting for HDMIPHY's PLL to get to steady state */
1430 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001431 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001432 if (val & HDMI_PHY_STATUS_READY)
1433 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001434 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001435 }
1436 /* steady state not achieved */
1437 if (tries == 0) {
1438 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1439 hdmi_regs_dump(hdata, "timing apply");
1440 }
1441
Sean Paul0bfb1f82013-06-11 12:24:02 +05301442 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301443 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301444 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001445
1446 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301447 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001448}
1449
Rahul Sharma16844fb2013-06-10 14:50:00 +05301450static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001451{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001452 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001453 int tries;
1454
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001455 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1456 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1457 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1458 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1459 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1460 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1461 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1462 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1463 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1464
1465 /*
1466 * Quirk requirement for exynos 5 HDMI IP design,
1467 * 2 pixels less than the actual calculation for hsync_start
1468 * and end.
1469 */
1470
1471 /* Following values & calculations differ for different type of modes */
1472 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1473 /* Interlaced Mode */
1474 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1475 (m->vsync_end - m->vdisplay) / 2);
1476 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1477 (m->vsync_start - m->vdisplay) / 2);
1478 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1479 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1480 (m->vtotal - m->vdisplay) / 2);
1481 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1482 m->vtotal - m->vdisplay / 2);
1483 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1484 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1485 (m->vtotal / 2) + 7);
1486 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1487 (m->vtotal / 2) + 2);
1488 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1489 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1490 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1491 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1492 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1493 (m->vtotal - m->vdisplay) / 2);
1494 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1495 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1496 m->vtotal - m->vdisplay / 2);
1497 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1498 (m->vtotal / 2) + 1);
1499 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1500 (m->vtotal / 2) + 1);
1501 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1502 (m->vtotal / 2) + 1);
1503 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1504 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1505 } else {
1506 /* Progressive Mode */
1507 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1508 m->vsync_end - m->vdisplay);
1509 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1510 m->vsync_start - m->vdisplay);
1511 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1512 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1513 m->vtotal - m->vdisplay);
1514 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1515 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1516 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1517 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1518 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1519 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1520 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1521 m->vtotal - m->vdisplay);
1522 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1523 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1524 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1525 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1526 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1527 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1528 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1529 }
1530
1531 /* Following values & calculations are same irrespective of mode type */
1532 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1533 m->hsync_start - m->hdisplay - 2);
1534 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1535 m->hsync_end - m->hdisplay - 2);
1536 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1538 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1539 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1540 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1541 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1542 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1543 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1544 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1546 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1547 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1548 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1549 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1550 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1551 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1552 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1553 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001554
1555 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001556 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1557 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1558 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1559 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1560 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1561 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1562 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1563 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1564 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001565
1566 /* waiting for HDMIPHY's PLL to get to steady state */
1567 for (tries = 100; tries; --tries) {
1568 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1569 if (val & HDMI_PHY_STATUS_READY)
1570 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001571 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001572 }
1573 /* steady state not achieved */
1574 if (tries == 0) {
1575 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1576 hdmi_regs_dump(hdata, "timing apply");
1577 }
1578
Sean Paul0bfb1f82013-06-11 12:24:02 +05301579 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301580 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301581 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001582
1583 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301584 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001585}
1586
Rahul Sharma16844fb2013-06-10 14:50:00 +05301587static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001588{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001589 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301590 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001591 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301592 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001593}
1594
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001595static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1596{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001597 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001598
Sean Paul0bfb1f82013-06-11 12:24:02 +05301599 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301600 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301601 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001602
1603 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001604 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1605 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001606
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001607 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001608 reg = HDMI_V13_PHY_RSTOUT;
1609 else
1610 reg = HDMI_PHY_RSTOUT;
1611
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001612 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001613 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001614 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001615 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001616 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001617}
1618
Rahul Sharmaa5562252012-11-28 11:30:25 +05301619static void hdmiphy_poweron(struct hdmi_context *hdata)
1620{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001621 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301622 return;
1623
1624 DRM_DEBUG_KMS("\n");
1625
1626 /* For PHY Mode Setting */
1627 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1628 HDMI_PHY_ENABLE_MODE_SET);
1629 /* Phy Power On */
1630 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1631 HDMI_PHY_POWER_ON);
1632 /* For PHY Mode Setting */
1633 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1634 HDMI_PHY_DISABLE_MODE_SET);
1635 /* PHY SW Reset */
1636 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301637}
1638
1639static void hdmiphy_poweroff(struct hdmi_context *hdata)
1640{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001641 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301642 return;
1643
1644 DRM_DEBUG_KMS("\n");
1645
1646 /* PHY SW Reset */
1647 hdmiphy_conf_reset(hdata);
1648 /* For PHY Mode Setting */
1649 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1650 HDMI_PHY_ENABLE_MODE_SET);
1651
1652 /* PHY Power Off */
1653 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1654 HDMI_PHY_POWER_OFF);
1655
1656 /* For PHY Mode Setting */
1657 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1658 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301659}
1660
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001661static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1662{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001663 int ret;
1664 int i;
1665
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001666 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001667 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001668 if (i < 0) {
1669 DRM_ERROR("failed to find hdmiphy conf\n");
1670 return;
1671 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001672
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001673 ret = hdmiphy_reg_write_buf(hdata, 0,
1674 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001675 if (ret) {
1676 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001677 return;
1678 }
1679
Sean Paul09760ea2013-01-14 17:03:20 -05001680 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001681
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001682 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1683 HDMI_PHY_DISABLE_MODE_SET);
1684 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001685 DRM_ERROR("failed to enable hdmiphy\n");
1686 return;
1687 }
1688
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001689}
1690
1691static void hdmi_conf_apply(struct hdmi_context *hdata)
1692{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001693 hdmiphy_conf_reset(hdata);
1694 hdmiphy_conf_apply(hdata);
1695
Rahul Sharmabfa48422014-04-03 20:41:04 +05301696 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001697 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001698
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001699 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001700
1701 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301702 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001703 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001704
1705 hdmi_regs_dump(hdata, "start");
1706}
1707
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001708static void hdmi_mode_set(struct drm_encoder *encoder,
1709 struct drm_display_mode *mode,
1710 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001711{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001712 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001713 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001714
YoungJun Chocbc4c332013-06-12 10:44:40 +09001715 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1716 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001717 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001718 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001719
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001720 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001721 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001722}
1723
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001724static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001725{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001726 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001727 struct hdmi_resources *res = &hdata->res;
1728
Andrzej Hajda882a0642015-07-09 16:28:08 +02001729 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001730 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001731
1732 hdata->powered = true;
1733
Sean Paulaf65c802014-01-30 16:19:27 -05001734 pm_runtime_get_sync(hdata->dev);
1735
Seung-Woo Kimad079452013-06-05 14:34:38 +09001736 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1737 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1738
Rahul Sharma049d34e2014-05-20 10:36:05 +05301739 /* set pmu hdmiphy control bit to enable hdmiphy */
1740 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1741 PMU_HDMI_PHY_ENABLE_BIT, 1);
1742
Sean Paul0bfb1f82013-06-11 12:24:02 +05301743 clk_prepare_enable(res->hdmi);
1744 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301745
1746 hdmiphy_poweron(hdata);
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001747 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001748}
1749
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001750static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001751{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001752 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001753 struct hdmi_resources *res = &hdata->res;
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001754 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001755 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001756
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001757 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001758 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001759
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001760 /*
1761 * The SFRs of VP and Mixer are updated by Vertical Sync of
1762 * Timing generator which is a part of HDMI so the sequence
1763 * to disable TV Subsystem should be as following,
1764 * VP -> Mixer -> HDMI
1765 *
1766 * Below codes will try to disable Mixer and VP(if used)
1767 * prior to disabling HDMI.
1768 */
1769 if (crtc)
1770 funcs = crtc->helper_private;
1771 if (funcs && funcs->disable)
1772 (*funcs->disable)(crtc);
1773
Rahul Sharmabfa48422014-04-03 20:41:04 +05301774 /* HDMI System Disable */
1775 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1776
Rahul Sharmaa5562252012-11-28 11:30:25 +05301777 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001778
Sean Paul724fd142014-05-09 15:05:10 +09001779 cancel_delayed_work(&hdata->hotplug_work);
1780
Sean Paul0bfb1f82013-06-11 12:24:02 +05301781 clk_disable_unprepare(res->sclk_hdmi);
1782 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301783
1784 /* reset pmu hdmiphy control bit to disable hdmiphy */
1785 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1786 PMU_HDMI_PHY_ENABLE_BIT, 0);
1787
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001788 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1789
Sean Paulaf65c802014-01-30 16:19:27 -05001790 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001791
1792 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001793}
1794
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001795static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001796 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001797 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001798 .enable = hdmi_enable,
1799 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001800};
1801
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001802static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1803 .destroy = drm_encoder_cleanup,
1804};
1805
Sean Paul724fd142014-05-09 15:05:10 +09001806static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001807{
Sean Paul724fd142014-05-09 15:05:10 +09001808 struct hdmi_context *hdata;
1809
1810 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001811
Sean Paul45517892014-01-30 16:19:05 -05001812 if (hdata->drm_dev)
1813 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001814}
1815
1816static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1817{
1818 struct hdmi_context *hdata = arg;
1819
1820 mod_delayed_work(system_wq, &hdata->hotplug_work,
1821 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001822
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001823 return IRQ_HANDLED;
1824}
1825
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001826static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001827{
1828 struct device *dev = hdata->dev;
1829 struct hdmi_resources *res = &hdata->res;
1830 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001831 "vdd",
1832 "vdd_osc",
1833 "vdd_pll",
1834 };
1835 int i, ret;
1836
1837 DRM_DEBUG_KMS("HDMI resource init\n");
1838
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001839 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301840 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301841 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001842 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001843 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001844 goto fail;
1845 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301846 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301847 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001848 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001849 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001850 goto fail;
1851 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301852 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301853 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001854 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001855 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001856 goto fail;
1857 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301858 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301859 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001860 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001861 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001862 goto fail;
1863 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301864 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1865 if (IS_ERR(res->mout_hdmi)) {
1866 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001867 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301868 goto fail;
1869 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001870
Rahul Sharma59956d32013-06-11 12:24:03 +05301871 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001872
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301873 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301874 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09001875 if (!res->regul_bulk) {
1876 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001877 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09001878 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001879 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1880 res->regul_bulk[i].supply = supply[i];
1881 res->regul_bulk[i].consumer = NULL;
1882 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301883 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001884 if (ret) {
1885 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001886 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001887 }
1888 res->regul_count = ARRAY_SIZE(supply);
1889
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001890 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
1891 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
1892 DRM_ERROR("failed to get hdmi-en regulator\n");
1893 return PTR_ERR(res->reg_hdmi_en);
1894 }
1895 if (!IS_ERR(res->reg_hdmi_en)) {
1896 ret = regulator_enable(res->reg_hdmi_en);
1897 if (ret) {
1898 DRM_ERROR("failed to enable hdmi-en regulator\n");
1899 return ret;
1900 }
1901 } else
1902 res->reg_hdmi_en = NULL;
1903
Inki Daedf5225b2014-05-29 18:28:02 +09001904 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001905fail:
1906 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001907 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001908}
1909
Rahul Sharma22c4f422012-10-04 20:48:55 +05301910static struct of_device_id hdmi_match_types[] = {
1911 {
1912 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001913 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301914 }, {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001915 .compatible = "samsung,exynos4210-hdmi",
1916 .data = &exynos4210_hdmi_driver_data,
1917 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301918 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001919 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301920 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301921 .compatible = "samsung,exynos5420-hdmi",
1922 .data = &exynos5420_hdmi_driver_data,
1923 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301924 /* end node */
1925 }
1926};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001927MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301928
Inki Daef37cd5e2014-05-09 14:25:20 +09001929static int hdmi_bind(struct device *dev, struct device *master, void *data)
1930{
1931 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001932 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001933 struct drm_encoder *encoder = &hdata->encoder;
1934 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001935
Inki Daef37cd5e2014-05-09 14:25:20 +09001936 hdata->drm_dev = drm_dev;
1937
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001938 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1939 EXYNOS_DISPLAY_TYPE_HDMI);
1940 if (pipe < 0)
1941 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001942
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001943 encoder->possible_crtcs = 1 << pipe;
1944
1945 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1946
1947 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1948 DRM_MODE_ENCODER_TMDS);
1949
1950 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1951
1952 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001953 if (ret) {
1954 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001955 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001956 return ret;
1957 }
1958
1959 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001960}
1961
1962static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1963{
Inki Daef37cd5e2014-05-09 14:25:20 +09001964}
1965
1966static const struct component_ops hdmi_component_ops = {
1967 .bind = hdmi_bind,
1968 .unbind = hdmi_unbind,
1969};
1970
Inki Daee2a562d2014-05-09 16:46:10 +09001971static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1972{
1973 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1974 struct device_node *np;
1975
1976 np = of_find_compatible_node(NULL, NULL, compatible_str);
1977 if (np)
1978 return of_get_next_parent(np);
1979
1980 return NULL;
1981}
1982
1983static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1984{
1985 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1986
1987 return of_find_compatible_node(NULL, NULL, compatible_str);
1988}
1989
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001990static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001991{
Inki Daef37cd5e2014-05-09 14:25:20 +09001992 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001993 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001995 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001996 struct resource *res;
1997 int ret;
1998
Andrzej Hajda930865f2014-11-17 09:54:20 +01001999 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2000 if (!hdata)
2001 return -ENOMEM;
2002
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002003 match = of_match_device(hdmi_match_types, dev);
2004 if (!match)
2005 return -ENODEV;
2006
2007 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002008
Andrzej Hajda930865f2014-11-17 09:54:20 +01002009 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002010
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002011 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002012 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2013 if (hdata->hpd_gpio < 0) {
2014 DRM_ERROR("cannot get hpd gpio property\n");
2015 return hdata->hpd_gpio;
2016 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002017
2018 ret = hdmi_resources_init(hdata);
2019 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302020 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002021 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002022 }
2023
2024 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002025 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002026 if (IS_ERR(hdata->regs)) {
2027 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002028 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002029 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002030
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002031 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302032 if (ret) {
2033 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002034 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302035 }
2036
Inki Daee2a562d2014-05-09 16:46:10 +09002037 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2038 if (ddc_node)
2039 goto out_get_ddc_adpt;
2040
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002041 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002042 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2043 if (!ddc_node) {
2044 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002045 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002046 }
Inki Daee2a562d2014-05-09 16:46:10 +09002047
2048out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002049 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2050 if (!hdata->ddc_adpt) {
2051 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002052 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002053 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054
Inki Daee2a562d2014-05-09 16:46:10 +09002055 phy_node = hdmi_legacy_phy_dt_binding(dev);
2056 if (phy_node)
2057 goto out_get_phy_port;
2058
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002059 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002060 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2061 if (!phy_node) {
2062 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2063 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002064 goto err_ddc;
2065 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002066
Inki Daee2a562d2014-05-09 16:46:10 +09002067out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002068 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002069 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2070 if (!hdata->regs_hdmiphy) {
2071 DRM_ERROR("failed to ioremap hdmi phy\n");
2072 ret = -ENOMEM;
2073 goto err_ddc;
2074 }
2075 } else {
2076 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2077 if (!hdata->hdmiphy_port) {
2078 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002079 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002080 goto err_ddc;
2081 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002082 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002083
Sean Paul77006a72013-01-16 10:17:20 -05002084 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2085 if (hdata->irq < 0) {
2086 DRM_ERROR("failed to get GPIO irq\n");
2087 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002088 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002089 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002090
Sean Paul724fd142014-05-09 15:05:10 +09002091 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2092
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002093 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002094 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002095 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002096 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002097 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002098 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002099 goto err_hdmiphy;
2100 }
2101
Rahul Sharma049d34e2014-05-20 10:36:05 +05302102 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2103 "samsung,syscon-phandle");
2104 if (IS_ERR(hdata->pmureg)) {
2105 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002106 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302107 goto err_hdmiphy;
2108 }
2109
Sean Paulaf65c802014-01-30 16:19:27 -05002110 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002111
Inki Daedf5225b2014-05-29 18:28:02 +09002112 ret = component_add(&pdev->dev, &hdmi_component_ops);
2113 if (ret)
2114 goto err_disable_pm_runtime;
2115
2116 return ret;
2117
2118err_disable_pm_runtime:
2119 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002120
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002121err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002122 if (hdata->hdmiphy_port)
2123 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002124err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002125 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002126
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002127 return ret;
2128}
2129
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002130static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002131{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002132 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133
Sean Paul724fd142014-05-09 15:05:10 +09002134 cancel_delayed_work_sync(&hdata->hotplug_work);
2135
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002136 if (hdata->res.reg_hdmi_en)
2137 regulator_disable(hdata->res.reg_hdmi_en);
2138
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002139 if (hdata->hdmiphy_port)
2140 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002141 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002142
Sean Paulaf65c802014-01-30 16:19:27 -05002143 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002144 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002145
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002146 return 0;
2147}
2148
2149struct platform_driver hdmi_driver = {
2150 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002151 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002152 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302153 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002154 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302155 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002156 },
2157};