blob: 1b60cc758affb5dc36e8bb1b364bf3d394a610ed [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
Andrzej Hajda2228b7c2015-09-25 14:48:24 +020033#include <linux/gpio/consumer.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020037#include <linux/of_device.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090047
Sean Paul724fd142014-05-09 15:05:10 +090048#define HOTPLUG_DEBOUNCE_MS 1100
49
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053050/* AVI header and aspect ratio */
51#define HDMI_AVI_VERSION 0x02
52#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053
54/* AUI header info */
55#define HDMI_AUI_VERSION 0x01
56#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053057#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
58#define AVI_4_3_CENTER_RATIO 0x9
59#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053060
Rahul Sharma5a325072012-10-04 20:48:54 +053061enum hdmi_type {
62 HDMI_TYPE13,
63 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020064 HDMI_TYPE_COUNT
65};
66
67#define HDMI_MAPPED_BASE 0xffff0000
68
69enum hdmi_mapped_regs {
70 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
71 HDMI_PHY_RSTOUT,
72 HDMI_ACR_CON,
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020073 HDMI_ACR_MCTS0,
74 HDMI_ACR_CTS0,
75 HDMI_ACR_N0
Andrzej Hajda633d00b2015-09-25 14:48:16 +020076};
77
78static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
79 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
80 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
81 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +020082 { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
83 { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
84 { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
Rahul Sharma5a325072012-10-04 20:48:54 +053085};
86
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020087static const char * const supply[] = {
88 "vdd",
89 "vdd_osc",
90 "vdd_pll",
91};
92
Andrzej Hajda65e98032015-11-02 14:16:41 +010093struct hdmiphy_config {
94 int pixel_clock;
95 u8 conf[32];
96};
97
98struct hdmiphy_configs {
99 int count;
100 const struct hdmiphy_config *data;
101};
102
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900103struct string_array_spec {
104 int count;
105 const char * const *data;
106};
107
108#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a }
109
Inki Daebfe4e842014-03-06 14:18:17 +0900110struct hdmi_driver_data {
111 unsigned int type;
112 unsigned int is_apb_phy:1;
Andrzej Hajda65e98032015-11-02 14:16:41 +0100113 struct hdmiphy_configs phy_confs;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900114 struct string_array_spec clk_gates;
115 /*
116 * Array of triplets (p_off, p_on, clock), where p_off and p_on are
117 * required parents of clock when HDMI-PHY is respectively off or on.
118 */
119 struct string_array_spec clk_muxes;
Inki Daebfe4e842014-03-06 14:18:17 +0900120};
121
Joonyoung Shim590f4182012-03-16 18:47:14 +0900122struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300123 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900124 struct device *dev;
125 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500126 struct drm_connector connector;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900127 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900128 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900129 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530130 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200131 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200132 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900133
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200134 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900135 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200136 struct i2c_client *hdmiphy_port;
137 struct i2c_adapter *ddc_adpt;
Gustavo Padovanf28464c2015-11-02 20:39:18 +0900138 struct gpio_desc *hpd_gpio;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200139 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530140 struct regmap *pmureg;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900141 struct clk **clk_gates;
142 struct clk **clk_muxes;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200143 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
144 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900145};
146
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300147static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100148{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900149 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100150}
151
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200152static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
153{
154 return container_of(c, struct hdmi_context, connector);
155}
156
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900157/* list of phy config settings */
158static const struct hdmiphy_config hdmiphy_v13_configs[] = {
159 {
160 .pixel_clock = 27000000,
161 .conf = {
162 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
163 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
164 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200165 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166 },
167 },
168 {
169 .pixel_clock = 27027000,
170 .conf = {
171 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
172 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
173 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200174 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900175 },
176 },
177 {
178 .pixel_clock = 74176000,
179 .conf = {
180 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
181 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
182 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200183 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900184 },
185 },
186 {
187 .pixel_clock = 74250000,
188 .conf = {
189 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
190 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
191 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200192 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900193 },
194 },
195 {
196 .pixel_clock = 148500000,
197 .conf = {
198 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
199 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
200 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200201 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900202 },
203 },
204};
205
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500206static const struct hdmiphy_config hdmiphy_v14_configs[] = {
207 {
208 .pixel_clock = 25200000,
209 .conf = {
210 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
211 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
212 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
213 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
214 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900215 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500216 {
217 .pixel_clock = 27000000,
218 .conf = {
219 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
220 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
221 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
222 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
223 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900224 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500225 {
226 .pixel_clock = 27027000,
227 .conf = {
228 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
229 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
230 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200231 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500232 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900233 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500234 {
235 .pixel_clock = 36000000,
236 .conf = {
237 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
238 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
239 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
240 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
241 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900242 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500243 {
244 .pixel_clock = 40000000,
245 .conf = {
246 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
247 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
248 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
249 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
250 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900251 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500252 {
253 .pixel_clock = 65000000,
254 .conf = {
255 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
256 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
257 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
258 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
259 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900260 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500261 {
Shirish Se1d883c2014-03-13 14:28:27 +0900262 .pixel_clock = 71000000,
263 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530264 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
265 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
266 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900267 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
268 },
269 },
270 {
271 .pixel_clock = 73250000,
272 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530273 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
274 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
275 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900276 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
277 },
278 },
279 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500280 .pixel_clock = 74176000,
281 .conf = {
282 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
283 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
284 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
285 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
286 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900287 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500288 {
289 .pixel_clock = 74250000,
290 .conf = {
291 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
292 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
293 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200294 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500295 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900296 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500297 {
298 .pixel_clock = 83500000,
299 .conf = {
300 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
301 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
302 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
303 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
304 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900305 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500306 {
307 .pixel_clock = 106500000,
308 .conf = {
309 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
310 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
311 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
312 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
313 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900314 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500315 {
316 .pixel_clock = 108000000,
317 .conf = {
318 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
319 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
320 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
321 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
322 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900323 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500324 {
Shirish Se1d883c2014-03-13 14:28:27 +0900325 .pixel_clock = 115500000,
326 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530327 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
328 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
329 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900330 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
331 },
332 },
333 {
334 .pixel_clock = 119000000,
335 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530336 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
337 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
338 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900339 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
340 },
341 },
342 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500343 .pixel_clock = 146250000,
344 .conf = {
345 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
346 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
347 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
348 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
349 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900350 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500351 {
352 .pixel_clock = 148500000,
353 .conf = {
354 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
355 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
356 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200357 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500358 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900359 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900360};
361
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530362static const struct hdmiphy_config hdmiphy_5420_configs[] = {
363 {
364 .pixel_clock = 25200000,
365 .conf = {
366 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
367 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
368 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
369 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
370 },
371 },
372 {
373 .pixel_clock = 27000000,
374 .conf = {
375 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
376 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
377 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
378 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
379 },
380 },
381 {
382 .pixel_clock = 27027000,
383 .conf = {
384 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
385 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
386 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
387 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
388 },
389 },
390 {
391 .pixel_clock = 36000000,
392 .conf = {
393 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
394 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
395 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
396 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
397 },
398 },
399 {
400 .pixel_clock = 40000000,
401 .conf = {
402 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
403 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
404 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
405 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
406 },
407 },
408 {
409 .pixel_clock = 65000000,
410 .conf = {
411 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
412 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
413 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
414 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
415 },
416 },
417 {
418 .pixel_clock = 71000000,
419 .conf = {
420 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
421 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
422 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
423 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
424 },
425 },
426 {
427 .pixel_clock = 73250000,
428 .conf = {
429 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
430 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
431 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
432 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
433 },
434 },
435 {
436 .pixel_clock = 74176000,
437 .conf = {
438 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
439 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
440 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
441 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
442 },
443 },
444 {
445 .pixel_clock = 74250000,
446 .conf = {
447 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
448 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
449 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
450 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
451 },
452 },
453 {
454 .pixel_clock = 83500000,
455 .conf = {
456 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
457 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
458 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
459 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
460 },
461 },
462 {
463 .pixel_clock = 88750000,
464 .conf = {
465 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
466 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
467 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
468 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
469 },
470 },
471 {
472 .pixel_clock = 106500000,
473 .conf = {
474 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
475 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
476 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
477 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
478 },
479 },
480 {
481 .pixel_clock = 108000000,
482 .conf = {
483 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
484 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
485 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
486 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
487 },
488 },
489 {
490 .pixel_clock = 115500000,
491 .conf = {
492 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
493 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
494 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
495 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
496 },
497 },
498 {
499 .pixel_clock = 146250000,
500 .conf = {
501 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
502 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
503 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
504 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
505 },
506 },
507 {
508 .pixel_clock = 148500000,
509 .conf = {
510 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
511 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
512 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
513 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
514 },
515 },
516};
517
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100518static const char * const hdmi_clk_gates4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900519 "hdmi", "sclk_hdmi"
520};
521
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100522static const char * const hdmi_clk_muxes4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900523 "sclk_pixel", "sclk_hdmiphy", "mout_hdmi"
524};
525
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100526static const struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530527 .type = HDMI_TYPE14,
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530528 .is_apb_phy = 1,
Andrzej Hajda65e98032015-11-02 14:16:41 +0100529 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900530 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
531 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530532};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900533
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100534static const struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900535 .type = HDMI_TYPE14,
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900536 .is_apb_phy = 0,
Andrzej Hajda65e98032015-11-02 14:16:41 +0100537 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900538 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
539 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900540};
541
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100542static const struct hdmi_driver_data exynos4210_hdmi_driver_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200543 .type = HDMI_TYPE13,
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200544 .is_apb_phy = 0,
Andrzej Hajda65e98032015-11-02 14:16:41 +0100545 .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs),
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900546 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
547 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200548};
549
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200550static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
551{
552 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
553 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
554 return reg_id;
555}
556
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900557static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
558{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200559 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900560}
561
562static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
563 u32 reg_id, u8 value)
564{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200565 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900566}
567
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200568static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
569 int bytes, u32 val)
570{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200571 reg_id = hdmi_map_reg(hdata, reg_id);
572
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200573 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200574 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200575 val >>= 8;
576 reg_id += 4;
577 }
578}
579
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900580static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
581 u32 reg_id, u32 value, u32 mask)
582{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200583 u32 old;
584
585 reg_id = hdmi_map_reg(hdata, reg_id);
586 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900587 value = (value & mask) | (old & ~mask);
588 writel(value, hdata->regs + reg_id);
589}
590
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900591static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
592 u32 reg_offset, const u8 *buf, u32 len)
593{
594 if ((reg_offset + len) > 32)
595 return -EINVAL;
596
597 if (hdata->hdmiphy_port) {
598 int ret;
599
600 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
601 if (ret == len)
602 return 0;
603 return ret;
604 } else {
605 int i;
606 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200607 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900608 ((reg_offset + i)<<2));
609 return 0;
610 }
611}
612
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900613static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900614{
615#define DUMPREG(reg_id) \
616 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
617 readl(hdata->regs + reg_id))
618 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
619 DUMPREG(HDMI_INTC_FLAG);
620 DUMPREG(HDMI_INTC_CON);
621 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900622 DUMPREG(HDMI_V13_PHY_RSTOUT);
623 DUMPREG(HDMI_V13_PHY_VPLL);
624 DUMPREG(HDMI_V13_PHY_CMU);
625 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900626
627 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
628 DUMPREG(HDMI_CON_0);
629 DUMPREG(HDMI_CON_1);
630 DUMPREG(HDMI_CON_2);
631 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900632 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900633 DUMPREG(HDMI_STATUS_EN);
634 DUMPREG(HDMI_HPD);
635 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900636 DUMPREG(HDMI_V13_HPD_GEN);
637 DUMPREG(HDMI_V13_DC_CONTROL);
638 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900639
640 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
641 DUMPREG(HDMI_H_BLANK_0);
642 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900643 DUMPREG(HDMI_V13_V_BLANK_0);
644 DUMPREG(HDMI_V13_V_BLANK_1);
645 DUMPREG(HDMI_V13_V_BLANK_2);
646 DUMPREG(HDMI_V13_H_V_LINE_0);
647 DUMPREG(HDMI_V13_H_V_LINE_1);
648 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900649 DUMPREG(HDMI_VSYNC_POL);
650 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900651 DUMPREG(HDMI_V13_V_BLANK_F_0);
652 DUMPREG(HDMI_V13_V_BLANK_F_1);
653 DUMPREG(HDMI_V13_V_BLANK_F_2);
654 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
655 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
656 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
657 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
658 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
659 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
660 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
661 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
662 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
663 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
664 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
665 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900666
667 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
668 DUMPREG(HDMI_TG_CMD);
669 DUMPREG(HDMI_TG_H_FSZ_L);
670 DUMPREG(HDMI_TG_H_FSZ_H);
671 DUMPREG(HDMI_TG_HACT_ST_L);
672 DUMPREG(HDMI_TG_HACT_ST_H);
673 DUMPREG(HDMI_TG_HACT_SZ_L);
674 DUMPREG(HDMI_TG_HACT_SZ_H);
675 DUMPREG(HDMI_TG_V_FSZ_L);
676 DUMPREG(HDMI_TG_V_FSZ_H);
677 DUMPREG(HDMI_TG_VSYNC_L);
678 DUMPREG(HDMI_TG_VSYNC_H);
679 DUMPREG(HDMI_TG_VSYNC2_L);
680 DUMPREG(HDMI_TG_VSYNC2_H);
681 DUMPREG(HDMI_TG_VACT_ST_L);
682 DUMPREG(HDMI_TG_VACT_ST_H);
683 DUMPREG(HDMI_TG_VACT_SZ_L);
684 DUMPREG(HDMI_TG_VACT_SZ_H);
685 DUMPREG(HDMI_TG_FIELD_CHG_L);
686 DUMPREG(HDMI_TG_FIELD_CHG_H);
687 DUMPREG(HDMI_TG_VACT_ST2_L);
688 DUMPREG(HDMI_TG_VACT_ST2_H);
689 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
690 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
691 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
692 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
693 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
694 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
695 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
696 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
697#undef DUMPREG
698}
699
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900700static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
701{
702 int i;
703
704#define DUMPREG(reg_id) \
705 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
706 readl(hdata->regs + reg_id))
707
708 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
709 DUMPREG(HDMI_INTC_CON);
710 DUMPREG(HDMI_INTC_FLAG);
711 DUMPREG(HDMI_HPD_STATUS);
712 DUMPREG(HDMI_INTC_CON_1);
713 DUMPREG(HDMI_INTC_FLAG_1);
714 DUMPREG(HDMI_PHY_STATUS_0);
715 DUMPREG(HDMI_PHY_STATUS_PLL);
716 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200717 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900718 DUMPREG(HDMI_PHY_VPLL);
719 DUMPREG(HDMI_PHY_CMU);
720 DUMPREG(HDMI_CORE_RSTOUT);
721
722 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
723 DUMPREG(HDMI_CON_0);
724 DUMPREG(HDMI_CON_1);
725 DUMPREG(HDMI_CON_2);
726 DUMPREG(HDMI_SYS_STATUS);
727 DUMPREG(HDMI_PHY_STATUS_0);
728 DUMPREG(HDMI_STATUS_EN);
729 DUMPREG(HDMI_HPD);
730 DUMPREG(HDMI_MODE_SEL);
731 DUMPREG(HDMI_ENC_EN);
732 DUMPREG(HDMI_DC_CONTROL);
733 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
734
735 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
736 DUMPREG(HDMI_H_BLANK_0);
737 DUMPREG(HDMI_H_BLANK_1);
738 DUMPREG(HDMI_V2_BLANK_0);
739 DUMPREG(HDMI_V2_BLANK_1);
740 DUMPREG(HDMI_V1_BLANK_0);
741 DUMPREG(HDMI_V1_BLANK_1);
742 DUMPREG(HDMI_V_LINE_0);
743 DUMPREG(HDMI_V_LINE_1);
744 DUMPREG(HDMI_H_LINE_0);
745 DUMPREG(HDMI_H_LINE_1);
746 DUMPREG(HDMI_HSYNC_POL);
747
748 DUMPREG(HDMI_VSYNC_POL);
749 DUMPREG(HDMI_INT_PRO_MODE);
750 DUMPREG(HDMI_V_BLANK_F0_0);
751 DUMPREG(HDMI_V_BLANK_F0_1);
752 DUMPREG(HDMI_V_BLANK_F1_0);
753 DUMPREG(HDMI_V_BLANK_F1_1);
754
755 DUMPREG(HDMI_H_SYNC_START_0);
756 DUMPREG(HDMI_H_SYNC_START_1);
757 DUMPREG(HDMI_H_SYNC_END_0);
758 DUMPREG(HDMI_H_SYNC_END_1);
759
760 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
761 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
762 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
763 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
764
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
769
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
773 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
774
775 DUMPREG(HDMI_V_BLANK_F2_0);
776 DUMPREG(HDMI_V_BLANK_F2_1);
777 DUMPREG(HDMI_V_BLANK_F3_0);
778 DUMPREG(HDMI_V_BLANK_F3_1);
779 DUMPREG(HDMI_V_BLANK_F4_0);
780 DUMPREG(HDMI_V_BLANK_F4_1);
781 DUMPREG(HDMI_V_BLANK_F5_0);
782 DUMPREG(HDMI_V_BLANK_F5_1);
783
784 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
785 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
786 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
787 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
788 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
789 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
790 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
791 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
792
793 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
794 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
795 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
796 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
797 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
798 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
799 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
800 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
801
802 DUMPREG(HDMI_VACT_SPACE_1_0);
803 DUMPREG(HDMI_VACT_SPACE_1_1);
804 DUMPREG(HDMI_VACT_SPACE_2_0);
805 DUMPREG(HDMI_VACT_SPACE_2_1);
806 DUMPREG(HDMI_VACT_SPACE_3_0);
807 DUMPREG(HDMI_VACT_SPACE_3_1);
808 DUMPREG(HDMI_VACT_SPACE_4_0);
809 DUMPREG(HDMI_VACT_SPACE_4_1);
810 DUMPREG(HDMI_VACT_SPACE_5_0);
811 DUMPREG(HDMI_VACT_SPACE_5_1);
812 DUMPREG(HDMI_VACT_SPACE_6_0);
813 DUMPREG(HDMI_VACT_SPACE_6_1);
814
815 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
816 DUMPREG(HDMI_TG_CMD);
817 DUMPREG(HDMI_TG_H_FSZ_L);
818 DUMPREG(HDMI_TG_H_FSZ_H);
819 DUMPREG(HDMI_TG_HACT_ST_L);
820 DUMPREG(HDMI_TG_HACT_ST_H);
821 DUMPREG(HDMI_TG_HACT_SZ_L);
822 DUMPREG(HDMI_TG_HACT_SZ_H);
823 DUMPREG(HDMI_TG_V_FSZ_L);
824 DUMPREG(HDMI_TG_V_FSZ_H);
825 DUMPREG(HDMI_TG_VSYNC_L);
826 DUMPREG(HDMI_TG_VSYNC_H);
827 DUMPREG(HDMI_TG_VSYNC2_L);
828 DUMPREG(HDMI_TG_VSYNC2_H);
829 DUMPREG(HDMI_TG_VACT_ST_L);
830 DUMPREG(HDMI_TG_VACT_ST_H);
831 DUMPREG(HDMI_TG_VACT_SZ_L);
832 DUMPREG(HDMI_TG_VACT_SZ_H);
833 DUMPREG(HDMI_TG_FIELD_CHG_L);
834 DUMPREG(HDMI_TG_FIELD_CHG_H);
835 DUMPREG(HDMI_TG_VACT_ST2_L);
836 DUMPREG(HDMI_TG_VACT_ST2_H);
837 DUMPREG(HDMI_TG_VACT_ST3_L);
838 DUMPREG(HDMI_TG_VACT_ST3_H);
839 DUMPREG(HDMI_TG_VACT_ST4_L);
840 DUMPREG(HDMI_TG_VACT_ST4_H);
841 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
842 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
843 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
844 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
845 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
846 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
847 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
848 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
849 DUMPREG(HDMI_TG_3D);
850
851 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
852 DUMPREG(HDMI_AVI_CON);
853 DUMPREG(HDMI_AVI_HEADER0);
854 DUMPREG(HDMI_AVI_HEADER1);
855 DUMPREG(HDMI_AVI_HEADER2);
856 DUMPREG(HDMI_AVI_CHECK_SUM);
857 DUMPREG(HDMI_VSI_CON);
858 DUMPREG(HDMI_VSI_HEADER0);
859 DUMPREG(HDMI_VSI_HEADER1);
860 DUMPREG(HDMI_VSI_HEADER2);
861 for (i = 0; i < 7; ++i)
862 DUMPREG(HDMI_VSI_DATA(i));
863
864#undef DUMPREG
865}
866
867static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
868{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200869 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900870 hdmi_v13_regs_dump(hdata, prefix);
871 else
872 hdmi_v14_regs_dump(hdata, prefix);
873}
874
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900875static int hdmi_clk_enable_gates(struct hdmi_context *hdata)
876{
877 int i, ret;
878
879 for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) {
880 ret = clk_prepare_enable(hdata->clk_gates[i]);
881 if (!ret)
882 continue;
883
884 dev_err(hdata->dev, "Cannot enable clock '%s', %d\n",
885 hdata->drv_data->clk_gates.data[i], ret);
886 while (i--)
887 clk_disable_unprepare(hdata->clk_gates[i]);
888 return ret;
889 }
890
891 return 0;
892}
893
894static void hdmi_clk_disable_gates(struct hdmi_context *hdata)
895{
896 int i = hdata->drv_data->clk_gates.count;
897
898 while (i--)
899 clk_disable_unprepare(hdata->clk_gates[i]);
900}
901
902static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
903{
904 struct device *dev = hdata->dev;
905 int ret = 0;
906 int i;
907
908 for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) {
909 struct clk **c = &hdata->clk_muxes[i];
910
911 ret = clk_set_parent(c[2], c[to_phy]);
912 if (!ret)
913 continue;
914
915 dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n",
916 hdata->drv_data->clk_muxes.data[i + 2],
917 hdata->drv_data->clk_muxes.data[i + to_phy], ret);
918 }
919
920 return ret;
921}
922
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530923static u8 hdmi_chksum(struct hdmi_context *hdata,
924 u32 start, u8 len, u32 hdr_sum)
925{
926 int i;
927
928 /* hdr_sum : header0 + header1 + header2
929 * start : start address of packet byte1
930 * len : packet bytes - 1 */
931 for (i = 0; i < len; ++i)
932 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
933
934 /* return 2's complement of 8 bit hdr_sum */
935 return (u8)(~(hdr_sum & 0xff) + 1);
936}
937
938static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530939 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530940{
941 u32 hdr_sum;
942 u8 chksum;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200943 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530944
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530945 if (hdata->dvi_mode) {
946 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
947 HDMI_VSI_CON_DO_NOT_TRANSMIT);
948 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
949 HDMI_AVI_CON_DO_NOT_TRANSMIT);
950 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
951 return;
952 }
953
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530954 switch (infoframe->any.type) {
955 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530956 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530957 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
958 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
959 infoframe->any.version);
960 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
961 hdr_sum = infoframe->any.type + infoframe->any.version +
962 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530963
964 /* Output format zero hardcoded ,RGB YBCR selection */
965 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
966 AVI_ACTIVE_FORMAT_VALID |
967 AVI_UNDERSCANNED_DISPLAY_VALID);
968
Shirish S46154152014-03-13 10:58:28 +0530969 /*
970 * Set the aspect ratio as per the mode, mentioned in
971 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
972 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200973 ar = hdata->current_mode.picture_aspect_ratio;
974 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530975 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200976 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530977 break;
978 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200979 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530980 break;
981 case HDMI_PICTURE_ASPECT_NONE:
982 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200983 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530984 break;
985 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200986 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530987
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200988 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530989
990 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530991 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530992 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
993 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
994 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530995 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530996 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530997 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
998 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
999 infoframe->any.version);
1000 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1001 hdr_sum = infoframe->any.type + infoframe->any.version +
1002 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301003 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301004 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301005 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1006 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1007 break;
1008 default:
1009 break;
1010 }
1011}
1012
Sean Pauld9716ee2014-01-30 16:19:29 -05001013static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1014 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001015{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001016 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -05001017
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001018 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001019 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301020
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001021 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001022}
1023
Sean Pauld9716ee2014-01-30 16:19:29 -05001024static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001025{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001026 drm_connector_unregister(connector);
1027 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001028}
1029
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001030static const struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001031 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001032 .fill_modes = drm_helper_probe_single_connector_modes,
1033 .detect = hdmi_detect,
1034 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001035 .reset = drm_atomic_helper_connector_reset,
1036 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1037 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001038};
1039
1040static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001041{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001042 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001043 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001044 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001045
Inki Dae8fa04aa2014-03-13 16:38:31 +09001046 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001047 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001048
Inki Dae8fa04aa2014-03-13 16:38:31 +09001049 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001050 if (!edid)
1051 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001052
Sean Pauld9716ee2014-01-30 16:19:29 -05001053 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001054 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1055 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001056 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001057
Sean Pauld9716ee2014-01-30 16:19:29 -05001058 drm_mode_connector_update_edid_property(connector, edid);
1059
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001060 ret = drm_add_edid_modes(connector, edid);
1061
1062 kfree(edid);
1063
1064 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001065}
1066
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001067static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001068{
Andrzej Hajda65e98032015-11-02 14:16:41 +01001069 const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001070 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001071
Andrzej Hajda65e98032015-11-02 14:16:41 +01001072 for (i = 0; i < confs->count; i++)
1073 if (confs->data[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001074 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001075
1076 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1077 return -EINVAL;
1078}
1079
Sean Pauld9716ee2014-01-30 16:19:29 -05001080static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001081 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001082{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001083 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001084 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001085
Rahul Sharma16844fb2013-06-10 14:50:00 +05301086 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1087 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1088 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1089 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001090
Rahul Sharma16844fb2013-06-10 14:50:00 +05301091 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001092 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001093 return MODE_BAD;
1094
1095 return MODE_OK;
1096}
1097
1098static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1099{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001100 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001101
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001102 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001103}
1104
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001105static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001106 .get_modes = hdmi_get_modes,
1107 .mode_valid = hdmi_mode_valid,
1108 .best_encoder = hdmi_best_encoder,
1109};
1110
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001111static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001112{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001113 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001114 struct drm_connector *connector = &hdata->connector;
1115 int ret;
1116
Sean Pauld9716ee2014-01-30 16:19:29 -05001117 connector->interlace_allowed = true;
1118 connector->polled = DRM_CONNECTOR_POLL_HPD;
1119
1120 ret = drm_connector_init(hdata->drm_dev, connector,
1121 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1122 if (ret) {
1123 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001124 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001125 }
1126
1127 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001128 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001129 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001130
1131 return 0;
1132}
1133
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001134static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1135 const struct drm_display_mode *mode,
1136 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001137{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001138 struct drm_device *dev = encoder->dev;
1139 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001140 struct drm_display_mode *m;
1141 int mode_ok;
1142
Sean Paulf041b252014-01-30 16:19:15 -05001143 drm_mode_set_crtcinfo(adjusted_mode, 0);
1144
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001145 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1146 if (connector->encoder == encoder)
1147 break;
1148 }
1149
1150 if (connector->encoder != encoder)
1151 return true;
1152
Sean Pauld9716ee2014-01-30 16:19:29 -05001153 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001154
1155 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001156 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001157 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001158
1159 /*
1160 * otherwise, find the most suitable mode among modes and change it
1161 * to adjusted_mode.
1162 */
1163 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001164 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001165
Sean Pauld9716ee2014-01-30 16:19:29 -05001166 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001167 DRM_INFO("desired mode doesn't exist so\n");
1168 DRM_INFO("use the most suitable mode among modes.\n");
1169
1170 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1171 m->hdisplay, m->vdisplay, m->vrefresh);
1172
Sean Paul75626852014-01-30 16:19:16 -05001173 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001174 break;
1175 }
1176 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001177
1178 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001179}
1180
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001181static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001182{
1183 u32 n, cts;
1184
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001185 cts = (freq % 9) ? 27000 : 30000;
1186 n = 128 * freq / (27000000 / cts);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001187
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001188 hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
1189 hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
1190 hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001191 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001192}
1193
1194static void hdmi_audio_init(struct hdmi_context *hdata)
1195{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301196 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001197 u32 data_num, bit_ch, sample_frq;
1198 u32 val;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001199
1200 sample_rate = 44100;
1201 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001202
1203 switch (bits_per_sample) {
1204 case 20:
1205 data_num = 2;
1206 bit_ch = 1;
1207 break;
1208 case 24:
1209 data_num = 3;
1210 bit_ch = 1;
1211 break;
1212 default:
1213 data_num = 1;
1214 bit_ch = 0;
1215 break;
1216 }
1217
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001218 hdmi_reg_acr(hdata, sample_rate);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001219
1220 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1221 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1222 | HDMI_I2S_MUX_ENABLE);
1223
1224 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1225 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1226
1227 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1228
1229 sample_frq = (sample_rate == 44100) ? 0 :
1230 (sample_rate == 48000) ? 2 :
1231 (sample_rate == 32000) ? 3 :
1232 (sample_rate == 96000) ? 0xa : 0x0;
1233
1234 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1235 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1236
1237 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1238 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1239
1240 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1241 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1242 | HDMI_I2S_SEL_LRCK(6));
1243 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1244 | HDMI_I2S_SEL_SDATA2(4));
1245 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1246 | HDMI_I2S_SEL_SDATA2(2));
1247 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1248
1249 /* I2S_CON_1 & 2 */
1250 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1251 | HDMI_I2S_L_CH_LOW_POL);
1252 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1253 | HDMI_I2S_SET_BIT_CH(bit_ch)
1254 | HDMI_I2S_SET_SDATA_BIT(data_num)
1255 | HDMI_I2S_BASIC_FORMAT);
1256
1257 /* Configure register related to CUV information */
1258 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1259 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1260 | HDMI_I2S_COPYRIGHT
1261 | HDMI_I2S_LINEAR_PCM
1262 | HDMI_I2S_CONSUMER_FORMAT);
1263 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1264 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1265 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1266 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1267 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1268 HDMI_I2S_ORG_SMP_FREQ_44_1
1269 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1270 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1271
1272 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1273}
1274
1275static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1276{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001277 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001278 return;
1279
1280 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1281 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1282 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1283}
1284
Rahul Sharmabfa48422014-04-03 20:41:04 +05301285static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001286{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301287 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001288
Rahul Sharmabfa48422014-04-03 20:41:04 +05301289 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1290 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001291
Rahul Sharmabfa48422014-04-03 20:41:04 +05301292 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1293 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001294}
1295
1296static void hdmi_conf_init(struct hdmi_context *hdata)
1297{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301298 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301299
Sean Paul77006a72013-01-16 10:17:20 -05001300 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001301 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1302 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001303
1304 /* choose HDMI mode */
1305 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1306 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301307 /* Apply Video preable and Guard band in HDMI mode only */
1308 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001309 /* disable bluescreen */
1310 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001311
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001312 if (hdata->dvi_mode) {
1313 /* choose DVI mode */
1314 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1315 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1316 hdmi_reg_writeb(hdata, HDMI_CON_2,
1317 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1318 }
1319
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001320 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001321 /* choose bluescreen (fecal) color */
1322 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1323 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1324 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1325
1326 /* enable AVI packet every vsync, fixes purple line problem */
1327 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1328 /* force RGB, look to CEA-861-D, table 7 for more detail */
1329 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1330 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1331
1332 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1333 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1334 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1335 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301336 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1337 infoframe.any.version = HDMI_AVI_VERSION;
1338 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301339 hdmi_reg_infoframe(hdata, &infoframe);
1340
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301341 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1342 infoframe.any.version = HDMI_AUI_VERSION;
1343 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301344 hdmi_reg_infoframe(hdata, &infoframe);
1345
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001346 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001347 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1348 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001349}
1350
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001351static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1352{
1353 int tries;
1354
1355 for (tries = 0; tries < 10; ++tries) {
1356 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1357
1358 if (val & HDMI_PHY_STATUS_READY) {
1359 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1360 return;
1361 }
1362 usleep_range(10, 20);
1363 }
1364
1365 DRM_ERROR("PLL could not reach steady state\n");
1366}
1367
Rahul Sharma16844fb2013-06-10 14:50:00 +05301368static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001369{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001370 struct drm_display_mode *m = &hdata->current_mode;
1371 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001372
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001373 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1374 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1375 (m->htotal << 12) | m->vtotal);
1376
1377 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1378 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1379
1380 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1381 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1382
1383 val = (m->hsync_start - m->hdisplay - 2);
1384 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1385 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1386 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1387
1388 /*
1389 * Quirk requirement for exynos HDMI IP design,
1390 * 2 pixels less than the actual calculation for hsync_start
1391 * and end.
1392 */
1393
1394 /* Following values & calculations differ for different type of modes */
1395 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1396 /* Interlaced Mode */
1397 val = ((m->vsync_end - m->vdisplay) / 2);
1398 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1399 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1400
1401 val = m->vtotal / 2;
1402 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1403 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1404
1405 val = (m->vtotal +
1406 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1407 val |= m->vtotal << 11;
1408 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1409
1410 val = ((m->vtotal / 2) + 7);
1411 val |= ((m->vtotal / 2) + 2) << 12;
1412 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1413
1414 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1415 val |= ((m->htotal / 2) +
1416 (m->hsync_start - m->hdisplay)) << 12;
1417 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1418
1419 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1420 (m->vtotal - m->vdisplay) / 2);
1421 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1422
1423 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1424 } else {
1425 /* Progressive Mode */
1426
1427 val = m->vtotal;
1428 val |= (m->vtotal - m->vdisplay) << 11;
1429 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1430
1431 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1432
1433 val = (m->vsync_end - m->vdisplay);
1434 val |= ((m->vsync_start - m->vdisplay) << 12);
1435 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1436
1437 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1438 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1439 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1440 m->vtotal - m->vdisplay);
1441 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1442 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1443 }
1444
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001445 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001446 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1447 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1448 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1449 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1450 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1451 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1452 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1453 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1454 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1455 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1456 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001457}
1458
Rahul Sharma16844fb2013-06-10 14:50:00 +05301459static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001460{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001461 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001462
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001463 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1464 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1465 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1466 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1467 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1468 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1469 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1470 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1471 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1472
1473 /*
1474 * Quirk requirement for exynos 5 HDMI IP design,
1475 * 2 pixels less than the actual calculation for hsync_start
1476 * and end.
1477 */
1478
1479 /* Following values & calculations differ for different type of modes */
1480 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1481 /* Interlaced Mode */
1482 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1483 (m->vsync_end - m->vdisplay) / 2);
1484 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1485 (m->vsync_start - m->vdisplay) / 2);
1486 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1487 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1488 (m->vtotal - m->vdisplay) / 2);
1489 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1490 m->vtotal - m->vdisplay / 2);
1491 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1492 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1493 (m->vtotal / 2) + 7);
1494 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1495 (m->vtotal / 2) + 2);
1496 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1497 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1498 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1499 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1500 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1501 (m->vtotal - m->vdisplay) / 2);
1502 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1503 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1504 m->vtotal - m->vdisplay / 2);
1505 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1506 (m->vtotal / 2) + 1);
1507 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1508 (m->vtotal / 2) + 1);
1509 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1510 (m->vtotal / 2) + 1);
1511 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1512 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1513 } else {
1514 /* Progressive Mode */
1515 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1516 m->vsync_end - m->vdisplay);
1517 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1518 m->vsync_start - m->vdisplay);
1519 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1520 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1521 m->vtotal - m->vdisplay);
1522 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1523 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1524 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1525 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1526 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1527 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1528 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1529 m->vtotal - m->vdisplay);
1530 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1531 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1532 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1533 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1534 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1535 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1536 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1537 }
1538
1539 /* Following values & calculations are same irrespective of mode type */
1540 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1541 m->hsync_start - m->hdisplay - 2);
1542 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1543 m->hsync_end - m->hdisplay - 2);
1544 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1546 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1547 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1548 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1549 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1550 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1551 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1552 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1553 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1554 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1555 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1556 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1557 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1558 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1559 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1560 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1561 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001562
1563 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001564 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1565 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1566 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1567 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1568 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1569 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1570 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1571 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1572 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001573}
1574
Rahul Sharma16844fb2013-06-10 14:50:00 +05301575static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001576{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001577 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301578 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001579 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301580 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001581
1582 hdmiphy_wait_for_pll(hdata);
1583
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001584 hdmi_clk_set_parents(hdata, true);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001585
1586 /* enable HDMI and timing generator */
1587 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001588}
1589
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001590static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1591{
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001592 hdmi_clk_set_parents(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001593
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001594 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001595 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001596 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001597 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001598 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001599}
1600
1601static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1602{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001603 int ret;
1604 int i;
1605
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001606 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001607 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001608 if (i < 0) {
1609 DRM_ERROR("failed to find hdmiphy conf\n");
1610 return;
1611 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001612
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001613 ret = hdmiphy_reg_write_buf(hdata, 0,
Andrzej Hajda65e98032015-11-02 14:16:41 +01001614 hdata->drv_data->phy_confs.data[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001615 if (ret) {
1616 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001617 return;
1618 }
1619
Sean Paul09760ea2013-01-14 17:03:20 -05001620 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001621}
1622
1623static void hdmi_conf_apply(struct hdmi_context *hdata)
1624{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001625 hdmiphy_conf_reset(hdata);
1626 hdmiphy_conf_apply(hdata);
1627
Rahul Sharmabfa48422014-04-03 20:41:04 +05301628 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001629 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001630
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001631 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001632
1633 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301634 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001635 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001636
1637 hdmi_regs_dump(hdata, "start");
1638}
1639
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001640static void hdmi_mode_set(struct drm_encoder *encoder,
1641 struct drm_display_mode *mode,
1642 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001643{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001644 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001645 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001646
YoungJun Chocbc4c332013-06-12 10:44:40 +09001647 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1648 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001649 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001650 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001651
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001652 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001653 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001654}
1655
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001656static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001657{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001658 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001659
Andrzej Hajda882a0642015-07-09 16:28:08 +02001660 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001661 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001662
Sean Paulaf65c802014-01-30 16:19:27 -05001663 pm_runtime_get_sync(hdata->dev);
1664
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001665 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001666 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1667
Rahul Sharma049d34e2014-05-20 10:36:05 +05301668 /* set pmu hdmiphy control bit to enable hdmiphy */
1669 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1670 PMU_HDMI_PHY_ENABLE_BIT, 1);
1671
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001672 hdmi_conf_apply(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09001673
1674 hdata->powered = true;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001675}
1676
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001677static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001678{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001679 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001680 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001681 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001682
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001683 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001684 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001685
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001686 /*
1687 * The SFRs of VP and Mixer are updated by Vertical Sync of
1688 * Timing generator which is a part of HDMI so the sequence
1689 * to disable TV Subsystem should be as following,
1690 * VP -> Mixer -> HDMI
1691 *
1692 * Below codes will try to disable Mixer and VP(if used)
1693 * prior to disabling HDMI.
1694 */
1695 if (crtc)
1696 funcs = crtc->helper_private;
1697 if (funcs && funcs->disable)
1698 (*funcs->disable)(crtc);
1699
Rahul Sharmabfa48422014-04-03 20:41:04 +05301700 /* HDMI System Disable */
1701 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1702
Sean Paul724fd142014-05-09 15:05:10 +09001703 cancel_delayed_work(&hdata->hotplug_work);
1704
Rahul Sharma049d34e2014-05-20 10:36:05 +05301705 /* reset pmu hdmiphy control bit to disable hdmiphy */
1706 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1707 PMU_HDMI_PHY_ENABLE_BIT, 0);
1708
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001709 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001710
Sean Paulaf65c802014-01-30 16:19:27 -05001711 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001712
1713 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001714}
1715
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001716static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001717 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001718 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001719 .enable = hdmi_enable,
1720 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001721};
1722
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001723static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001724 .destroy = drm_encoder_cleanup,
1725};
1726
Sean Paul724fd142014-05-09 15:05:10 +09001727static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001728{
Sean Paul724fd142014-05-09 15:05:10 +09001729 struct hdmi_context *hdata;
1730
1731 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001732
Sean Paul45517892014-01-30 16:19:05 -05001733 if (hdata->drm_dev)
1734 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001735}
1736
1737static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1738{
1739 struct hdmi_context *hdata = arg;
1740
1741 mod_delayed_work(system_wq, &hdata->hotplug_work,
1742 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001743
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001744 return IRQ_HANDLED;
1745}
1746
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001747static int hdmi_clks_get(struct hdmi_context *hdata,
1748 const struct string_array_spec *names,
1749 struct clk **clks)
1750{
1751 struct device *dev = hdata->dev;
1752 int i;
1753
1754 for (i = 0; i < names->count; ++i) {
1755 struct clk *clk = devm_clk_get(dev, names->data[i]);
1756
1757 if (IS_ERR(clk)) {
1758 int ret = PTR_ERR(clk);
1759
1760 dev_err(dev, "Cannot get clock %s, %d\n",
1761 names->data[i], ret);
1762
1763 return ret;
1764 }
1765
1766 clks[i] = clk;
1767 }
1768
1769 return 0;
1770}
1771
1772static int hdmi_clk_init(struct hdmi_context *hdata)
1773{
1774 const struct hdmi_driver_data *drv_data = hdata->drv_data;
1775 int count = drv_data->clk_gates.count + drv_data->clk_muxes.count;
1776 struct device *dev = hdata->dev;
1777 struct clk **clks;
1778 int ret;
1779
1780 if (!count)
1781 return 0;
1782
1783 clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL);
1784 if (!clks)
1785 return -ENOMEM;
1786
1787 hdata->clk_gates = clks;
1788 hdata->clk_muxes = clks + drv_data->clk_gates.count;
1789
1790 ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates);
1791 if (ret)
1792 return ret;
1793
1794 return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes);
1795}
1796
1797
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001798static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001799{
1800 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001801 int i, ret;
1802
1803 DRM_DEBUG_KMS("HDMI resource init\n");
1804
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001805 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1806 if (IS_ERR(hdata->hpd_gpio)) {
1807 DRM_ERROR("cannot get hpd gpio property\n");
1808 return PTR_ERR(hdata->hpd_gpio);
1809 }
1810
1811 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1812 if (hdata->irq < 0) {
1813 DRM_ERROR("failed to get GPIO irq\n");
1814 return hdata->irq;
1815 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001816
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001817 ret = hdmi_clk_init(hdata);
1818 if (ret)
1819 return ret;
1820
1821 ret = hdmi_clk_set_parents(hdata, false);
1822 if (ret)
1823 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001824
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001825 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001826 hdata->regul_bulk[i].supply = supply[i];
1827 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001828 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001829 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001830 if (ret) {
1831 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001832 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001833 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001834
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001835 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001836
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001837 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001838 return 0;
1839
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001840 if (IS_ERR(hdata->reg_hdmi_en))
1841 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001842
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001843 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001844 if (ret)
1845 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001846
Inki Daedf5225b2014-05-29 18:28:02 +09001847 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001848}
1849
Rahul Sharma22c4f422012-10-04 20:48:55 +05301850static struct of_device_id hdmi_match_types[] = {
1851 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001852 .compatible = "samsung,exynos4210-hdmi",
1853 .data = &exynos4210_hdmi_driver_data,
1854 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301855 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001856 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301857 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301858 .compatible = "samsung,exynos5420-hdmi",
1859 .data = &exynos5420_hdmi_driver_data,
1860 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301861 /* end node */
1862 }
1863};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001864MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301865
Inki Daef37cd5e2014-05-09 14:25:20 +09001866static int hdmi_bind(struct device *dev, struct device *master, void *data)
1867{
1868 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001869 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001870 struct drm_encoder *encoder = &hdata->encoder;
1871 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001872
Inki Daef37cd5e2014-05-09 14:25:20 +09001873 hdata->drm_dev = drm_dev;
1874
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001875 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1876 EXYNOS_DISPLAY_TYPE_HDMI);
1877 if (pipe < 0)
1878 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001879
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001880 encoder->possible_crtcs = 1 << pipe;
1881
1882 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1883
1884 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
Ville Syrjälä13a3d912015-12-09 16:20:18 +02001885 DRM_MODE_ENCODER_TMDS, NULL);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001886
1887 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1888
1889 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001890 if (ret) {
1891 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001892 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001893 return ret;
1894 }
1895
1896 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001897}
1898
1899static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1900{
Inki Daef37cd5e2014-05-09 14:25:20 +09001901}
1902
1903static const struct component_ops hdmi_component_ops = {
1904 .bind = hdmi_bind,
1905 .unbind = hdmi_unbind,
1906};
1907
Inki Daee2a562d2014-05-09 16:46:10 +09001908static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1909{
1910 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1911 struct device_node *np;
1912
1913 np = of_find_compatible_node(NULL, NULL, compatible_str);
1914 if (np)
1915 return of_get_next_parent(np);
1916
1917 return NULL;
1918}
1919
1920static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1921{
1922 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1923
1924 return of_find_compatible_node(NULL, NULL, compatible_str);
1925}
1926
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001927static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001928{
Inki Daef37cd5e2014-05-09 14:25:20 +09001929 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001930 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001931 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001932 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001933 struct resource *res;
1934 int ret;
1935
Andrzej Hajda930865f2014-11-17 09:54:20 +01001936 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1937 if (!hdata)
1938 return -ENOMEM;
1939
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001940 match = of_match_device(hdmi_match_types, dev);
1941 if (!match)
1942 return -ENODEV;
1943
1944 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001945
Andrzej Hajda930865f2014-11-17 09:54:20 +01001946 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001947
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001948 hdata->dev = dev;
1949
1950 ret = hdmi_resources_init(hdata);
1951 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301952 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001953 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001954 }
1955
1956 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001957 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001958 if (IS_ERR(hdata->regs)) {
1959 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001960 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001961 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001962
Inki Daee2a562d2014-05-09 16:46:10 +09001963 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1964 if (ddc_node)
1965 goto out_get_ddc_adpt;
1966
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001967 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001968 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1969 if (!ddc_node) {
1970 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001971 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001972 }
Inki Daee2a562d2014-05-09 16:46:10 +09001973
1974out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001975 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1976 if (!hdata->ddc_adpt) {
1977 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001978 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001979 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001980
Inki Daee2a562d2014-05-09 16:46:10 +09001981 phy_node = hdmi_legacy_phy_dt_binding(dev);
1982 if (phy_node)
1983 goto out_get_phy_port;
1984
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001985 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001986 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1987 if (!phy_node) {
1988 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1989 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001990 goto err_ddc;
1991 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001992
Inki Daee2a562d2014-05-09 16:46:10 +09001993out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001994 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001995 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1996 if (!hdata->regs_hdmiphy) {
1997 DRM_ERROR("failed to ioremap hdmi phy\n");
1998 ret = -ENOMEM;
1999 goto err_ddc;
2000 }
2001 } else {
2002 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2003 if (!hdata->hdmiphy_port) {
2004 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002005 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002006 goto err_ddc;
2007 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002008 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002009
Sean Paul724fd142014-05-09 15:05:10 +09002010 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2011
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002012 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002013 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002014 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002015 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002016 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002017 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002018 goto err_hdmiphy;
2019 }
2020
Rahul Sharma049d34e2014-05-20 10:36:05 +05302021 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2022 "samsung,syscon-phandle");
2023 if (IS_ERR(hdata->pmureg)) {
2024 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002025 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302026 goto err_hdmiphy;
2027 }
2028
Sean Paulaf65c802014-01-30 16:19:27 -05002029 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002030
Inki Daedf5225b2014-05-29 18:28:02 +09002031 ret = component_add(&pdev->dev, &hdmi_component_ops);
2032 if (ret)
2033 goto err_disable_pm_runtime;
2034
2035 return ret;
2036
2037err_disable_pm_runtime:
2038 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002039
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002040err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002041 if (hdata->hdmiphy_port)
2042 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002043err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002044 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002045
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002046 return ret;
2047}
2048
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002049static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002050{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002051 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002052
Sean Paul724fd142014-05-09 15:05:10 +09002053 cancel_delayed_work_sync(&hdata->hotplug_work);
2054
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002055 component_del(&pdev->dev, &hdmi_component_ops);
2056
2057 pm_runtime_disable(&pdev->dev);
2058
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02002059 if (!IS_ERR(hdata->reg_hdmi_en))
2060 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002061
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002062 if (hdata->hdmiphy_port)
2063 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002064
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002065 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002066
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002067 return 0;
2068}
2069
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002070#ifdef CONFIG_PM
2071static int exynos_hdmi_suspend(struct device *dev)
2072{
2073 struct hdmi_context *hdata = dev_get_drvdata(dev);
2074
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002075 hdmi_clk_disable_gates(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002076
2077 return 0;
2078}
2079
2080static int exynos_hdmi_resume(struct device *dev)
2081{
2082 struct hdmi_context *hdata = dev_get_drvdata(dev);
2083 int ret;
2084
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002085 ret = hdmi_clk_enable_gates(hdata);
2086 if (ret < 0)
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002087 return ret;
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002088
2089 return 0;
2090}
2091#endif
2092
2093static const struct dev_pm_ops exynos_hdmi_pm_ops = {
2094 SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
2095};
2096
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002097struct platform_driver hdmi_driver = {
2098 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002099 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002100 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302101 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002102 .owner = THIS_MODULE,
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002103 .pm = &exynos_hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302104 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002105 },
2106};