blob: 8905f082ec657a81fd8e2387ffa0a951875c42ac [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 *
Andrzej Hajda5eefadb2016-01-14 14:28:20 +090010 * 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
Seung-Woo Kimd8408322011-12-21 17:39:39 +090013 * 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
Andrzej Hajda5eefadb2016-01-14 14:28:20 +090052#define HDMI_AVI_LENGTH 0x0d
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053
54/* AUI header info */
Andrzej Hajda5eefadb2016-01-14 14:28:20 +090055#define HDMI_AUI_VERSION 0x01
56#define HDMI_AUI_LENGTH 0x0a
57
58/* AVI active format aspect ratio */
59#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x08
60#define AVI_4_3_CENTER_RATIO 0x09
61#define AVI_16_9_CENTER_RATIO 0x0a
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053062
Rahul Sharma5a325072012-10-04 20:48:54 +053063enum hdmi_type {
64 HDMI_TYPE13,
65 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020066 HDMI_TYPE_COUNT
67};
68
69#define HDMI_MAPPED_BASE 0xffff0000
70
71enum hdmi_mapped_regs {
72 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
73 HDMI_PHY_RSTOUT,
74 HDMI_ACR_CON,
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020075 HDMI_ACR_MCTS0,
76 HDMI_ACR_CTS0,
77 HDMI_ACR_N0
Andrzej Hajda633d00b2015-09-25 14:48:16 +020078};
79
80static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
81 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
82 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
83 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020084 { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
85 { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
86 { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
Rahul Sharma5a325072012-10-04 20:48:54 +053087};
88
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020089static const char * const supply[] = {
90 "vdd",
91 "vdd_osc",
92 "vdd_pll",
93};
94
Andrzej Hajda65e98032015-11-02 14:16:41 +010095struct hdmiphy_config {
96 int pixel_clock;
97 u8 conf[32];
98};
99
100struct hdmiphy_configs {
101 int count;
102 const struct hdmiphy_config *data;
103};
104
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900105struct string_array_spec {
106 int count;
107 const char * const *data;
108};
109
110#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a }
111
Inki Daebfe4e842014-03-06 14:18:17 +0900112struct hdmi_driver_data {
113 unsigned int type;
114 unsigned int is_apb_phy:1;
Andrzej Hajda65e98032015-11-02 14:16:41 +0100115 struct hdmiphy_configs phy_confs;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900116 struct string_array_spec clk_gates;
117 /*
118 * Array of triplets (p_off, p_on, clock), where p_off and p_on are
119 * required parents of clock when HDMI-PHY is respectively off or on.
120 */
121 struct string_array_spec clk_muxes;
Inki Daebfe4e842014-03-06 14:18:17 +0900122};
123
Joonyoung Shim590f4182012-03-16 18:47:14 +0900124struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300125 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900126 struct device *dev;
127 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500128 struct drm_connector connector;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900129 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900130 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900131 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530132 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200133 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200134 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900135
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200136 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900137 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200138 struct i2c_client *hdmiphy_port;
139 struct i2c_adapter *ddc_adpt;
Gustavo Padovanf28464c2015-11-02 20:39:18 +0900140 struct gpio_desc *hpd_gpio;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200141 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530142 struct regmap *pmureg;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900143 struct clk **clk_gates;
144 struct clk **clk_muxes;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200145 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
146 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900147};
148
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300149static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100150{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900151 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100152}
153
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200154static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
155{
156 return container_of(c, struct hdmi_context, connector);
157}
158
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900159static const struct hdmiphy_config hdmiphy_v13_configs[] = {
160 {
161 .pixel_clock = 27000000,
162 .conf = {
163 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
164 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
165 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200166 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900167 },
168 },
169 {
170 .pixel_clock = 27027000,
171 .conf = {
172 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
173 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
174 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200175 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900176 },
177 },
178 {
179 .pixel_clock = 74176000,
180 .conf = {
181 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
182 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
183 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200184 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900185 },
186 },
187 {
188 .pixel_clock = 74250000,
189 .conf = {
190 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
191 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
192 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200193 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900194 },
195 },
196 {
197 .pixel_clock = 148500000,
198 .conf = {
199 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
200 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
201 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200202 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900203 },
204 },
205};
206
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500207static const struct hdmiphy_config hdmiphy_v14_configs[] = {
208 {
209 .pixel_clock = 25200000,
210 .conf = {
211 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
212 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
213 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
214 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
215 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900216 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500217 {
218 .pixel_clock = 27000000,
219 .conf = {
220 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
221 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
222 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
223 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
224 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900225 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500226 {
227 .pixel_clock = 27027000,
228 .conf = {
229 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
230 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
231 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200232 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500233 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900234 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500235 {
236 .pixel_clock = 36000000,
237 .conf = {
238 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
239 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
240 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
241 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
242 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900243 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500244 {
245 .pixel_clock = 40000000,
246 .conf = {
247 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
248 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
249 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
250 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
251 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900252 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500253 {
254 .pixel_clock = 65000000,
255 .conf = {
256 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
257 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
258 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
259 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
260 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900261 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500262 {
Shirish Se1d883c2014-03-13 14:28:27 +0900263 .pixel_clock = 71000000,
264 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530265 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
266 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
267 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900268 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
269 },
270 },
271 {
272 .pixel_clock = 73250000,
273 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530274 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
275 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
276 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900277 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
278 },
279 },
280 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500281 .pixel_clock = 74176000,
282 .conf = {
283 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
284 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
285 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
286 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
287 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900288 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500289 {
290 .pixel_clock = 74250000,
291 .conf = {
292 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
293 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
294 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200295 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500296 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900297 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 {
299 .pixel_clock = 83500000,
300 .conf = {
301 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
302 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
303 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
304 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
305 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900306 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500307 {
308 .pixel_clock = 106500000,
309 .conf = {
310 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
311 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
312 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
313 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
314 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900315 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500316 {
317 .pixel_clock = 108000000,
318 .conf = {
319 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
320 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
321 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
322 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
323 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900324 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 {
Shirish Se1d883c2014-03-13 14:28:27 +0900326 .pixel_clock = 115500000,
327 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530328 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
329 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
330 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900331 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
332 },
333 },
334 {
335 .pixel_clock = 119000000,
336 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530337 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
338 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
339 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900340 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
341 },
342 },
343 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500344 .pixel_clock = 146250000,
345 .conf = {
346 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
347 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
348 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
349 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
350 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900351 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500352 {
353 .pixel_clock = 148500000,
354 .conf = {
355 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
356 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
357 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200358 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500359 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900360 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900361};
362
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530363static const struct hdmiphy_config hdmiphy_5420_configs[] = {
364 {
365 .pixel_clock = 25200000,
366 .conf = {
367 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
368 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
369 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
370 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
371 },
372 },
373 {
374 .pixel_clock = 27000000,
375 .conf = {
376 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
377 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
378 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
379 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
380 },
381 },
382 {
383 .pixel_clock = 27027000,
384 .conf = {
385 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
386 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
387 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
388 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
389 },
390 },
391 {
392 .pixel_clock = 36000000,
393 .conf = {
394 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
395 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
396 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
397 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
398 },
399 },
400 {
401 .pixel_clock = 40000000,
402 .conf = {
403 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
404 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
405 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
406 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
407 },
408 },
409 {
410 .pixel_clock = 65000000,
411 .conf = {
412 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
413 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
414 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
415 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
416 },
417 },
418 {
419 .pixel_clock = 71000000,
420 .conf = {
421 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
422 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
423 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
424 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
425 },
426 },
427 {
428 .pixel_clock = 73250000,
429 .conf = {
430 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
431 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
432 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
433 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
434 },
435 },
436 {
437 .pixel_clock = 74176000,
438 .conf = {
439 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
440 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
441 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
442 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
443 },
444 },
445 {
446 .pixel_clock = 74250000,
447 .conf = {
448 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
449 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
450 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
451 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
452 },
453 },
454 {
455 .pixel_clock = 83500000,
456 .conf = {
457 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
458 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
459 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
460 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
461 },
462 },
463 {
464 .pixel_clock = 88750000,
465 .conf = {
466 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
467 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
468 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
469 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
470 },
471 },
472 {
473 .pixel_clock = 106500000,
474 .conf = {
475 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
476 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
477 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
478 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
479 },
480 },
481 {
482 .pixel_clock = 108000000,
483 .conf = {
484 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
485 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
486 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
487 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
488 },
489 },
490 {
491 .pixel_clock = 115500000,
492 .conf = {
493 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
494 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
495 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
496 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
497 },
498 },
499 {
500 .pixel_clock = 146250000,
501 .conf = {
502 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
503 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
504 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
505 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
506 },
507 },
508 {
509 .pixel_clock = 148500000,
510 .conf = {
511 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
512 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
513 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
514 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
515 },
516 },
517};
518
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100519static const char * const hdmi_clk_gates4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900520 "hdmi", "sclk_hdmi"
521};
522
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100523static const char * const hdmi_clk_muxes4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900524 "sclk_pixel", "sclk_hdmiphy", "mout_hdmi"
525};
526
Andrzej Hajda5eefadb2016-01-14 14:28:20 +0900527static const struct hdmi_driver_data exynos4210_hdmi_driver_data = {
528 .type = HDMI_TYPE13,
529 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900530 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
531 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530532};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900533
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100534static const struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900535 .type = HDMI_TYPE14,
Andrzej Hajda65e98032015-11-02 14:16:41 +0100536 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900537 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
538 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900539};
540
Andrzej Hajda5eefadb2016-01-14 14:28:20 +0900541static const struct hdmi_driver_data exynos5420_hdmi_driver_data = {
542 .type = HDMI_TYPE14,
543 .is_apb_phy = 1,
544 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900545 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
546 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200547};
548
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200549static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
550{
551 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
552 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
553 return reg_id;
554}
555
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900556static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
557{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200558 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900559}
560
561static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
562 u32 reg_id, u8 value)
563{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200564 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565}
566
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200567static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
568 int bytes, u32 val)
569{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200570 reg_id = hdmi_map_reg(hdata, reg_id);
571
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200572 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200573 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200574 val >>= 8;
575 reg_id += 4;
576 }
577}
578
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900579static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
580 u32 reg_id, u32 value, u32 mask)
581{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200582 u32 old;
583
584 reg_id = hdmi_map_reg(hdata, reg_id);
585 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900586 value = (value & mask) | (old & ~mask);
587 writel(value, hdata->regs + reg_id);
588}
589
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900590static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
591 u32 reg_offset, const u8 *buf, u32 len)
592{
593 if ((reg_offset + len) > 32)
594 return -EINVAL;
595
596 if (hdata->hdmiphy_port) {
597 int ret;
598
599 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
600 if (ret == len)
601 return 0;
602 return ret;
603 } else {
604 int i;
605 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200606 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900607 ((reg_offset + i)<<2));
608 return 0;
609 }
610}
611
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900612static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900613{
614#define DUMPREG(reg_id) \
615 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
616 readl(hdata->regs + reg_id))
617 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
618 DUMPREG(HDMI_INTC_FLAG);
619 DUMPREG(HDMI_INTC_CON);
620 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900621 DUMPREG(HDMI_V13_PHY_RSTOUT);
622 DUMPREG(HDMI_V13_PHY_VPLL);
623 DUMPREG(HDMI_V13_PHY_CMU);
624 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900625
626 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
627 DUMPREG(HDMI_CON_0);
628 DUMPREG(HDMI_CON_1);
629 DUMPREG(HDMI_CON_2);
630 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900631 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900632 DUMPREG(HDMI_STATUS_EN);
633 DUMPREG(HDMI_HPD);
634 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900635 DUMPREG(HDMI_V13_HPD_GEN);
636 DUMPREG(HDMI_V13_DC_CONTROL);
637 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900638
639 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
640 DUMPREG(HDMI_H_BLANK_0);
641 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900642 DUMPREG(HDMI_V13_V_BLANK_0);
643 DUMPREG(HDMI_V13_V_BLANK_1);
644 DUMPREG(HDMI_V13_V_BLANK_2);
645 DUMPREG(HDMI_V13_H_V_LINE_0);
646 DUMPREG(HDMI_V13_H_V_LINE_1);
647 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900648 DUMPREG(HDMI_VSYNC_POL);
649 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900650 DUMPREG(HDMI_V13_V_BLANK_F_0);
651 DUMPREG(HDMI_V13_V_BLANK_F_1);
652 DUMPREG(HDMI_V13_V_BLANK_F_2);
653 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
654 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
655 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
656 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
657 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
658 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
659 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
660 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
661 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
662 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
663 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
664 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900665
666 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
667 DUMPREG(HDMI_TG_CMD);
668 DUMPREG(HDMI_TG_H_FSZ_L);
669 DUMPREG(HDMI_TG_H_FSZ_H);
670 DUMPREG(HDMI_TG_HACT_ST_L);
671 DUMPREG(HDMI_TG_HACT_ST_H);
672 DUMPREG(HDMI_TG_HACT_SZ_L);
673 DUMPREG(HDMI_TG_HACT_SZ_H);
674 DUMPREG(HDMI_TG_V_FSZ_L);
675 DUMPREG(HDMI_TG_V_FSZ_H);
676 DUMPREG(HDMI_TG_VSYNC_L);
677 DUMPREG(HDMI_TG_VSYNC_H);
678 DUMPREG(HDMI_TG_VSYNC2_L);
679 DUMPREG(HDMI_TG_VSYNC2_H);
680 DUMPREG(HDMI_TG_VACT_ST_L);
681 DUMPREG(HDMI_TG_VACT_ST_H);
682 DUMPREG(HDMI_TG_VACT_SZ_L);
683 DUMPREG(HDMI_TG_VACT_SZ_H);
684 DUMPREG(HDMI_TG_FIELD_CHG_L);
685 DUMPREG(HDMI_TG_FIELD_CHG_H);
686 DUMPREG(HDMI_TG_VACT_ST2_L);
687 DUMPREG(HDMI_TG_VACT_ST2_H);
688 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
689 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
690 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
691 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
692 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
693 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
694 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
695 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
696#undef DUMPREG
697}
698
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900699static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
700{
701 int i;
702
703#define DUMPREG(reg_id) \
704 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
705 readl(hdata->regs + reg_id))
706
707 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
708 DUMPREG(HDMI_INTC_CON);
709 DUMPREG(HDMI_INTC_FLAG);
710 DUMPREG(HDMI_HPD_STATUS);
711 DUMPREG(HDMI_INTC_CON_1);
712 DUMPREG(HDMI_INTC_FLAG_1);
713 DUMPREG(HDMI_PHY_STATUS_0);
714 DUMPREG(HDMI_PHY_STATUS_PLL);
715 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200716 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900717 DUMPREG(HDMI_PHY_VPLL);
718 DUMPREG(HDMI_PHY_CMU);
719 DUMPREG(HDMI_CORE_RSTOUT);
720
721 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
722 DUMPREG(HDMI_CON_0);
723 DUMPREG(HDMI_CON_1);
724 DUMPREG(HDMI_CON_2);
725 DUMPREG(HDMI_SYS_STATUS);
726 DUMPREG(HDMI_PHY_STATUS_0);
727 DUMPREG(HDMI_STATUS_EN);
728 DUMPREG(HDMI_HPD);
729 DUMPREG(HDMI_MODE_SEL);
730 DUMPREG(HDMI_ENC_EN);
731 DUMPREG(HDMI_DC_CONTROL);
732 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
733
734 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
735 DUMPREG(HDMI_H_BLANK_0);
736 DUMPREG(HDMI_H_BLANK_1);
737 DUMPREG(HDMI_V2_BLANK_0);
738 DUMPREG(HDMI_V2_BLANK_1);
739 DUMPREG(HDMI_V1_BLANK_0);
740 DUMPREG(HDMI_V1_BLANK_1);
741 DUMPREG(HDMI_V_LINE_0);
742 DUMPREG(HDMI_V_LINE_1);
743 DUMPREG(HDMI_H_LINE_0);
744 DUMPREG(HDMI_H_LINE_1);
745 DUMPREG(HDMI_HSYNC_POL);
746
747 DUMPREG(HDMI_VSYNC_POL);
748 DUMPREG(HDMI_INT_PRO_MODE);
749 DUMPREG(HDMI_V_BLANK_F0_0);
750 DUMPREG(HDMI_V_BLANK_F0_1);
751 DUMPREG(HDMI_V_BLANK_F1_0);
752 DUMPREG(HDMI_V_BLANK_F1_1);
753
754 DUMPREG(HDMI_H_SYNC_START_0);
755 DUMPREG(HDMI_H_SYNC_START_1);
756 DUMPREG(HDMI_H_SYNC_END_0);
757 DUMPREG(HDMI_H_SYNC_END_1);
758
759 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
760 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
761 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
762 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
763
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
768
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
773
774 DUMPREG(HDMI_V_BLANK_F2_0);
775 DUMPREG(HDMI_V_BLANK_F2_1);
776 DUMPREG(HDMI_V_BLANK_F3_0);
777 DUMPREG(HDMI_V_BLANK_F3_1);
778 DUMPREG(HDMI_V_BLANK_F4_0);
779 DUMPREG(HDMI_V_BLANK_F4_1);
780 DUMPREG(HDMI_V_BLANK_F5_0);
781 DUMPREG(HDMI_V_BLANK_F5_1);
782
783 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
784 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
785 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
786 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
787 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
788 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
789 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
790 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
791
792 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
793 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
794 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
795 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
796 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
797 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
798 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
799 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
800
801 DUMPREG(HDMI_VACT_SPACE_1_0);
802 DUMPREG(HDMI_VACT_SPACE_1_1);
803 DUMPREG(HDMI_VACT_SPACE_2_0);
804 DUMPREG(HDMI_VACT_SPACE_2_1);
805 DUMPREG(HDMI_VACT_SPACE_3_0);
806 DUMPREG(HDMI_VACT_SPACE_3_1);
807 DUMPREG(HDMI_VACT_SPACE_4_0);
808 DUMPREG(HDMI_VACT_SPACE_4_1);
809 DUMPREG(HDMI_VACT_SPACE_5_0);
810 DUMPREG(HDMI_VACT_SPACE_5_1);
811 DUMPREG(HDMI_VACT_SPACE_6_0);
812 DUMPREG(HDMI_VACT_SPACE_6_1);
813
814 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
815 DUMPREG(HDMI_TG_CMD);
816 DUMPREG(HDMI_TG_H_FSZ_L);
817 DUMPREG(HDMI_TG_H_FSZ_H);
818 DUMPREG(HDMI_TG_HACT_ST_L);
819 DUMPREG(HDMI_TG_HACT_ST_H);
820 DUMPREG(HDMI_TG_HACT_SZ_L);
821 DUMPREG(HDMI_TG_HACT_SZ_H);
822 DUMPREG(HDMI_TG_V_FSZ_L);
823 DUMPREG(HDMI_TG_V_FSZ_H);
824 DUMPREG(HDMI_TG_VSYNC_L);
825 DUMPREG(HDMI_TG_VSYNC_H);
826 DUMPREG(HDMI_TG_VSYNC2_L);
827 DUMPREG(HDMI_TG_VSYNC2_H);
828 DUMPREG(HDMI_TG_VACT_ST_L);
829 DUMPREG(HDMI_TG_VACT_ST_H);
830 DUMPREG(HDMI_TG_VACT_SZ_L);
831 DUMPREG(HDMI_TG_VACT_SZ_H);
832 DUMPREG(HDMI_TG_FIELD_CHG_L);
833 DUMPREG(HDMI_TG_FIELD_CHG_H);
834 DUMPREG(HDMI_TG_VACT_ST2_L);
835 DUMPREG(HDMI_TG_VACT_ST2_H);
836 DUMPREG(HDMI_TG_VACT_ST3_L);
837 DUMPREG(HDMI_TG_VACT_ST3_H);
838 DUMPREG(HDMI_TG_VACT_ST4_L);
839 DUMPREG(HDMI_TG_VACT_ST4_H);
840 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
841 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
842 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
843 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
844 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
845 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
846 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
847 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
848 DUMPREG(HDMI_TG_3D);
849
850 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
851 DUMPREG(HDMI_AVI_CON);
852 DUMPREG(HDMI_AVI_HEADER0);
853 DUMPREG(HDMI_AVI_HEADER1);
854 DUMPREG(HDMI_AVI_HEADER2);
855 DUMPREG(HDMI_AVI_CHECK_SUM);
856 DUMPREG(HDMI_VSI_CON);
857 DUMPREG(HDMI_VSI_HEADER0);
858 DUMPREG(HDMI_VSI_HEADER1);
859 DUMPREG(HDMI_VSI_HEADER2);
860 for (i = 0; i < 7; ++i)
861 DUMPREG(HDMI_VSI_DATA(i));
862
863#undef DUMPREG
864}
865
866static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
867{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200868 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900869 hdmi_v13_regs_dump(hdata, prefix);
870 else
871 hdmi_v14_regs_dump(hdata, prefix);
872}
873
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900874static int hdmi_clk_enable_gates(struct hdmi_context *hdata)
875{
876 int i, ret;
877
878 for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) {
879 ret = clk_prepare_enable(hdata->clk_gates[i]);
880 if (!ret)
881 continue;
882
883 dev_err(hdata->dev, "Cannot enable clock '%s', %d\n",
884 hdata->drv_data->clk_gates.data[i], ret);
885 while (i--)
886 clk_disable_unprepare(hdata->clk_gates[i]);
887 return ret;
888 }
889
890 return 0;
891}
892
893static void hdmi_clk_disable_gates(struct hdmi_context *hdata)
894{
895 int i = hdata->drv_data->clk_gates.count;
896
897 while (i--)
898 clk_disable_unprepare(hdata->clk_gates[i]);
899}
900
901static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
902{
903 struct device *dev = hdata->dev;
904 int ret = 0;
905 int i;
906
907 for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) {
908 struct clk **c = &hdata->clk_muxes[i];
909
910 ret = clk_set_parent(c[2], c[to_phy]);
911 if (!ret)
912 continue;
913
914 dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n",
915 hdata->drv_data->clk_muxes.data[i + 2],
916 hdata->drv_data->clk_muxes.data[i + to_phy], ret);
917 }
918
919 return ret;
920}
921
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530922static u8 hdmi_chksum(struct hdmi_context *hdata,
923 u32 start, u8 len, u32 hdr_sum)
924{
925 int i;
926
927 /* hdr_sum : header0 + header1 + header2
928 * start : start address of packet byte1
929 * len : packet bytes - 1 */
930 for (i = 0; i < len; ++i)
931 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
932
933 /* return 2's complement of 8 bit hdr_sum */
934 return (u8)(~(hdr_sum & 0xff) + 1);
935}
936
937static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530938 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530939{
940 u32 hdr_sum;
941 u8 chksum;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200942 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530943
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530944 if (hdata->dvi_mode) {
945 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
946 HDMI_VSI_CON_DO_NOT_TRANSMIT);
947 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
948 HDMI_AVI_CON_DO_NOT_TRANSMIT);
949 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
950 return;
951 }
952
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530953 switch (infoframe->any.type) {
954 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530955 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530956 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
957 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
958 infoframe->any.version);
959 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
960 hdr_sum = infoframe->any.type + infoframe->any.version +
961 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530962
963 /* Output format zero hardcoded ,RGB YBCR selection */
964 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
965 AVI_ACTIVE_FORMAT_VALID |
966 AVI_UNDERSCANNED_DISPLAY_VALID);
967
Shirish S46154152014-03-13 10:58:28 +0530968 /*
969 * Set the aspect ratio as per the mode, mentioned in
970 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
971 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200972 ar = hdata->current_mode.picture_aspect_ratio;
973 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530974 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200975 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530976 break;
977 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200978 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530979 break;
980 case HDMI_PICTURE_ASPECT_NONE:
981 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200982 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530983 break;
984 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200985 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530986
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200987 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530988
989 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530990 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530991 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
992 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
993 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530994 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530995 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530996 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
997 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
998 infoframe->any.version);
999 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1000 hdr_sum = infoframe->any.type + infoframe->any.version +
1001 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301002 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301003 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301004 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1005 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1006 break;
1007 default:
1008 break;
1009 }
1010}
1011
Sean Pauld9716ee2014-01-30 16:19:29 -05001012static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1013 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001014{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001015 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -05001016
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001017 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001018 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301019
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001020 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001021}
1022
Sean Pauld9716ee2014-01-30 16:19:29 -05001023static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001024{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001025 drm_connector_unregister(connector);
1026 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001027}
1028
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001029static const struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001030 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001031 .fill_modes = drm_helper_probe_single_connector_modes,
1032 .detect = hdmi_detect,
1033 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001034 .reset = drm_atomic_helper_connector_reset,
1035 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1036 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001037};
1038
1039static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001040{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001041 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001043 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001044
Inki Dae8fa04aa2014-03-13 16:38:31 +09001045 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001046 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001047
Inki Dae8fa04aa2014-03-13 16:38:31 +09001048 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001049 if (!edid)
1050 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001051
Sean Pauld9716ee2014-01-30 16:19:29 -05001052 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001053 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1054 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001055 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001056
Sean Pauld9716ee2014-01-30 16:19:29 -05001057 drm_mode_connector_update_edid_property(connector, edid);
1058
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001059 ret = drm_add_edid_modes(connector, edid);
1060
1061 kfree(edid);
1062
1063 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001064}
1065
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001066static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001067{
Andrzej Hajda65e98032015-11-02 14:16:41 +01001068 const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001069 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001070
Andrzej Hajda65e98032015-11-02 14:16:41 +01001071 for (i = 0; i < confs->count; i++)
1072 if (confs->data[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001073 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001074
1075 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1076 return -EINVAL;
1077}
1078
Sean Pauld9716ee2014-01-30 16:19:29 -05001079static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001080 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001081{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001082 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001083 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001084
Rahul Sharma16844fb2013-06-10 14:50:00 +05301085 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1086 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1087 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1088 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001089
Rahul Sharma16844fb2013-06-10 14:50:00 +05301090 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001091 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001092 return MODE_BAD;
1093
1094 return MODE_OK;
1095}
1096
1097static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1098{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001099 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001100
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001101 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001102}
1103
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001104static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001105 .get_modes = hdmi_get_modes,
1106 .mode_valid = hdmi_mode_valid,
1107 .best_encoder = hdmi_best_encoder,
1108};
1109
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001110static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001111{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001112 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001113 struct drm_connector *connector = &hdata->connector;
1114 int ret;
1115
Sean Pauld9716ee2014-01-30 16:19:29 -05001116 connector->interlace_allowed = true;
1117 connector->polled = DRM_CONNECTOR_POLL_HPD;
1118
1119 ret = drm_connector_init(hdata->drm_dev, connector,
1120 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1121 if (ret) {
1122 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001123 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001124 }
1125
1126 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001127 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001128 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001129
1130 return 0;
1131}
1132
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001133static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1134 const struct drm_display_mode *mode,
1135 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001136{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001137 struct drm_device *dev = encoder->dev;
1138 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001139 struct drm_display_mode *m;
1140 int mode_ok;
1141
Sean Paulf041b252014-01-30 16:19:15 -05001142 drm_mode_set_crtcinfo(adjusted_mode, 0);
1143
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001144 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1145 if (connector->encoder == encoder)
1146 break;
1147 }
1148
1149 if (connector->encoder != encoder)
1150 return true;
1151
Sean Pauld9716ee2014-01-30 16:19:29 -05001152 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001153
Sean Pauld9716ee2014-01-30 16:19:29 -05001154 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001155 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001156
1157 /*
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001158 * Find the most suitable mode and copy it to adjusted_mode.
Sean Paulf041b252014-01-30 16:19:15 -05001159 */
1160 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001161 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001162
Sean Pauld9716ee2014-01-30 16:19:29 -05001163 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001164 DRM_INFO("desired mode doesn't exist so\n");
1165 DRM_INFO("use the most suitable mode among modes.\n");
1166
1167 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1168 m->hdisplay, m->vdisplay, m->vrefresh);
1169
Sean Paul75626852014-01-30 16:19:16 -05001170 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001171 break;
1172 }
1173 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001174
1175 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001176}
1177
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001178static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001179{
1180 u32 n, cts;
1181
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001182 cts = (freq % 9) ? 27000 : 30000;
1183 n = 128 * freq / (27000000 / cts);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001184
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001185 hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
1186 hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
1187 hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001188 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001189}
1190
1191static void hdmi_audio_init(struct hdmi_context *hdata)
1192{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301193 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001194 u32 data_num, bit_ch, sample_frq;
1195 u32 val;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001196
1197 sample_rate = 44100;
1198 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001199
1200 switch (bits_per_sample) {
1201 case 20:
1202 data_num = 2;
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001203 bit_ch = 1;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001204 break;
1205 case 24:
1206 data_num = 3;
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001207 bit_ch = 1;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001208 break;
1209 default:
1210 data_num = 1;
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001211 bit_ch = 0;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001212 break;
1213 }
1214
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001215 hdmi_reg_acr(hdata, sample_rate);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001216
1217 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1218 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1219 | HDMI_I2S_MUX_ENABLE);
1220
1221 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1222 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1223
1224 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1225
1226 sample_frq = (sample_rate == 44100) ? 0 :
1227 (sample_rate == 48000) ? 2 :
1228 (sample_rate == 32000) ? 3 :
1229 (sample_rate == 96000) ? 0xa : 0x0;
1230
1231 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1232 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1233
1234 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1235 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1236
1237 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1238 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1239 | HDMI_I2S_SEL_LRCK(6));
1240 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1241 | HDMI_I2S_SEL_SDATA2(4));
1242 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1243 | HDMI_I2S_SEL_SDATA2(2));
1244 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1245
1246 /* I2S_CON_1 & 2 */
1247 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1248 | HDMI_I2S_L_CH_LOW_POL);
1249 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1250 | HDMI_I2S_SET_BIT_CH(bit_ch)
1251 | HDMI_I2S_SET_SDATA_BIT(data_num)
1252 | HDMI_I2S_BASIC_FORMAT);
1253
1254 /* Configure register related to CUV information */
1255 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1256 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1257 | HDMI_I2S_COPYRIGHT
1258 | HDMI_I2S_LINEAR_PCM
1259 | HDMI_I2S_CONSUMER_FORMAT);
1260 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1261 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1262 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1263 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1264 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1265 HDMI_I2S_ORG_SMP_FREQ_44_1
1266 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1267 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1268
1269 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1270}
1271
1272static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1273{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001274 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001275 return;
1276
1277 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1278 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1279 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1280}
1281
Rahul Sharmabfa48422014-04-03 20:41:04 +05301282static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001283{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301284 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001285
Rahul Sharmabfa48422014-04-03 20:41:04 +05301286 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1287 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001288
Rahul Sharmabfa48422014-04-03 20:41:04 +05301289 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1290 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001291}
1292
1293static void hdmi_conf_init(struct hdmi_context *hdata)
1294{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301295 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301296
Sean Paul77006a72013-01-16 10:17:20 -05001297 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001298 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1299 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001300
1301 /* choose HDMI mode */
1302 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1303 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001304 /* apply video pre-amble and guard band in HDMI mode only */
Shirish S9a8e1cb2014-02-14 13:04:57 +05301305 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001306 /* disable bluescreen */
1307 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001308
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001309 if (hdata->dvi_mode) {
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001310 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1311 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1312 hdmi_reg_writeb(hdata, HDMI_CON_2,
1313 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1314 }
1315
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001316 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001317 /* choose bluescreen (fecal) color */
1318 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1319 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1320 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1321
1322 /* enable AVI packet every vsync, fixes purple line problem */
1323 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1324 /* force RGB, look to CEA-861-D, table 7 for more detail */
1325 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1326 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1327
1328 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1329 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1330 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1331 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301332 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1333 infoframe.any.version = HDMI_AVI_VERSION;
1334 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301335 hdmi_reg_infoframe(hdata, &infoframe);
1336
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301337 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1338 infoframe.any.version = HDMI_AUI_VERSION;
1339 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301340 hdmi_reg_infoframe(hdata, &infoframe);
1341
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001342 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001343 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1344 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001345}
1346
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001347static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1348{
1349 int tries;
1350
1351 for (tries = 0; tries < 10; ++tries) {
1352 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1353
1354 if (val & HDMI_PHY_STATUS_READY) {
1355 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1356 return;
1357 }
1358 usleep_range(10, 20);
1359 }
1360
1361 DRM_ERROR("PLL could not reach steady state\n");
1362}
1363
Rahul Sharma16844fb2013-06-10 14:50:00 +05301364static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001365{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001366 struct drm_display_mode *m = &hdata->current_mode;
1367 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001368
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001369 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1370 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1371 (m->htotal << 12) | m->vtotal);
1372
1373 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1374 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1375
1376 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1377 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1378
1379 val = (m->hsync_start - m->hdisplay - 2);
1380 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001381 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001382 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1383
1384 /*
1385 * Quirk requirement for exynos HDMI IP design,
1386 * 2 pixels less than the actual calculation for hsync_start
1387 * and end.
1388 */
1389
1390 /* Following values & calculations differ for different type of modes */
1391 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001392 val = ((m->vsync_end - m->vdisplay) / 2);
1393 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1394 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1395
1396 val = m->vtotal / 2;
1397 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1398 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1399
1400 val = (m->vtotal +
1401 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1402 val |= m->vtotal << 11;
1403 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1404
1405 val = ((m->vtotal / 2) + 7);
1406 val |= ((m->vtotal / 2) + 2) << 12;
1407 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1408
1409 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1410 val |= ((m->htotal / 2) +
1411 (m->hsync_start - m->hdisplay)) << 12;
1412 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1413
1414 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1415 (m->vtotal - m->vdisplay) / 2);
1416 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1417
1418 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1419 } else {
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001420 val = m->vtotal;
1421 val |= (m->vtotal - m->vdisplay) << 11;
1422 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1423
1424 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1425
1426 val = (m->vsync_end - m->vdisplay);
1427 val |= ((m->vsync_start - m->vdisplay) << 12);
1428 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1429
1430 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1431 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1432 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1433 m->vtotal - m->vdisplay);
1434 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001435 }
1436
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001437 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1438 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1439 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1440 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001441}
1442
Rahul Sharma16844fb2013-06-10 14:50:00 +05301443static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001444{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001445 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001446
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001447 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1448 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1449 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1450 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001451 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001452 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1453 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1454 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1455 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1456
1457 /*
1458 * Quirk requirement for exynos 5 HDMI IP design,
1459 * 2 pixels less than the actual calculation for hsync_start
1460 * and end.
1461 */
1462
1463 /* Following values & calculations differ for different type of modes */
1464 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001465 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1466 (m->vsync_end - m->vdisplay) / 2);
1467 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1468 (m->vsync_start - m->vdisplay) / 2);
1469 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1470 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1471 (m->vtotal - m->vdisplay) / 2);
1472 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1473 m->vtotal - m->vdisplay / 2);
1474 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1475 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1476 (m->vtotal / 2) + 7);
1477 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1478 (m->vtotal / 2) + 2);
1479 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1480 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1481 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1482 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1483 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1484 (m->vtotal - m->vdisplay) / 2);
1485 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1486 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1487 m->vtotal - m->vdisplay / 2);
1488 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1489 (m->vtotal / 2) + 1);
1490 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1491 (m->vtotal / 2) + 1);
1492 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1493 (m->vtotal / 2) + 1);
1494 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1495 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1496 } else {
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001497 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1498 m->vsync_end - m->vdisplay);
1499 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1500 m->vsync_start - m->vdisplay);
1501 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1502 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1503 m->vtotal - m->vdisplay);
1504 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1505 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1506 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1507 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1508 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1509 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1510 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1511 m->vtotal - m->vdisplay);
1512 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001513 }
1514
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001515 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1516 m->hsync_start - m->hdisplay - 2);
1517 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1518 m->hsync_end - m->hdisplay - 2);
1519 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1520 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1521 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1522 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1523 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1524 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1525 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1526 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1527 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1528 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1529 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1530 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001537
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001538 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1539 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1540 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1541 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001542}
1543
Rahul Sharma16844fb2013-06-10 14:50:00 +05301544static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001545{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001546 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301547 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001548 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301549 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001550
1551 hdmiphy_wait_for_pll(hdata);
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001552 hdmi_clk_set_parents(hdata, true);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001553 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001554}
1555
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001556static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1557{
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001558 hdmi_clk_set_parents(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001559
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001560 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001561 usleep_range(10000, 12000);
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001562 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001563 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001564}
1565
1566static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1567{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001568 int ret;
1569 int i;
1570
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001571 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001572 if (i < 0) {
1573 DRM_ERROR("failed to find hdmiphy conf\n");
1574 return;
1575 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001576
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001577 ret = hdmiphy_reg_write_buf(hdata, 0,
Andrzej Hajda65e98032015-11-02 14:16:41 +01001578 hdata->drv_data->phy_confs.data[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001579 if (ret) {
1580 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001581 return;
1582 }
1583
Sean Paul09760ea2013-01-14 17:03:20 -05001584 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001585}
1586
1587static void hdmi_conf_apply(struct hdmi_context *hdata)
1588{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001589 hdmiphy_conf_reset(hdata);
1590 hdmiphy_conf_apply(hdata);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301591 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001592 hdmi_conf_init(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001593 hdmi_audio_init(hdata);
Rahul Sharma16844fb2013-06-10 14:50:00 +05301594 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001595 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001596 hdmi_regs_dump(hdata, "start");
1597}
1598
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001599static void hdmi_mode_set(struct drm_encoder *encoder,
1600 struct drm_display_mode *mode,
1601 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001602{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001603 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001604 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001605
YoungJun Chocbc4c332013-06-12 10:44:40 +09001606 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1607 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001608 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001609 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001610
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001611 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001612 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001613}
1614
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001615static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001616{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001617 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001618
Andrzej Hajda882a0642015-07-09 16:28:08 +02001619 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001620 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001621
Sean Paulaf65c802014-01-30 16:19:27 -05001622 pm_runtime_get_sync(hdata->dev);
1623
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001624 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001625 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1626
Rahul Sharma049d34e2014-05-20 10:36:05 +05301627 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1628 PMU_HDMI_PHY_ENABLE_BIT, 1);
1629
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001630 hdmi_conf_apply(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09001631
1632 hdata->powered = true;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001633}
1634
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001635static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001636{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001637 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001638 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001639 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001640
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001641 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001642 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001643
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001644 /*
1645 * The SFRs of VP and Mixer are updated by Vertical Sync of
1646 * Timing generator which is a part of HDMI so the sequence
1647 * to disable TV Subsystem should be as following,
1648 * VP -> Mixer -> HDMI
1649 *
1650 * Below codes will try to disable Mixer and VP(if used)
1651 * prior to disabling HDMI.
1652 */
1653 if (crtc)
1654 funcs = crtc->helper_private;
1655 if (funcs && funcs->disable)
1656 (*funcs->disable)(crtc);
1657
Rahul Sharmabfa48422014-04-03 20:41:04 +05301658 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1659
Sean Paul724fd142014-05-09 15:05:10 +09001660 cancel_delayed_work(&hdata->hotplug_work);
1661
Rahul Sharma049d34e2014-05-20 10:36:05 +05301662 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1663 PMU_HDMI_PHY_ENABLE_BIT, 0);
1664
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001665 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001666
Sean Paulaf65c802014-01-30 16:19:27 -05001667 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001668
1669 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001670}
1671
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001672static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001673 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001674 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001675 .enable = hdmi_enable,
1676 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001677};
1678
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001679static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001680 .destroy = drm_encoder_cleanup,
1681};
1682
Sean Paul724fd142014-05-09 15:05:10 +09001683static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001684{
Sean Paul724fd142014-05-09 15:05:10 +09001685 struct hdmi_context *hdata;
1686
1687 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001688
Sean Paul45517892014-01-30 16:19:05 -05001689 if (hdata->drm_dev)
1690 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001691}
1692
1693static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1694{
1695 struct hdmi_context *hdata = arg;
1696
1697 mod_delayed_work(system_wq, &hdata->hotplug_work,
1698 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001699
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001700 return IRQ_HANDLED;
1701}
1702
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001703static int hdmi_clks_get(struct hdmi_context *hdata,
1704 const struct string_array_spec *names,
1705 struct clk **clks)
1706{
1707 struct device *dev = hdata->dev;
1708 int i;
1709
1710 for (i = 0; i < names->count; ++i) {
1711 struct clk *clk = devm_clk_get(dev, names->data[i]);
1712
1713 if (IS_ERR(clk)) {
1714 int ret = PTR_ERR(clk);
1715
1716 dev_err(dev, "Cannot get clock %s, %d\n",
1717 names->data[i], ret);
1718
1719 return ret;
1720 }
1721
1722 clks[i] = clk;
1723 }
1724
1725 return 0;
1726}
1727
1728static int hdmi_clk_init(struct hdmi_context *hdata)
1729{
1730 const struct hdmi_driver_data *drv_data = hdata->drv_data;
1731 int count = drv_data->clk_gates.count + drv_data->clk_muxes.count;
1732 struct device *dev = hdata->dev;
1733 struct clk **clks;
1734 int ret;
1735
1736 if (!count)
1737 return 0;
1738
1739 clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL);
1740 if (!clks)
1741 return -ENOMEM;
1742
1743 hdata->clk_gates = clks;
1744 hdata->clk_muxes = clks + drv_data->clk_gates.count;
1745
1746 ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates);
1747 if (ret)
1748 return ret;
1749
1750 return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes);
1751}
1752
1753
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001754static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001755{
1756 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001757 int i, ret;
1758
1759 DRM_DEBUG_KMS("HDMI resource init\n");
1760
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001761 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1762 if (IS_ERR(hdata->hpd_gpio)) {
1763 DRM_ERROR("cannot get hpd gpio property\n");
1764 return PTR_ERR(hdata->hpd_gpio);
1765 }
1766
1767 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1768 if (hdata->irq < 0) {
1769 DRM_ERROR("failed to get GPIO irq\n");
1770 return hdata->irq;
1771 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001772
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001773 ret = hdmi_clk_init(hdata);
1774 if (ret)
1775 return ret;
1776
1777 ret = hdmi_clk_set_parents(hdata, false);
1778 if (ret)
1779 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001780
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001781 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001782 hdata->regul_bulk[i].supply = supply[i];
1783 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001784 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001785 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001786 if (ret) {
1787 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001788 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001789 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001790
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001791 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001792
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001793 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001794 return 0;
1795
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001796 if (IS_ERR(hdata->reg_hdmi_en))
1797 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001798
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001799 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001800 if (ret)
1801 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001802
Inki Daedf5225b2014-05-29 18:28:02 +09001803 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001804}
1805
Rahul Sharma22c4f422012-10-04 20:48:55 +05301806static struct of_device_id hdmi_match_types[] = {
1807 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001808 .compatible = "samsung,exynos4210-hdmi",
1809 .data = &exynos4210_hdmi_driver_data,
1810 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301811 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001812 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301813 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301814 .compatible = "samsung,exynos5420-hdmi",
1815 .data = &exynos5420_hdmi_driver_data,
1816 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301817 /* end node */
1818 }
1819};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001820MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301821
Inki Daef37cd5e2014-05-09 14:25:20 +09001822static int hdmi_bind(struct device *dev, struct device *master, void *data)
1823{
1824 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001825 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001826 struct drm_encoder *encoder = &hdata->encoder;
1827 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001828
Inki Daef37cd5e2014-05-09 14:25:20 +09001829 hdata->drm_dev = drm_dev;
1830
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001831 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1832 EXYNOS_DISPLAY_TYPE_HDMI);
1833 if (pipe < 0)
1834 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001835
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001836 encoder->possible_crtcs = 1 << pipe;
1837
1838 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1839
1840 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
Ville Syrjälä13a3d912015-12-09 16:20:18 +02001841 DRM_MODE_ENCODER_TMDS, NULL);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001842
1843 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1844
1845 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001846 if (ret) {
1847 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001848 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001849 return ret;
1850 }
1851
1852 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001853}
1854
1855static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1856{
Inki Daef37cd5e2014-05-09 14:25:20 +09001857}
1858
1859static const struct component_ops hdmi_component_ops = {
1860 .bind = hdmi_bind,
1861 .unbind = hdmi_unbind,
1862};
1863
Inki Daee2a562d2014-05-09 16:46:10 +09001864static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1865{
1866 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1867 struct device_node *np;
1868
1869 np = of_find_compatible_node(NULL, NULL, compatible_str);
1870 if (np)
1871 return of_get_next_parent(np);
1872
1873 return NULL;
1874}
1875
1876static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1877{
1878 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1879
1880 return of_find_compatible_node(NULL, NULL, compatible_str);
1881}
1882
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001883static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001884{
Inki Daef37cd5e2014-05-09 14:25:20 +09001885 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001886 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001887 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001888 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001889 struct resource *res;
1890 int ret;
1891
Andrzej Hajda930865f2014-11-17 09:54:20 +01001892 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1893 if (!hdata)
1894 return -ENOMEM;
1895
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001896 match = of_match_device(hdmi_match_types, dev);
1897 if (!match)
1898 return -ENODEV;
1899
1900 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001901
Andrzej Hajda930865f2014-11-17 09:54:20 +01001902 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001903
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001904 hdata->dev = dev;
1905
1906 ret = hdmi_resources_init(hdata);
1907 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301908 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001909 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001910 }
1911
1912 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001913 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001914 if (IS_ERR(hdata->regs)) {
1915 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001916 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001917 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001918
Inki Daee2a562d2014-05-09 16:46:10 +09001919 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1920 if (ddc_node)
1921 goto out_get_ddc_adpt;
1922
Daniel Kurtz2b768132014-02-24 18:52:51 +09001923 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1924 if (!ddc_node) {
1925 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001926 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001927 }
Inki Daee2a562d2014-05-09 16:46:10 +09001928
1929out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001930 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1931 if (!hdata->ddc_adpt) {
1932 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001933 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001934 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001935
Inki Daee2a562d2014-05-09 16:46:10 +09001936 phy_node = hdmi_legacy_phy_dt_binding(dev);
1937 if (phy_node)
1938 goto out_get_phy_port;
1939
Daniel Kurtz2b768132014-02-24 18:52:51 +09001940 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1941 if (!phy_node) {
1942 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1943 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001944 goto err_ddc;
1945 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001946
Inki Daee2a562d2014-05-09 16:46:10 +09001947out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001948 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001949 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1950 if (!hdata->regs_hdmiphy) {
1951 DRM_ERROR("failed to ioremap hdmi phy\n");
1952 ret = -ENOMEM;
1953 goto err_ddc;
1954 }
1955 } else {
1956 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1957 if (!hdata->hdmiphy_port) {
1958 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001959 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001960 goto err_ddc;
1961 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001962 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001963
Sean Paul724fd142014-05-09 15:05:10 +09001964 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1965
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001966 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001967 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001968 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001969 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001970 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001971 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001972 goto err_hdmiphy;
1973 }
1974
Rahul Sharma049d34e2014-05-20 10:36:05 +05301975 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
1976 "samsung,syscon-phandle");
1977 if (IS_ERR(hdata->pmureg)) {
1978 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001979 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05301980 goto err_hdmiphy;
1981 }
1982
Sean Paulaf65c802014-01-30 16:19:27 -05001983 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984
Inki Daedf5225b2014-05-29 18:28:02 +09001985 ret = component_add(&pdev->dev, &hdmi_component_ops);
1986 if (ret)
1987 goto err_disable_pm_runtime;
1988
1989 return ret;
1990
1991err_disable_pm_runtime:
1992 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001993
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09001995 if (hdata->hdmiphy_port)
1996 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001997err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001998 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09001999
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002000 return ret;
2001}
2002
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002003static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002004{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002005 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002006
Sean Paul724fd142014-05-09 15:05:10 +09002007 cancel_delayed_work_sync(&hdata->hotplug_work);
2008
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002009 component_del(&pdev->dev, &hdmi_component_ops);
2010
2011 pm_runtime_disable(&pdev->dev);
2012
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02002013 if (!IS_ERR(hdata->reg_hdmi_en))
2014 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002015
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002016 if (hdata->hdmiphy_port)
2017 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002018
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002019 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002021 return 0;
2022}
2023
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002024#ifdef CONFIG_PM
2025static int exynos_hdmi_suspend(struct device *dev)
2026{
2027 struct hdmi_context *hdata = dev_get_drvdata(dev);
2028
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002029 hdmi_clk_disable_gates(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002030
2031 return 0;
2032}
2033
2034static int exynos_hdmi_resume(struct device *dev)
2035{
2036 struct hdmi_context *hdata = dev_get_drvdata(dev);
2037 int ret;
2038
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002039 ret = hdmi_clk_enable_gates(hdata);
2040 if (ret < 0)
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002041 return ret;
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002042
2043 return 0;
2044}
2045#endif
2046
2047static const struct dev_pm_ops exynos_hdmi_pm_ops = {
2048 SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
2049};
2050
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002051struct platform_driver hdmi_driver = {
2052 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002053 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302055 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002056 .owner = THIS_MODULE,
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002057 .pm = &exynos_hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302058 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002059 },
2060};