blob: c25b892034321ee39696c864c4168e101a7eddd6 [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
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900510static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
511{
512 return readl(hdata->regs + reg_id);
513}
514
515static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
516 u32 reg_id, u8 value)
517{
518 writeb(value, hdata->regs + reg_id);
519}
520
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200521static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
522 int bytes, u32 val)
523{
524 while (--bytes >= 0) {
525 writeb(val & 0xff, hdata->regs + reg_id);
526 val >>= 8;
527 reg_id += 4;
528 }
529}
530
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900531static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
532 u32 reg_id, u32 value, u32 mask)
533{
534 u32 old = readl(hdata->regs + reg_id);
535 value = (value & mask) | (old & ~mask);
536 writel(value, hdata->regs + reg_id);
537}
538
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900539static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
540 u32 reg_offset, u8 value)
541{
542 if (hdata->hdmiphy_port) {
543 u8 buffer[2];
544 int ret;
545
546 buffer[0] = reg_offset;
547 buffer[1] = value;
548
549 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
550 if (ret == 2)
551 return 0;
552 return ret;
553 } else {
554 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
555 return 0;
556 }
557}
558
559static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
560 u32 reg_offset, const u8 *buf, u32 len)
561{
562 if ((reg_offset + len) > 32)
563 return -EINVAL;
564
565 if (hdata->hdmiphy_port) {
566 int ret;
567
568 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
569 if (ret == len)
570 return 0;
571 return ret;
572 } else {
573 int i;
574 for (i = 0; i < len; i++)
575 writeb(buf[i], hdata->regs_hdmiphy +
576 ((reg_offset + i)<<2));
577 return 0;
578 }
579}
580
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900581static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900582{
583#define DUMPREG(reg_id) \
584 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
585 readl(hdata->regs + reg_id))
586 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
587 DUMPREG(HDMI_INTC_FLAG);
588 DUMPREG(HDMI_INTC_CON);
589 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900590 DUMPREG(HDMI_V13_PHY_RSTOUT);
591 DUMPREG(HDMI_V13_PHY_VPLL);
592 DUMPREG(HDMI_V13_PHY_CMU);
593 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900594
595 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
596 DUMPREG(HDMI_CON_0);
597 DUMPREG(HDMI_CON_1);
598 DUMPREG(HDMI_CON_2);
599 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900600 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900601 DUMPREG(HDMI_STATUS_EN);
602 DUMPREG(HDMI_HPD);
603 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900604 DUMPREG(HDMI_V13_HPD_GEN);
605 DUMPREG(HDMI_V13_DC_CONTROL);
606 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900607
608 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
609 DUMPREG(HDMI_H_BLANK_0);
610 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900611 DUMPREG(HDMI_V13_V_BLANK_0);
612 DUMPREG(HDMI_V13_V_BLANK_1);
613 DUMPREG(HDMI_V13_V_BLANK_2);
614 DUMPREG(HDMI_V13_H_V_LINE_0);
615 DUMPREG(HDMI_V13_H_V_LINE_1);
616 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900617 DUMPREG(HDMI_VSYNC_POL);
618 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900619 DUMPREG(HDMI_V13_V_BLANK_F_0);
620 DUMPREG(HDMI_V13_V_BLANK_F_1);
621 DUMPREG(HDMI_V13_V_BLANK_F_2);
622 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
623 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
624 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
625 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
626 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
627 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
628 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
629 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
630 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
631 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
632 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
633 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900634
635 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
636 DUMPREG(HDMI_TG_CMD);
637 DUMPREG(HDMI_TG_H_FSZ_L);
638 DUMPREG(HDMI_TG_H_FSZ_H);
639 DUMPREG(HDMI_TG_HACT_ST_L);
640 DUMPREG(HDMI_TG_HACT_ST_H);
641 DUMPREG(HDMI_TG_HACT_SZ_L);
642 DUMPREG(HDMI_TG_HACT_SZ_H);
643 DUMPREG(HDMI_TG_V_FSZ_L);
644 DUMPREG(HDMI_TG_V_FSZ_H);
645 DUMPREG(HDMI_TG_VSYNC_L);
646 DUMPREG(HDMI_TG_VSYNC_H);
647 DUMPREG(HDMI_TG_VSYNC2_L);
648 DUMPREG(HDMI_TG_VSYNC2_H);
649 DUMPREG(HDMI_TG_VACT_ST_L);
650 DUMPREG(HDMI_TG_VACT_ST_H);
651 DUMPREG(HDMI_TG_VACT_SZ_L);
652 DUMPREG(HDMI_TG_VACT_SZ_H);
653 DUMPREG(HDMI_TG_FIELD_CHG_L);
654 DUMPREG(HDMI_TG_FIELD_CHG_H);
655 DUMPREG(HDMI_TG_VACT_ST2_L);
656 DUMPREG(HDMI_TG_VACT_ST2_H);
657 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
658 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
659 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
660 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
661 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
662 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
663 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
664 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
665#undef DUMPREG
666}
667
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900668static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
669{
670 int i;
671
672#define DUMPREG(reg_id) \
673 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
674 readl(hdata->regs + reg_id))
675
676 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
677 DUMPREG(HDMI_INTC_CON);
678 DUMPREG(HDMI_INTC_FLAG);
679 DUMPREG(HDMI_HPD_STATUS);
680 DUMPREG(HDMI_INTC_CON_1);
681 DUMPREG(HDMI_INTC_FLAG_1);
682 DUMPREG(HDMI_PHY_STATUS_0);
683 DUMPREG(HDMI_PHY_STATUS_PLL);
684 DUMPREG(HDMI_PHY_CON_0);
685 DUMPREG(HDMI_PHY_RSTOUT);
686 DUMPREG(HDMI_PHY_VPLL);
687 DUMPREG(HDMI_PHY_CMU);
688 DUMPREG(HDMI_CORE_RSTOUT);
689
690 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
691 DUMPREG(HDMI_CON_0);
692 DUMPREG(HDMI_CON_1);
693 DUMPREG(HDMI_CON_2);
694 DUMPREG(HDMI_SYS_STATUS);
695 DUMPREG(HDMI_PHY_STATUS_0);
696 DUMPREG(HDMI_STATUS_EN);
697 DUMPREG(HDMI_HPD);
698 DUMPREG(HDMI_MODE_SEL);
699 DUMPREG(HDMI_ENC_EN);
700 DUMPREG(HDMI_DC_CONTROL);
701 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
702
703 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
704 DUMPREG(HDMI_H_BLANK_0);
705 DUMPREG(HDMI_H_BLANK_1);
706 DUMPREG(HDMI_V2_BLANK_0);
707 DUMPREG(HDMI_V2_BLANK_1);
708 DUMPREG(HDMI_V1_BLANK_0);
709 DUMPREG(HDMI_V1_BLANK_1);
710 DUMPREG(HDMI_V_LINE_0);
711 DUMPREG(HDMI_V_LINE_1);
712 DUMPREG(HDMI_H_LINE_0);
713 DUMPREG(HDMI_H_LINE_1);
714 DUMPREG(HDMI_HSYNC_POL);
715
716 DUMPREG(HDMI_VSYNC_POL);
717 DUMPREG(HDMI_INT_PRO_MODE);
718 DUMPREG(HDMI_V_BLANK_F0_0);
719 DUMPREG(HDMI_V_BLANK_F0_1);
720 DUMPREG(HDMI_V_BLANK_F1_0);
721 DUMPREG(HDMI_V_BLANK_F1_1);
722
723 DUMPREG(HDMI_H_SYNC_START_0);
724 DUMPREG(HDMI_H_SYNC_START_1);
725 DUMPREG(HDMI_H_SYNC_END_0);
726 DUMPREG(HDMI_H_SYNC_END_1);
727
728 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
729 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
730 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
731 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
732
733 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
734 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
735 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
736 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
737
738 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
739 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
740 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
741 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
742
743 DUMPREG(HDMI_V_BLANK_F2_0);
744 DUMPREG(HDMI_V_BLANK_F2_1);
745 DUMPREG(HDMI_V_BLANK_F3_0);
746 DUMPREG(HDMI_V_BLANK_F3_1);
747 DUMPREG(HDMI_V_BLANK_F4_0);
748 DUMPREG(HDMI_V_BLANK_F4_1);
749 DUMPREG(HDMI_V_BLANK_F5_0);
750 DUMPREG(HDMI_V_BLANK_F5_1);
751
752 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
753 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
754 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
755 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
756 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
757 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
758 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
759 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
760
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
769
770 DUMPREG(HDMI_VACT_SPACE_1_0);
771 DUMPREG(HDMI_VACT_SPACE_1_1);
772 DUMPREG(HDMI_VACT_SPACE_2_0);
773 DUMPREG(HDMI_VACT_SPACE_2_1);
774 DUMPREG(HDMI_VACT_SPACE_3_0);
775 DUMPREG(HDMI_VACT_SPACE_3_1);
776 DUMPREG(HDMI_VACT_SPACE_4_0);
777 DUMPREG(HDMI_VACT_SPACE_4_1);
778 DUMPREG(HDMI_VACT_SPACE_5_0);
779 DUMPREG(HDMI_VACT_SPACE_5_1);
780 DUMPREG(HDMI_VACT_SPACE_6_0);
781 DUMPREG(HDMI_VACT_SPACE_6_1);
782
783 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
784 DUMPREG(HDMI_TG_CMD);
785 DUMPREG(HDMI_TG_H_FSZ_L);
786 DUMPREG(HDMI_TG_H_FSZ_H);
787 DUMPREG(HDMI_TG_HACT_ST_L);
788 DUMPREG(HDMI_TG_HACT_ST_H);
789 DUMPREG(HDMI_TG_HACT_SZ_L);
790 DUMPREG(HDMI_TG_HACT_SZ_H);
791 DUMPREG(HDMI_TG_V_FSZ_L);
792 DUMPREG(HDMI_TG_V_FSZ_H);
793 DUMPREG(HDMI_TG_VSYNC_L);
794 DUMPREG(HDMI_TG_VSYNC_H);
795 DUMPREG(HDMI_TG_VSYNC2_L);
796 DUMPREG(HDMI_TG_VSYNC2_H);
797 DUMPREG(HDMI_TG_VACT_ST_L);
798 DUMPREG(HDMI_TG_VACT_ST_H);
799 DUMPREG(HDMI_TG_VACT_SZ_L);
800 DUMPREG(HDMI_TG_VACT_SZ_H);
801 DUMPREG(HDMI_TG_FIELD_CHG_L);
802 DUMPREG(HDMI_TG_FIELD_CHG_H);
803 DUMPREG(HDMI_TG_VACT_ST2_L);
804 DUMPREG(HDMI_TG_VACT_ST2_H);
805 DUMPREG(HDMI_TG_VACT_ST3_L);
806 DUMPREG(HDMI_TG_VACT_ST3_H);
807 DUMPREG(HDMI_TG_VACT_ST4_L);
808 DUMPREG(HDMI_TG_VACT_ST4_H);
809 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
810 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
811 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
812 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
813 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
814 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
815 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
816 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
817 DUMPREG(HDMI_TG_3D);
818
819 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
820 DUMPREG(HDMI_AVI_CON);
821 DUMPREG(HDMI_AVI_HEADER0);
822 DUMPREG(HDMI_AVI_HEADER1);
823 DUMPREG(HDMI_AVI_HEADER2);
824 DUMPREG(HDMI_AVI_CHECK_SUM);
825 DUMPREG(HDMI_VSI_CON);
826 DUMPREG(HDMI_VSI_HEADER0);
827 DUMPREG(HDMI_VSI_HEADER1);
828 DUMPREG(HDMI_VSI_HEADER2);
829 for (i = 0; i < 7; ++i)
830 DUMPREG(HDMI_VSI_DATA(i));
831
832#undef DUMPREG
833}
834
835static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
836{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200837 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900838 hdmi_v13_regs_dump(hdata, prefix);
839 else
840 hdmi_v14_regs_dump(hdata, prefix);
841}
842
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530843static u8 hdmi_chksum(struct hdmi_context *hdata,
844 u32 start, u8 len, u32 hdr_sum)
845{
846 int i;
847
848 /* hdr_sum : header0 + header1 + header2
849 * start : start address of packet byte1
850 * len : packet bytes - 1 */
851 for (i = 0; i < len; ++i)
852 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
853
854 /* return 2's complement of 8 bit hdr_sum */
855 return (u8)(~(hdr_sum & 0xff) + 1);
856}
857
858static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530859 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530860{
861 u32 hdr_sum;
862 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530863 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200864 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530865
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530866 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
867 if (hdata->dvi_mode) {
868 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
869 HDMI_VSI_CON_DO_NOT_TRANSMIT);
870 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
871 HDMI_AVI_CON_DO_NOT_TRANSMIT);
872 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
873 return;
874 }
875
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530876 switch (infoframe->any.type) {
877 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530878 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530879 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
880 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
881 infoframe->any.version);
882 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
883 hdr_sum = infoframe->any.type + infoframe->any.version +
884 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530885
886 /* Output format zero hardcoded ,RGB YBCR selection */
887 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
888 AVI_ACTIVE_FORMAT_VALID |
889 AVI_UNDERSCANNED_DISPLAY_VALID);
890
Shirish S46154152014-03-13 10:58:28 +0530891 /*
892 * Set the aspect ratio as per the mode, mentioned in
893 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
894 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200895 ar = hdata->current_mode.picture_aspect_ratio;
896 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530897 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200898 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530899 break;
900 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200901 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530902 break;
903 case HDMI_PICTURE_ASPECT_NONE:
904 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200905 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530906 break;
907 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200908 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530909
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200910 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530911
912 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530913 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530914 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
915 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
916 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530917 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530918 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530919 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
920 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
921 infoframe->any.version);
922 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
923 hdr_sum = infoframe->any.type + infoframe->any.version +
924 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530925 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530926 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530927 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
928 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
929 break;
930 default:
931 break;
932 }
933}
934
Sean Pauld9716ee2014-01-30 16:19:29 -0500935static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
936 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500937{
Sean Pauld9716ee2014-01-30 16:19:29 -0500938 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500939
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200940 if (gpio_get_value(hdata->hpd_gpio))
941 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530942
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200943 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500944}
945
Sean Pauld9716ee2014-01-30 16:19:29 -0500946static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900947{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200948 drm_connector_unregister(connector);
949 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950}
951
Sean Pauld9716ee2014-01-30 16:19:29 -0500952static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300953 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500954 .fill_modes = drm_helper_probe_single_connector_modes,
955 .detect = hdmi_detect,
956 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300957 .reset = drm_atomic_helper_connector_reset,
958 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
959 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500960};
961
962static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900963{
Sean Pauld9716ee2014-01-30 16:19:29 -0500964 struct hdmi_context *hdata = ctx_from_connector(connector);
965 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200966 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900967
Inki Dae8fa04aa2014-03-13 16:38:31 +0900968 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500969 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970
Inki Dae8fa04aa2014-03-13 16:38:31 +0900971 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500972 if (!edid)
973 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974
Sean Pauld9716ee2014-01-30 16:19:29 -0500975 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500976 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
977 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500978 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500979
Sean Pauld9716ee2014-01-30 16:19:29 -0500980 drm_mode_connector_update_edid_property(connector, edid);
981
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200982 ret = drm_add_edid_modes(connector, edid);
983
984 kfree(edid);
985
986 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900987}
988
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900989static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900991 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900992
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200993 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
994 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500995 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500996
997 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
998 return -EINVAL;
999}
1000
Sean Pauld9716ee2014-01-30 16:19:29 -05001001static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001002 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001003{
Sean Pauld9716ee2014-01-30 16:19:29 -05001004 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001005 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001006
Rahul Sharma16844fb2013-06-10 14:50:00 +05301007 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1008 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1009 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1010 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001011
Sean Paulf041b252014-01-30 16:19:15 -05001012 ret = mixer_check_mode(mode);
1013 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001014 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001015
Rahul Sharma16844fb2013-06-10 14:50:00 +05301016 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001017 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001018 return MODE_BAD;
1019
1020 return MODE_OK;
1021}
1022
1023static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1024{
1025 struct hdmi_context *hdata = ctx_from_connector(connector);
1026
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001027 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001028}
1029
1030static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1031 .get_modes = hdmi_get_modes,
1032 .mode_valid = hdmi_mode_valid,
1033 .best_encoder = hdmi_best_encoder,
1034};
1035
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001036static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001037{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001038 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001039 struct drm_connector *connector = &hdata->connector;
1040 int ret;
1041
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 connector->interlace_allowed = true;
1043 connector->polled = DRM_CONNECTOR_POLL_HPD;
1044
1045 ret = drm_connector_init(hdata->drm_dev, connector,
1046 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1047 if (ret) {
1048 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001049 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001050 }
1051
1052 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001053 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001054 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001055
1056 return 0;
1057}
1058
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001059static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1060 const struct drm_display_mode *mode,
1061 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001062{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001063 struct drm_device *dev = encoder->dev;
1064 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001065 struct drm_display_mode *m;
1066 int mode_ok;
1067
Sean Paulf041b252014-01-30 16:19:15 -05001068 drm_mode_set_crtcinfo(adjusted_mode, 0);
1069
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001070 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1071 if (connector->encoder == encoder)
1072 break;
1073 }
1074
1075 if (connector->encoder != encoder)
1076 return true;
1077
Sean Pauld9716ee2014-01-30 16:19:29 -05001078 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001079
1080 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001081 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001082 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001083
1084 /*
1085 * otherwise, find the most suitable mode among modes and change it
1086 * to adjusted_mode.
1087 */
1088 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001089 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001090
Sean Pauld9716ee2014-01-30 16:19:29 -05001091 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001092 DRM_INFO("desired mode doesn't exist so\n");
1093 DRM_INFO("use the most suitable mode among modes.\n");
1094
1095 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1096 m->hdisplay, m->vdisplay, m->vrefresh);
1097
Sean Paul75626852014-01-30 16:19:16 -05001098 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001099 break;
1100 }
1101 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001102
1103 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001104}
1105
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001106static void hdmi_set_acr(u32 freq, u8 *acr)
1107{
1108 u32 n, cts;
1109
1110 switch (freq) {
1111 case 32000:
1112 n = 4096;
1113 cts = 27000;
1114 break;
1115 case 44100:
1116 n = 6272;
1117 cts = 30000;
1118 break;
1119 case 88200:
1120 n = 12544;
1121 cts = 30000;
1122 break;
1123 case 176400:
1124 n = 25088;
1125 cts = 30000;
1126 break;
1127 case 48000:
1128 n = 6144;
1129 cts = 27000;
1130 break;
1131 case 96000:
1132 n = 12288;
1133 cts = 27000;
1134 break;
1135 case 192000:
1136 n = 24576;
1137 cts = 27000;
1138 break;
1139 default:
1140 n = 0;
1141 cts = 0;
1142 break;
1143 }
1144
1145 acr[1] = cts >> 16;
1146 acr[2] = cts >> 8 & 0xff;
1147 acr[3] = cts & 0xff;
1148
1149 acr[4] = n >> 16;
1150 acr[5] = n >> 8 & 0xff;
1151 acr[6] = n & 0xff;
1152}
1153
1154static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1155{
1156 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1157 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1158 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1159 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1160 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1161 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1162 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1163 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1164 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1165
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001166 if (hdata->drv_data->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001167 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1168 else
1169 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1170}
1171
1172static void hdmi_audio_init(struct hdmi_context *hdata)
1173{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301174 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001175 u32 data_num, bit_ch, sample_frq;
1176 u32 val;
1177 u8 acr[7];
1178
1179 sample_rate = 44100;
1180 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001181
1182 switch (bits_per_sample) {
1183 case 20:
1184 data_num = 2;
1185 bit_ch = 1;
1186 break;
1187 case 24:
1188 data_num = 3;
1189 bit_ch = 1;
1190 break;
1191 default:
1192 data_num = 1;
1193 bit_ch = 0;
1194 break;
1195 }
1196
1197 hdmi_set_acr(sample_rate, acr);
1198 hdmi_reg_acr(hdata, acr);
1199
1200 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1201 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1202 | HDMI_I2S_MUX_ENABLE);
1203
1204 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1205 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1206
1207 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1208
1209 sample_frq = (sample_rate == 44100) ? 0 :
1210 (sample_rate == 48000) ? 2 :
1211 (sample_rate == 32000) ? 3 :
1212 (sample_rate == 96000) ? 0xa : 0x0;
1213
1214 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1215 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1216
1217 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1218 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1219
1220 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1221 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1222 | HDMI_I2S_SEL_LRCK(6));
1223 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1224 | HDMI_I2S_SEL_SDATA2(4));
1225 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1226 | HDMI_I2S_SEL_SDATA2(2));
1227 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1228
1229 /* I2S_CON_1 & 2 */
1230 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1231 | HDMI_I2S_L_CH_LOW_POL);
1232 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1233 | HDMI_I2S_SET_BIT_CH(bit_ch)
1234 | HDMI_I2S_SET_SDATA_BIT(data_num)
1235 | HDMI_I2S_BASIC_FORMAT);
1236
1237 /* Configure register related to CUV information */
1238 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1239 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1240 | HDMI_I2S_COPYRIGHT
1241 | HDMI_I2S_LINEAR_PCM
1242 | HDMI_I2S_CONSUMER_FORMAT);
1243 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1244 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1245 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1246 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1247 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1248 HDMI_I2S_ORG_SMP_FREQ_44_1
1249 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1250 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1251
1252 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1253}
1254
1255static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1256{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001257 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001258 return;
1259
1260 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1261 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1262 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1263}
1264
Rahul Sharmabfa48422014-04-03 20:41:04 +05301265static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001266{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301267 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001268
Rahul Sharmabfa48422014-04-03 20:41:04 +05301269 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1270 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001271
Rahul Sharmabfa48422014-04-03 20:41:04 +05301272 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1273 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001274}
1275
1276static void hdmi_conf_init(struct hdmi_context *hdata)
1277{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301278 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301279
Sean Paul77006a72013-01-16 10:17:20 -05001280 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001281 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1282 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001283
1284 /* choose HDMI mode */
1285 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1286 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301287 /* Apply Video preable and Guard band in HDMI mode only */
1288 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289 /* disable bluescreen */
1290 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001291
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001292 if (hdata->dvi_mode) {
1293 /* choose DVI mode */
1294 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1295 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1296 hdmi_reg_writeb(hdata, HDMI_CON_2,
1297 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1298 }
1299
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001300 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001301 /* choose bluescreen (fecal) color */
1302 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1303 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1304 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1305
1306 /* enable AVI packet every vsync, fixes purple line problem */
1307 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1308 /* force RGB, look to CEA-861-D, table 7 for more detail */
1309 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1310 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1311
1312 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1313 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1314 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1315 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301316 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1317 infoframe.any.version = HDMI_AVI_VERSION;
1318 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301319 hdmi_reg_infoframe(hdata, &infoframe);
1320
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301321 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1322 infoframe.any.version = HDMI_AUI_VERSION;
1323 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301324 hdmi_reg_infoframe(hdata, &infoframe);
1325
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001326 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001327 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1328 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001329}
1330
Rahul Sharma16844fb2013-06-10 14:50:00 +05301331static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001332{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001333 struct drm_display_mode *m = &hdata->current_mode;
1334 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001335 int tries;
1336
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001337 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1338 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1339 (m->htotal << 12) | m->vtotal);
1340
1341 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1342 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1343
1344 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1345 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1346
1347 val = (m->hsync_start - m->hdisplay - 2);
1348 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1349 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1350 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1351
1352 /*
1353 * Quirk requirement for exynos HDMI IP design,
1354 * 2 pixels less than the actual calculation for hsync_start
1355 * and end.
1356 */
1357
1358 /* Following values & calculations differ for different type of modes */
1359 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1360 /* Interlaced Mode */
1361 val = ((m->vsync_end - m->vdisplay) / 2);
1362 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1363 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1364
1365 val = m->vtotal / 2;
1366 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1367 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1368
1369 val = (m->vtotal +
1370 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1371 val |= m->vtotal << 11;
1372 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1373
1374 val = ((m->vtotal / 2) + 7);
1375 val |= ((m->vtotal / 2) + 2) << 12;
1376 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1377
1378 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1379 val |= ((m->htotal / 2) +
1380 (m->hsync_start - m->hdisplay)) << 12;
1381 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1382
1383 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1384 (m->vtotal - m->vdisplay) / 2);
1385 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1386
1387 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1388 } else {
1389 /* Progressive Mode */
1390
1391 val = m->vtotal;
1392 val |= (m->vtotal - m->vdisplay) << 11;
1393 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1394
1395 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1396
1397 val = (m->vsync_end - m->vdisplay);
1398 val |= ((m->vsync_start - m->vdisplay) << 12);
1399 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1400
1401 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1402 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1403 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1404 m->vtotal - m->vdisplay);
1405 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1406 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1407 }
1408
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001409 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001410 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1411 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1412 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1413 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1414 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1415 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1416 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1417 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1418 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1419 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1420 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001421
1422 /* waiting for HDMIPHY's PLL to get to steady state */
1423 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001424 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001425 if (val & HDMI_PHY_STATUS_READY)
1426 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001427 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001428 }
1429 /* steady state not achieved */
1430 if (tries == 0) {
1431 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1432 hdmi_regs_dump(hdata, "timing apply");
1433 }
1434
Sean Paul0bfb1f82013-06-11 12:24:02 +05301435 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301436 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301437 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001438
1439 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301440 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001441}
1442
Rahul Sharma16844fb2013-06-10 14:50:00 +05301443static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001444{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001445 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001446 int tries;
1447
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001448 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1449 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1450 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1451 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1452 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1453 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1454 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1455 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1456 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1457
1458 /*
1459 * Quirk requirement for exynos 5 HDMI IP design,
1460 * 2 pixels less than the actual calculation for hsync_start
1461 * and end.
1462 */
1463
1464 /* Following values & calculations differ for different type of modes */
1465 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1466 /* Interlaced Mode */
1467 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1468 (m->vsync_end - m->vdisplay) / 2);
1469 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1470 (m->vsync_start - m->vdisplay) / 2);
1471 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1472 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1473 (m->vtotal - m->vdisplay) / 2);
1474 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1475 m->vtotal - m->vdisplay / 2);
1476 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1477 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1478 (m->vtotal / 2) + 7);
1479 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1480 (m->vtotal / 2) + 2);
1481 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1482 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1483 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1484 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1485 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1486 (m->vtotal - m->vdisplay) / 2);
1487 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1488 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1489 m->vtotal - m->vdisplay / 2);
1490 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1491 (m->vtotal / 2) + 1);
1492 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1493 (m->vtotal / 2) + 1);
1494 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1495 (m->vtotal / 2) + 1);
1496 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1497 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1498 } else {
1499 /* Progressive Mode */
1500 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1501 m->vsync_end - m->vdisplay);
1502 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1503 m->vsync_start - m->vdisplay);
1504 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1505 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1506 m->vtotal - m->vdisplay);
1507 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1508 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1509 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1510 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1511 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1512 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1513 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1514 m->vtotal - m->vdisplay);
1515 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1516 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1517 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1518 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1519 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1520 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1521 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1522 }
1523
1524 /* Following values & calculations are same irrespective of mode type */
1525 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1526 m->hsync_start - m->hdisplay - 2);
1527 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1528 m->hsync_end - m->hdisplay - 2);
1529 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1530 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1538 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1539 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1540 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1541 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1542 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1543 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1544 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1546 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001547
1548 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001549 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1550 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1551 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1552 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1553 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1554 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1555 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1556 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1557 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001558
1559 /* waiting for HDMIPHY's PLL to get to steady state */
1560 for (tries = 100; tries; --tries) {
1561 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1562 if (val & HDMI_PHY_STATUS_READY)
1563 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001564 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001565 }
1566 /* steady state not achieved */
1567 if (tries == 0) {
1568 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1569 hdmi_regs_dump(hdata, "timing apply");
1570 }
1571
Sean Paul0bfb1f82013-06-11 12:24:02 +05301572 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301573 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301574 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001575
1576 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301577 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001578}
1579
Rahul Sharma16844fb2013-06-10 14:50:00 +05301580static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001581{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001582 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301583 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001584 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301585 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001586}
1587
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001588static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1589{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001590 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001591
Sean Paul0bfb1f82013-06-11 12:24:02 +05301592 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301593 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301594 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001595
1596 /* operation mode */
Joonyoung Shim265134a2015-01-12 14:35:16 +09001597 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1598 HDMI_PHY_ENABLE_MODE_SET);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001599
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001600 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001601 reg = HDMI_V13_PHY_RSTOUT;
1602 else
1603 reg = HDMI_PHY_RSTOUT;
1604
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001605 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001606 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001607 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001608 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001609 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001610}
1611
Rahul Sharmaa5562252012-11-28 11:30:25 +05301612static void hdmiphy_poweron(struct hdmi_context *hdata)
1613{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001614 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301615 return;
1616
1617 DRM_DEBUG_KMS("\n");
1618
1619 /* For PHY Mode Setting */
1620 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1621 HDMI_PHY_ENABLE_MODE_SET);
1622 /* Phy Power On */
1623 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1624 HDMI_PHY_POWER_ON);
1625 /* For PHY Mode Setting */
1626 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1627 HDMI_PHY_DISABLE_MODE_SET);
1628 /* PHY SW Reset */
1629 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301630}
1631
1632static void hdmiphy_poweroff(struct hdmi_context *hdata)
1633{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001634 if (hdata->drv_data->type != HDMI_TYPE14)
Shirish S6a296e22014-04-03 20:41:02 +05301635 return;
1636
1637 DRM_DEBUG_KMS("\n");
1638
1639 /* PHY SW Reset */
1640 hdmiphy_conf_reset(hdata);
1641 /* For PHY Mode Setting */
1642 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1643 HDMI_PHY_ENABLE_MODE_SET);
1644
1645 /* PHY Power Off */
1646 hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
1647 HDMI_PHY_POWER_OFF);
1648
1649 /* For PHY Mode Setting */
1650 hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1651 HDMI_PHY_DISABLE_MODE_SET);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301652}
1653
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001654static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1655{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001656 int ret;
1657 int i;
1658
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001659 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001660 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001661 if (i < 0) {
1662 DRM_ERROR("failed to find hdmiphy conf\n");
1663 return;
1664 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001665
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001666 ret = hdmiphy_reg_write_buf(hdata, 0,
1667 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001668 if (ret) {
1669 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001670 return;
1671 }
1672
Sean Paul09760ea2013-01-14 17:03:20 -05001673 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001674
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001675 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1676 HDMI_PHY_DISABLE_MODE_SET);
1677 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001678 DRM_ERROR("failed to enable hdmiphy\n");
1679 return;
1680 }
1681
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001682}
1683
1684static void hdmi_conf_apply(struct hdmi_context *hdata)
1685{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001686 hdmiphy_conf_reset(hdata);
1687 hdmiphy_conf_apply(hdata);
1688
Rahul Sharmabfa48422014-04-03 20:41:04 +05301689 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001690 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001691
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001692 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001693
1694 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301695 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001696 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001697
1698 hdmi_regs_dump(hdata, "start");
1699}
1700
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001701static void hdmi_mode_set(struct drm_encoder *encoder,
1702 struct drm_display_mode *mode,
1703 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001704{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001705 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001706 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001707
YoungJun Chocbc4c332013-06-12 10:44:40 +09001708 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1709 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001710 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001711 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001712
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001713 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001714 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001715}
1716
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001717static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001718{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001719 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001720 struct hdmi_resources *res = &hdata->res;
1721
Andrzej Hajda882a0642015-07-09 16:28:08 +02001722 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001723 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001724
1725 hdata->powered = true;
1726
Sean Paulaf65c802014-01-30 16:19:27 -05001727 pm_runtime_get_sync(hdata->dev);
1728
Seung-Woo Kimad079452013-06-05 14:34:38 +09001729 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1730 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1731
Rahul Sharma049d34e2014-05-20 10:36:05 +05301732 /* set pmu hdmiphy control bit to enable hdmiphy */
1733 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1734 PMU_HDMI_PHY_ENABLE_BIT, 1);
1735
Sean Paul0bfb1f82013-06-11 12:24:02 +05301736 clk_prepare_enable(res->hdmi);
1737 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301738
1739 hdmiphy_poweron(hdata);
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001740 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001741}
1742
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001743static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001744{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001745 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001746 struct hdmi_resources *res = &hdata->res;
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001747 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001748 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001749
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001750 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001751 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001752
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001753 /*
1754 * The SFRs of VP and Mixer are updated by Vertical Sync of
1755 * Timing generator which is a part of HDMI so the sequence
1756 * to disable TV Subsystem should be as following,
1757 * VP -> Mixer -> HDMI
1758 *
1759 * Below codes will try to disable Mixer and VP(if used)
1760 * prior to disabling HDMI.
1761 */
1762 if (crtc)
1763 funcs = crtc->helper_private;
1764 if (funcs && funcs->disable)
1765 (*funcs->disable)(crtc);
1766
Rahul Sharmabfa48422014-04-03 20:41:04 +05301767 /* HDMI System Disable */
1768 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1769
Rahul Sharmaa5562252012-11-28 11:30:25 +05301770 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001771
Sean Paul724fd142014-05-09 15:05:10 +09001772 cancel_delayed_work(&hdata->hotplug_work);
1773
Sean Paul0bfb1f82013-06-11 12:24:02 +05301774 clk_disable_unprepare(res->sclk_hdmi);
1775 clk_disable_unprepare(res->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301776
1777 /* reset pmu hdmiphy control bit to disable hdmiphy */
1778 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1779 PMU_HDMI_PHY_ENABLE_BIT, 0);
1780
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001781 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1782
Sean Paulaf65c802014-01-30 16:19:27 -05001783 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001784
1785 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001786}
1787
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001788static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001789 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001790 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001791 .enable = hdmi_enable,
1792 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001793};
1794
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001795static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1796 .destroy = drm_encoder_cleanup,
1797};
1798
Sean Paul724fd142014-05-09 15:05:10 +09001799static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001800{
Sean Paul724fd142014-05-09 15:05:10 +09001801 struct hdmi_context *hdata;
1802
1803 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001804
Sean Paul45517892014-01-30 16:19:05 -05001805 if (hdata->drm_dev)
1806 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001807}
1808
1809static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1810{
1811 struct hdmi_context *hdata = arg;
1812
1813 mod_delayed_work(system_wq, &hdata->hotplug_work,
1814 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001815
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001816 return IRQ_HANDLED;
1817}
1818
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001819static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001820{
1821 struct device *dev = hdata->dev;
1822 struct hdmi_resources *res = &hdata->res;
1823 static char *supply[] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001824 "vdd",
1825 "vdd_osc",
1826 "vdd_pll",
1827 };
1828 int i, ret;
1829
1830 DRM_DEBUG_KMS("HDMI resource init\n");
1831
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001832 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301833 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301834 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001835 DRM_ERROR("failed to get clock 'hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001836 ret = PTR_ERR(res->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001837 goto fail;
1838 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301839 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301840 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001841 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001842 ret = PTR_ERR(res->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001843 goto fail;
1844 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301845 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301846 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001847 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001848 ret = PTR_ERR(res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001849 goto fail;
1850 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301851 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301852 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001853 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001854 ret = PTR_ERR(res->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001855 goto fail;
1856 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301857 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1858 if (IS_ERR(res->mout_hdmi)) {
1859 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001860 ret = PTR_ERR(res->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301861 goto fail;
1862 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001863
Rahul Sharma59956d32013-06-11 12:24:03 +05301864 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001865
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301866 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301867 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Inki Daedf5225b2014-05-29 18:28:02 +09001868 if (!res->regul_bulk) {
1869 ret = -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001870 goto fail;
Inki Daedf5225b2014-05-29 18:28:02 +09001871 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001872 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1873 res->regul_bulk[i].supply = supply[i];
1874 res->regul_bulk[i].consumer = NULL;
1875 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301876 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001877 if (ret) {
1878 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001879 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001880 }
1881 res->regul_count = ARRAY_SIZE(supply);
1882
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001883 res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
1884 if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
1885 DRM_ERROR("failed to get hdmi-en regulator\n");
1886 return PTR_ERR(res->reg_hdmi_en);
1887 }
1888 if (!IS_ERR(res->reg_hdmi_en)) {
1889 ret = regulator_enable(res->reg_hdmi_en);
1890 if (ret) {
1891 DRM_ERROR("failed to enable hdmi-en regulator\n");
1892 return ret;
1893 }
1894 } else
1895 res->reg_hdmi_en = NULL;
1896
Inki Daedf5225b2014-05-29 18:28:02 +09001897 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001898fail:
1899 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001900 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001901}
1902
Rahul Sharma22c4f422012-10-04 20:48:55 +05301903static struct of_device_id hdmi_match_types[] = {
1904 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001905 .compatible = "samsung,exynos4210-hdmi",
1906 .data = &exynos4210_hdmi_driver_data,
1907 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301908 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001909 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301910 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301911 .compatible = "samsung,exynos5420-hdmi",
1912 .data = &exynos5420_hdmi_driver_data,
1913 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301914 /* end node */
1915 }
1916};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001917MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301918
Inki Daef37cd5e2014-05-09 14:25:20 +09001919static int hdmi_bind(struct device *dev, struct device *master, void *data)
1920{
1921 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001922 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001923 struct drm_encoder *encoder = &hdata->encoder;
1924 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001925
Inki Daef37cd5e2014-05-09 14:25:20 +09001926 hdata->drm_dev = drm_dev;
1927
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001928 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1929 EXYNOS_DISPLAY_TYPE_HDMI);
1930 if (pipe < 0)
1931 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001932
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001933 encoder->possible_crtcs = 1 << pipe;
1934
1935 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1936
1937 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1938 DRM_MODE_ENCODER_TMDS);
1939
1940 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1941
1942 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001943 if (ret) {
1944 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001945 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001946 return ret;
1947 }
1948
1949 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001950}
1951
1952static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1953{
Inki Daef37cd5e2014-05-09 14:25:20 +09001954}
1955
1956static const struct component_ops hdmi_component_ops = {
1957 .bind = hdmi_bind,
1958 .unbind = hdmi_unbind,
1959};
1960
Inki Daee2a562d2014-05-09 16:46:10 +09001961static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1962{
1963 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1964 struct device_node *np;
1965
1966 np = of_find_compatible_node(NULL, NULL, compatible_str);
1967 if (np)
1968 return of_get_next_parent(np);
1969
1970 return NULL;
1971}
1972
1973static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1974{
1975 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1976
1977 return of_find_compatible_node(NULL, NULL, compatible_str);
1978}
1979
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001980static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001981{
Inki Daef37cd5e2014-05-09 14:25:20 +09001982 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001983 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001985 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001986 struct resource *res;
1987 int ret;
1988
Andrzej Hajda930865f2014-11-17 09:54:20 +01001989 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1990 if (!hdata)
1991 return -ENOMEM;
1992
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001993 match = of_match_device(hdmi_match_types, dev);
1994 if (!match)
1995 return -ENODEV;
1996
1997 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001998
Andrzej Hajda930865f2014-11-17 09:54:20 +01001999 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002000
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002001 hdata->dev = dev;
Andrzej Hajdad36b3002015-07-09 16:28:06 +02002002 hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
2003 if (hdata->hpd_gpio < 0) {
2004 DRM_ERROR("cannot get hpd gpio property\n");
2005 return hdata->hpd_gpio;
2006 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002007
2008 ret = hdmi_resources_init(hdata);
2009 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302010 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002011 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002012 }
2013
2014 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002015 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002016 if (IS_ERR(hdata->regs)) {
2017 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002018 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002019 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002021 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302022 if (ret) {
2023 DRM_ERROR("failed to request HPD gpio\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002024 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302025 }
2026
Inki Daee2a562d2014-05-09 16:46:10 +09002027 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2028 if (ddc_node)
2029 goto out_get_ddc_adpt;
2030
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002031 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002032 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2033 if (!ddc_node) {
2034 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002035 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002036 }
Inki Daee2a562d2014-05-09 16:46:10 +09002037
2038out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002039 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2040 if (!hdata->ddc_adpt) {
2041 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002042 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002043 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002044
Inki Daee2a562d2014-05-09 16:46:10 +09002045 phy_node = hdmi_legacy_phy_dt_binding(dev);
2046 if (phy_node)
2047 goto out_get_phy_port;
2048
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002049 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002050 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2051 if (!phy_node) {
2052 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2053 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054 goto err_ddc;
2055 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002056
Inki Daee2a562d2014-05-09 16:46:10 +09002057out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002058 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002059 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2060 if (!hdata->regs_hdmiphy) {
2061 DRM_ERROR("failed to ioremap hdmi phy\n");
2062 ret = -ENOMEM;
2063 goto err_ddc;
2064 }
2065 } else {
2066 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2067 if (!hdata->hdmiphy_port) {
2068 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002069 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002070 goto err_ddc;
2071 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002072 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002073
Sean Paul77006a72013-01-16 10:17:20 -05002074 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2075 if (hdata->irq < 0) {
2076 DRM_ERROR("failed to get GPIO irq\n");
2077 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002078 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002079 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002080
Sean Paul724fd142014-05-09 15:05:10 +09002081 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2082
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002083 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002084 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002085 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002086 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002087 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002088 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002089 goto err_hdmiphy;
2090 }
2091
Rahul Sharma049d34e2014-05-20 10:36:05 +05302092 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2093 "samsung,syscon-phandle");
2094 if (IS_ERR(hdata->pmureg)) {
2095 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002096 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302097 goto err_hdmiphy;
2098 }
2099
Sean Paulaf65c802014-01-30 16:19:27 -05002100 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002101
Inki Daedf5225b2014-05-29 18:28:02 +09002102 ret = component_add(&pdev->dev, &hdmi_component_ops);
2103 if (ret)
2104 goto err_disable_pm_runtime;
2105
2106 return ret;
2107
2108err_disable_pm_runtime:
2109 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002110
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002111err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002112 if (hdata->hdmiphy_port)
2113 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002114err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002115 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002116
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002117 return ret;
2118}
2119
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002120static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002121{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002122 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002123
Sean Paul724fd142014-05-09 15:05:10 +09002124 cancel_delayed_work_sync(&hdata->hotplug_work);
2125
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002126 if (hdata->res.reg_hdmi_en)
2127 regulator_disable(hdata->res.reg_hdmi_en);
2128
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002129 if (hdata->hdmiphy_port)
2130 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002131 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002132
Sean Paulaf65c802014-01-30 16:19:27 -05002133 pm_runtime_disable(&pdev->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002134 component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002135
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002136 return 0;
2137}
2138
2139struct platform_driver hdmi_driver = {
2140 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002141 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002142 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302143 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002144 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302145 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002146 },
2147};