blob: 06105feb6c87f96afa23b317928cc025f023ad0c [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 Hajda68cd0042016-01-14 14:40:07 +0900115 unsigned int has_sysreg:1;
Andrzej Hajda65e98032015-11-02 14:16:41 +0100116 struct hdmiphy_configs phy_confs;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900117 struct string_array_spec clk_gates;
118 /*
119 * Array of triplets (p_off, p_on, clock), where p_off and p_on are
120 * required parents of clock when HDMI-PHY is respectively off or on.
121 */
122 struct string_array_spec clk_muxes;
Inki Daebfe4e842014-03-06 14:18:17 +0900123};
124
Joonyoung Shim590f4182012-03-16 18:47:14 +0900125struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300126 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900127 struct device *dev;
128 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500129 struct drm_connector connector;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900130 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900131 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900132 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530133 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200134 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200135 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900136
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200137 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900138 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200139 struct i2c_client *hdmiphy_port;
140 struct i2c_adapter *ddc_adpt;
Gustavo Padovanf28464c2015-11-02 20:39:18 +0900141 struct gpio_desc *hpd_gpio;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200142 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530143 struct regmap *pmureg;
Andrzej Hajda68cd0042016-01-14 14:40:07 +0900144 struct regmap *sysreg;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900145 struct clk **clk_gates;
146 struct clk **clk_muxes;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200147 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
148 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900149};
150
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300151static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100152{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900153 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100154}
155
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200156static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
157{
158 return container_of(c, struct hdmi_context, connector);
159}
160
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900161static const struct hdmiphy_config hdmiphy_v13_configs[] = {
162 {
163 .pixel_clock = 27000000,
164 .conf = {
165 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
166 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
167 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200168 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900169 },
170 },
171 {
172 .pixel_clock = 27027000,
173 .conf = {
174 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
175 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
176 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200177 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900178 },
179 },
180 {
181 .pixel_clock = 74176000,
182 .conf = {
183 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
184 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
185 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200186 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900187 },
188 },
189 {
190 .pixel_clock = 74250000,
191 .conf = {
192 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
193 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
194 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200195 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900196 },
197 },
198 {
199 .pixel_clock = 148500000,
200 .conf = {
201 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
202 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
203 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200204 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900205 },
206 },
207};
208
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500209static const struct hdmiphy_config hdmiphy_v14_configs[] = {
210 {
211 .pixel_clock = 25200000,
212 .conf = {
213 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
214 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
215 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
216 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
217 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900218 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500219 {
220 .pixel_clock = 27000000,
221 .conf = {
222 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
223 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
224 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
225 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
226 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900227 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500228 {
229 .pixel_clock = 27027000,
230 .conf = {
231 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
232 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
233 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200234 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500235 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900236 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500237 {
238 .pixel_clock = 36000000,
239 .conf = {
240 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
241 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
242 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
243 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
244 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900245 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500246 {
247 .pixel_clock = 40000000,
248 .conf = {
249 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
250 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
251 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
252 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
253 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900254 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500255 {
256 .pixel_clock = 65000000,
257 .conf = {
258 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
259 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
260 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
261 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
262 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900263 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500264 {
Shirish Se1d883c2014-03-13 14:28:27 +0900265 .pixel_clock = 71000000,
266 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530267 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
268 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
269 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900270 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
271 },
272 },
273 {
274 .pixel_clock = 73250000,
275 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530276 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
277 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
278 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900279 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
280 },
281 },
282 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500283 .pixel_clock = 74176000,
284 .conf = {
285 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
286 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
287 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
288 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
289 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900290 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500291 {
292 .pixel_clock = 74250000,
293 .conf = {
294 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
295 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
296 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200297 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900299 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500300 {
301 .pixel_clock = 83500000,
302 .conf = {
303 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
304 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
305 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
306 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
307 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900308 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500309 {
310 .pixel_clock = 106500000,
311 .conf = {
312 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
313 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
314 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
315 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
316 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900317 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500318 {
319 .pixel_clock = 108000000,
320 .conf = {
321 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
322 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
323 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
324 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
325 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900326 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500327 {
Shirish Se1d883c2014-03-13 14:28:27 +0900328 .pixel_clock = 115500000,
329 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530330 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
331 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
332 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900333 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
334 },
335 },
336 {
337 .pixel_clock = 119000000,
338 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530339 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
340 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
341 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900342 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
343 },
344 },
345 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500346 .pixel_clock = 146250000,
347 .conf = {
348 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
349 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
350 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
351 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
352 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900353 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500354 {
355 .pixel_clock = 148500000,
356 .conf = {
357 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
358 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
359 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200360 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500361 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900362 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900363};
364
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530365static const struct hdmiphy_config hdmiphy_5420_configs[] = {
366 {
367 .pixel_clock = 25200000,
368 .conf = {
369 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
370 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
371 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
372 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
373 },
374 },
375 {
376 .pixel_clock = 27000000,
377 .conf = {
378 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
379 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
380 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
381 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
382 },
383 },
384 {
385 .pixel_clock = 27027000,
386 .conf = {
387 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
388 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
389 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
390 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
391 },
392 },
393 {
394 .pixel_clock = 36000000,
395 .conf = {
396 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
397 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
398 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
399 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
400 },
401 },
402 {
403 .pixel_clock = 40000000,
404 .conf = {
405 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
406 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
407 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
408 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
409 },
410 },
411 {
412 .pixel_clock = 65000000,
413 .conf = {
414 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
415 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
416 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
417 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
418 },
419 },
420 {
421 .pixel_clock = 71000000,
422 .conf = {
423 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
424 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
425 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
426 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
427 },
428 },
429 {
430 .pixel_clock = 73250000,
431 .conf = {
432 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
433 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
434 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
435 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
436 },
437 },
438 {
439 .pixel_clock = 74176000,
440 .conf = {
441 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
442 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
443 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
444 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
445 },
446 },
447 {
448 .pixel_clock = 74250000,
449 .conf = {
450 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
451 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
452 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
453 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
454 },
455 },
456 {
457 .pixel_clock = 83500000,
458 .conf = {
459 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
460 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
461 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
462 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
463 },
464 },
465 {
466 .pixel_clock = 88750000,
467 .conf = {
468 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
469 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
470 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
471 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
472 },
473 },
474 {
475 .pixel_clock = 106500000,
476 .conf = {
477 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
478 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
479 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
480 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
481 },
482 },
483 {
484 .pixel_clock = 108000000,
485 .conf = {
486 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
487 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
488 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
489 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
490 },
491 },
492 {
493 .pixel_clock = 115500000,
494 .conf = {
495 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
496 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
497 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
498 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
499 },
500 },
501 {
502 .pixel_clock = 146250000,
503 .conf = {
504 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
505 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
506 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
507 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
508 },
509 },
510 {
511 .pixel_clock = 148500000,
512 .conf = {
513 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
514 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
515 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
516 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
517 },
518 },
519};
520
Andrzej Hajda68cd0042016-01-14 14:40:07 +0900521static const struct hdmiphy_config hdmiphy_5433_configs[] = {
522 {
523 .pixel_clock = 27000000,
524 .conf = {
525 0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46,
526 0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
527 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
528 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
529 },
530 },
531 {
532 .pixel_clock = 27027000,
533 .conf = {
534 0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3,
535 0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5,
536 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
537 0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
538 },
539 },
540 {
541 .pixel_clock = 40000000,
542 .conf = {
543 0x01, 0x51, 0x32, 0x55, 0x01, 0x00, 0x88, 0x02,
544 0x4d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
545 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
546 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
547 },
548 },
549 {
550 .pixel_clock = 50000000,
551 .conf = {
552 0x01, 0x51, 0x34, 0x40, 0x64, 0x09, 0x88, 0xc3,
553 0x3d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
554 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
555 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
556 },
557 },
558 {
559 .pixel_clock = 65000000,
560 .conf = {
561 0x01, 0x51, 0x36, 0x31, 0x40, 0x10, 0x04, 0xc6,
562 0x2e, 0xe8, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
563 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
564 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
565 },
566 },
567 {
568 .pixel_clock = 74176000,
569 .conf = {
570 0x01, 0x51, 0x3E, 0x35, 0x5B, 0xDE, 0x88, 0x42,
571 0x53, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
572 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
573 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
574 },
575 },
576 {
577 .pixel_clock = 74250000,
578 .conf = {
579 0x01, 0x51, 0x3E, 0x35, 0x40, 0xF0, 0x88, 0xC2,
580 0x52, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
581 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
582 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
583 },
584 },
585 {
586 .pixel_clock = 108000000,
587 .conf = {
588 0x01, 0x51, 0x2d, 0x15, 0x01, 0x00, 0x88, 0x02,
589 0x72, 0x52, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC,
590 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
591 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
592 },
593 },
594 {
595 .pixel_clock = 148500000,
596 .conf = {
597 0x01, 0x51, 0x1f, 0x00, 0x40, 0xf8, 0x88, 0xc1,
598 0x52, 0x52, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5,
599 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30,
600 0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40,
601 },
602 },
603};
604
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100605static const char * const hdmi_clk_gates4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900606 "hdmi", "sclk_hdmi"
607};
608
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100609static const char * const hdmi_clk_muxes4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900610 "sclk_pixel", "sclk_hdmiphy", "mout_hdmi"
611};
612
Andrzej Hajda68cd0042016-01-14 14:40:07 +0900613static const char * const hdmi_clk_gates5433[] = {
614 "hdmi_pclk", "hdmi_i_pclk", "i_tmds_clk", "i_pixel_clk", "i_spdif_clk"
615};
616
617static const char * const hdmi_clk_muxes5433[] = {
618 "oscclk", "tmds_clko", "tmds_clko_user",
619 "oscclk", "pixel_clko", "pixel_clko_user"
620};
621
Andrzej Hajda5eefadb2016-01-14 14:28:20 +0900622static const struct hdmi_driver_data exynos4210_hdmi_driver_data = {
623 .type = HDMI_TYPE13,
624 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900625 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
626 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530627};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900628
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100629static const struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900630 .type = HDMI_TYPE14,
Andrzej Hajda65e98032015-11-02 14:16:41 +0100631 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900632 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
633 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900634};
635
Andrzej Hajda5eefadb2016-01-14 14:28:20 +0900636static const struct hdmi_driver_data exynos5420_hdmi_driver_data = {
637 .type = HDMI_TYPE14,
638 .is_apb_phy = 1,
639 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900640 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
641 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200642};
643
Andrzej Hajda68cd0042016-01-14 14:40:07 +0900644static const struct hdmi_driver_data exynos5433_hdmi_driver_data = {
645 .type = HDMI_TYPE14,
646 .is_apb_phy = 1,
647 .has_sysreg = 1,
648 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5433_configs),
649 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates5433),
650 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes5433),
651};
652
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200653static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
654{
655 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
656 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
657 return reg_id;
658}
659
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900660static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
661{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200662 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900663}
664
665static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
666 u32 reg_id, u8 value)
667{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200668 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900669}
670
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200671static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
672 int bytes, u32 val)
673{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200674 reg_id = hdmi_map_reg(hdata, reg_id);
675
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200676 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200677 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200678 val >>= 8;
679 reg_id += 4;
680 }
681}
682
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900683static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
684 u32 reg_id, u32 value, u32 mask)
685{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200686 u32 old;
687
688 reg_id = hdmi_map_reg(hdata, reg_id);
689 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900690 value = (value & mask) | (old & ~mask);
691 writel(value, hdata->regs + reg_id);
692}
693
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900694static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
695 u32 reg_offset, const u8 *buf, u32 len)
696{
697 if ((reg_offset + len) > 32)
698 return -EINVAL;
699
700 if (hdata->hdmiphy_port) {
701 int ret;
702
703 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
704 if (ret == len)
705 return 0;
706 return ret;
707 } else {
708 int i;
709 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200710 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900711 ((reg_offset + i)<<2));
712 return 0;
713 }
714}
715
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900716static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900717{
718#define DUMPREG(reg_id) \
719 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
720 readl(hdata->regs + reg_id))
721 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
722 DUMPREG(HDMI_INTC_FLAG);
723 DUMPREG(HDMI_INTC_CON);
724 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900725 DUMPREG(HDMI_V13_PHY_RSTOUT);
726 DUMPREG(HDMI_V13_PHY_VPLL);
727 DUMPREG(HDMI_V13_PHY_CMU);
728 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900729
730 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
731 DUMPREG(HDMI_CON_0);
732 DUMPREG(HDMI_CON_1);
733 DUMPREG(HDMI_CON_2);
734 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900735 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900736 DUMPREG(HDMI_STATUS_EN);
737 DUMPREG(HDMI_HPD);
738 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900739 DUMPREG(HDMI_V13_HPD_GEN);
740 DUMPREG(HDMI_V13_DC_CONTROL);
741 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900742
743 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
744 DUMPREG(HDMI_H_BLANK_0);
745 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900746 DUMPREG(HDMI_V13_V_BLANK_0);
747 DUMPREG(HDMI_V13_V_BLANK_1);
748 DUMPREG(HDMI_V13_V_BLANK_2);
749 DUMPREG(HDMI_V13_H_V_LINE_0);
750 DUMPREG(HDMI_V13_H_V_LINE_1);
751 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900752 DUMPREG(HDMI_VSYNC_POL);
753 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900754 DUMPREG(HDMI_V13_V_BLANK_F_0);
755 DUMPREG(HDMI_V13_V_BLANK_F_1);
756 DUMPREG(HDMI_V13_V_BLANK_F_2);
757 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
758 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
759 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
760 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
761 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
762 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
763 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
764 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
765 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
766 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
767 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
768 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900769
770 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
771 DUMPREG(HDMI_TG_CMD);
772 DUMPREG(HDMI_TG_H_FSZ_L);
773 DUMPREG(HDMI_TG_H_FSZ_H);
774 DUMPREG(HDMI_TG_HACT_ST_L);
775 DUMPREG(HDMI_TG_HACT_ST_H);
776 DUMPREG(HDMI_TG_HACT_SZ_L);
777 DUMPREG(HDMI_TG_HACT_SZ_H);
778 DUMPREG(HDMI_TG_V_FSZ_L);
779 DUMPREG(HDMI_TG_V_FSZ_H);
780 DUMPREG(HDMI_TG_VSYNC_L);
781 DUMPREG(HDMI_TG_VSYNC_H);
782 DUMPREG(HDMI_TG_VSYNC2_L);
783 DUMPREG(HDMI_TG_VSYNC2_H);
784 DUMPREG(HDMI_TG_VACT_ST_L);
785 DUMPREG(HDMI_TG_VACT_ST_H);
786 DUMPREG(HDMI_TG_VACT_SZ_L);
787 DUMPREG(HDMI_TG_VACT_SZ_H);
788 DUMPREG(HDMI_TG_FIELD_CHG_L);
789 DUMPREG(HDMI_TG_FIELD_CHG_H);
790 DUMPREG(HDMI_TG_VACT_ST2_L);
791 DUMPREG(HDMI_TG_VACT_ST2_H);
792 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
793 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
794 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
795 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
796 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
797 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
798 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
799 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
800#undef DUMPREG
801}
802
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900803static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
804{
805 int i;
806
807#define DUMPREG(reg_id) \
808 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
809 readl(hdata->regs + reg_id))
810
811 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
812 DUMPREG(HDMI_INTC_CON);
813 DUMPREG(HDMI_INTC_FLAG);
814 DUMPREG(HDMI_HPD_STATUS);
815 DUMPREG(HDMI_INTC_CON_1);
816 DUMPREG(HDMI_INTC_FLAG_1);
817 DUMPREG(HDMI_PHY_STATUS_0);
818 DUMPREG(HDMI_PHY_STATUS_PLL);
819 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200820 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900821 DUMPREG(HDMI_PHY_VPLL);
822 DUMPREG(HDMI_PHY_CMU);
823 DUMPREG(HDMI_CORE_RSTOUT);
824
825 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
826 DUMPREG(HDMI_CON_0);
827 DUMPREG(HDMI_CON_1);
828 DUMPREG(HDMI_CON_2);
829 DUMPREG(HDMI_SYS_STATUS);
830 DUMPREG(HDMI_PHY_STATUS_0);
831 DUMPREG(HDMI_STATUS_EN);
832 DUMPREG(HDMI_HPD);
833 DUMPREG(HDMI_MODE_SEL);
834 DUMPREG(HDMI_ENC_EN);
835 DUMPREG(HDMI_DC_CONTROL);
836 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
837
838 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
839 DUMPREG(HDMI_H_BLANK_0);
840 DUMPREG(HDMI_H_BLANK_1);
841 DUMPREG(HDMI_V2_BLANK_0);
842 DUMPREG(HDMI_V2_BLANK_1);
843 DUMPREG(HDMI_V1_BLANK_0);
844 DUMPREG(HDMI_V1_BLANK_1);
845 DUMPREG(HDMI_V_LINE_0);
846 DUMPREG(HDMI_V_LINE_1);
847 DUMPREG(HDMI_H_LINE_0);
848 DUMPREG(HDMI_H_LINE_1);
849 DUMPREG(HDMI_HSYNC_POL);
850
851 DUMPREG(HDMI_VSYNC_POL);
852 DUMPREG(HDMI_INT_PRO_MODE);
853 DUMPREG(HDMI_V_BLANK_F0_0);
854 DUMPREG(HDMI_V_BLANK_F0_1);
855 DUMPREG(HDMI_V_BLANK_F1_0);
856 DUMPREG(HDMI_V_BLANK_F1_1);
857
858 DUMPREG(HDMI_H_SYNC_START_0);
859 DUMPREG(HDMI_H_SYNC_START_1);
860 DUMPREG(HDMI_H_SYNC_END_0);
861 DUMPREG(HDMI_H_SYNC_END_1);
862
863 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
864 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
865 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
866 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
867
868 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
869 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
870 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
871 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
872
873 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
874 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
875 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
876 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
877
878 DUMPREG(HDMI_V_BLANK_F2_0);
879 DUMPREG(HDMI_V_BLANK_F2_1);
880 DUMPREG(HDMI_V_BLANK_F3_0);
881 DUMPREG(HDMI_V_BLANK_F3_1);
882 DUMPREG(HDMI_V_BLANK_F4_0);
883 DUMPREG(HDMI_V_BLANK_F4_1);
884 DUMPREG(HDMI_V_BLANK_F5_0);
885 DUMPREG(HDMI_V_BLANK_F5_1);
886
887 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
888 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
889 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
890 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
891 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
892 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
893 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
894 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
895
896 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
897 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
898 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
899 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
900 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
901 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
902 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
903 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
904
905 DUMPREG(HDMI_VACT_SPACE_1_0);
906 DUMPREG(HDMI_VACT_SPACE_1_1);
907 DUMPREG(HDMI_VACT_SPACE_2_0);
908 DUMPREG(HDMI_VACT_SPACE_2_1);
909 DUMPREG(HDMI_VACT_SPACE_3_0);
910 DUMPREG(HDMI_VACT_SPACE_3_1);
911 DUMPREG(HDMI_VACT_SPACE_4_0);
912 DUMPREG(HDMI_VACT_SPACE_4_1);
913 DUMPREG(HDMI_VACT_SPACE_5_0);
914 DUMPREG(HDMI_VACT_SPACE_5_1);
915 DUMPREG(HDMI_VACT_SPACE_6_0);
916 DUMPREG(HDMI_VACT_SPACE_6_1);
917
918 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
919 DUMPREG(HDMI_TG_CMD);
920 DUMPREG(HDMI_TG_H_FSZ_L);
921 DUMPREG(HDMI_TG_H_FSZ_H);
922 DUMPREG(HDMI_TG_HACT_ST_L);
923 DUMPREG(HDMI_TG_HACT_ST_H);
924 DUMPREG(HDMI_TG_HACT_SZ_L);
925 DUMPREG(HDMI_TG_HACT_SZ_H);
926 DUMPREG(HDMI_TG_V_FSZ_L);
927 DUMPREG(HDMI_TG_V_FSZ_H);
928 DUMPREG(HDMI_TG_VSYNC_L);
929 DUMPREG(HDMI_TG_VSYNC_H);
930 DUMPREG(HDMI_TG_VSYNC2_L);
931 DUMPREG(HDMI_TG_VSYNC2_H);
932 DUMPREG(HDMI_TG_VACT_ST_L);
933 DUMPREG(HDMI_TG_VACT_ST_H);
934 DUMPREG(HDMI_TG_VACT_SZ_L);
935 DUMPREG(HDMI_TG_VACT_SZ_H);
936 DUMPREG(HDMI_TG_FIELD_CHG_L);
937 DUMPREG(HDMI_TG_FIELD_CHG_H);
938 DUMPREG(HDMI_TG_VACT_ST2_L);
939 DUMPREG(HDMI_TG_VACT_ST2_H);
940 DUMPREG(HDMI_TG_VACT_ST3_L);
941 DUMPREG(HDMI_TG_VACT_ST3_H);
942 DUMPREG(HDMI_TG_VACT_ST4_L);
943 DUMPREG(HDMI_TG_VACT_ST4_H);
944 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
945 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
946 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
947 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
948 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
949 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
950 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
951 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
952 DUMPREG(HDMI_TG_3D);
953
954 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
955 DUMPREG(HDMI_AVI_CON);
956 DUMPREG(HDMI_AVI_HEADER0);
957 DUMPREG(HDMI_AVI_HEADER1);
958 DUMPREG(HDMI_AVI_HEADER2);
959 DUMPREG(HDMI_AVI_CHECK_SUM);
960 DUMPREG(HDMI_VSI_CON);
961 DUMPREG(HDMI_VSI_HEADER0);
962 DUMPREG(HDMI_VSI_HEADER1);
963 DUMPREG(HDMI_VSI_HEADER2);
964 for (i = 0; i < 7; ++i)
965 DUMPREG(HDMI_VSI_DATA(i));
966
967#undef DUMPREG
968}
969
970static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
971{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200972 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900973 hdmi_v13_regs_dump(hdata, prefix);
974 else
975 hdmi_v14_regs_dump(hdata, prefix);
976}
977
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900978static int hdmi_clk_enable_gates(struct hdmi_context *hdata)
979{
980 int i, ret;
981
982 for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) {
983 ret = clk_prepare_enable(hdata->clk_gates[i]);
984 if (!ret)
985 continue;
986
987 dev_err(hdata->dev, "Cannot enable clock '%s', %d\n",
988 hdata->drv_data->clk_gates.data[i], ret);
989 while (i--)
990 clk_disable_unprepare(hdata->clk_gates[i]);
991 return ret;
992 }
993
994 return 0;
995}
996
997static void hdmi_clk_disable_gates(struct hdmi_context *hdata)
998{
999 int i = hdata->drv_data->clk_gates.count;
1000
1001 while (i--)
1002 clk_disable_unprepare(hdata->clk_gates[i]);
1003}
1004
1005static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
1006{
1007 struct device *dev = hdata->dev;
1008 int ret = 0;
1009 int i;
1010
1011 for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) {
1012 struct clk **c = &hdata->clk_muxes[i];
1013
1014 ret = clk_set_parent(c[2], c[to_phy]);
1015 if (!ret)
1016 continue;
1017
1018 dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n",
1019 hdata->drv_data->clk_muxes.data[i + 2],
1020 hdata->drv_data->clk_muxes.data[i + to_phy], ret);
1021 }
1022
1023 return ret;
1024}
1025
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301026static u8 hdmi_chksum(struct hdmi_context *hdata,
1027 u32 start, u8 len, u32 hdr_sum)
1028{
1029 int i;
1030
1031 /* hdr_sum : header0 + header1 + header2
1032 * start : start address of packet byte1
1033 * len : packet bytes - 1 */
1034 for (i = 0; i < len; ++i)
1035 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
1036
1037 /* return 2's complement of 8 bit hdr_sum */
1038 return (u8)(~(hdr_sum & 0xff) + 1);
1039}
1040
1041static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301042 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301043{
1044 u32 hdr_sum;
1045 u8 chksum;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001046 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301047
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301048 if (hdata->dvi_mode) {
1049 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
1050 HDMI_VSI_CON_DO_NOT_TRANSMIT);
1051 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
1052 HDMI_AVI_CON_DO_NOT_TRANSMIT);
1053 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
1054 return;
1055 }
1056
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301057 switch (infoframe->any.type) {
1058 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301059 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301060 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
1061 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
1062 infoframe->any.version);
1063 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
1064 hdr_sum = infoframe->any.type + infoframe->any.version +
1065 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301066
1067 /* Output format zero hardcoded ,RGB YBCR selection */
1068 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
1069 AVI_ACTIVE_FORMAT_VALID |
1070 AVI_UNDERSCANNED_DISPLAY_VALID);
1071
Shirish S46154152014-03-13 10:58:28 +05301072 /*
1073 * Set the aspect ratio as per the mode, mentioned in
1074 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
1075 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001076 ar = hdata->current_mode.picture_aspect_ratio;
1077 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +05301078 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001079 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +05301080 break;
1081 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001082 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +05301083 break;
1084 case HDMI_PICTURE_ASPECT_NONE:
1085 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001086 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +05301087 break;
1088 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001089 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301090
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001091 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301092
1093 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301094 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301095 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
1096 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
1097 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301098 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301099 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301100 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
1101 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
1102 infoframe->any.version);
1103 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1104 hdr_sum = infoframe->any.type + infoframe->any.version +
1105 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301106 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301107 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301108 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1109 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1110 break;
1111 default:
1112 break;
1113 }
1114}
1115
Sean Pauld9716ee2014-01-30 16:19:29 -05001116static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1117 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001118{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001119 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -05001120
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001121 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001122 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301123
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001124 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001125}
1126
Sean Pauld9716ee2014-01-30 16:19:29 -05001127static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001128{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001129 drm_connector_unregister(connector);
1130 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001131}
1132
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001133static const struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001134 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001135 .fill_modes = drm_helper_probe_single_connector_modes,
1136 .detect = hdmi_detect,
1137 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001138 .reset = drm_atomic_helper_connector_reset,
1139 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1140 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001141};
1142
1143static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001144{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001145 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001146 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001147 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001148
Inki Dae8fa04aa2014-03-13 16:38:31 +09001149 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001150 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001151
Inki Dae8fa04aa2014-03-13 16:38:31 +09001152 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001153 if (!edid)
1154 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001155
Sean Pauld9716ee2014-01-30 16:19:29 -05001156 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001157 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1158 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001159 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001160
Sean Pauld9716ee2014-01-30 16:19:29 -05001161 drm_mode_connector_update_edid_property(connector, edid);
1162
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001163 ret = drm_add_edid_modes(connector, edid);
1164
1165 kfree(edid);
1166
1167 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001168}
1169
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001170static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001171{
Andrzej Hajda65e98032015-11-02 14:16:41 +01001172 const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001173 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001174
Andrzej Hajda65e98032015-11-02 14:16:41 +01001175 for (i = 0; i < confs->count; i++)
1176 if (confs->data[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001177 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001178
1179 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1180 return -EINVAL;
1181}
1182
Sean Pauld9716ee2014-01-30 16:19:29 -05001183static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001184 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001185{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001186 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001187 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001188
Rahul Sharma16844fb2013-06-10 14:50:00 +05301189 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1190 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1191 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1192 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001193
Rahul Sharma16844fb2013-06-10 14:50:00 +05301194 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001195 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001196 return MODE_BAD;
1197
1198 return MODE_OK;
1199}
1200
1201static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1202{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001203 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001204
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001205 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001206}
1207
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001208static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001209 .get_modes = hdmi_get_modes,
1210 .mode_valid = hdmi_mode_valid,
1211 .best_encoder = hdmi_best_encoder,
1212};
1213
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001214static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001215{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001216 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001217 struct drm_connector *connector = &hdata->connector;
1218 int ret;
1219
Sean Pauld9716ee2014-01-30 16:19:29 -05001220 connector->interlace_allowed = true;
1221 connector->polled = DRM_CONNECTOR_POLL_HPD;
1222
1223 ret = drm_connector_init(hdata->drm_dev, connector,
1224 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1225 if (ret) {
1226 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001227 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001228 }
1229
1230 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001231 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001232 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001233
1234 return 0;
1235}
1236
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001237static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1238 const struct drm_display_mode *mode,
1239 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001240{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001241 struct drm_device *dev = encoder->dev;
1242 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001243 struct drm_display_mode *m;
1244 int mode_ok;
1245
Sean Paulf041b252014-01-30 16:19:15 -05001246 drm_mode_set_crtcinfo(adjusted_mode, 0);
1247
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001248 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1249 if (connector->encoder == encoder)
1250 break;
1251 }
1252
1253 if (connector->encoder != encoder)
1254 return true;
1255
Sean Pauld9716ee2014-01-30 16:19:29 -05001256 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001257
Sean Pauld9716ee2014-01-30 16:19:29 -05001258 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001259 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001260
1261 /*
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001262 * Find the most suitable mode and copy it to adjusted_mode.
Sean Paulf041b252014-01-30 16:19:15 -05001263 */
1264 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001265 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001266
Sean Pauld9716ee2014-01-30 16:19:29 -05001267 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001268 DRM_INFO("desired mode doesn't exist so\n");
1269 DRM_INFO("use the most suitable mode among modes.\n");
1270
1271 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1272 m->hdisplay, m->vdisplay, m->vrefresh);
1273
Sean Paul75626852014-01-30 16:19:16 -05001274 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001275 break;
1276 }
1277 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001278
1279 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001280}
1281
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001282static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001283{
1284 u32 n, cts;
1285
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001286 cts = (freq % 9) ? 27000 : 30000;
1287 n = 128 * freq / (27000000 / cts);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001288
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001289 hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
1290 hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
1291 hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001292 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001293}
1294
1295static void hdmi_audio_init(struct hdmi_context *hdata)
1296{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301297 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001298 u32 data_num, bit_ch, sample_frq;
1299 u32 val;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001300
1301 sample_rate = 44100;
1302 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001303
1304 switch (bits_per_sample) {
1305 case 20:
1306 data_num = 2;
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001307 bit_ch = 1;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001308 break;
1309 case 24:
1310 data_num = 3;
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001311 bit_ch = 1;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001312 break;
1313 default:
1314 data_num = 1;
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001315 bit_ch = 0;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001316 break;
1317 }
1318
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001319 hdmi_reg_acr(hdata, sample_rate);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001320
1321 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1322 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1323 | HDMI_I2S_MUX_ENABLE);
1324
1325 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1326 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1327
1328 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1329
1330 sample_frq = (sample_rate == 44100) ? 0 :
1331 (sample_rate == 48000) ? 2 :
1332 (sample_rate == 32000) ? 3 :
1333 (sample_rate == 96000) ? 0xa : 0x0;
1334
1335 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1336 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1337
1338 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1339 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1340
1341 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1342 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1343 | HDMI_I2S_SEL_LRCK(6));
1344 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1345 | HDMI_I2S_SEL_SDATA2(4));
1346 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1347 | HDMI_I2S_SEL_SDATA2(2));
1348 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1349
1350 /* I2S_CON_1 & 2 */
1351 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1352 | HDMI_I2S_L_CH_LOW_POL);
1353 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1354 | HDMI_I2S_SET_BIT_CH(bit_ch)
1355 | HDMI_I2S_SET_SDATA_BIT(data_num)
1356 | HDMI_I2S_BASIC_FORMAT);
1357
1358 /* Configure register related to CUV information */
1359 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1360 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1361 | HDMI_I2S_COPYRIGHT
1362 | HDMI_I2S_LINEAR_PCM
1363 | HDMI_I2S_CONSUMER_FORMAT);
1364 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1365 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1366 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1367 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1368 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1369 HDMI_I2S_ORG_SMP_FREQ_44_1
1370 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1371 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1372
1373 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1374}
1375
1376static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1377{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001378 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001379 return;
1380
1381 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1382 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1383 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1384}
1385
Rahul Sharmabfa48422014-04-03 20:41:04 +05301386static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001387{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301388 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001389
Rahul Sharmabfa48422014-04-03 20:41:04 +05301390 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1391 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001392
Rahul Sharmabfa48422014-04-03 20:41:04 +05301393 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1394 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001395}
1396
1397static void hdmi_conf_init(struct hdmi_context *hdata)
1398{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301399 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301400
Sean Paul77006a72013-01-16 10:17:20 -05001401 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001402 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1403 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001404
1405 /* choose HDMI mode */
1406 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1407 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001408 /* apply video pre-amble and guard band in HDMI mode only */
Shirish S9a8e1cb2014-02-14 13:04:57 +05301409 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001410 /* disable bluescreen */
1411 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001412
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001413 if (hdata->dvi_mode) {
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001414 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1415 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1416 hdmi_reg_writeb(hdata, HDMI_CON_2,
1417 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1418 }
1419
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001420 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001421 /* choose bluescreen (fecal) color */
1422 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1423 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1424 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1425
1426 /* enable AVI packet every vsync, fixes purple line problem */
1427 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1428 /* force RGB, look to CEA-861-D, table 7 for more detail */
1429 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1430 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1431
1432 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1433 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1434 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1435 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301436 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1437 infoframe.any.version = HDMI_AVI_VERSION;
1438 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301439 hdmi_reg_infoframe(hdata, &infoframe);
1440
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301441 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1442 infoframe.any.version = HDMI_AUI_VERSION;
1443 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301444 hdmi_reg_infoframe(hdata, &infoframe);
1445
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001446 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001447 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1448 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001449}
1450
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001451static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1452{
1453 int tries;
1454
1455 for (tries = 0; tries < 10; ++tries) {
1456 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1457
1458 if (val & HDMI_PHY_STATUS_READY) {
1459 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1460 return;
1461 }
1462 usleep_range(10, 20);
1463 }
1464
1465 DRM_ERROR("PLL could not reach steady state\n");
1466}
1467
Rahul Sharma16844fb2013-06-10 14:50:00 +05301468static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001469{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001470 struct drm_display_mode *m = &hdata->current_mode;
1471 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001472
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001473 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1474 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1475 (m->htotal << 12) | m->vtotal);
1476
1477 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1478 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1479
1480 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1481 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1482
1483 val = (m->hsync_start - m->hdisplay - 2);
1484 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001485 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001486 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1487
1488 /*
1489 * Quirk requirement for exynos HDMI IP design,
1490 * 2 pixels less than the actual calculation for hsync_start
1491 * and end.
1492 */
1493
1494 /* Following values & calculations differ for different type of modes */
1495 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001496 val = ((m->vsync_end - m->vdisplay) / 2);
1497 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1498 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1499
1500 val = m->vtotal / 2;
1501 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1502 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1503
1504 val = (m->vtotal +
1505 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1506 val |= m->vtotal << 11;
1507 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1508
1509 val = ((m->vtotal / 2) + 7);
1510 val |= ((m->vtotal / 2) + 2) << 12;
1511 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1512
1513 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1514 val |= ((m->htotal / 2) +
1515 (m->hsync_start - m->hdisplay)) << 12;
1516 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1517
1518 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1519 (m->vtotal - m->vdisplay) / 2);
1520 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1521
1522 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1523 } else {
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001524 val = m->vtotal;
1525 val |= (m->vtotal - m->vdisplay) << 11;
1526 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1527
1528 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1529
1530 val = (m->vsync_end - m->vdisplay);
1531 val |= ((m->vsync_start - m->vdisplay) << 12);
1532 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1533
1534 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1535 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1536 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1537 m->vtotal - m->vdisplay);
1538 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001539 }
1540
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001541 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1542 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1543 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1544 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001545}
1546
Rahul Sharma16844fb2013-06-10 14:50:00 +05301547static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001548{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001549 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001550
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001551 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1552 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1553 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1554 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001555 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001556 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1557 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1558 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1559 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1560
1561 /*
1562 * Quirk requirement for exynos 5 HDMI IP design,
1563 * 2 pixels less than the actual calculation for hsync_start
1564 * and end.
1565 */
1566
1567 /* Following values & calculations differ for different type of modes */
1568 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001569 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1570 (m->vsync_end - m->vdisplay) / 2);
1571 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1572 (m->vsync_start - m->vdisplay) / 2);
1573 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1574 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1575 (m->vtotal - m->vdisplay) / 2);
1576 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1577 m->vtotal - m->vdisplay / 2);
1578 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1579 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1580 (m->vtotal / 2) + 7);
1581 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1582 (m->vtotal / 2) + 2);
1583 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1584 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1585 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1586 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1587 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1588 (m->vtotal - m->vdisplay) / 2);
1589 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1590 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1591 m->vtotal - m->vdisplay / 2);
1592 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1593 (m->vtotal / 2) + 1);
1594 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1595 (m->vtotal / 2) + 1);
1596 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1597 (m->vtotal / 2) + 1);
1598 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1599 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1600 } else {
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001601 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1602 m->vsync_end - m->vdisplay);
1603 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1604 m->vsync_start - m->vdisplay);
1605 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1606 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1607 m->vtotal - m->vdisplay);
1608 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1609 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1610 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1611 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1612 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1613 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1614 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1615 m->vtotal - m->vdisplay);
1616 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001617 }
1618
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001619 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1620 m->hsync_start - m->hdisplay - 2);
1621 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1622 m->hsync_end - m->hdisplay - 2);
1623 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1624 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1625 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1626 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1627 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1628 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1629 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1630 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1631 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1632 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1633 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1634 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1635 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1636 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1637 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1638 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1639 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1640 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001641
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001642 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1643 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1644 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1645 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001646 if (hdata->drv_data == &exynos5433_hdmi_driver_data)
1647 hdmi_reg_writeb(hdata, HDMI_TG_DECON_EN, 1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001648}
1649
Rahul Sharma16844fb2013-06-10 14:50:00 +05301650static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001651{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001652 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301653 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001654 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301655 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001656
1657 hdmiphy_wait_for_pll(hdata);
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001658 hdmi_clk_set_parents(hdata, true);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001659 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001660}
1661
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001662static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1663{
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001664 hdmi_clk_set_parents(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001665
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001666 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001667 usleep_range(10000, 12000);
Andrzej Hajda5eefadb2016-01-14 14:28:20 +09001668 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001669 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001670}
1671
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001672static void hdmiphy_enable_mode_set(struct hdmi_context *hdata, bool enable)
1673{
1674 u8 v = enable ? HDMI_PHY_ENABLE_MODE_SET : HDMI_PHY_DISABLE_MODE_SET;
1675
1676 if (hdata->drv_data == &exynos5433_hdmi_driver_data)
1677 writel(v, hdata->regs_hdmiphy + HDMIPHY5433_MODE_SET_DONE);
1678}
1679
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001680static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1681{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001682 int ret;
1683 int i;
1684
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001685 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001686 if (i < 0) {
1687 DRM_ERROR("failed to find hdmiphy conf\n");
1688 return;
1689 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001690
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001691 hdmiphy_enable_mode_set(hdata, true);
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001692 ret = hdmiphy_reg_write_buf(hdata, 0,
Andrzej Hajda65e98032015-11-02 14:16:41 +01001693 hdata->drv_data->phy_confs.data[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001694 if (ret) {
1695 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001696 return;
1697 }
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001698 hdmiphy_enable_mode_set(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001699
Sean Paul09760ea2013-01-14 17:03:20 -05001700 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001701}
1702
1703static void hdmi_conf_apply(struct hdmi_context *hdata)
1704{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001705 hdmiphy_conf_reset(hdata);
1706 hdmiphy_conf_apply(hdata);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301707 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001708 hdmi_conf_init(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001709 hdmi_audio_init(hdata);
Rahul Sharma16844fb2013-06-10 14:50:00 +05301710 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001711 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001712 hdmi_regs_dump(hdata, "start");
1713}
1714
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001715static void hdmi_mode_set(struct drm_encoder *encoder,
1716 struct drm_display_mode *mode,
1717 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001718{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001719 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001720 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001721
YoungJun Chocbc4c332013-06-12 10:44:40 +09001722 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1723 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001724 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001725 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001726
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001727 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001728 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001729}
1730
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001731static void hdmi_set_refclk(struct hdmi_context *hdata, bool on)
1732{
1733 if (!hdata->sysreg)
1734 return;
1735
1736 regmap_update_bits(hdata->sysreg, EXYNOS5433_SYSREG_DISP_HDMI_PHY,
1737 SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0);
1738}
1739
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001740static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001741{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001742 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001743
Andrzej Hajda882a0642015-07-09 16:28:08 +02001744 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001745 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001746
Sean Paulaf65c802014-01-30 16:19:27 -05001747 pm_runtime_get_sync(hdata->dev);
1748
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001749 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001750 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1751
Rahul Sharma049d34e2014-05-20 10:36:05 +05301752 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1753 PMU_HDMI_PHY_ENABLE_BIT, 1);
1754
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001755 hdmi_set_refclk(hdata, true);
1756
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001757 hdmi_conf_apply(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09001758
1759 hdata->powered = true;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001760}
1761
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001762static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001763{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001764 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001765 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001766 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001767
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001768 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001769 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001770
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001771 /*
1772 * The SFRs of VP and Mixer are updated by Vertical Sync of
1773 * Timing generator which is a part of HDMI so the sequence
1774 * to disable TV Subsystem should be as following,
1775 * VP -> Mixer -> HDMI
1776 *
1777 * Below codes will try to disable Mixer and VP(if used)
1778 * prior to disabling HDMI.
1779 */
1780 if (crtc)
1781 funcs = crtc->helper_private;
1782 if (funcs && funcs->disable)
1783 (*funcs->disable)(crtc);
1784
Rahul Sharmabfa48422014-04-03 20:41:04 +05301785 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1786
Sean Paul724fd142014-05-09 15:05:10 +09001787 cancel_delayed_work(&hdata->hotplug_work);
1788
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001789 hdmi_set_refclk(hdata, false);
1790
Rahul Sharma049d34e2014-05-20 10:36:05 +05301791 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1792 PMU_HDMI_PHY_ENABLE_BIT, 0);
1793
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001794 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001795
Sean Paulaf65c802014-01-30 16:19:27 -05001796 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001797
1798 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001799}
1800
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001801static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001802 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001803 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001804 .enable = hdmi_enable,
1805 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001806};
1807
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001808static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001809 .destroy = drm_encoder_cleanup,
1810};
1811
Sean Paul724fd142014-05-09 15:05:10 +09001812static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001813{
Sean Paul724fd142014-05-09 15:05:10 +09001814 struct hdmi_context *hdata;
1815
1816 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001817
Sean Paul45517892014-01-30 16:19:05 -05001818 if (hdata->drm_dev)
1819 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001820}
1821
1822static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1823{
1824 struct hdmi_context *hdata = arg;
1825
1826 mod_delayed_work(system_wq, &hdata->hotplug_work,
1827 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001828
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001829 return IRQ_HANDLED;
1830}
1831
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001832static int hdmi_clks_get(struct hdmi_context *hdata,
1833 const struct string_array_spec *names,
1834 struct clk **clks)
1835{
1836 struct device *dev = hdata->dev;
1837 int i;
1838
1839 for (i = 0; i < names->count; ++i) {
1840 struct clk *clk = devm_clk_get(dev, names->data[i]);
1841
1842 if (IS_ERR(clk)) {
1843 int ret = PTR_ERR(clk);
1844
1845 dev_err(dev, "Cannot get clock %s, %d\n",
1846 names->data[i], ret);
1847
1848 return ret;
1849 }
1850
1851 clks[i] = clk;
1852 }
1853
1854 return 0;
1855}
1856
1857static int hdmi_clk_init(struct hdmi_context *hdata)
1858{
1859 const struct hdmi_driver_data *drv_data = hdata->drv_data;
1860 int count = drv_data->clk_gates.count + drv_data->clk_muxes.count;
1861 struct device *dev = hdata->dev;
1862 struct clk **clks;
1863 int ret;
1864
1865 if (!count)
1866 return 0;
1867
1868 clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL);
1869 if (!clks)
1870 return -ENOMEM;
1871
1872 hdata->clk_gates = clks;
1873 hdata->clk_muxes = clks + drv_data->clk_gates.count;
1874
1875 ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates);
1876 if (ret)
1877 return ret;
1878
1879 return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes);
1880}
1881
1882
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001883static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001884{
1885 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001886 int i, ret;
1887
1888 DRM_DEBUG_KMS("HDMI resource init\n");
1889
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001890 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1891 if (IS_ERR(hdata->hpd_gpio)) {
1892 DRM_ERROR("cannot get hpd gpio property\n");
1893 return PTR_ERR(hdata->hpd_gpio);
1894 }
1895
1896 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1897 if (hdata->irq < 0) {
1898 DRM_ERROR("failed to get GPIO irq\n");
1899 return hdata->irq;
1900 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001901
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001902 ret = hdmi_clk_init(hdata);
1903 if (ret)
1904 return ret;
1905
1906 ret = hdmi_clk_set_parents(hdata, false);
1907 if (ret)
1908 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001909
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001910 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001911 hdata->regul_bulk[i].supply = supply[i];
1912 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001913 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001914 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001915 if (ret) {
1916 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001917 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001918 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001919
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001920 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001921
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001922 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001923 return 0;
1924
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001925 if (IS_ERR(hdata->reg_hdmi_en))
1926 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001927
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001928 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001929 if (ret)
1930 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001931
Inki Daedf5225b2014-05-29 18:28:02 +09001932 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001933}
1934
Rahul Sharma22c4f422012-10-04 20:48:55 +05301935static struct of_device_id hdmi_match_types[] = {
1936 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001937 .compatible = "samsung,exynos4210-hdmi",
1938 .data = &exynos4210_hdmi_driver_data,
1939 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301940 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001941 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301942 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301943 .compatible = "samsung,exynos5420-hdmi",
1944 .data = &exynos5420_hdmi_driver_data,
1945 }, {
Andrzej Hajda68cd0042016-01-14 14:40:07 +09001946 .compatible = "samsung,exynos5433-hdmi",
1947 .data = &exynos5433_hdmi_driver_data,
1948 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301949 /* end node */
1950 }
1951};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001952MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301953
Inki Daef37cd5e2014-05-09 14:25:20 +09001954static int hdmi_bind(struct device *dev, struct device *master, void *data)
1955{
1956 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001957 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001958 struct drm_encoder *encoder = &hdata->encoder;
1959 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001960
Inki Daef37cd5e2014-05-09 14:25:20 +09001961 hdata->drm_dev = drm_dev;
1962
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001963 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1964 EXYNOS_DISPLAY_TYPE_HDMI);
1965 if (pipe < 0)
1966 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001967
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001968 encoder->possible_crtcs = 1 << pipe;
1969
1970 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1971
1972 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
Ville Syrjälä13a3d912015-12-09 16:20:18 +02001973 DRM_MODE_ENCODER_TMDS, NULL);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001974
1975 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1976
1977 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001978 if (ret) {
1979 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001980 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001981 return ret;
1982 }
1983
1984 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001985}
1986
1987static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1988{
Inki Daef37cd5e2014-05-09 14:25:20 +09001989}
1990
1991static const struct component_ops hdmi_component_ops = {
1992 .bind = hdmi_bind,
1993 .unbind = hdmi_unbind,
1994};
1995
Inki Daee2a562d2014-05-09 16:46:10 +09001996static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1997{
1998 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1999 struct device_node *np;
2000
2001 np = of_find_compatible_node(NULL, NULL, compatible_str);
2002 if (np)
2003 return of_get_next_parent(np);
2004
2005 return NULL;
2006}
2007
2008static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
2009{
2010 const char *compatible_str = "samsung,exynos4212-hdmiphy";
2011
2012 return of_find_compatible_node(NULL, NULL, compatible_str);
2013}
2014
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002015static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002016{
Inki Daef37cd5e2014-05-09 14:25:20 +09002017 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09002018 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002019 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002021 struct resource *res;
2022 int ret;
2023
Andrzej Hajda930865f2014-11-17 09:54:20 +01002024 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
2025 if (!hdata)
2026 return -ENOMEM;
2027
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002028 match = of_match_device(hdmi_match_types, dev);
2029 if (!match)
2030 return -ENODEV;
2031
2032 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01002033
Andrzej Hajda930865f2014-11-17 09:54:20 +01002034 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002035
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002036 hdata->dev = dev;
2037
2038 ret = hdmi_resources_init(hdata);
2039 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302040 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002041 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002042 }
2043
2044 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002045 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09002046 if (IS_ERR(hdata->regs)) {
2047 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09002048 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09002049 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002050
Inki Daee2a562d2014-05-09 16:46:10 +09002051 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
2052 if (ddc_node)
2053 goto out_get_ddc_adpt;
2054
Daniel Kurtz2b768132014-02-24 18:52:51 +09002055 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2056 if (!ddc_node) {
2057 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09002058 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002059 }
Inki Daee2a562d2014-05-09 16:46:10 +09002060
2061out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002062 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2063 if (!hdata->ddc_adpt) {
2064 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002065 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002066 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002067
Inki Daee2a562d2014-05-09 16:46:10 +09002068 phy_node = hdmi_legacy_phy_dt_binding(dev);
2069 if (phy_node)
2070 goto out_get_phy_port;
2071
Daniel Kurtz2b768132014-02-24 18:52:51 +09002072 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2073 if (!phy_node) {
2074 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2075 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002076 goto err_ddc;
2077 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002078
Inki Daee2a562d2014-05-09 16:46:10 +09002079out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02002080 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002081 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2082 if (!hdata->regs_hdmiphy) {
2083 DRM_ERROR("failed to ioremap hdmi phy\n");
2084 ret = -ENOMEM;
2085 goto err_ddc;
2086 }
2087 } else {
2088 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2089 if (!hdata->hdmiphy_port) {
2090 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002091 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002092 goto err_ddc;
2093 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002094 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002095
Sean Paul724fd142014-05-09 15:05:10 +09002096 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2097
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002098 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002099 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002100 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002101 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002102 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002103 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002104 goto err_hdmiphy;
2105 }
2106
Rahul Sharma049d34e2014-05-20 10:36:05 +05302107 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2108 "samsung,syscon-phandle");
2109 if (IS_ERR(hdata->pmureg)) {
2110 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002111 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302112 goto err_hdmiphy;
2113 }
2114
Andrzej Hajda68cd0042016-01-14 14:40:07 +09002115 if (hdata->drv_data->has_sysreg) {
2116 hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
2117 "samsung,sysreg-phandle");
2118 if (IS_ERR(hdata->sysreg)) {
2119 DRM_ERROR("sysreg regmap lookup failed.\n");
2120 ret = -EPROBE_DEFER;
2121 goto err_hdmiphy;
2122 }
2123 }
2124
Sean Paulaf65c802014-01-30 16:19:27 -05002125 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002126
Inki Daedf5225b2014-05-29 18:28:02 +09002127 ret = component_add(&pdev->dev, &hdmi_component_ops);
2128 if (ret)
2129 goto err_disable_pm_runtime;
2130
2131 return ret;
2132
2133err_disable_pm_runtime:
2134 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002135
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002136err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002137 if (hdata->hdmiphy_port)
2138 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002139err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002140 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002141
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002142 return ret;
2143}
2144
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002145static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002146{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002147 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002148
Sean Paul724fd142014-05-09 15:05:10 +09002149 cancel_delayed_work_sync(&hdata->hotplug_work);
2150
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002151 component_del(&pdev->dev, &hdmi_component_ops);
2152
2153 pm_runtime_disable(&pdev->dev);
2154
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02002155 if (!IS_ERR(hdata->reg_hdmi_en))
2156 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002157
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002158 if (hdata->hdmiphy_port)
2159 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002160
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002161 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002162
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002163 return 0;
2164}
2165
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002166#ifdef CONFIG_PM
2167static int exynos_hdmi_suspend(struct device *dev)
2168{
2169 struct hdmi_context *hdata = dev_get_drvdata(dev);
2170
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002171 hdmi_clk_disable_gates(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002172
2173 return 0;
2174}
2175
2176static int exynos_hdmi_resume(struct device *dev)
2177{
2178 struct hdmi_context *hdata = dev_get_drvdata(dev);
2179 int ret;
2180
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002181 ret = hdmi_clk_enable_gates(hdata);
2182 if (ret < 0)
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002183 return ret;
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002184
2185 return 0;
2186}
2187#endif
2188
2189static const struct dev_pm_ops exynos_hdmi_pm_ops = {
2190 SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
2191};
2192
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002193struct platform_driver hdmi_driver = {
2194 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002195 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302197 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002198 .owner = THIS_MODULE,
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002199 .pm = &exynos_hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302200 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002201 },
2202};