blob: 57b675563e943120a5b47a8d05b9b50260c13e02 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
Andrzej Hajda2228b7c2015-09-25 14:48:24 +020033#include <linux/gpio/consumer.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020037#include <linux/of_device.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090047
Sean Paul724fd142014-05-09 15:05:10 +090048#define HOTPLUG_DEBOUNCE_MS 1100
49
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053050/* AVI header and aspect ratio */
51#define HDMI_AVI_VERSION 0x02
52#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053
54/* AUI header info */
55#define HDMI_AUI_VERSION 0x01
56#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053057#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
58#define AVI_4_3_CENTER_RATIO 0x9
59#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053060
Rahul Sharma5a325072012-10-04 20:48:54 +053061enum hdmi_type {
62 HDMI_TYPE13,
63 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020064 HDMI_TYPE_COUNT
65};
66
67#define HDMI_MAPPED_BASE 0xffff0000
68
69enum hdmi_mapped_regs {
70 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
71 HDMI_PHY_RSTOUT,
72 HDMI_ACR_CON,
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020073 HDMI_ACR_MCTS0,
74 HDMI_ACR_CTS0,
75 HDMI_ACR_N0
Andrzej Hajda633d00b2015-09-25 14:48:16 +020076};
77
78static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
79 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
80 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
81 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020082 { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
83 { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
84 { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
Rahul Sharma5a325072012-10-04 20:48:54 +053085};
86
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020087static const char * const supply[] = {
88 "vdd",
89 "vdd_osc",
90 "vdd_pll",
91};
92
Inki Daebfe4e842014-03-06 14:18:17 +090093struct hdmi_driver_data {
94 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090095 const struct hdmiphy_config *phy_confs;
96 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090097 unsigned int is_apb_phy:1;
98};
99
Joonyoung Shim590f4182012-03-16 18:47:14 +0900100struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300101 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900102 struct device *dev;
103 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500104 struct drm_connector connector;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900105 bool powered;
Seung-Woo Kim872d20d2012-04-24 17:39:15 +0900106 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900107 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530108 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200109 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200110 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900111
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200112 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900113 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200114 struct i2c_client *hdmiphy_port;
115 struct i2c_adapter *ddc_adpt;
116 struct gpio_desc *hpd_gpio;
117 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530118 struct regmap *pmureg;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200119 struct clk *hdmi;
120 struct clk *sclk_hdmi;
121 struct clk *sclk_pixel;
122 struct clk *sclk_hdmiphy;
123 struct clk *mout_hdmi;
124 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
125 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900126};
127
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300128static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100129{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900130 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100131}
132
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200133static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
134{
135 return container_of(c, struct hdmi_context, connector);
136}
137
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500138struct hdmiphy_config {
139 int pixel_clock;
140 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900141};
142
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900143/* list of phy config settings */
144static const struct hdmiphy_config hdmiphy_v13_configs[] = {
145 {
146 .pixel_clock = 27000000,
147 .conf = {
148 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
149 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
150 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200151 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900152 },
153 },
154 {
155 .pixel_clock = 27027000,
156 .conf = {
157 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
158 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
159 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200160 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900161 },
162 },
163 {
164 .pixel_clock = 74176000,
165 .conf = {
166 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
167 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
168 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200169 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900170 },
171 },
172 {
173 .pixel_clock = 74250000,
174 .conf = {
175 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
176 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
177 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200178 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900179 },
180 },
181 {
182 .pixel_clock = 148500000,
183 .conf = {
184 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
185 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
186 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200187 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900188 },
189 },
190};
191
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500192static const struct hdmiphy_config hdmiphy_v14_configs[] = {
193 {
194 .pixel_clock = 25200000,
195 .conf = {
196 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
197 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
198 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
199 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
200 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900201 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500202 {
203 .pixel_clock = 27000000,
204 .conf = {
205 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
206 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
207 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
208 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
209 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900210 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500211 {
212 .pixel_clock = 27027000,
213 .conf = {
214 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
215 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
216 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200217 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500218 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900219 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500220 {
221 .pixel_clock = 36000000,
222 .conf = {
223 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
224 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
225 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
226 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
227 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900228 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500229 {
230 .pixel_clock = 40000000,
231 .conf = {
232 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
233 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
234 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
235 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
236 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900237 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500238 {
239 .pixel_clock = 65000000,
240 .conf = {
241 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
242 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
243 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
244 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
245 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900246 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500247 {
Shirish Se1d883c2014-03-13 14:28:27 +0900248 .pixel_clock = 71000000,
249 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530250 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
251 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
252 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900253 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
254 },
255 },
256 {
257 .pixel_clock = 73250000,
258 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530259 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
260 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
261 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900262 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
263 },
264 },
265 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500266 .pixel_clock = 74176000,
267 .conf = {
268 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
269 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
270 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
271 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
272 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900273 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500274 {
275 .pixel_clock = 74250000,
276 .conf = {
277 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
278 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
279 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200280 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500281 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900282 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500283 {
284 .pixel_clock = 83500000,
285 .conf = {
286 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
287 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
288 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
289 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
290 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900291 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500292 {
293 .pixel_clock = 106500000,
294 .conf = {
295 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
296 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
297 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
298 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
299 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900300 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500301 {
302 .pixel_clock = 108000000,
303 .conf = {
304 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
305 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
306 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
307 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
308 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900309 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500310 {
Shirish Se1d883c2014-03-13 14:28:27 +0900311 .pixel_clock = 115500000,
312 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530313 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
314 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
315 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900316 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
317 },
318 },
319 {
320 .pixel_clock = 119000000,
321 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530322 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
323 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
324 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900325 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
326 },
327 },
328 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500329 .pixel_clock = 146250000,
330 .conf = {
331 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
332 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
333 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
334 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
335 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900336 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500337 {
338 .pixel_clock = 148500000,
339 .conf = {
340 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
341 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
342 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200343 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500344 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900345 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900346};
347
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530348static const struct hdmiphy_config hdmiphy_5420_configs[] = {
349 {
350 .pixel_clock = 25200000,
351 .conf = {
352 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
353 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
354 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
355 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
356 },
357 },
358 {
359 .pixel_clock = 27000000,
360 .conf = {
361 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
362 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
363 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
364 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
365 },
366 },
367 {
368 .pixel_clock = 27027000,
369 .conf = {
370 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
371 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
372 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
373 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
374 },
375 },
376 {
377 .pixel_clock = 36000000,
378 .conf = {
379 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
380 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
381 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
382 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
383 },
384 },
385 {
386 .pixel_clock = 40000000,
387 .conf = {
388 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
389 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
390 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
391 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
392 },
393 },
394 {
395 .pixel_clock = 65000000,
396 .conf = {
397 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
398 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
399 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
400 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
401 },
402 },
403 {
404 .pixel_clock = 71000000,
405 .conf = {
406 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
407 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
408 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
409 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
410 },
411 },
412 {
413 .pixel_clock = 73250000,
414 .conf = {
415 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
416 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
417 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
418 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
419 },
420 },
421 {
422 .pixel_clock = 74176000,
423 .conf = {
424 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
425 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
426 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
427 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
428 },
429 },
430 {
431 .pixel_clock = 74250000,
432 .conf = {
433 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
434 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
435 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
436 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
437 },
438 },
439 {
440 .pixel_clock = 83500000,
441 .conf = {
442 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
443 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
444 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
445 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
446 },
447 },
448 {
449 .pixel_clock = 88750000,
450 .conf = {
451 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
452 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
453 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
454 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
455 },
456 },
457 {
458 .pixel_clock = 106500000,
459 .conf = {
460 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
461 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
462 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
463 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
464 },
465 },
466 {
467 .pixel_clock = 108000000,
468 .conf = {
469 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
470 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
471 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
472 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
473 },
474 },
475 {
476 .pixel_clock = 115500000,
477 .conf = {
478 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
479 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
480 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
481 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
482 },
483 },
484 {
485 .pixel_clock = 146250000,
486 .conf = {
487 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
488 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
489 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
490 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
491 },
492 },
493 {
494 .pixel_clock = 148500000,
495 .conf = {
496 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
497 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
498 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
499 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
500 },
501 },
502};
503
Sachin Kamat16337072014-05-22 10:32:56 +0530504static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530505 .type = HDMI_TYPE14,
506 .phy_confs = hdmiphy_5420_configs,
507 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
508 .is_apb_phy = 1,
509};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900510
Sachin Kamat16337072014-05-22 10:32:56 +0530511static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900512 .type = HDMI_TYPE14,
513 .phy_confs = hdmiphy_v14_configs,
514 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
515 .is_apb_phy = 0,
516};
517
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200518static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
519 .type = HDMI_TYPE13,
520 .phy_confs = hdmiphy_v13_configs,
521 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
522 .is_apb_phy = 0,
523};
524
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200525static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
526{
527 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
528 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
529 return reg_id;
530}
531
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900532static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
533{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200534 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900535}
536
537static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
538 u32 reg_id, u8 value)
539{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200540 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900541}
542
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200543static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
544 int bytes, u32 val)
545{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200546 reg_id = hdmi_map_reg(hdata, reg_id);
547
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200548 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200549 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200550 val >>= 8;
551 reg_id += 4;
552 }
553}
554
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900555static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
556 u32 reg_id, u32 value, u32 mask)
557{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200558 u32 old;
559
560 reg_id = hdmi_map_reg(hdata, reg_id);
561 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900562 value = (value & mask) | (old & ~mask);
563 writel(value, hdata->regs + reg_id);
564}
565
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900566static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
567 u32 reg_offset, const u8 *buf, u32 len)
568{
569 if ((reg_offset + len) > 32)
570 return -EINVAL;
571
572 if (hdata->hdmiphy_port) {
573 int ret;
574
575 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
576 if (ret == len)
577 return 0;
578 return ret;
579 } else {
580 int i;
581 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200582 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900583 ((reg_offset + i)<<2));
584 return 0;
585 }
586}
587
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900588static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900589{
590#define DUMPREG(reg_id) \
591 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
592 readl(hdata->regs + reg_id))
593 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
594 DUMPREG(HDMI_INTC_FLAG);
595 DUMPREG(HDMI_INTC_CON);
596 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900597 DUMPREG(HDMI_V13_PHY_RSTOUT);
598 DUMPREG(HDMI_V13_PHY_VPLL);
599 DUMPREG(HDMI_V13_PHY_CMU);
600 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900601
602 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
603 DUMPREG(HDMI_CON_0);
604 DUMPREG(HDMI_CON_1);
605 DUMPREG(HDMI_CON_2);
606 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900607 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900608 DUMPREG(HDMI_STATUS_EN);
609 DUMPREG(HDMI_HPD);
610 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900611 DUMPREG(HDMI_V13_HPD_GEN);
612 DUMPREG(HDMI_V13_DC_CONTROL);
613 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614
615 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
616 DUMPREG(HDMI_H_BLANK_0);
617 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900618 DUMPREG(HDMI_V13_V_BLANK_0);
619 DUMPREG(HDMI_V13_V_BLANK_1);
620 DUMPREG(HDMI_V13_V_BLANK_2);
621 DUMPREG(HDMI_V13_H_V_LINE_0);
622 DUMPREG(HDMI_V13_H_V_LINE_1);
623 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900624 DUMPREG(HDMI_VSYNC_POL);
625 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900626 DUMPREG(HDMI_V13_V_BLANK_F_0);
627 DUMPREG(HDMI_V13_V_BLANK_F_1);
628 DUMPREG(HDMI_V13_V_BLANK_F_2);
629 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
630 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
631 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
632 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
633 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
634 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
635 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
636 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
637 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
638 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
639 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
640 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900641
642 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
643 DUMPREG(HDMI_TG_CMD);
644 DUMPREG(HDMI_TG_H_FSZ_L);
645 DUMPREG(HDMI_TG_H_FSZ_H);
646 DUMPREG(HDMI_TG_HACT_ST_L);
647 DUMPREG(HDMI_TG_HACT_ST_H);
648 DUMPREG(HDMI_TG_HACT_SZ_L);
649 DUMPREG(HDMI_TG_HACT_SZ_H);
650 DUMPREG(HDMI_TG_V_FSZ_L);
651 DUMPREG(HDMI_TG_V_FSZ_H);
652 DUMPREG(HDMI_TG_VSYNC_L);
653 DUMPREG(HDMI_TG_VSYNC_H);
654 DUMPREG(HDMI_TG_VSYNC2_L);
655 DUMPREG(HDMI_TG_VSYNC2_H);
656 DUMPREG(HDMI_TG_VACT_ST_L);
657 DUMPREG(HDMI_TG_VACT_ST_H);
658 DUMPREG(HDMI_TG_VACT_SZ_L);
659 DUMPREG(HDMI_TG_VACT_SZ_H);
660 DUMPREG(HDMI_TG_FIELD_CHG_L);
661 DUMPREG(HDMI_TG_FIELD_CHG_H);
662 DUMPREG(HDMI_TG_VACT_ST2_L);
663 DUMPREG(HDMI_TG_VACT_ST2_H);
664 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
665 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
666 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
667 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
668 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
669 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
670 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
671 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
672#undef DUMPREG
673}
674
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900675static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
676{
677 int i;
678
679#define DUMPREG(reg_id) \
680 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
681 readl(hdata->regs + reg_id))
682
683 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
684 DUMPREG(HDMI_INTC_CON);
685 DUMPREG(HDMI_INTC_FLAG);
686 DUMPREG(HDMI_HPD_STATUS);
687 DUMPREG(HDMI_INTC_CON_1);
688 DUMPREG(HDMI_INTC_FLAG_1);
689 DUMPREG(HDMI_PHY_STATUS_0);
690 DUMPREG(HDMI_PHY_STATUS_PLL);
691 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200692 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900693 DUMPREG(HDMI_PHY_VPLL);
694 DUMPREG(HDMI_PHY_CMU);
695 DUMPREG(HDMI_CORE_RSTOUT);
696
697 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
698 DUMPREG(HDMI_CON_0);
699 DUMPREG(HDMI_CON_1);
700 DUMPREG(HDMI_CON_2);
701 DUMPREG(HDMI_SYS_STATUS);
702 DUMPREG(HDMI_PHY_STATUS_0);
703 DUMPREG(HDMI_STATUS_EN);
704 DUMPREG(HDMI_HPD);
705 DUMPREG(HDMI_MODE_SEL);
706 DUMPREG(HDMI_ENC_EN);
707 DUMPREG(HDMI_DC_CONTROL);
708 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
709
710 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
711 DUMPREG(HDMI_H_BLANK_0);
712 DUMPREG(HDMI_H_BLANK_1);
713 DUMPREG(HDMI_V2_BLANK_0);
714 DUMPREG(HDMI_V2_BLANK_1);
715 DUMPREG(HDMI_V1_BLANK_0);
716 DUMPREG(HDMI_V1_BLANK_1);
717 DUMPREG(HDMI_V_LINE_0);
718 DUMPREG(HDMI_V_LINE_1);
719 DUMPREG(HDMI_H_LINE_0);
720 DUMPREG(HDMI_H_LINE_1);
721 DUMPREG(HDMI_HSYNC_POL);
722
723 DUMPREG(HDMI_VSYNC_POL);
724 DUMPREG(HDMI_INT_PRO_MODE);
725 DUMPREG(HDMI_V_BLANK_F0_0);
726 DUMPREG(HDMI_V_BLANK_F0_1);
727 DUMPREG(HDMI_V_BLANK_F1_0);
728 DUMPREG(HDMI_V_BLANK_F1_1);
729
730 DUMPREG(HDMI_H_SYNC_START_0);
731 DUMPREG(HDMI_H_SYNC_START_1);
732 DUMPREG(HDMI_H_SYNC_END_0);
733 DUMPREG(HDMI_H_SYNC_END_1);
734
735 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
736 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
737 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
738 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
739
740 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
741 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
742 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
743 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
744
745 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
746 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
747 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
748 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
749
750 DUMPREG(HDMI_V_BLANK_F2_0);
751 DUMPREG(HDMI_V_BLANK_F2_1);
752 DUMPREG(HDMI_V_BLANK_F3_0);
753 DUMPREG(HDMI_V_BLANK_F3_1);
754 DUMPREG(HDMI_V_BLANK_F4_0);
755 DUMPREG(HDMI_V_BLANK_F4_1);
756 DUMPREG(HDMI_V_BLANK_F5_0);
757 DUMPREG(HDMI_V_BLANK_F5_1);
758
759 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
760 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
767
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
774 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
775 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
776
777 DUMPREG(HDMI_VACT_SPACE_1_0);
778 DUMPREG(HDMI_VACT_SPACE_1_1);
779 DUMPREG(HDMI_VACT_SPACE_2_0);
780 DUMPREG(HDMI_VACT_SPACE_2_1);
781 DUMPREG(HDMI_VACT_SPACE_3_0);
782 DUMPREG(HDMI_VACT_SPACE_3_1);
783 DUMPREG(HDMI_VACT_SPACE_4_0);
784 DUMPREG(HDMI_VACT_SPACE_4_1);
785 DUMPREG(HDMI_VACT_SPACE_5_0);
786 DUMPREG(HDMI_VACT_SPACE_5_1);
787 DUMPREG(HDMI_VACT_SPACE_6_0);
788 DUMPREG(HDMI_VACT_SPACE_6_1);
789
790 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
791 DUMPREG(HDMI_TG_CMD);
792 DUMPREG(HDMI_TG_H_FSZ_L);
793 DUMPREG(HDMI_TG_H_FSZ_H);
794 DUMPREG(HDMI_TG_HACT_ST_L);
795 DUMPREG(HDMI_TG_HACT_ST_H);
796 DUMPREG(HDMI_TG_HACT_SZ_L);
797 DUMPREG(HDMI_TG_HACT_SZ_H);
798 DUMPREG(HDMI_TG_V_FSZ_L);
799 DUMPREG(HDMI_TG_V_FSZ_H);
800 DUMPREG(HDMI_TG_VSYNC_L);
801 DUMPREG(HDMI_TG_VSYNC_H);
802 DUMPREG(HDMI_TG_VSYNC2_L);
803 DUMPREG(HDMI_TG_VSYNC2_H);
804 DUMPREG(HDMI_TG_VACT_ST_L);
805 DUMPREG(HDMI_TG_VACT_ST_H);
806 DUMPREG(HDMI_TG_VACT_SZ_L);
807 DUMPREG(HDMI_TG_VACT_SZ_H);
808 DUMPREG(HDMI_TG_FIELD_CHG_L);
809 DUMPREG(HDMI_TG_FIELD_CHG_H);
810 DUMPREG(HDMI_TG_VACT_ST2_L);
811 DUMPREG(HDMI_TG_VACT_ST2_H);
812 DUMPREG(HDMI_TG_VACT_ST3_L);
813 DUMPREG(HDMI_TG_VACT_ST3_H);
814 DUMPREG(HDMI_TG_VACT_ST4_L);
815 DUMPREG(HDMI_TG_VACT_ST4_H);
816 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
817 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
818 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
819 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
820 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
821 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
822 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
823 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
824 DUMPREG(HDMI_TG_3D);
825
826 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
827 DUMPREG(HDMI_AVI_CON);
828 DUMPREG(HDMI_AVI_HEADER0);
829 DUMPREG(HDMI_AVI_HEADER1);
830 DUMPREG(HDMI_AVI_HEADER2);
831 DUMPREG(HDMI_AVI_CHECK_SUM);
832 DUMPREG(HDMI_VSI_CON);
833 DUMPREG(HDMI_VSI_HEADER0);
834 DUMPREG(HDMI_VSI_HEADER1);
835 DUMPREG(HDMI_VSI_HEADER2);
836 for (i = 0; i < 7; ++i)
837 DUMPREG(HDMI_VSI_DATA(i));
838
839#undef DUMPREG
840}
841
842static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
843{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200844 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900845 hdmi_v13_regs_dump(hdata, prefix);
846 else
847 hdmi_v14_regs_dump(hdata, prefix);
848}
849
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530850static u8 hdmi_chksum(struct hdmi_context *hdata,
851 u32 start, u8 len, u32 hdr_sum)
852{
853 int i;
854
855 /* hdr_sum : header0 + header1 + header2
856 * start : start address of packet byte1
857 * len : packet bytes - 1 */
858 for (i = 0; i < len; ++i)
859 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
860
861 /* return 2's complement of 8 bit hdr_sum */
862 return (u8)(~(hdr_sum & 0xff) + 1);
863}
864
865static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530866 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530867{
868 u32 hdr_sum;
869 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530870 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200871 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530872
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530873 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
874 if (hdata->dvi_mode) {
875 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
876 HDMI_VSI_CON_DO_NOT_TRANSMIT);
877 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
878 HDMI_AVI_CON_DO_NOT_TRANSMIT);
879 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
880 return;
881 }
882
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530883 switch (infoframe->any.type) {
884 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530885 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530886 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
887 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
888 infoframe->any.version);
889 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
890 hdr_sum = infoframe->any.type + infoframe->any.version +
891 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530892
893 /* Output format zero hardcoded ,RGB YBCR selection */
894 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
895 AVI_ACTIVE_FORMAT_VALID |
896 AVI_UNDERSCANNED_DISPLAY_VALID);
897
Shirish S46154152014-03-13 10:58:28 +0530898 /*
899 * Set the aspect ratio as per the mode, mentioned in
900 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
901 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200902 ar = hdata->current_mode.picture_aspect_ratio;
903 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530904 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200905 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530906 break;
907 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200908 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530909 break;
910 case HDMI_PICTURE_ASPECT_NONE:
911 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200912 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530913 break;
914 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200915 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530916
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200917 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530918
919 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530920 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530921 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
922 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
923 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530924 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530925 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530926 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
927 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
928 infoframe->any.version);
929 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
930 hdr_sum = infoframe->any.type + infoframe->any.version +
931 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530932 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530933 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530934 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
935 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
936 break;
937 default:
938 break;
939 }
940}
941
Sean Pauld9716ee2014-01-30 16:19:29 -0500942static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
943 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500944{
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200945 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -0500946
Andrzej Hajda2228b7c2015-09-25 14:48:24 +0200947 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200948 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530949
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200950 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500951}
952
Sean Pauld9716ee2014-01-30 16:19:29 -0500953static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900954{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200955 drm_connector_unregister(connector);
956 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900957}
958
Sean Pauld9716ee2014-01-30 16:19:29 -0500959static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300960 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500961 .fill_modes = drm_helper_probe_single_connector_modes,
962 .detect = hdmi_detect,
963 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300964 .reset = drm_atomic_helper_connector_reset,
965 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
966 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500967};
968
969static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970{
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200971 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -0500972 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200973 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900974
Inki Dae8fa04aa2014-03-13 16:38:31 +0900975 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500976 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977
Inki Dae8fa04aa2014-03-13 16:38:31 +0900978 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500979 if (!edid)
980 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900981
Sean Pauld9716ee2014-01-30 16:19:29 -0500982 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500983 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
984 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500985 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500986
Sean Pauld9716ee2014-01-30 16:19:29 -0500987 drm_mode_connector_update_edid_property(connector, edid);
988
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200989 ret = drm_add_edid_modes(connector, edid);
990
991 kfree(edid);
992
993 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900994}
995
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900996static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900997{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900998 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001000 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1001 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001002 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001003
1004 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1005 return -EINVAL;
1006}
1007
Sean Pauld9716ee2014-01-30 16:19:29 -05001008static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001009 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001010{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001011 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001012 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001013
Rahul Sharma16844fb2013-06-10 14:50:00 +05301014 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1015 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1016 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1017 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001018
Rahul Sharma16844fb2013-06-10 14:50:00 +05301019 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001020 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001021 return MODE_BAD;
1022
1023 return MODE_OK;
1024}
1025
1026static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1027{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001028 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001029
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001030 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001031}
1032
1033static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1034 .get_modes = hdmi_get_modes,
1035 .mode_valid = hdmi_mode_valid,
1036 .best_encoder = hdmi_best_encoder,
1037};
1038
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001039static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001040{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001041 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 struct drm_connector *connector = &hdata->connector;
1043 int ret;
1044
Sean Pauld9716ee2014-01-30 16:19:29 -05001045 connector->interlace_allowed = true;
1046 connector->polled = DRM_CONNECTOR_POLL_HPD;
1047
1048 ret = drm_connector_init(hdata->drm_dev, connector,
1049 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1050 if (ret) {
1051 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001052 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001053 }
1054
1055 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001056 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001057 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001058
1059 return 0;
1060}
1061
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001062static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1063 const struct drm_display_mode *mode,
1064 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001065{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001066 struct drm_device *dev = encoder->dev;
1067 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001068 struct drm_display_mode *m;
1069 int mode_ok;
1070
Sean Paulf041b252014-01-30 16:19:15 -05001071 drm_mode_set_crtcinfo(adjusted_mode, 0);
1072
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001073 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1074 if (connector->encoder == encoder)
1075 break;
1076 }
1077
1078 if (connector->encoder != encoder)
1079 return true;
1080
Sean Pauld9716ee2014-01-30 16:19:29 -05001081 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001082
1083 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001084 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001085 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001086
1087 /*
1088 * otherwise, find the most suitable mode among modes and change it
1089 * to adjusted_mode.
1090 */
1091 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001092 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001093
Sean Pauld9716ee2014-01-30 16:19:29 -05001094 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001095 DRM_INFO("desired mode doesn't exist so\n");
1096 DRM_INFO("use the most suitable mode among modes.\n");
1097
1098 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1099 m->hdisplay, m->vdisplay, m->vrefresh);
1100
Sean Paul75626852014-01-30 16:19:16 -05001101 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001102 break;
1103 }
1104 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001105
1106 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001107}
1108
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001109static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001110{
1111 u32 n, cts;
1112
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001113 cts = (freq % 9) ? 27000 : 30000;
1114 n = 128 * freq / (27000000 / cts);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001115
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001116 hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
1117 hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
1118 hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001119 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001120}
1121
1122static void hdmi_audio_init(struct hdmi_context *hdata)
1123{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301124 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001125 u32 data_num, bit_ch, sample_frq;
1126 u32 val;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001127
1128 sample_rate = 44100;
1129 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001130
1131 switch (bits_per_sample) {
1132 case 20:
1133 data_num = 2;
1134 bit_ch = 1;
1135 break;
1136 case 24:
1137 data_num = 3;
1138 bit_ch = 1;
1139 break;
1140 default:
1141 data_num = 1;
1142 bit_ch = 0;
1143 break;
1144 }
1145
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001146 hdmi_reg_acr(hdata, sample_rate);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001147
1148 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1149 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1150 | HDMI_I2S_MUX_ENABLE);
1151
1152 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1153 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1154
1155 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1156
1157 sample_frq = (sample_rate == 44100) ? 0 :
1158 (sample_rate == 48000) ? 2 :
1159 (sample_rate == 32000) ? 3 :
1160 (sample_rate == 96000) ? 0xa : 0x0;
1161
1162 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1163 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1164
1165 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1166 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1167
1168 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1169 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1170 | HDMI_I2S_SEL_LRCK(6));
1171 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1172 | HDMI_I2S_SEL_SDATA2(4));
1173 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1174 | HDMI_I2S_SEL_SDATA2(2));
1175 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1176
1177 /* I2S_CON_1 & 2 */
1178 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1179 | HDMI_I2S_L_CH_LOW_POL);
1180 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1181 | HDMI_I2S_SET_BIT_CH(bit_ch)
1182 | HDMI_I2S_SET_SDATA_BIT(data_num)
1183 | HDMI_I2S_BASIC_FORMAT);
1184
1185 /* Configure register related to CUV information */
1186 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1187 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1188 | HDMI_I2S_COPYRIGHT
1189 | HDMI_I2S_LINEAR_PCM
1190 | HDMI_I2S_CONSUMER_FORMAT);
1191 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1192 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1193 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1194 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1195 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1196 HDMI_I2S_ORG_SMP_FREQ_44_1
1197 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1198 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1199
1200 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1201}
1202
1203static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1204{
Seung-Woo Kim872d20d2012-04-24 17:39:15 +09001205 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001206 return;
1207
1208 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1209 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1210 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1211}
1212
Rahul Sharmabfa48422014-04-03 20:41:04 +05301213static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001214{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301215 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001216
Rahul Sharmabfa48422014-04-03 20:41:04 +05301217 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1218 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001219
Rahul Sharmabfa48422014-04-03 20:41:04 +05301220 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1221 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001222}
1223
1224static void hdmi_conf_init(struct hdmi_context *hdata)
1225{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301226 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301227
Sean Paul77006a72013-01-16 10:17:20 -05001228 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001229 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1230 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001231
1232 /* choose HDMI mode */
1233 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1234 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301235 /* Apply Video preable and Guard band in HDMI mode only */
1236 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001237 /* disable bluescreen */
1238 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001239
Seung-Woo Kim872d20d2012-04-24 17:39:15 +09001240 if (hdata->dvi_mode) {
1241 /* choose DVI mode */
1242 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1243 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1244 hdmi_reg_writeb(hdata, HDMI_CON_2,
1245 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1246 }
1247
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001248 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001249 /* choose bluescreen (fecal) color */
1250 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1251 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1252 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1253
1254 /* enable AVI packet every vsync, fixes purple line problem */
1255 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1256 /* force RGB, look to CEA-861-D, table 7 for more detail */
1257 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1258 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1259
1260 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1261 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1262 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1263 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301264 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1265 infoframe.any.version = HDMI_AVI_VERSION;
1266 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301267 hdmi_reg_infoframe(hdata, &infoframe);
1268
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301269 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1270 infoframe.any.version = HDMI_AUI_VERSION;
1271 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301272 hdmi_reg_infoframe(hdata, &infoframe);
1273
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001274 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001275 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1276 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001277}
1278
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001279static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1280{
1281 int tries;
1282
1283 for (tries = 0; tries < 10; ++tries) {
1284 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1285
1286 if (val & HDMI_PHY_STATUS_READY) {
1287 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1288 return;
1289 }
1290 usleep_range(10, 20);
1291 }
1292
1293 DRM_ERROR("PLL could not reach steady state\n");
1294}
1295
Rahul Sharma16844fb2013-06-10 14:50:00 +05301296static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001298 struct drm_display_mode *m = &hdata->current_mode;
1299 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001300
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001301 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1302 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1303 (m->htotal << 12) | m->vtotal);
1304
1305 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1306 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1307
1308 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1309 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1310
1311 val = (m->hsync_start - m->hdisplay - 2);
1312 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1313 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1314 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1315
1316 /*
1317 * Quirk requirement for exynos HDMI IP design,
1318 * 2 pixels less than the actual calculation for hsync_start
1319 * and end.
1320 */
1321
1322 /* Following values & calculations differ for different type of modes */
1323 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1324 /* Interlaced Mode */
1325 val = ((m->vsync_end - m->vdisplay) / 2);
1326 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1327 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1328
1329 val = m->vtotal / 2;
1330 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1331 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1332
1333 val = (m->vtotal +
1334 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1335 val |= m->vtotal << 11;
1336 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1337
1338 val = ((m->vtotal / 2) + 7);
1339 val |= ((m->vtotal / 2) + 2) << 12;
1340 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1341
1342 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1343 val |= ((m->htotal / 2) +
1344 (m->hsync_start - m->hdisplay)) << 12;
1345 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1346
1347 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1348 (m->vtotal - m->vdisplay) / 2);
1349 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1350
1351 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1352 } else {
1353 /* Progressive Mode */
1354
1355 val = m->vtotal;
1356 val |= (m->vtotal - m->vdisplay) << 11;
1357 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1358
1359 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1360
1361 val = (m->vsync_end - m->vdisplay);
1362 val |= ((m->vsync_start - m->vdisplay) << 12);
1363 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1364
1365 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1366 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1367 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1368 m->vtotal - m->vdisplay);
1369 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1370 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1371 }
1372
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001373 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001374 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1375 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1376 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1377 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1378 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1379 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1380 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1381 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1382 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1383 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1384 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001385}
1386
Rahul Sharma16844fb2013-06-10 14:50:00 +05301387static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001388{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001389 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001390
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001391 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1392 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1393 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1394 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1395 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1396 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1397 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1398 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1399 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1400
1401 /*
1402 * Quirk requirement for exynos 5 HDMI IP design,
1403 * 2 pixels less than the actual calculation for hsync_start
1404 * and end.
1405 */
1406
1407 /* Following values & calculations differ for different type of modes */
1408 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1409 /* Interlaced Mode */
1410 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1411 (m->vsync_end - m->vdisplay) / 2);
1412 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1413 (m->vsync_start - m->vdisplay) / 2);
1414 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1415 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1416 (m->vtotal - m->vdisplay) / 2);
1417 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1418 m->vtotal - m->vdisplay / 2);
1419 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1420 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1421 (m->vtotal / 2) + 7);
1422 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1423 (m->vtotal / 2) + 2);
1424 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1425 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1426 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1427 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1428 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1429 (m->vtotal - m->vdisplay) / 2);
1430 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1431 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1432 m->vtotal - m->vdisplay / 2);
1433 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1434 (m->vtotal / 2) + 1);
1435 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1436 (m->vtotal / 2) + 1);
1437 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1438 (m->vtotal / 2) + 1);
1439 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1440 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1441 } else {
1442 /* Progressive Mode */
1443 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1444 m->vsync_end - m->vdisplay);
1445 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1446 m->vsync_start - m->vdisplay);
1447 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1448 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1449 m->vtotal - m->vdisplay);
1450 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1451 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1452 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1453 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1454 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1455 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1456 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1457 m->vtotal - m->vdisplay);
1458 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1459 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1460 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1461 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1462 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1463 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1464 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1465 }
1466
1467 /* Following values & calculations are same irrespective of mode type */
1468 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1469 m->hsync_start - m->hdisplay - 2);
1470 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1471 m->hsync_end - m->hdisplay - 2);
1472 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1473 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1474 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1475 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1476 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1477 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1478 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1479 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1480 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1481 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1482 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1483 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1484 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1485 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1486 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1487 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1488 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1489 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001490
1491 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001492 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1493 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1494 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1495 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1496 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1497 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1498 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1499 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1500 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001501}
1502
Rahul Sharma16844fb2013-06-10 14:50:00 +05301503static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001504{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001505 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301506 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001507 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301508 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001509
1510 hdmiphy_wait_for_pll(hdata);
1511
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001512 clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001513
1514 /* enable HDMI and timing generator */
1515 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001516}
1517
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001518static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1519{
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001520 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001521
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001522 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001523 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001524 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001525 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001526 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001527}
1528
1529static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1530{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001531 int ret;
1532 int i;
1533
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001534 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001535 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001536 if (i < 0) {
1537 DRM_ERROR("failed to find hdmiphy conf\n");
1538 return;
1539 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001540
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001541 ret = hdmiphy_reg_write_buf(hdata, 0,
1542 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001543 if (ret) {
1544 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001545 return;
1546 }
1547
Sean Paul09760ea2013-01-14 17:03:20 -05001548 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001549}
1550
1551static void hdmi_conf_apply(struct hdmi_context *hdata)
1552{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001553 hdmiphy_conf_reset(hdata);
1554 hdmiphy_conf_apply(hdata);
1555
Rahul Sharmabfa48422014-04-03 20:41:04 +05301556 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001557 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001558
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001559 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001560
1561 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301562 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001563 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001564
1565 hdmi_regs_dump(hdata, "start");
1566}
1567
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001568static void hdmi_mode_set(struct drm_encoder *encoder,
1569 struct drm_display_mode *mode,
1570 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001571{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001572 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001573 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001574
YoungJun Chocbc4c332013-06-12 10:44:40 +09001575 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1576 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001577 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001578 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001579
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001580 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001581 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001582}
1583
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001584static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001585{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001586 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001587
Andrzej Hajda882a0642015-07-09 16:28:08 +02001588 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001589 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001590
1591 hdata->powered = true;
1592
Sean Paulaf65c802014-01-30 16:19:27 -05001593 pm_runtime_get_sync(hdata->dev);
1594
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001595 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001596 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1597
Rahul Sharma049d34e2014-05-20 10:36:05 +05301598 /* set pmu hdmiphy control bit to enable hdmiphy */
1599 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1600 PMU_HDMI_PHY_ENABLE_BIT, 1);
1601
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001602 clk_prepare_enable(hdata->hdmi);
1603 clk_prepare_enable(hdata->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301604
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001605 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001606}
1607
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001608static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001609{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001610 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001611 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001612 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001613
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001614 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001615 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001616
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001617 /*
1618 * The SFRs of VP and Mixer are updated by Vertical Sync of
1619 * Timing generator which is a part of HDMI so the sequence
1620 * to disable TV Subsystem should be as following,
1621 * VP -> Mixer -> HDMI
1622 *
1623 * Below codes will try to disable Mixer and VP(if used)
1624 * prior to disabling HDMI.
1625 */
1626 if (crtc)
1627 funcs = crtc->helper_private;
1628 if (funcs && funcs->disable)
1629 (*funcs->disable)(crtc);
1630
Rahul Sharmabfa48422014-04-03 20:41:04 +05301631 /* HDMI System Disable */
1632 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1633
Sean Paul724fd142014-05-09 15:05:10 +09001634 cancel_delayed_work(&hdata->hotplug_work);
1635
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001636 clk_disable_unprepare(hdata->sclk_hdmi);
1637 clk_disable_unprepare(hdata->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301638
1639 /* reset pmu hdmiphy control bit to disable hdmiphy */
1640 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1641 PMU_HDMI_PHY_ENABLE_BIT, 0);
1642
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001643 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001644
Sean Paulaf65c802014-01-30 16:19:27 -05001645 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001646
1647 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001648}
1649
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001650static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001651 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001652 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001653 .enable = hdmi_enable,
1654 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001655};
1656
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001657static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1658 .destroy = drm_encoder_cleanup,
1659};
1660
Sean Paul724fd142014-05-09 15:05:10 +09001661static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001662{
Sean Paul724fd142014-05-09 15:05:10 +09001663 struct hdmi_context *hdata;
1664
1665 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001666
Sean Paul45517892014-01-30 16:19:05 -05001667 if (hdata->drm_dev)
1668 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001669}
1670
1671static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1672{
1673 struct hdmi_context *hdata = arg;
1674
1675 mod_delayed_work(system_wq, &hdata->hotplug_work,
1676 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001677
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001678 return IRQ_HANDLED;
1679}
1680
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001681static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001682{
1683 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001684 int i, ret;
1685
1686 DRM_DEBUG_KMS("HDMI resource init\n");
1687
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001688 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1689 if (IS_ERR(hdata->hpd_gpio)) {
1690 DRM_ERROR("cannot get hpd gpio property\n");
1691 return PTR_ERR(hdata->hpd_gpio);
1692 }
1693
1694 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1695 if (hdata->irq < 0) {
1696 DRM_ERROR("failed to get GPIO irq\n");
1697 return hdata->irq;
1698 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001699 /* get clocks, power */
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001700 hdata->hdmi = devm_clk_get(dev, "hdmi");
1701 if (IS_ERR(hdata->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001702 DRM_ERROR("failed to get clock 'hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001703 ret = PTR_ERR(hdata->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001704 goto fail;
1705 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001706 hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
1707 if (IS_ERR(hdata->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001708 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001709 ret = PTR_ERR(hdata->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001710 goto fail;
1711 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001712 hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
1713 if (IS_ERR(hdata->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001714 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001715 ret = PTR_ERR(hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001716 goto fail;
1717 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001718 hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
1719 if (IS_ERR(hdata->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001720 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001721 ret = PTR_ERR(hdata->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001722 goto fail;
1723 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001724 hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1725 if (IS_ERR(hdata->mout_hdmi)) {
Rahul Sharma59956d32013-06-11 12:24:03 +05301726 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001727 ret = PTR_ERR(hdata->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301728 goto fail;
1729 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001730
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001731 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001732
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001733 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001734 hdata->regul_bulk[i].supply = supply[i];
1735 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001736 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001737 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001738 if (ret) {
1739 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001740 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001741 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001742
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001743 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001744
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001745 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001746 return 0;
1747
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001748 if (IS_ERR(hdata->reg_hdmi_en))
1749 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001750
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001751 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001752 if (ret)
1753 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001754
Inki Daedf5225b2014-05-29 18:28:02 +09001755 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001756fail:
1757 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001758 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001759}
1760
Rahul Sharma22c4f422012-10-04 20:48:55 +05301761static struct of_device_id hdmi_match_types[] = {
1762 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001763 .compatible = "samsung,exynos4210-hdmi",
1764 .data = &exynos4210_hdmi_driver_data,
1765 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301766 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001767 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301768 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301769 .compatible = "samsung,exynos5420-hdmi",
1770 .data = &exynos5420_hdmi_driver_data,
1771 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301772 /* end node */
1773 }
1774};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001775MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301776
Inki Daef37cd5e2014-05-09 14:25:20 +09001777static int hdmi_bind(struct device *dev, struct device *master, void *data)
1778{
1779 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001780 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001781 struct drm_encoder *encoder = &hdata->encoder;
1782 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001783
Inki Daef37cd5e2014-05-09 14:25:20 +09001784 hdata->drm_dev = drm_dev;
1785
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001786 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1787 EXYNOS_DISPLAY_TYPE_HDMI);
1788 if (pipe < 0)
1789 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001790
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001791 encoder->possible_crtcs = 1 << pipe;
1792
1793 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1794
1795 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1796 DRM_MODE_ENCODER_TMDS);
1797
1798 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1799
1800 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001801 if (ret) {
1802 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001803 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001804 return ret;
1805 }
1806
1807 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001808}
1809
1810static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1811{
Inki Daef37cd5e2014-05-09 14:25:20 +09001812}
1813
1814static const struct component_ops hdmi_component_ops = {
1815 .bind = hdmi_bind,
1816 .unbind = hdmi_unbind,
1817};
1818
Inki Daee2a562d2014-05-09 16:46:10 +09001819static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1820{
1821 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1822 struct device_node *np;
1823
1824 np = of_find_compatible_node(NULL, NULL, compatible_str);
1825 if (np)
1826 return of_get_next_parent(np);
1827
1828 return NULL;
1829}
1830
1831static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1832{
1833 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1834
1835 return of_find_compatible_node(NULL, NULL, compatible_str);
1836}
1837
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001838static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001839{
Inki Daef37cd5e2014-05-09 14:25:20 +09001840 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001841 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001842 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001843 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001844 struct resource *res;
1845 int ret;
1846
Andrzej Hajda930865f2014-11-17 09:54:20 +01001847 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1848 if (!hdata)
1849 return -ENOMEM;
1850
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001851 match = of_match_device(hdmi_match_types, dev);
1852 if (!match)
1853 return -ENODEV;
1854
1855 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001856
Andrzej Hajda930865f2014-11-17 09:54:20 +01001857 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001858
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001859 hdata->dev = dev;
1860
1861 ret = hdmi_resources_init(hdata);
1862 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301863 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001864 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001865 }
1866
1867 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001868 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001869 if (IS_ERR(hdata->regs)) {
1870 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001871 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001872 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001873
Inki Daee2a562d2014-05-09 16:46:10 +09001874 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1875 if (ddc_node)
1876 goto out_get_ddc_adpt;
1877
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001878 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001879 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1880 if (!ddc_node) {
1881 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001882 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001883 }
Inki Daee2a562d2014-05-09 16:46:10 +09001884
1885out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001886 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1887 if (!hdata->ddc_adpt) {
1888 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001889 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001890 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001891
Inki Daee2a562d2014-05-09 16:46:10 +09001892 phy_node = hdmi_legacy_phy_dt_binding(dev);
1893 if (phy_node)
1894 goto out_get_phy_port;
1895
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001896 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001897 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1898 if (!phy_node) {
1899 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1900 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001901 goto err_ddc;
1902 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001903
Inki Daee2a562d2014-05-09 16:46:10 +09001904out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001905 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001906 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1907 if (!hdata->regs_hdmiphy) {
1908 DRM_ERROR("failed to ioremap hdmi phy\n");
1909 ret = -ENOMEM;
1910 goto err_ddc;
1911 }
1912 } else {
1913 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1914 if (!hdata->hdmiphy_port) {
1915 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001916 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001917 goto err_ddc;
1918 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001919 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001920
Sean Paul724fd142014-05-09 15:05:10 +09001921 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1922
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001923 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001924 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001925 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001926 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001927 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001928 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001929 goto err_hdmiphy;
1930 }
1931
Rahul Sharma049d34e2014-05-20 10:36:05 +05301932 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
1933 "samsung,syscon-phandle");
1934 if (IS_ERR(hdata->pmureg)) {
1935 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001936 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05301937 goto err_hdmiphy;
1938 }
1939
Sean Paulaf65c802014-01-30 16:19:27 -05001940 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001941
Inki Daedf5225b2014-05-29 18:28:02 +09001942 ret = component_add(&pdev->dev, &hdmi_component_ops);
1943 if (ret)
1944 goto err_disable_pm_runtime;
1945
1946 return ret;
1947
1948err_disable_pm_runtime:
1949 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001950
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001951err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09001952 if (hdata->hdmiphy_port)
1953 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001954err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001955 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001956
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001957 return ret;
1958}
1959
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001960static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001961{
Andrzej Hajda930865f2014-11-17 09:54:20 +01001962 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001963
Sean Paul724fd142014-05-09 15:05:10 +09001964 cancel_delayed_work_sync(&hdata->hotplug_work);
1965
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02001966 component_del(&pdev->dev, &hdmi_component_ops);
1967
1968 pm_runtime_disable(&pdev->dev);
1969
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001970 if (!IS_ERR(hdata->reg_hdmi_en))
1971 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001972
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09001973 if (hdata->hdmiphy_port)
1974 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001975
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02001976 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001977
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001978 return 0;
1979}
1980
1981struct platform_driver hdmi_driver = {
1982 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001983 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301985 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001986 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05301987 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001988 },
1989};