blob: a4ec8b9446109882fe0bb0f825441592df8241d8 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
Andrzej Hajda2228b7c2015-09-25 14:48:24 +020033#include <linux/gpio/consumer.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020037#include <linux/of_device.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Sean Paul724fd142014-05-09 15:05:10 +090049#define HOTPLUG_DEBOUNCE_MS 1100
50
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053051/* AVI header and aspect ratio */
52#define HDMI_AVI_VERSION 0x02
53#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053054
55/* AUI header info */
56#define HDMI_AUI_VERSION 0x01
57#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053058#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
59#define AVI_4_3_CENTER_RATIO 0x9
60#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053061
Rahul Sharma5a325072012-10-04 20:48:54 +053062enum hdmi_type {
63 HDMI_TYPE13,
64 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020065 HDMI_TYPE_COUNT
66};
67
68#define HDMI_MAPPED_BASE 0xffff0000
69
70enum hdmi_mapped_regs {
71 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
72 HDMI_PHY_RSTOUT,
73 HDMI_ACR_CON,
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020074 HDMI_ACR_MCTS0,
75 HDMI_ACR_CTS0,
76 HDMI_ACR_N0
Andrzej Hajda633d00b2015-09-25 14:48:16 +020077};
78
79static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
80 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
81 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
82 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020083 { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
84 { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
85 { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
Rahul Sharma5a325072012-10-04 20:48:54 +053086};
87
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020088static const char * const supply[] = {
89 "vdd",
90 "vdd_osc",
91 "vdd_pll",
92};
93
Inki Daebfe4e842014-03-06 14:18:17 +090094struct hdmi_driver_data {
95 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090096 const struct hdmiphy_config *phy_confs;
97 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090098 unsigned int is_apb_phy:1;
99};
100
Joonyoung Shim590f4182012-03-16 18:47:14 +0900101struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300102 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900103 struct device *dev;
104 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500105 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900106 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900107 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900108 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900109 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530110 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200111 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200112 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900113
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200114 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900115 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200116 struct i2c_client *hdmiphy_port;
117 struct i2c_adapter *ddc_adpt;
118 struct gpio_desc *hpd_gpio;
119 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530120 struct regmap *pmureg;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200121 struct clk *hdmi;
122 struct clk *sclk_hdmi;
123 struct clk *sclk_pixel;
124 struct clk *sclk_hdmiphy;
125 struct clk *mout_hdmi;
126 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
127 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900128};
129
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300130static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100131{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900132 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100133}
134
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200135static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
136{
137 return container_of(c, struct hdmi_context, connector);
138}
139
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500140struct hdmiphy_config {
141 int pixel_clock;
142 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900143};
144
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900145/* list of phy config settings */
146static const struct hdmiphy_config hdmiphy_v13_configs[] = {
147 {
148 .pixel_clock = 27000000,
149 .conf = {
150 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
151 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
152 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200153 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900154 },
155 },
156 {
157 .pixel_clock = 27027000,
158 .conf = {
159 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
160 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
161 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200162 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163 },
164 },
165 {
166 .pixel_clock = 74176000,
167 .conf = {
168 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
169 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
170 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200171 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900172 },
173 },
174 {
175 .pixel_clock = 74250000,
176 .conf = {
177 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
178 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
179 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200180 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900181 },
182 },
183 {
184 .pixel_clock = 148500000,
185 .conf = {
186 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
187 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
188 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200189 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900190 },
191 },
192};
193
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500194static const struct hdmiphy_config hdmiphy_v14_configs[] = {
195 {
196 .pixel_clock = 25200000,
197 .conf = {
198 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
199 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
200 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
201 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
202 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900203 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500204 {
205 .pixel_clock = 27000000,
206 .conf = {
207 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
208 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
209 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
210 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
211 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900212 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500213 {
214 .pixel_clock = 27027000,
215 .conf = {
216 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
217 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
218 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200219 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500220 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900221 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500222 {
223 .pixel_clock = 36000000,
224 .conf = {
225 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
226 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
227 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
228 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
229 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900230 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500231 {
232 .pixel_clock = 40000000,
233 .conf = {
234 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
235 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
236 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
237 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
238 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900239 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500240 {
241 .pixel_clock = 65000000,
242 .conf = {
243 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
244 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
245 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
246 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
247 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900248 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500249 {
Shirish Se1d883c2014-03-13 14:28:27 +0900250 .pixel_clock = 71000000,
251 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530252 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
253 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
254 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900255 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
256 },
257 },
258 {
259 .pixel_clock = 73250000,
260 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530261 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
262 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
263 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900264 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
265 },
266 },
267 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500268 .pixel_clock = 74176000,
269 .conf = {
270 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
271 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
272 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
273 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
274 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900275 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500276 {
277 .pixel_clock = 74250000,
278 .conf = {
279 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
280 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
281 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200282 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500283 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900284 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500285 {
286 .pixel_clock = 83500000,
287 .conf = {
288 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
289 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
290 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
291 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
292 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900293 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500294 {
295 .pixel_clock = 106500000,
296 .conf = {
297 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
298 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
299 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
300 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
301 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900302 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500303 {
304 .pixel_clock = 108000000,
305 .conf = {
306 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
307 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
308 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
309 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
310 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900311 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500312 {
Shirish Se1d883c2014-03-13 14:28:27 +0900313 .pixel_clock = 115500000,
314 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530315 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
316 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
317 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900318 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
319 },
320 },
321 {
322 .pixel_clock = 119000000,
323 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530324 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
325 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
326 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900327 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
328 },
329 },
330 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500331 .pixel_clock = 146250000,
332 .conf = {
333 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
334 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
335 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
336 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
337 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900338 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500339 {
340 .pixel_clock = 148500000,
341 .conf = {
342 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
343 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
344 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200345 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500346 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900347 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900348};
349
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530350static const struct hdmiphy_config hdmiphy_5420_configs[] = {
351 {
352 .pixel_clock = 25200000,
353 .conf = {
354 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
355 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
356 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
357 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
358 },
359 },
360 {
361 .pixel_clock = 27000000,
362 .conf = {
363 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
364 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
365 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
366 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
367 },
368 },
369 {
370 .pixel_clock = 27027000,
371 .conf = {
372 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
373 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
374 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
375 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
376 },
377 },
378 {
379 .pixel_clock = 36000000,
380 .conf = {
381 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
382 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
383 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
384 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
385 },
386 },
387 {
388 .pixel_clock = 40000000,
389 .conf = {
390 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
391 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
392 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
393 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
394 },
395 },
396 {
397 .pixel_clock = 65000000,
398 .conf = {
399 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
400 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
401 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
402 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
403 },
404 },
405 {
406 .pixel_clock = 71000000,
407 .conf = {
408 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
409 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
410 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
411 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
412 },
413 },
414 {
415 .pixel_clock = 73250000,
416 .conf = {
417 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
418 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
419 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
420 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
421 },
422 },
423 {
424 .pixel_clock = 74176000,
425 .conf = {
426 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
427 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
428 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
429 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
430 },
431 },
432 {
433 .pixel_clock = 74250000,
434 .conf = {
435 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
436 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
437 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
438 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
439 },
440 },
441 {
442 .pixel_clock = 83500000,
443 .conf = {
444 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
445 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
446 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
447 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
448 },
449 },
450 {
451 .pixel_clock = 88750000,
452 .conf = {
453 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
454 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
455 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
456 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
457 },
458 },
459 {
460 .pixel_clock = 106500000,
461 .conf = {
462 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
463 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
464 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
465 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
466 },
467 },
468 {
469 .pixel_clock = 108000000,
470 .conf = {
471 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
472 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
473 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
474 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
475 },
476 },
477 {
478 .pixel_clock = 115500000,
479 .conf = {
480 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
481 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
482 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
483 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
484 },
485 },
486 {
487 .pixel_clock = 146250000,
488 .conf = {
489 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
490 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
491 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
492 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
493 },
494 },
495 {
496 .pixel_clock = 148500000,
497 .conf = {
498 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
499 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
500 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
501 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
502 },
503 },
504};
505
Sachin Kamat16337072014-05-22 10:32:56 +0530506static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530507 .type = HDMI_TYPE14,
508 .phy_confs = hdmiphy_5420_configs,
509 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
510 .is_apb_phy = 1,
511};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900512
Sachin Kamat16337072014-05-22 10:32:56 +0530513static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900514 .type = HDMI_TYPE14,
515 .phy_confs = hdmiphy_v14_configs,
516 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
517 .is_apb_phy = 0,
518};
519
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200520static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
521 .type = HDMI_TYPE13,
522 .phy_confs = hdmiphy_v13_configs,
523 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
524 .is_apb_phy = 0,
525};
526
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200527static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
528{
529 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
530 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
531 return reg_id;
532}
533
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900534static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
535{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200536 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900537}
538
539static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
540 u32 reg_id, u8 value)
541{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200542 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900543}
544
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200545static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
546 int bytes, u32 val)
547{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200548 reg_id = hdmi_map_reg(hdata, reg_id);
549
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200550 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200551 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200552 val >>= 8;
553 reg_id += 4;
554 }
555}
556
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
558 u32 reg_id, u32 value, u32 mask)
559{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200560 u32 old;
561
562 reg_id = hdmi_map_reg(hdata, reg_id);
563 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900564 value = (value & mask) | (old & ~mask);
565 writel(value, hdata->regs + reg_id);
566}
567
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900568static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
569 u32 reg_offset, const u8 *buf, u32 len)
570{
571 if ((reg_offset + len) > 32)
572 return -EINVAL;
573
574 if (hdata->hdmiphy_port) {
575 int ret;
576
577 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
578 if (ret == len)
579 return 0;
580 return ret;
581 } else {
582 int i;
583 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200584 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900585 ((reg_offset + i)<<2));
586 return 0;
587 }
588}
589
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900590static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900591{
592#define DUMPREG(reg_id) \
593 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
594 readl(hdata->regs + reg_id))
595 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
596 DUMPREG(HDMI_INTC_FLAG);
597 DUMPREG(HDMI_INTC_CON);
598 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900599 DUMPREG(HDMI_V13_PHY_RSTOUT);
600 DUMPREG(HDMI_V13_PHY_VPLL);
601 DUMPREG(HDMI_V13_PHY_CMU);
602 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900603
604 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
605 DUMPREG(HDMI_CON_0);
606 DUMPREG(HDMI_CON_1);
607 DUMPREG(HDMI_CON_2);
608 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900609 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610 DUMPREG(HDMI_STATUS_EN);
611 DUMPREG(HDMI_HPD);
612 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900613 DUMPREG(HDMI_V13_HPD_GEN);
614 DUMPREG(HDMI_V13_DC_CONTROL);
615 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900616
617 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
618 DUMPREG(HDMI_H_BLANK_0);
619 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900620 DUMPREG(HDMI_V13_V_BLANK_0);
621 DUMPREG(HDMI_V13_V_BLANK_1);
622 DUMPREG(HDMI_V13_V_BLANK_2);
623 DUMPREG(HDMI_V13_H_V_LINE_0);
624 DUMPREG(HDMI_V13_H_V_LINE_1);
625 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626 DUMPREG(HDMI_VSYNC_POL);
627 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900628 DUMPREG(HDMI_V13_V_BLANK_F_0);
629 DUMPREG(HDMI_V13_V_BLANK_F_1);
630 DUMPREG(HDMI_V13_V_BLANK_F_2);
631 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
632 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
633 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
634 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
635 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
636 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
637 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
638 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
639 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
640 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
641 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
642 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900643
644 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
645 DUMPREG(HDMI_TG_CMD);
646 DUMPREG(HDMI_TG_H_FSZ_L);
647 DUMPREG(HDMI_TG_H_FSZ_H);
648 DUMPREG(HDMI_TG_HACT_ST_L);
649 DUMPREG(HDMI_TG_HACT_ST_H);
650 DUMPREG(HDMI_TG_HACT_SZ_L);
651 DUMPREG(HDMI_TG_HACT_SZ_H);
652 DUMPREG(HDMI_TG_V_FSZ_L);
653 DUMPREG(HDMI_TG_V_FSZ_H);
654 DUMPREG(HDMI_TG_VSYNC_L);
655 DUMPREG(HDMI_TG_VSYNC_H);
656 DUMPREG(HDMI_TG_VSYNC2_L);
657 DUMPREG(HDMI_TG_VSYNC2_H);
658 DUMPREG(HDMI_TG_VACT_ST_L);
659 DUMPREG(HDMI_TG_VACT_ST_H);
660 DUMPREG(HDMI_TG_VACT_SZ_L);
661 DUMPREG(HDMI_TG_VACT_SZ_H);
662 DUMPREG(HDMI_TG_FIELD_CHG_L);
663 DUMPREG(HDMI_TG_FIELD_CHG_H);
664 DUMPREG(HDMI_TG_VACT_ST2_L);
665 DUMPREG(HDMI_TG_VACT_ST2_H);
666 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
667 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
668 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
669 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
670 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
671 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
672 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
673 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
674#undef DUMPREG
675}
676
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900677static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
678{
679 int i;
680
681#define DUMPREG(reg_id) \
682 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
683 readl(hdata->regs + reg_id))
684
685 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
686 DUMPREG(HDMI_INTC_CON);
687 DUMPREG(HDMI_INTC_FLAG);
688 DUMPREG(HDMI_HPD_STATUS);
689 DUMPREG(HDMI_INTC_CON_1);
690 DUMPREG(HDMI_INTC_FLAG_1);
691 DUMPREG(HDMI_PHY_STATUS_0);
692 DUMPREG(HDMI_PHY_STATUS_PLL);
693 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200694 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900695 DUMPREG(HDMI_PHY_VPLL);
696 DUMPREG(HDMI_PHY_CMU);
697 DUMPREG(HDMI_CORE_RSTOUT);
698
699 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
700 DUMPREG(HDMI_CON_0);
701 DUMPREG(HDMI_CON_1);
702 DUMPREG(HDMI_CON_2);
703 DUMPREG(HDMI_SYS_STATUS);
704 DUMPREG(HDMI_PHY_STATUS_0);
705 DUMPREG(HDMI_STATUS_EN);
706 DUMPREG(HDMI_HPD);
707 DUMPREG(HDMI_MODE_SEL);
708 DUMPREG(HDMI_ENC_EN);
709 DUMPREG(HDMI_DC_CONTROL);
710 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
711
712 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
713 DUMPREG(HDMI_H_BLANK_0);
714 DUMPREG(HDMI_H_BLANK_1);
715 DUMPREG(HDMI_V2_BLANK_0);
716 DUMPREG(HDMI_V2_BLANK_1);
717 DUMPREG(HDMI_V1_BLANK_0);
718 DUMPREG(HDMI_V1_BLANK_1);
719 DUMPREG(HDMI_V_LINE_0);
720 DUMPREG(HDMI_V_LINE_1);
721 DUMPREG(HDMI_H_LINE_0);
722 DUMPREG(HDMI_H_LINE_1);
723 DUMPREG(HDMI_HSYNC_POL);
724
725 DUMPREG(HDMI_VSYNC_POL);
726 DUMPREG(HDMI_INT_PRO_MODE);
727 DUMPREG(HDMI_V_BLANK_F0_0);
728 DUMPREG(HDMI_V_BLANK_F0_1);
729 DUMPREG(HDMI_V_BLANK_F1_0);
730 DUMPREG(HDMI_V_BLANK_F1_1);
731
732 DUMPREG(HDMI_H_SYNC_START_0);
733 DUMPREG(HDMI_H_SYNC_START_1);
734 DUMPREG(HDMI_H_SYNC_END_0);
735 DUMPREG(HDMI_H_SYNC_END_1);
736
737 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
738 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
739 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
740 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
741
742 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
743 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
744 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
745 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
746
747 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
748 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
749 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
750 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
751
752 DUMPREG(HDMI_V_BLANK_F2_0);
753 DUMPREG(HDMI_V_BLANK_F2_1);
754 DUMPREG(HDMI_V_BLANK_F3_0);
755 DUMPREG(HDMI_V_BLANK_F3_1);
756 DUMPREG(HDMI_V_BLANK_F4_0);
757 DUMPREG(HDMI_V_BLANK_F4_1);
758 DUMPREG(HDMI_V_BLANK_F5_0);
759 DUMPREG(HDMI_V_BLANK_F5_1);
760
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
763 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
769
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
774 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
775 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
776 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
777 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
778
779 DUMPREG(HDMI_VACT_SPACE_1_0);
780 DUMPREG(HDMI_VACT_SPACE_1_1);
781 DUMPREG(HDMI_VACT_SPACE_2_0);
782 DUMPREG(HDMI_VACT_SPACE_2_1);
783 DUMPREG(HDMI_VACT_SPACE_3_0);
784 DUMPREG(HDMI_VACT_SPACE_3_1);
785 DUMPREG(HDMI_VACT_SPACE_4_0);
786 DUMPREG(HDMI_VACT_SPACE_4_1);
787 DUMPREG(HDMI_VACT_SPACE_5_0);
788 DUMPREG(HDMI_VACT_SPACE_5_1);
789 DUMPREG(HDMI_VACT_SPACE_6_0);
790 DUMPREG(HDMI_VACT_SPACE_6_1);
791
792 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
793 DUMPREG(HDMI_TG_CMD);
794 DUMPREG(HDMI_TG_H_FSZ_L);
795 DUMPREG(HDMI_TG_H_FSZ_H);
796 DUMPREG(HDMI_TG_HACT_ST_L);
797 DUMPREG(HDMI_TG_HACT_ST_H);
798 DUMPREG(HDMI_TG_HACT_SZ_L);
799 DUMPREG(HDMI_TG_HACT_SZ_H);
800 DUMPREG(HDMI_TG_V_FSZ_L);
801 DUMPREG(HDMI_TG_V_FSZ_H);
802 DUMPREG(HDMI_TG_VSYNC_L);
803 DUMPREG(HDMI_TG_VSYNC_H);
804 DUMPREG(HDMI_TG_VSYNC2_L);
805 DUMPREG(HDMI_TG_VSYNC2_H);
806 DUMPREG(HDMI_TG_VACT_ST_L);
807 DUMPREG(HDMI_TG_VACT_ST_H);
808 DUMPREG(HDMI_TG_VACT_SZ_L);
809 DUMPREG(HDMI_TG_VACT_SZ_H);
810 DUMPREG(HDMI_TG_FIELD_CHG_L);
811 DUMPREG(HDMI_TG_FIELD_CHG_H);
812 DUMPREG(HDMI_TG_VACT_ST2_L);
813 DUMPREG(HDMI_TG_VACT_ST2_H);
814 DUMPREG(HDMI_TG_VACT_ST3_L);
815 DUMPREG(HDMI_TG_VACT_ST3_H);
816 DUMPREG(HDMI_TG_VACT_ST4_L);
817 DUMPREG(HDMI_TG_VACT_ST4_H);
818 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
819 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
820 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
821 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
822 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
823 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
824 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
825 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
826 DUMPREG(HDMI_TG_3D);
827
828 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
829 DUMPREG(HDMI_AVI_CON);
830 DUMPREG(HDMI_AVI_HEADER0);
831 DUMPREG(HDMI_AVI_HEADER1);
832 DUMPREG(HDMI_AVI_HEADER2);
833 DUMPREG(HDMI_AVI_CHECK_SUM);
834 DUMPREG(HDMI_VSI_CON);
835 DUMPREG(HDMI_VSI_HEADER0);
836 DUMPREG(HDMI_VSI_HEADER1);
837 DUMPREG(HDMI_VSI_HEADER2);
838 for (i = 0; i < 7; ++i)
839 DUMPREG(HDMI_VSI_DATA(i));
840
841#undef DUMPREG
842}
843
844static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
845{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200846 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900847 hdmi_v13_regs_dump(hdata, prefix);
848 else
849 hdmi_v14_regs_dump(hdata, prefix);
850}
851
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530852static u8 hdmi_chksum(struct hdmi_context *hdata,
853 u32 start, u8 len, u32 hdr_sum)
854{
855 int i;
856
857 /* hdr_sum : header0 + header1 + header2
858 * start : start address of packet byte1
859 * len : packet bytes - 1 */
860 for (i = 0; i < len; ++i)
861 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
862
863 /* return 2's complement of 8 bit hdr_sum */
864 return (u8)(~(hdr_sum & 0xff) + 1);
865}
866
867static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530868 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530869{
870 u32 hdr_sum;
871 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530872 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200873 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530874
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530875 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
876 if (hdata->dvi_mode) {
877 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
878 HDMI_VSI_CON_DO_NOT_TRANSMIT);
879 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
880 HDMI_AVI_CON_DO_NOT_TRANSMIT);
881 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
882 return;
883 }
884
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530885 switch (infoframe->any.type) {
886 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530887 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530888 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
889 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
890 infoframe->any.version);
891 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
892 hdr_sum = infoframe->any.type + infoframe->any.version +
893 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530894
895 /* Output format zero hardcoded ,RGB YBCR selection */
896 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
897 AVI_ACTIVE_FORMAT_VALID |
898 AVI_UNDERSCANNED_DISPLAY_VALID);
899
Shirish S46154152014-03-13 10:58:28 +0530900 /*
901 * Set the aspect ratio as per the mode, mentioned in
902 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
903 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200904 ar = hdata->current_mode.picture_aspect_ratio;
905 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530906 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200907 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530908 break;
909 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200910 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530911 break;
912 case HDMI_PICTURE_ASPECT_NONE:
913 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200914 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530915 break;
916 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200917 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530918
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200919 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530920
921 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530922 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530923 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
924 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
925 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530926 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530927 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530928 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
929 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
930 infoframe->any.version);
931 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
932 hdr_sum = infoframe->any.type + infoframe->any.version +
933 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530934 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530935 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530936 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
937 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
938 break;
939 default:
940 break;
941 }
942}
943
Sean Pauld9716ee2014-01-30 16:19:29 -0500944static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
945 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500946{
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200947 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -0500948
Andrzej Hajda2228b7c2015-09-25 14:48:24 +0200949 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200950 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530951
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200952 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500953}
954
Sean Pauld9716ee2014-01-30 16:19:29 -0500955static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900956{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200957 drm_connector_unregister(connector);
958 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900959}
960
Sean Pauld9716ee2014-01-30 16:19:29 -0500961static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300962 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500963 .fill_modes = drm_helper_probe_single_connector_modes,
964 .detect = hdmi_detect,
965 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300966 .reset = drm_atomic_helper_connector_reset,
967 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
968 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500969};
970
971static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900972{
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200973 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -0500974 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200975 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900976
Inki Dae8fa04aa2014-03-13 16:38:31 +0900977 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500978 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900979
Inki Dae8fa04aa2014-03-13 16:38:31 +0900980 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500981 if (!edid)
982 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900983
Sean Pauld9716ee2014-01-30 16:19:29 -0500984 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500985 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
986 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500987 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500988
Sean Pauld9716ee2014-01-30 16:19:29 -0500989 drm_mode_connector_update_edid_property(connector, edid);
990
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200991 ret = drm_add_edid_modes(connector, edid);
992
993 kfree(edid);
994
995 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900996}
997
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900998static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900999{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001000 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001001
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001002 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1003 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001004 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001005
1006 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1007 return -EINVAL;
1008}
1009
Sean Pauld9716ee2014-01-30 16:19:29 -05001010static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001011 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001012{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001013 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001014 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001015
Rahul Sharma16844fb2013-06-10 14:50:00 +05301016 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1017 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1018 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1019 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001020
Sean Paulf041b252014-01-30 16:19:15 -05001021 ret = mixer_check_mode(mode);
1022 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001023 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001024
Rahul Sharma16844fb2013-06-10 14:50:00 +05301025 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001026 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001027 return MODE_BAD;
1028
1029 return MODE_OK;
1030}
1031
1032static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1033{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001034 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001035
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001036 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001037}
1038
1039static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1040 .get_modes = hdmi_get_modes,
1041 .mode_valid = hdmi_mode_valid,
1042 .best_encoder = hdmi_best_encoder,
1043};
1044
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001045static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001046{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001047 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001048 struct drm_connector *connector = &hdata->connector;
1049 int ret;
1050
Sean Pauld9716ee2014-01-30 16:19:29 -05001051 connector->interlace_allowed = true;
1052 connector->polled = DRM_CONNECTOR_POLL_HPD;
1053
1054 ret = drm_connector_init(hdata->drm_dev, connector,
1055 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1056 if (ret) {
1057 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001058 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001059 }
1060
1061 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001062 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001063 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001064
1065 return 0;
1066}
1067
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001068static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1069 const struct drm_display_mode *mode,
1070 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001071{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001072 struct drm_device *dev = encoder->dev;
1073 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001074 struct drm_display_mode *m;
1075 int mode_ok;
1076
Sean Paulf041b252014-01-30 16:19:15 -05001077 drm_mode_set_crtcinfo(adjusted_mode, 0);
1078
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001079 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1080 if (connector->encoder == encoder)
1081 break;
1082 }
1083
1084 if (connector->encoder != encoder)
1085 return true;
1086
Sean Pauld9716ee2014-01-30 16:19:29 -05001087 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001088
1089 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001090 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001091 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001092
1093 /*
1094 * otherwise, find the most suitable mode among modes and change it
1095 * to adjusted_mode.
1096 */
1097 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001098 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001099
Sean Pauld9716ee2014-01-30 16:19:29 -05001100 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001101 DRM_INFO("desired mode doesn't exist so\n");
1102 DRM_INFO("use the most suitable mode among modes.\n");
1103
1104 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1105 m->hdisplay, m->vdisplay, m->vrefresh);
1106
Sean Paul75626852014-01-30 16:19:16 -05001107 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001108 break;
1109 }
1110 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001111
1112 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001113}
1114
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001115static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001116{
1117 u32 n, cts;
1118
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001119 cts = (freq % 9) ? 27000 : 30000;
1120 n = 128 * freq / (27000000 / cts);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001121
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001122 hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
1123 hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
1124 hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001125 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001126}
1127
1128static void hdmi_audio_init(struct hdmi_context *hdata)
1129{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301130 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001131 u32 data_num, bit_ch, sample_frq;
1132 u32 val;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001133
1134 sample_rate = 44100;
1135 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001136
1137 switch (bits_per_sample) {
1138 case 20:
1139 data_num = 2;
1140 bit_ch = 1;
1141 break;
1142 case 24:
1143 data_num = 3;
1144 bit_ch = 1;
1145 break;
1146 default:
1147 data_num = 1;
1148 bit_ch = 0;
1149 break;
1150 }
1151
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001152 hdmi_reg_acr(hdata, sample_rate);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001153
1154 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1155 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1156 | HDMI_I2S_MUX_ENABLE);
1157
1158 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1159 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1160
1161 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1162
1163 sample_frq = (sample_rate == 44100) ? 0 :
1164 (sample_rate == 48000) ? 2 :
1165 (sample_rate == 32000) ? 3 :
1166 (sample_rate == 96000) ? 0xa : 0x0;
1167
1168 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1169 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1170
1171 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1172 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1173
1174 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1175 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1176 | HDMI_I2S_SEL_LRCK(6));
1177 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1178 | HDMI_I2S_SEL_SDATA2(4));
1179 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1180 | HDMI_I2S_SEL_SDATA2(2));
1181 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1182
1183 /* I2S_CON_1 & 2 */
1184 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1185 | HDMI_I2S_L_CH_LOW_POL);
1186 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1187 | HDMI_I2S_SET_BIT_CH(bit_ch)
1188 | HDMI_I2S_SET_SDATA_BIT(data_num)
1189 | HDMI_I2S_BASIC_FORMAT);
1190
1191 /* Configure register related to CUV information */
1192 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1193 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1194 | HDMI_I2S_COPYRIGHT
1195 | HDMI_I2S_LINEAR_PCM
1196 | HDMI_I2S_CONSUMER_FORMAT);
1197 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1198 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1199 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1200 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1201 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1202 HDMI_I2S_ORG_SMP_FREQ_44_1
1203 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1204 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1205
1206 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1207}
1208
1209static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1210{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001211 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001212 return;
1213
1214 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1215 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1216 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1217}
1218
Rahul Sharmabfa48422014-04-03 20:41:04 +05301219static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001220{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301221 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001222
Rahul Sharmabfa48422014-04-03 20:41:04 +05301223 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1224 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001225
Rahul Sharmabfa48422014-04-03 20:41:04 +05301226 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1227 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001228}
1229
1230static void hdmi_conf_init(struct hdmi_context *hdata)
1231{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301232 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301233
Sean Paul77006a72013-01-16 10:17:20 -05001234 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001235 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1236 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001237
1238 /* choose HDMI mode */
1239 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1240 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301241 /* Apply Video preable and Guard band in HDMI mode only */
1242 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001243 /* disable bluescreen */
1244 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001245
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001246 if (hdata->dvi_mode) {
1247 /* choose DVI mode */
1248 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1249 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1250 hdmi_reg_writeb(hdata, HDMI_CON_2,
1251 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1252 }
1253
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001254 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001255 /* choose bluescreen (fecal) color */
1256 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1257 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1258 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1259
1260 /* enable AVI packet every vsync, fixes purple line problem */
1261 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1262 /* force RGB, look to CEA-861-D, table 7 for more detail */
1263 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1264 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1265
1266 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1267 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1268 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1269 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301270 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1271 infoframe.any.version = HDMI_AVI_VERSION;
1272 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301273 hdmi_reg_infoframe(hdata, &infoframe);
1274
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301275 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1276 infoframe.any.version = HDMI_AUI_VERSION;
1277 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301278 hdmi_reg_infoframe(hdata, &infoframe);
1279
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001280 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001281 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1282 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001283}
1284
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001285static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1286{
1287 int tries;
1288
1289 for (tries = 0; tries < 10; ++tries) {
1290 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1291
1292 if (val & HDMI_PHY_STATUS_READY) {
1293 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1294 return;
1295 }
1296 usleep_range(10, 20);
1297 }
1298
1299 DRM_ERROR("PLL could not reach steady state\n");
1300}
1301
Rahul Sharma16844fb2013-06-10 14:50:00 +05301302static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001303{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001304 struct drm_display_mode *m = &hdata->current_mode;
1305 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001306
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001307 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1308 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1309 (m->htotal << 12) | m->vtotal);
1310
1311 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1312 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1313
1314 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1315 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1316
1317 val = (m->hsync_start - m->hdisplay - 2);
1318 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1319 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1320 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1321
1322 /*
1323 * Quirk requirement for exynos HDMI IP design,
1324 * 2 pixels less than the actual calculation for hsync_start
1325 * and end.
1326 */
1327
1328 /* Following values & calculations differ for different type of modes */
1329 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1330 /* Interlaced Mode */
1331 val = ((m->vsync_end - m->vdisplay) / 2);
1332 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1333 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1334
1335 val = m->vtotal / 2;
1336 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1337 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1338
1339 val = (m->vtotal +
1340 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1341 val |= m->vtotal << 11;
1342 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1343
1344 val = ((m->vtotal / 2) + 7);
1345 val |= ((m->vtotal / 2) + 2) << 12;
1346 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1347
1348 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1349 val |= ((m->htotal / 2) +
1350 (m->hsync_start - m->hdisplay)) << 12;
1351 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1352
1353 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1354 (m->vtotal - m->vdisplay) / 2);
1355 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1356
1357 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1358 } else {
1359 /* Progressive Mode */
1360
1361 val = m->vtotal;
1362 val |= (m->vtotal - m->vdisplay) << 11;
1363 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1364
1365 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1366
1367 val = (m->vsync_end - m->vdisplay);
1368 val |= ((m->vsync_start - m->vdisplay) << 12);
1369 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1370
1371 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1372 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1373 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1374 m->vtotal - m->vdisplay);
1375 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1376 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1377 }
1378
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001379 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001380 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1381 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1382 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1383 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1384 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1385 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1386 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1387 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1388 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1389 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1390 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001391}
1392
Rahul Sharma16844fb2013-06-10 14:50:00 +05301393static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001394{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001395 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001396
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001397 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1398 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1399 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1400 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1401 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1402 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1403 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1404 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1405 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1406
1407 /*
1408 * Quirk requirement for exynos 5 HDMI IP design,
1409 * 2 pixels less than the actual calculation for hsync_start
1410 * and end.
1411 */
1412
1413 /* Following values & calculations differ for different type of modes */
1414 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1415 /* Interlaced Mode */
1416 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1417 (m->vsync_end - m->vdisplay) / 2);
1418 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1419 (m->vsync_start - m->vdisplay) / 2);
1420 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1421 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1422 (m->vtotal - m->vdisplay) / 2);
1423 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1424 m->vtotal - m->vdisplay / 2);
1425 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1426 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1427 (m->vtotal / 2) + 7);
1428 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1429 (m->vtotal / 2) + 2);
1430 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1431 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1432 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1433 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1434 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1435 (m->vtotal - m->vdisplay) / 2);
1436 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1437 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1438 m->vtotal - m->vdisplay / 2);
1439 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1440 (m->vtotal / 2) + 1);
1441 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1442 (m->vtotal / 2) + 1);
1443 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1444 (m->vtotal / 2) + 1);
1445 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1446 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1447 } else {
1448 /* Progressive Mode */
1449 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1450 m->vsync_end - m->vdisplay);
1451 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1452 m->vsync_start - m->vdisplay);
1453 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1454 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1455 m->vtotal - m->vdisplay);
1456 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1457 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1458 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1459 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1460 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1461 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1462 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1463 m->vtotal - m->vdisplay);
1464 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1465 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1466 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1467 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1468 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1469 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1470 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1471 }
1472
1473 /* Following values & calculations are same irrespective of mode type */
1474 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1475 m->hsync_start - m->hdisplay - 2);
1476 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1477 m->hsync_end - m->hdisplay - 2);
1478 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1479 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1480 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1481 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1482 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1483 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1484 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1485 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1486 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1487 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1488 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1489 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1490 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1491 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1492 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1493 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1494 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1495 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001496
1497 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001498 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1499 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1500 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1501 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1502 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1503 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1504 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1505 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1506 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001507}
1508
Rahul Sharma16844fb2013-06-10 14:50:00 +05301509static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001510{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001511 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301512 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001513 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301514 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001515
1516 hdmiphy_wait_for_pll(hdata);
1517
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001518 clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001519
1520 /* enable HDMI and timing generator */
1521 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001522}
1523
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001524static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1525{
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001526 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001527
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001528 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001529 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001530 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001531 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001532 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001533}
1534
1535static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1536{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001537 int ret;
1538 int i;
1539
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001540 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001541 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001542 if (i < 0) {
1543 DRM_ERROR("failed to find hdmiphy conf\n");
1544 return;
1545 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001546
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001547 ret = hdmiphy_reg_write_buf(hdata, 0,
1548 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001549 if (ret) {
1550 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001551 return;
1552 }
1553
Sean Paul09760ea2013-01-14 17:03:20 -05001554 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001555}
1556
1557static void hdmi_conf_apply(struct hdmi_context *hdata)
1558{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001559 hdmiphy_conf_reset(hdata);
1560 hdmiphy_conf_apply(hdata);
1561
Rahul Sharmabfa48422014-04-03 20:41:04 +05301562 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001563 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001564
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001565 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001566
1567 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301568 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001569 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001570
1571 hdmi_regs_dump(hdata, "start");
1572}
1573
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001574static void hdmi_mode_set(struct drm_encoder *encoder,
1575 struct drm_display_mode *mode,
1576 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001577{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001578 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001579 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001580
YoungJun Chocbc4c332013-06-12 10:44:40 +09001581 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1582 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001583 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001584 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001585
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001586 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001587 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001588}
1589
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001590static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001591{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001592 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001593
Andrzej Hajda882a0642015-07-09 16:28:08 +02001594 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001595 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001596
1597 hdata->powered = true;
1598
Sean Paulaf65c802014-01-30 16:19:27 -05001599 pm_runtime_get_sync(hdata->dev);
1600
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001601 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001602 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1603
Rahul Sharma049d34e2014-05-20 10:36:05 +05301604 /* set pmu hdmiphy control bit to enable hdmiphy */
1605 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1606 PMU_HDMI_PHY_ENABLE_BIT, 1);
1607
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001608 clk_prepare_enable(hdata->hdmi);
1609 clk_prepare_enable(hdata->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301610
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001611 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001612}
1613
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001614static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001615{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001616 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001617 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001618 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001619
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001620 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001621 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001622
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001623 /*
1624 * The SFRs of VP and Mixer are updated by Vertical Sync of
1625 * Timing generator which is a part of HDMI so the sequence
1626 * to disable TV Subsystem should be as following,
1627 * VP -> Mixer -> HDMI
1628 *
1629 * Below codes will try to disable Mixer and VP(if used)
1630 * prior to disabling HDMI.
1631 */
1632 if (crtc)
1633 funcs = crtc->helper_private;
1634 if (funcs && funcs->disable)
1635 (*funcs->disable)(crtc);
1636
Rahul Sharmabfa48422014-04-03 20:41:04 +05301637 /* HDMI System Disable */
1638 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1639
Sean Paul724fd142014-05-09 15:05:10 +09001640 cancel_delayed_work(&hdata->hotplug_work);
1641
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001642 clk_disable_unprepare(hdata->sclk_hdmi);
1643 clk_disable_unprepare(hdata->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301644
1645 /* reset pmu hdmiphy control bit to disable hdmiphy */
1646 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1647 PMU_HDMI_PHY_ENABLE_BIT, 0);
1648
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001649 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001650
Sean Paulaf65c802014-01-30 16:19:27 -05001651 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001652
1653 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001654}
1655
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001656static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001657 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001658 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001659 .enable = hdmi_enable,
1660 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001661};
1662
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001663static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1664 .destroy = drm_encoder_cleanup,
1665};
1666
Sean Paul724fd142014-05-09 15:05:10 +09001667static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001668{
Sean Paul724fd142014-05-09 15:05:10 +09001669 struct hdmi_context *hdata;
1670
1671 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001672
Sean Paul45517892014-01-30 16:19:05 -05001673 if (hdata->drm_dev)
1674 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001675}
1676
1677static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1678{
1679 struct hdmi_context *hdata = arg;
1680
1681 mod_delayed_work(system_wq, &hdata->hotplug_work,
1682 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001683
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001684 return IRQ_HANDLED;
1685}
1686
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001687static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001688{
1689 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001690 int i, ret;
1691
1692 DRM_DEBUG_KMS("HDMI resource init\n");
1693
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001694 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1695 if (IS_ERR(hdata->hpd_gpio)) {
1696 DRM_ERROR("cannot get hpd gpio property\n");
1697 return PTR_ERR(hdata->hpd_gpio);
1698 }
1699
1700 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1701 if (hdata->irq < 0) {
1702 DRM_ERROR("failed to get GPIO irq\n");
1703 return hdata->irq;
1704 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001705 /* get clocks, power */
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001706 hdata->hdmi = devm_clk_get(dev, "hdmi");
1707 if (IS_ERR(hdata->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001708 DRM_ERROR("failed to get clock 'hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001709 ret = PTR_ERR(hdata->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001710 goto fail;
1711 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001712 hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
1713 if (IS_ERR(hdata->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001714 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001715 ret = PTR_ERR(hdata->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001716 goto fail;
1717 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001718 hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
1719 if (IS_ERR(hdata->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001720 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001721 ret = PTR_ERR(hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001722 goto fail;
1723 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001724 hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
1725 if (IS_ERR(hdata->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001726 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001727 ret = PTR_ERR(hdata->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001728 goto fail;
1729 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001730 hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1731 if (IS_ERR(hdata->mout_hdmi)) {
Rahul Sharma59956d32013-06-11 12:24:03 +05301732 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001733 ret = PTR_ERR(hdata->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301734 goto fail;
1735 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001736
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001737 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001738
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001739 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001740 hdata->regul_bulk[i].supply = supply[i];
1741 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001742 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001743 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001744 if (ret) {
1745 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001746 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001747 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001748
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001749 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001750
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001751 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001752 return 0;
1753
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001754 if (IS_ERR(hdata->reg_hdmi_en))
1755 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001756
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001757 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001758 if (ret)
1759 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001760
Inki Daedf5225b2014-05-29 18:28:02 +09001761 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001762fail:
1763 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001764 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001765}
1766
Rahul Sharma22c4f422012-10-04 20:48:55 +05301767static struct of_device_id hdmi_match_types[] = {
1768 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001769 .compatible = "samsung,exynos4210-hdmi",
1770 .data = &exynos4210_hdmi_driver_data,
1771 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301772 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001773 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301774 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301775 .compatible = "samsung,exynos5420-hdmi",
1776 .data = &exynos5420_hdmi_driver_data,
1777 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301778 /* end node */
1779 }
1780};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001781MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301782
Inki Daef37cd5e2014-05-09 14:25:20 +09001783static int hdmi_bind(struct device *dev, struct device *master, void *data)
1784{
1785 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001786 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001787 struct drm_encoder *encoder = &hdata->encoder;
1788 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001789
Inki Daef37cd5e2014-05-09 14:25:20 +09001790 hdata->drm_dev = drm_dev;
1791
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001792 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1793 EXYNOS_DISPLAY_TYPE_HDMI);
1794 if (pipe < 0)
1795 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001796
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001797 encoder->possible_crtcs = 1 << pipe;
1798
1799 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1800
1801 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1802 DRM_MODE_ENCODER_TMDS);
1803
1804 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1805
1806 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001807 if (ret) {
1808 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001809 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001810 return ret;
1811 }
1812
1813 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001814}
1815
1816static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1817{
Inki Daef37cd5e2014-05-09 14:25:20 +09001818}
1819
1820static const struct component_ops hdmi_component_ops = {
1821 .bind = hdmi_bind,
1822 .unbind = hdmi_unbind,
1823};
1824
Inki Daee2a562d2014-05-09 16:46:10 +09001825static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1826{
1827 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1828 struct device_node *np;
1829
1830 np = of_find_compatible_node(NULL, NULL, compatible_str);
1831 if (np)
1832 return of_get_next_parent(np);
1833
1834 return NULL;
1835}
1836
1837static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1838{
1839 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1840
1841 return of_find_compatible_node(NULL, NULL, compatible_str);
1842}
1843
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001844static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001845{
Inki Daef37cd5e2014-05-09 14:25:20 +09001846 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001847 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001848 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001849 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001850 struct resource *res;
1851 int ret;
1852
Andrzej Hajda930865f2014-11-17 09:54:20 +01001853 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1854 if (!hdata)
1855 return -ENOMEM;
1856
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001857 match = of_match_device(hdmi_match_types, dev);
1858 if (!match)
1859 return -ENODEV;
1860
1861 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001862
Andrzej Hajda930865f2014-11-17 09:54:20 +01001863 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001864
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001865 hdata->dev = dev;
1866
1867 ret = hdmi_resources_init(hdata);
1868 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301869 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001870 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001871 }
1872
1873 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001874 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001875 if (IS_ERR(hdata->regs)) {
1876 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001877 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001878 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001879
Inki Daee2a562d2014-05-09 16:46:10 +09001880 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1881 if (ddc_node)
1882 goto out_get_ddc_adpt;
1883
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001884 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001885 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1886 if (!ddc_node) {
1887 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001888 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001889 }
Inki Daee2a562d2014-05-09 16:46:10 +09001890
1891out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001892 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1893 if (!hdata->ddc_adpt) {
1894 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001895 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001896 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001897
Inki Daee2a562d2014-05-09 16:46:10 +09001898 phy_node = hdmi_legacy_phy_dt_binding(dev);
1899 if (phy_node)
1900 goto out_get_phy_port;
1901
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001902 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001903 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1904 if (!phy_node) {
1905 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1906 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001907 goto err_ddc;
1908 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001909
Inki Daee2a562d2014-05-09 16:46:10 +09001910out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001911 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001912 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1913 if (!hdata->regs_hdmiphy) {
1914 DRM_ERROR("failed to ioremap hdmi phy\n");
1915 ret = -ENOMEM;
1916 goto err_ddc;
1917 }
1918 } else {
1919 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1920 if (!hdata->hdmiphy_port) {
1921 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001922 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001923 goto err_ddc;
1924 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001925 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001926
Sean Paul724fd142014-05-09 15:05:10 +09001927 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1928
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001929 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001930 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001931 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001932 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001933 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001934 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001935 goto err_hdmiphy;
1936 }
1937
Rahul Sharma049d34e2014-05-20 10:36:05 +05301938 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
1939 "samsung,syscon-phandle");
1940 if (IS_ERR(hdata->pmureg)) {
1941 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001942 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05301943 goto err_hdmiphy;
1944 }
1945
Sean Paulaf65c802014-01-30 16:19:27 -05001946 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001947
Inki Daedf5225b2014-05-29 18:28:02 +09001948 ret = component_add(&pdev->dev, &hdmi_component_ops);
1949 if (ret)
1950 goto err_disable_pm_runtime;
1951
1952 return ret;
1953
1954err_disable_pm_runtime:
1955 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001956
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001957err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09001958 if (hdata->hdmiphy_port)
1959 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001960err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001961 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001962
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001963 return ret;
1964}
1965
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001966static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001967{
Andrzej Hajda930865f2014-11-17 09:54:20 +01001968 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001969
Sean Paul724fd142014-05-09 15:05:10 +09001970 cancel_delayed_work_sync(&hdata->hotplug_work);
1971
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02001972 component_del(&pdev->dev, &hdmi_component_ops);
1973
1974 pm_runtime_disable(&pdev->dev);
1975
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001976 if (!IS_ERR(hdata->reg_hdmi_en))
1977 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001978
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09001979 if (hdata->hdmiphy_port)
1980 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001981
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02001982 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001983
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984 return 0;
1985}
1986
1987struct platform_driver hdmi_driver = {
1988 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001989 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001990 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301991 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001992 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05301993 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994 },
1995};