blob: 9bef72f6fb53292c4aa01f61362736847f851bcf [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 Hajda9be7e982016-01-14 14:22:47 +090093struct string_array_spec {
94 int count;
95 const char * const *data;
96};
97
98#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a }
99
Inki Daebfe4e842014-03-06 14:18:17 +0900100struct hdmi_driver_data {
101 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900102 const struct hdmiphy_config *phy_confs;
103 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +0900104 unsigned int is_apb_phy:1;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900105 struct string_array_spec clk_gates;
106 /*
107 * Array of triplets (p_off, p_on, clock), where p_off and p_on are
108 * required parents of clock when HDMI-PHY is respectively off or on.
109 */
110 struct string_array_spec clk_muxes;
Inki Daebfe4e842014-03-06 14:18:17 +0900111};
112
Joonyoung Shim590f4182012-03-16 18:47:14 +0900113struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300114 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900115 struct device *dev;
116 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500117 struct drm_connector connector;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900118 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900119 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900120 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530121 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200122 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200123 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900124
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200125 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900126 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200127 struct i2c_client *hdmiphy_port;
128 struct i2c_adapter *ddc_adpt;
Gustavo Padovanf28464c2015-11-02 20:39:18 +0900129 struct gpio_desc *hpd_gpio;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200130 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530131 struct regmap *pmureg;
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900132 struct clk **clk_gates;
133 struct clk **clk_muxes;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200134 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
135 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900136};
137
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300138static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100139{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900140 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100141}
142
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200143static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
144{
145 return container_of(c, struct hdmi_context, connector);
146}
147
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500148struct hdmiphy_config {
149 int pixel_clock;
150 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900151};
152
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900153/* list of phy config settings */
154static const struct hdmiphy_config hdmiphy_v13_configs[] = {
155 {
156 .pixel_clock = 27000000,
157 .conf = {
158 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
159 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
160 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200161 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900162 },
163 },
164 {
165 .pixel_clock = 27027000,
166 .conf = {
167 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
168 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
169 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200170 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900171 },
172 },
173 {
174 .pixel_clock = 74176000,
175 .conf = {
176 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
177 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
178 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200179 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900180 },
181 },
182 {
183 .pixel_clock = 74250000,
184 .conf = {
185 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
186 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
187 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200188 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900189 },
190 },
191 {
192 .pixel_clock = 148500000,
193 .conf = {
194 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
195 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
196 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200197 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900198 },
199 },
200};
201
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500202static const struct hdmiphy_config hdmiphy_v14_configs[] = {
203 {
204 .pixel_clock = 25200000,
205 .conf = {
206 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
207 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
208 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
209 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
210 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900211 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500212 {
213 .pixel_clock = 27000000,
214 .conf = {
215 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
216 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
217 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
218 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
219 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900220 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500221 {
222 .pixel_clock = 27027000,
223 .conf = {
224 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
225 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
226 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200227 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500228 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900229 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500230 {
231 .pixel_clock = 36000000,
232 .conf = {
233 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
234 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
235 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
236 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
237 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900238 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500239 {
240 .pixel_clock = 40000000,
241 .conf = {
242 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
243 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
244 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
245 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
246 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900247 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500248 {
249 .pixel_clock = 65000000,
250 .conf = {
251 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
252 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
253 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
254 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
255 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900256 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500257 {
Shirish Se1d883c2014-03-13 14:28:27 +0900258 .pixel_clock = 71000000,
259 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530260 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
261 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
262 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900263 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
264 },
265 },
266 {
267 .pixel_clock = 73250000,
268 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530269 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
270 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
271 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900272 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
273 },
274 },
275 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500276 .pixel_clock = 74176000,
277 .conf = {
278 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
279 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
280 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
281 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
282 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900283 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500284 {
285 .pixel_clock = 74250000,
286 .conf = {
287 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
288 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
289 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200290 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500291 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900292 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500293 {
294 .pixel_clock = 83500000,
295 .conf = {
296 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
297 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
298 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
299 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
300 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900301 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500302 {
303 .pixel_clock = 106500000,
304 .conf = {
305 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
306 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
307 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
308 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
309 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900310 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500311 {
312 .pixel_clock = 108000000,
313 .conf = {
314 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
315 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
316 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
317 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
318 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900319 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500320 {
Shirish Se1d883c2014-03-13 14:28:27 +0900321 .pixel_clock = 115500000,
322 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530323 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
324 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
325 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900326 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
327 },
328 },
329 {
330 .pixel_clock = 119000000,
331 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530332 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
333 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
334 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900335 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
336 },
337 },
338 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500339 .pixel_clock = 146250000,
340 .conf = {
341 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
342 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
343 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
344 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
345 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900346 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500347 {
348 .pixel_clock = 148500000,
349 .conf = {
350 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
351 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
352 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200353 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500354 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900355 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900356};
357
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530358static const struct hdmiphy_config hdmiphy_5420_configs[] = {
359 {
360 .pixel_clock = 25200000,
361 .conf = {
362 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
363 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
364 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
365 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
366 },
367 },
368 {
369 .pixel_clock = 27000000,
370 .conf = {
371 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
372 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
373 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
374 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
375 },
376 },
377 {
378 .pixel_clock = 27027000,
379 .conf = {
380 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
381 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
382 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
383 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
384 },
385 },
386 {
387 .pixel_clock = 36000000,
388 .conf = {
389 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
390 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
391 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
392 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
393 },
394 },
395 {
396 .pixel_clock = 40000000,
397 .conf = {
398 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
399 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
400 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
401 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
402 },
403 },
404 {
405 .pixel_clock = 65000000,
406 .conf = {
407 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
408 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
409 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
410 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
411 },
412 },
413 {
414 .pixel_clock = 71000000,
415 .conf = {
416 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
417 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
418 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
419 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
420 },
421 },
422 {
423 .pixel_clock = 73250000,
424 .conf = {
425 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
426 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
427 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
428 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
429 },
430 },
431 {
432 .pixel_clock = 74176000,
433 .conf = {
434 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
435 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
436 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
437 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
438 },
439 },
440 {
441 .pixel_clock = 74250000,
442 .conf = {
443 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
444 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
445 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
446 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
447 },
448 },
449 {
450 .pixel_clock = 83500000,
451 .conf = {
452 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
453 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
454 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
455 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
456 },
457 },
458 {
459 .pixel_clock = 88750000,
460 .conf = {
461 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
462 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
463 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
464 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
465 },
466 },
467 {
468 .pixel_clock = 106500000,
469 .conf = {
470 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
471 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
472 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
473 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
474 },
475 },
476 {
477 .pixel_clock = 108000000,
478 .conf = {
479 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
480 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
481 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
482 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
483 },
484 },
485 {
486 .pixel_clock = 115500000,
487 .conf = {
488 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
489 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
490 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
491 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
492 },
493 },
494 {
495 .pixel_clock = 146250000,
496 .conf = {
497 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
498 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
499 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
500 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
501 },
502 },
503 {
504 .pixel_clock = 148500000,
505 .conf = {
506 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
507 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
508 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
509 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
510 },
511 },
512};
513
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100514static const char * const hdmi_clk_gates4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900515 "hdmi", "sclk_hdmi"
516};
517
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100518static const char * const hdmi_clk_muxes4[] = {
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900519 "sclk_pixel", "sclk_hdmiphy", "mout_hdmi"
520};
521
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100522static const struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530523 .type = HDMI_TYPE14,
524 .phy_confs = hdmiphy_5420_configs,
525 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
526 .is_apb_phy = 1,
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900527 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
528 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530529};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900530
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100531static const struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900532 .type = HDMI_TYPE14,
533 .phy_confs = hdmiphy_v14_configs,
534 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
535 .is_apb_phy = 0,
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900536 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
537 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900538};
539
Andrzej Hajda190a3c62015-11-02 14:16:40 +0100540static const struct hdmi_driver_data exynos4210_hdmi_driver_data = {
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200541 .type = HDMI_TYPE13,
542 .phy_confs = hdmiphy_v13_configs,
543 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
544 .is_apb_phy = 0,
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900545 .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4),
546 .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4),
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200547};
548
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200549static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
550{
551 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
552 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
553 return reg_id;
554}
555
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900556static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
557{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200558 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900559}
560
561static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
562 u32 reg_id, u8 value)
563{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200564 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900565}
566
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200567static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
568 int bytes, u32 val)
569{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200570 reg_id = hdmi_map_reg(hdata, reg_id);
571
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200572 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200573 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200574 val >>= 8;
575 reg_id += 4;
576 }
577}
578
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900579static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
580 u32 reg_id, u32 value, u32 mask)
581{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200582 u32 old;
583
584 reg_id = hdmi_map_reg(hdata, reg_id);
585 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900586 value = (value & mask) | (old & ~mask);
587 writel(value, hdata->regs + reg_id);
588}
589
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900590static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
591 u32 reg_offset, const u8 *buf, u32 len)
592{
593 if ((reg_offset + len) > 32)
594 return -EINVAL;
595
596 if (hdata->hdmiphy_port) {
597 int ret;
598
599 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
600 if (ret == len)
601 return 0;
602 return ret;
603 } else {
604 int i;
605 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200606 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900607 ((reg_offset + i)<<2));
608 return 0;
609 }
610}
611
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900612static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900613{
614#define DUMPREG(reg_id) \
615 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
616 readl(hdata->regs + reg_id))
617 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
618 DUMPREG(HDMI_INTC_FLAG);
619 DUMPREG(HDMI_INTC_CON);
620 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900621 DUMPREG(HDMI_V13_PHY_RSTOUT);
622 DUMPREG(HDMI_V13_PHY_VPLL);
623 DUMPREG(HDMI_V13_PHY_CMU);
624 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900625
626 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
627 DUMPREG(HDMI_CON_0);
628 DUMPREG(HDMI_CON_1);
629 DUMPREG(HDMI_CON_2);
630 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900631 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900632 DUMPREG(HDMI_STATUS_EN);
633 DUMPREG(HDMI_HPD);
634 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900635 DUMPREG(HDMI_V13_HPD_GEN);
636 DUMPREG(HDMI_V13_DC_CONTROL);
637 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900638
639 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
640 DUMPREG(HDMI_H_BLANK_0);
641 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900642 DUMPREG(HDMI_V13_V_BLANK_0);
643 DUMPREG(HDMI_V13_V_BLANK_1);
644 DUMPREG(HDMI_V13_V_BLANK_2);
645 DUMPREG(HDMI_V13_H_V_LINE_0);
646 DUMPREG(HDMI_V13_H_V_LINE_1);
647 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900648 DUMPREG(HDMI_VSYNC_POL);
649 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900650 DUMPREG(HDMI_V13_V_BLANK_F_0);
651 DUMPREG(HDMI_V13_V_BLANK_F_1);
652 DUMPREG(HDMI_V13_V_BLANK_F_2);
653 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
654 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
655 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
656 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
657 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
658 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
659 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
660 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
661 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
662 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
663 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
664 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900665
666 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
667 DUMPREG(HDMI_TG_CMD);
668 DUMPREG(HDMI_TG_H_FSZ_L);
669 DUMPREG(HDMI_TG_H_FSZ_H);
670 DUMPREG(HDMI_TG_HACT_ST_L);
671 DUMPREG(HDMI_TG_HACT_ST_H);
672 DUMPREG(HDMI_TG_HACT_SZ_L);
673 DUMPREG(HDMI_TG_HACT_SZ_H);
674 DUMPREG(HDMI_TG_V_FSZ_L);
675 DUMPREG(HDMI_TG_V_FSZ_H);
676 DUMPREG(HDMI_TG_VSYNC_L);
677 DUMPREG(HDMI_TG_VSYNC_H);
678 DUMPREG(HDMI_TG_VSYNC2_L);
679 DUMPREG(HDMI_TG_VSYNC2_H);
680 DUMPREG(HDMI_TG_VACT_ST_L);
681 DUMPREG(HDMI_TG_VACT_ST_H);
682 DUMPREG(HDMI_TG_VACT_SZ_L);
683 DUMPREG(HDMI_TG_VACT_SZ_H);
684 DUMPREG(HDMI_TG_FIELD_CHG_L);
685 DUMPREG(HDMI_TG_FIELD_CHG_H);
686 DUMPREG(HDMI_TG_VACT_ST2_L);
687 DUMPREG(HDMI_TG_VACT_ST2_H);
688 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
689 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
690 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
691 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
692 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
693 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
694 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
695 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
696#undef DUMPREG
697}
698
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900699static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
700{
701 int i;
702
703#define DUMPREG(reg_id) \
704 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
705 readl(hdata->regs + reg_id))
706
707 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
708 DUMPREG(HDMI_INTC_CON);
709 DUMPREG(HDMI_INTC_FLAG);
710 DUMPREG(HDMI_HPD_STATUS);
711 DUMPREG(HDMI_INTC_CON_1);
712 DUMPREG(HDMI_INTC_FLAG_1);
713 DUMPREG(HDMI_PHY_STATUS_0);
714 DUMPREG(HDMI_PHY_STATUS_PLL);
715 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200716 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900717 DUMPREG(HDMI_PHY_VPLL);
718 DUMPREG(HDMI_PHY_CMU);
719 DUMPREG(HDMI_CORE_RSTOUT);
720
721 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
722 DUMPREG(HDMI_CON_0);
723 DUMPREG(HDMI_CON_1);
724 DUMPREG(HDMI_CON_2);
725 DUMPREG(HDMI_SYS_STATUS);
726 DUMPREG(HDMI_PHY_STATUS_0);
727 DUMPREG(HDMI_STATUS_EN);
728 DUMPREG(HDMI_HPD);
729 DUMPREG(HDMI_MODE_SEL);
730 DUMPREG(HDMI_ENC_EN);
731 DUMPREG(HDMI_DC_CONTROL);
732 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
733
734 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
735 DUMPREG(HDMI_H_BLANK_0);
736 DUMPREG(HDMI_H_BLANK_1);
737 DUMPREG(HDMI_V2_BLANK_0);
738 DUMPREG(HDMI_V2_BLANK_1);
739 DUMPREG(HDMI_V1_BLANK_0);
740 DUMPREG(HDMI_V1_BLANK_1);
741 DUMPREG(HDMI_V_LINE_0);
742 DUMPREG(HDMI_V_LINE_1);
743 DUMPREG(HDMI_H_LINE_0);
744 DUMPREG(HDMI_H_LINE_1);
745 DUMPREG(HDMI_HSYNC_POL);
746
747 DUMPREG(HDMI_VSYNC_POL);
748 DUMPREG(HDMI_INT_PRO_MODE);
749 DUMPREG(HDMI_V_BLANK_F0_0);
750 DUMPREG(HDMI_V_BLANK_F0_1);
751 DUMPREG(HDMI_V_BLANK_F1_0);
752 DUMPREG(HDMI_V_BLANK_F1_1);
753
754 DUMPREG(HDMI_H_SYNC_START_0);
755 DUMPREG(HDMI_H_SYNC_START_1);
756 DUMPREG(HDMI_H_SYNC_END_0);
757 DUMPREG(HDMI_H_SYNC_END_1);
758
759 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
760 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
761 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
762 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
763
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
768
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
772 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
773
774 DUMPREG(HDMI_V_BLANK_F2_0);
775 DUMPREG(HDMI_V_BLANK_F2_1);
776 DUMPREG(HDMI_V_BLANK_F3_0);
777 DUMPREG(HDMI_V_BLANK_F3_1);
778 DUMPREG(HDMI_V_BLANK_F4_0);
779 DUMPREG(HDMI_V_BLANK_F4_1);
780 DUMPREG(HDMI_V_BLANK_F5_0);
781 DUMPREG(HDMI_V_BLANK_F5_1);
782
783 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
784 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
785 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
786 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
787 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
788 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
789 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
790 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
791
792 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
793 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
794 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
795 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
796 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
797 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
798 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
799 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
800
801 DUMPREG(HDMI_VACT_SPACE_1_0);
802 DUMPREG(HDMI_VACT_SPACE_1_1);
803 DUMPREG(HDMI_VACT_SPACE_2_0);
804 DUMPREG(HDMI_VACT_SPACE_2_1);
805 DUMPREG(HDMI_VACT_SPACE_3_0);
806 DUMPREG(HDMI_VACT_SPACE_3_1);
807 DUMPREG(HDMI_VACT_SPACE_4_0);
808 DUMPREG(HDMI_VACT_SPACE_4_1);
809 DUMPREG(HDMI_VACT_SPACE_5_0);
810 DUMPREG(HDMI_VACT_SPACE_5_1);
811 DUMPREG(HDMI_VACT_SPACE_6_0);
812 DUMPREG(HDMI_VACT_SPACE_6_1);
813
814 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
815 DUMPREG(HDMI_TG_CMD);
816 DUMPREG(HDMI_TG_H_FSZ_L);
817 DUMPREG(HDMI_TG_H_FSZ_H);
818 DUMPREG(HDMI_TG_HACT_ST_L);
819 DUMPREG(HDMI_TG_HACT_ST_H);
820 DUMPREG(HDMI_TG_HACT_SZ_L);
821 DUMPREG(HDMI_TG_HACT_SZ_H);
822 DUMPREG(HDMI_TG_V_FSZ_L);
823 DUMPREG(HDMI_TG_V_FSZ_H);
824 DUMPREG(HDMI_TG_VSYNC_L);
825 DUMPREG(HDMI_TG_VSYNC_H);
826 DUMPREG(HDMI_TG_VSYNC2_L);
827 DUMPREG(HDMI_TG_VSYNC2_H);
828 DUMPREG(HDMI_TG_VACT_ST_L);
829 DUMPREG(HDMI_TG_VACT_ST_H);
830 DUMPREG(HDMI_TG_VACT_SZ_L);
831 DUMPREG(HDMI_TG_VACT_SZ_H);
832 DUMPREG(HDMI_TG_FIELD_CHG_L);
833 DUMPREG(HDMI_TG_FIELD_CHG_H);
834 DUMPREG(HDMI_TG_VACT_ST2_L);
835 DUMPREG(HDMI_TG_VACT_ST2_H);
836 DUMPREG(HDMI_TG_VACT_ST3_L);
837 DUMPREG(HDMI_TG_VACT_ST3_H);
838 DUMPREG(HDMI_TG_VACT_ST4_L);
839 DUMPREG(HDMI_TG_VACT_ST4_H);
840 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
841 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
842 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
843 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
844 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
845 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
846 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
847 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
848 DUMPREG(HDMI_TG_3D);
849
850 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
851 DUMPREG(HDMI_AVI_CON);
852 DUMPREG(HDMI_AVI_HEADER0);
853 DUMPREG(HDMI_AVI_HEADER1);
854 DUMPREG(HDMI_AVI_HEADER2);
855 DUMPREG(HDMI_AVI_CHECK_SUM);
856 DUMPREG(HDMI_VSI_CON);
857 DUMPREG(HDMI_VSI_HEADER0);
858 DUMPREG(HDMI_VSI_HEADER1);
859 DUMPREG(HDMI_VSI_HEADER2);
860 for (i = 0; i < 7; ++i)
861 DUMPREG(HDMI_VSI_DATA(i));
862
863#undef DUMPREG
864}
865
866static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
867{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200868 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900869 hdmi_v13_regs_dump(hdata, prefix);
870 else
871 hdmi_v14_regs_dump(hdata, prefix);
872}
873
Andrzej Hajda9be7e982016-01-14 14:22:47 +0900874static int hdmi_clk_enable_gates(struct hdmi_context *hdata)
875{
876 int i, ret;
877
878 for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) {
879 ret = clk_prepare_enable(hdata->clk_gates[i]);
880 if (!ret)
881 continue;
882
883 dev_err(hdata->dev, "Cannot enable clock '%s', %d\n",
884 hdata->drv_data->clk_gates.data[i], ret);
885 while (i--)
886 clk_disable_unprepare(hdata->clk_gates[i]);
887 return ret;
888 }
889
890 return 0;
891}
892
893static void hdmi_clk_disable_gates(struct hdmi_context *hdata)
894{
895 int i = hdata->drv_data->clk_gates.count;
896
897 while (i--)
898 clk_disable_unprepare(hdata->clk_gates[i]);
899}
900
901static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy)
902{
903 struct device *dev = hdata->dev;
904 int ret = 0;
905 int i;
906
907 for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) {
908 struct clk **c = &hdata->clk_muxes[i];
909
910 ret = clk_set_parent(c[2], c[to_phy]);
911 if (!ret)
912 continue;
913
914 dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n",
915 hdata->drv_data->clk_muxes.data[i + 2],
916 hdata->drv_data->clk_muxes.data[i + to_phy], ret);
917 }
918
919 return ret;
920}
921
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530922static u8 hdmi_chksum(struct hdmi_context *hdata,
923 u32 start, u8 len, u32 hdr_sum)
924{
925 int i;
926
927 /* hdr_sum : header0 + header1 + header2
928 * start : start address of packet byte1
929 * len : packet bytes - 1 */
930 for (i = 0; i < len; ++i)
931 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
932
933 /* return 2's complement of 8 bit hdr_sum */
934 return (u8)(~(hdr_sum & 0xff) + 1);
935}
936
937static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530938 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530939{
940 u32 hdr_sum;
941 u8 chksum;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200942 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530943
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530944 if (hdata->dvi_mode) {
945 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
946 HDMI_VSI_CON_DO_NOT_TRANSMIT);
947 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
948 HDMI_AVI_CON_DO_NOT_TRANSMIT);
949 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
950 return;
951 }
952
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530953 switch (infoframe->any.type) {
954 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530955 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530956 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
957 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
958 infoframe->any.version);
959 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
960 hdr_sum = infoframe->any.type + infoframe->any.version +
961 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530962
963 /* Output format zero hardcoded ,RGB YBCR selection */
964 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
965 AVI_ACTIVE_FORMAT_VALID |
966 AVI_UNDERSCANNED_DISPLAY_VALID);
967
Shirish S46154152014-03-13 10:58:28 +0530968 /*
969 * Set the aspect ratio as per the mode, mentioned in
970 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
971 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200972 ar = hdata->current_mode.picture_aspect_ratio;
973 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530974 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200975 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530976 break;
977 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200978 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530979 break;
980 case HDMI_PICTURE_ASPECT_NONE:
981 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200982 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530983 break;
984 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200985 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530986
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200987 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530988
989 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530990 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530991 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
992 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
993 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530994 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530995 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530996 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
997 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
998 infoframe->any.version);
999 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
1000 hdr_sum = infoframe->any.type + infoframe->any.version +
1001 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301002 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301003 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301004 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
1005 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
1006 break;
1007 default:
1008 break;
1009 }
1010}
1011
Sean Pauld9716ee2014-01-30 16:19:29 -05001012static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
1013 bool force)
Sean Paul45517892014-01-30 16:19:05 -05001014{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001015 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -05001016
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001017 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001018 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +05301019
Andrzej Hajdaef6ce282015-07-09 16:28:07 +02001020 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -05001021}
1022
Sean Pauld9716ee2014-01-30 16:19:29 -05001023static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001024{
Andrzej Hajdaad279312014-09-09 15:16:13 +02001025 drm_connector_unregister(connector);
1026 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001027}
1028
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001029static const struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -03001030 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -05001031 .fill_modes = drm_helper_probe_single_connector_modes,
1032 .detect = hdmi_detect,
1033 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -03001034 .reset = drm_atomic_helper_connector_reset,
1035 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1036 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -05001037};
1038
1039static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001040{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001041 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001043 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001044
Inki Dae8fa04aa2014-03-13 16:38:31 +09001045 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -05001046 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001047
Inki Dae8fa04aa2014-03-13 16:38:31 +09001048 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -05001049 if (!edid)
1050 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001051
Sean Pauld9716ee2014-01-30 16:19:29 -05001052 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001053 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
1054 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -05001055 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -05001056
Sean Pauld9716ee2014-01-30 16:19:29 -05001057 drm_mode_connector_update_edid_property(connector, edid);
1058
Andrzej Hajda64ebd892015-07-09 08:25:38 +02001059 ret = drm_add_edid_modes(connector, edid);
1060
1061 kfree(edid);
1062
1063 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001064}
1065
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001066static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001067{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001068 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001069
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001070 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
1071 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001072 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001073
1074 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1075 return -EINVAL;
1076}
1077
Sean Pauld9716ee2014-01-30 16:19:29 -05001078static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001079 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001080{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001081 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001082 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001083
Rahul Sharma16844fb2013-06-10 14:50:00 +05301084 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1085 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1086 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1087 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001088
Rahul Sharma16844fb2013-06-10 14:50:00 +05301089 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001090 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001091 return MODE_BAD;
1092
1093 return MODE_OK;
1094}
1095
1096static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1097{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001098 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001099
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001100 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001101}
1102
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001103static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001104 .get_modes = hdmi_get_modes,
1105 .mode_valid = hdmi_mode_valid,
1106 .best_encoder = hdmi_best_encoder,
1107};
1108
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001109static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001110{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001111 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001112 struct drm_connector *connector = &hdata->connector;
1113 int ret;
1114
Sean Pauld9716ee2014-01-30 16:19:29 -05001115 connector->interlace_allowed = true;
1116 connector->polled = DRM_CONNECTOR_POLL_HPD;
1117
1118 ret = drm_connector_init(hdata->drm_dev, connector,
1119 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1120 if (ret) {
1121 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001122 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001123 }
1124
1125 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001126 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001127 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001128
1129 return 0;
1130}
1131
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001132static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1133 const struct drm_display_mode *mode,
1134 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001135{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001136 struct drm_device *dev = encoder->dev;
1137 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001138 struct drm_display_mode *m;
1139 int mode_ok;
1140
Sean Paulf041b252014-01-30 16:19:15 -05001141 drm_mode_set_crtcinfo(adjusted_mode, 0);
1142
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001143 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1144 if (connector->encoder == encoder)
1145 break;
1146 }
1147
1148 if (connector->encoder != encoder)
1149 return true;
1150
Sean Pauld9716ee2014-01-30 16:19:29 -05001151 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001152
1153 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001154 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001155 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001156
1157 /*
1158 * otherwise, find the most suitable mode among modes and change it
1159 * to adjusted_mode.
1160 */
1161 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001162 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001163
Sean Pauld9716ee2014-01-30 16:19:29 -05001164 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001165 DRM_INFO("desired mode doesn't exist so\n");
1166 DRM_INFO("use the most suitable mode among modes.\n");
1167
1168 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1169 m->hdisplay, m->vdisplay, m->vrefresh);
1170
Sean Paul75626852014-01-30 16:19:16 -05001171 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001172 break;
1173 }
1174 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001175
1176 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001177}
1178
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001179static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001180{
1181 u32 n, cts;
1182
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001183 cts = (freq % 9) ? 27000 : 30000;
1184 n = 128 * freq / (27000000 / cts);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001185
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001186 hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
1187 hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
1188 hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001189 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001190}
1191
1192static void hdmi_audio_init(struct hdmi_context *hdata)
1193{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301194 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001195 u32 data_num, bit_ch, sample_frq;
1196 u32 val;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001197
1198 sample_rate = 44100;
1199 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001200
1201 switch (bits_per_sample) {
1202 case 20:
1203 data_num = 2;
1204 bit_ch = 1;
1205 break;
1206 case 24:
1207 data_num = 3;
1208 bit_ch = 1;
1209 break;
1210 default:
1211 data_num = 1;
1212 bit_ch = 0;
1213 break;
1214 }
1215
Andrzej Hajdad24bb3e2015-09-25 14:48:27 +02001216 hdmi_reg_acr(hdata, sample_rate);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001217
1218 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1219 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1220 | HDMI_I2S_MUX_ENABLE);
1221
1222 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1223 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1224
1225 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1226
1227 sample_frq = (sample_rate == 44100) ? 0 :
1228 (sample_rate == 48000) ? 2 :
1229 (sample_rate == 32000) ? 3 :
1230 (sample_rate == 96000) ? 0xa : 0x0;
1231
1232 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1233 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1234
1235 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1236 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1237
1238 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1239 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1240 | HDMI_I2S_SEL_LRCK(6));
1241 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1242 | HDMI_I2S_SEL_SDATA2(4));
1243 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1244 | HDMI_I2S_SEL_SDATA2(2));
1245 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1246
1247 /* I2S_CON_1 & 2 */
1248 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1249 | HDMI_I2S_L_CH_LOW_POL);
1250 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1251 | HDMI_I2S_SET_BIT_CH(bit_ch)
1252 | HDMI_I2S_SET_SDATA_BIT(data_num)
1253 | HDMI_I2S_BASIC_FORMAT);
1254
1255 /* Configure register related to CUV information */
1256 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1257 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1258 | HDMI_I2S_COPYRIGHT
1259 | HDMI_I2S_LINEAR_PCM
1260 | HDMI_I2S_CONSUMER_FORMAT);
1261 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1262 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1263 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1264 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1265 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1266 HDMI_I2S_ORG_SMP_FREQ_44_1
1267 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1268 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1269
1270 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1271}
1272
1273static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1274{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001275 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001276 return;
1277
1278 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1279 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1280 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1281}
1282
Rahul Sharmabfa48422014-04-03 20:41:04 +05301283static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001284{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301285 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001286
Rahul Sharmabfa48422014-04-03 20:41:04 +05301287 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1288 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001289
Rahul Sharmabfa48422014-04-03 20:41:04 +05301290 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1291 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001292}
1293
1294static void hdmi_conf_init(struct hdmi_context *hdata)
1295{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301296 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301297
Sean Paul77006a72013-01-16 10:17:20 -05001298 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001299 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1300 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001301
1302 /* choose HDMI mode */
1303 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1304 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301305 /* Apply Video preable and Guard band in HDMI mode only */
1306 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001307 /* disable bluescreen */
1308 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001309
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001310 if (hdata->dvi_mode) {
1311 /* choose DVI mode */
1312 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1313 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1314 hdmi_reg_writeb(hdata, HDMI_CON_2,
1315 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1316 }
1317
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001318 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001319 /* choose bluescreen (fecal) color */
1320 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1321 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1322 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1323
1324 /* enable AVI packet every vsync, fixes purple line problem */
1325 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1326 /* force RGB, look to CEA-861-D, table 7 for more detail */
1327 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1328 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1329
1330 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1331 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1332 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1333 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301334 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1335 infoframe.any.version = HDMI_AVI_VERSION;
1336 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301337 hdmi_reg_infoframe(hdata, &infoframe);
1338
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301339 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1340 infoframe.any.version = HDMI_AUI_VERSION;
1341 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301342 hdmi_reg_infoframe(hdata, &infoframe);
1343
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001344 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001345 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1346 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001347}
1348
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001349static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1350{
1351 int tries;
1352
1353 for (tries = 0; tries < 10; ++tries) {
1354 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1355
1356 if (val & HDMI_PHY_STATUS_READY) {
1357 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1358 return;
1359 }
1360 usleep_range(10, 20);
1361 }
1362
1363 DRM_ERROR("PLL could not reach steady state\n");
1364}
1365
Rahul Sharma16844fb2013-06-10 14:50:00 +05301366static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001367{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001368 struct drm_display_mode *m = &hdata->current_mode;
1369 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001370
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001371 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1372 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1373 (m->htotal << 12) | m->vtotal);
1374
1375 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1376 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1377
1378 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1379 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1380
1381 val = (m->hsync_start - m->hdisplay - 2);
1382 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1383 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1384 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1385
1386 /*
1387 * Quirk requirement for exynos HDMI IP design,
1388 * 2 pixels less than the actual calculation for hsync_start
1389 * and end.
1390 */
1391
1392 /* Following values & calculations differ for different type of modes */
1393 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1394 /* Interlaced Mode */
1395 val = ((m->vsync_end - m->vdisplay) / 2);
1396 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1397 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1398
1399 val = m->vtotal / 2;
1400 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1401 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1402
1403 val = (m->vtotal +
1404 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1405 val |= m->vtotal << 11;
1406 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1407
1408 val = ((m->vtotal / 2) + 7);
1409 val |= ((m->vtotal / 2) + 2) << 12;
1410 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1411
1412 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1413 val |= ((m->htotal / 2) +
1414 (m->hsync_start - m->hdisplay)) << 12;
1415 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1416
1417 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1418 (m->vtotal - m->vdisplay) / 2);
1419 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1420
1421 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1422 } else {
1423 /* Progressive Mode */
1424
1425 val = m->vtotal;
1426 val |= (m->vtotal - m->vdisplay) << 11;
1427 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1428
1429 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1430
1431 val = (m->vsync_end - m->vdisplay);
1432 val |= ((m->vsync_start - m->vdisplay) << 12);
1433 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1434
1435 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1436 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1437 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1438 m->vtotal - m->vdisplay);
1439 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1440 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1441 }
1442
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001443 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001444 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1445 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1446 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1447 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1448 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1449 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1450 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1451 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1452 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1453 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1454 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001455}
1456
Rahul Sharma16844fb2013-06-10 14:50:00 +05301457static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001458{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001459 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001460
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001461 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1462 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1463 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1464 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1465 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1466 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1467 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1468 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1469 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1470
1471 /*
1472 * Quirk requirement for exynos 5 HDMI IP design,
1473 * 2 pixels less than the actual calculation for hsync_start
1474 * and end.
1475 */
1476
1477 /* Following values & calculations differ for different type of modes */
1478 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1479 /* Interlaced Mode */
1480 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1481 (m->vsync_end - m->vdisplay) / 2);
1482 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1483 (m->vsync_start - m->vdisplay) / 2);
1484 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1485 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1486 (m->vtotal - m->vdisplay) / 2);
1487 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1488 m->vtotal - m->vdisplay / 2);
1489 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1490 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1491 (m->vtotal / 2) + 7);
1492 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1493 (m->vtotal / 2) + 2);
1494 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1495 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1496 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1497 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1498 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1499 (m->vtotal - m->vdisplay) / 2);
1500 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1501 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1502 m->vtotal - m->vdisplay / 2);
1503 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1504 (m->vtotal / 2) + 1);
1505 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1506 (m->vtotal / 2) + 1);
1507 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1508 (m->vtotal / 2) + 1);
1509 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1510 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1511 } else {
1512 /* Progressive Mode */
1513 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1514 m->vsync_end - m->vdisplay);
1515 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1516 m->vsync_start - m->vdisplay);
1517 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1518 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1519 m->vtotal - m->vdisplay);
1520 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1521 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1522 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1523 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1524 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1525 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1526 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1527 m->vtotal - m->vdisplay);
1528 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1529 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1530 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1531 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1532 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1533 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1534 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1535 }
1536
1537 /* Following values & calculations are same irrespective of mode type */
1538 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1539 m->hsync_start - m->hdisplay - 2);
1540 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1541 m->hsync_end - m->hdisplay - 2);
1542 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1543 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1544 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1545 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1546 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1547 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1548 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1549 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1550 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1551 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1552 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1553 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1554 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1555 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1556 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1557 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1558 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1559 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001560
1561 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001562 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1563 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1564 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1565 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1566 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1567 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1568 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1569 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1570 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001571}
1572
Rahul Sharma16844fb2013-06-10 14:50:00 +05301573static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001574{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001575 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301576 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001577 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301578 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001579
1580 hdmiphy_wait_for_pll(hdata);
1581
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001582 hdmi_clk_set_parents(hdata, true);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001583
1584 /* enable HDMI and timing generator */
1585 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001586}
1587
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001588static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1589{
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001590 hdmi_clk_set_parents(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001591
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001592 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001593 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001594 usleep_range(10000, 12000);
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);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001597}
1598
1599static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1600{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001601 int ret;
1602 int i;
1603
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001604 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001605 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001606 if (i < 0) {
1607 DRM_ERROR("failed to find hdmiphy conf\n");
1608 return;
1609 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001610
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001611 ret = hdmiphy_reg_write_buf(hdata, 0,
1612 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001613 if (ret) {
1614 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001615 return;
1616 }
1617
Sean Paul09760ea2013-01-14 17:03:20 -05001618 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001619}
1620
1621static void hdmi_conf_apply(struct hdmi_context *hdata)
1622{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001623 hdmiphy_conf_reset(hdata);
1624 hdmiphy_conf_apply(hdata);
1625
Rahul Sharmabfa48422014-04-03 20:41:04 +05301626 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001627 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001628
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001629 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001630
1631 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301632 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001633 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001634
1635 hdmi_regs_dump(hdata, "start");
1636}
1637
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001638static void hdmi_mode_set(struct drm_encoder *encoder,
1639 struct drm_display_mode *mode,
1640 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001641{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001642 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001643 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001644
YoungJun Chocbc4c332013-06-12 10:44:40 +09001645 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1646 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001647 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001648 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001649
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001650 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001651 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001652}
1653
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001654static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001655{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001656 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001657
Andrzej Hajda882a0642015-07-09 16:28:08 +02001658 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001659 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001660
Sean Paulaf65c802014-01-30 16:19:27 -05001661 pm_runtime_get_sync(hdata->dev);
1662
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001663 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001664 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1665
Rahul Sharma049d34e2014-05-20 10:36:05 +05301666 /* set pmu hdmiphy control bit to enable hdmiphy */
1667 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1668 PMU_HDMI_PHY_ENABLE_BIT, 1);
1669
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001670 hdmi_conf_apply(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09001671
1672 hdata->powered = true;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001673}
1674
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001675static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001676{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001677 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001678 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001679 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001680
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001681 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001682 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001683
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001684 /*
1685 * The SFRs of VP and Mixer are updated by Vertical Sync of
1686 * Timing generator which is a part of HDMI so the sequence
1687 * to disable TV Subsystem should be as following,
1688 * VP -> Mixer -> HDMI
1689 *
1690 * Below codes will try to disable Mixer and VP(if used)
1691 * prior to disabling HDMI.
1692 */
1693 if (crtc)
1694 funcs = crtc->helper_private;
1695 if (funcs && funcs->disable)
1696 (*funcs->disable)(crtc);
1697
Rahul Sharmabfa48422014-04-03 20:41:04 +05301698 /* HDMI System Disable */
1699 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1700
Sean Paul724fd142014-05-09 15:05:10 +09001701 cancel_delayed_work(&hdata->hotplug_work);
1702
Rahul Sharma049d34e2014-05-20 10:36:05 +05301703 /* reset pmu hdmiphy control bit to disable hdmiphy */
1704 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1705 PMU_HDMI_PHY_ENABLE_BIT, 0);
1706
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001707 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001708
Sean Paulaf65c802014-01-30 16:19:27 -05001709 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001710
1711 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001712}
1713
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001714static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001715 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001716 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001717 .enable = hdmi_enable,
1718 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001719};
1720
Ville Syrjälä800ba2b2015-12-15 12:21:06 +01001721static const struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001722 .destroy = drm_encoder_cleanup,
1723};
1724
Sean Paul724fd142014-05-09 15:05:10 +09001725static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001726{
Sean Paul724fd142014-05-09 15:05:10 +09001727 struct hdmi_context *hdata;
1728
1729 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001730
Sean Paul45517892014-01-30 16:19:05 -05001731 if (hdata->drm_dev)
1732 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001733}
1734
1735static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1736{
1737 struct hdmi_context *hdata = arg;
1738
1739 mod_delayed_work(system_wq, &hdata->hotplug_work,
1740 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001741
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001742 return IRQ_HANDLED;
1743}
1744
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001745static int hdmi_clks_get(struct hdmi_context *hdata,
1746 const struct string_array_spec *names,
1747 struct clk **clks)
1748{
1749 struct device *dev = hdata->dev;
1750 int i;
1751
1752 for (i = 0; i < names->count; ++i) {
1753 struct clk *clk = devm_clk_get(dev, names->data[i]);
1754
1755 if (IS_ERR(clk)) {
1756 int ret = PTR_ERR(clk);
1757
1758 dev_err(dev, "Cannot get clock %s, %d\n",
1759 names->data[i], ret);
1760
1761 return ret;
1762 }
1763
1764 clks[i] = clk;
1765 }
1766
1767 return 0;
1768}
1769
1770static int hdmi_clk_init(struct hdmi_context *hdata)
1771{
1772 const struct hdmi_driver_data *drv_data = hdata->drv_data;
1773 int count = drv_data->clk_gates.count + drv_data->clk_muxes.count;
1774 struct device *dev = hdata->dev;
1775 struct clk **clks;
1776 int ret;
1777
1778 if (!count)
1779 return 0;
1780
1781 clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL);
1782 if (!clks)
1783 return -ENOMEM;
1784
1785 hdata->clk_gates = clks;
1786 hdata->clk_muxes = clks + drv_data->clk_gates.count;
1787
1788 ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates);
1789 if (ret)
1790 return ret;
1791
1792 return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes);
1793}
1794
1795
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001796static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001797{
1798 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001799 int i, ret;
1800
1801 DRM_DEBUG_KMS("HDMI resource init\n");
1802
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001803 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1804 if (IS_ERR(hdata->hpd_gpio)) {
1805 DRM_ERROR("cannot get hpd gpio property\n");
1806 return PTR_ERR(hdata->hpd_gpio);
1807 }
1808
1809 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1810 if (hdata->irq < 0) {
1811 DRM_ERROR("failed to get GPIO irq\n");
1812 return hdata->irq;
1813 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001814
Andrzej Hajda9be7e982016-01-14 14:22:47 +09001815 ret = hdmi_clk_init(hdata);
1816 if (ret)
1817 return ret;
1818
1819 ret = hdmi_clk_set_parents(hdata, false);
1820 if (ret)
1821 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001822
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001823 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001824 hdata->regul_bulk[i].supply = supply[i];
1825 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001826 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001827 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001828 if (ret) {
1829 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001830 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001831 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001832
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001833 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001834
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001835 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001836 return 0;
1837
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001838 if (IS_ERR(hdata->reg_hdmi_en))
1839 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001840
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001841 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001842 if (ret)
1843 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001844
Inki Daedf5225b2014-05-29 18:28:02 +09001845 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001846}
1847
Rahul Sharma22c4f422012-10-04 20:48:55 +05301848static struct of_device_id hdmi_match_types[] = {
1849 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001850 .compatible = "samsung,exynos4210-hdmi",
1851 .data = &exynos4210_hdmi_driver_data,
1852 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301853 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001854 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301855 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301856 .compatible = "samsung,exynos5420-hdmi",
1857 .data = &exynos5420_hdmi_driver_data,
1858 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301859 /* end node */
1860 }
1861};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001862MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301863
Inki Daef37cd5e2014-05-09 14:25:20 +09001864static int hdmi_bind(struct device *dev, struct device *master, void *data)
1865{
1866 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001867 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001868 struct drm_encoder *encoder = &hdata->encoder;
1869 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001870
Inki Daef37cd5e2014-05-09 14:25:20 +09001871 hdata->drm_dev = drm_dev;
1872
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001873 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1874 EXYNOS_DISPLAY_TYPE_HDMI);
1875 if (pipe < 0)
1876 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001877
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001878 encoder->possible_crtcs = 1 << pipe;
1879
1880 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1881
1882 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
Ville Syrjälä13a3d912015-12-09 16:20:18 +02001883 DRM_MODE_ENCODER_TMDS, NULL);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001884
1885 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1886
1887 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001888 if (ret) {
1889 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001890 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001891 return ret;
1892 }
1893
1894 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001895}
1896
1897static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1898{
Inki Daef37cd5e2014-05-09 14:25:20 +09001899}
1900
1901static const struct component_ops hdmi_component_ops = {
1902 .bind = hdmi_bind,
1903 .unbind = hdmi_unbind,
1904};
1905
Inki Daee2a562d2014-05-09 16:46:10 +09001906static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1907{
1908 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1909 struct device_node *np;
1910
1911 np = of_find_compatible_node(NULL, NULL, compatible_str);
1912 if (np)
1913 return of_get_next_parent(np);
1914
1915 return NULL;
1916}
1917
1918static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1919{
1920 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1921
1922 return of_find_compatible_node(NULL, NULL, compatible_str);
1923}
1924
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001925static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001926{
Inki Daef37cd5e2014-05-09 14:25:20 +09001927 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001928 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001929 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001930 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001931 struct resource *res;
1932 int ret;
1933
Andrzej Hajda930865f2014-11-17 09:54:20 +01001934 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1935 if (!hdata)
1936 return -ENOMEM;
1937
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001938 match = of_match_device(hdmi_match_types, dev);
1939 if (!match)
1940 return -ENODEV;
1941
1942 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001943
Andrzej Hajda930865f2014-11-17 09:54:20 +01001944 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001945
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001946 hdata->dev = dev;
1947
1948 ret = hdmi_resources_init(hdata);
1949 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301950 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001951 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952 }
1953
1954 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001955 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001956 if (IS_ERR(hdata->regs)) {
1957 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001958 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001959 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001960
Inki Daee2a562d2014-05-09 16:46:10 +09001961 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1962 if (ddc_node)
1963 goto out_get_ddc_adpt;
1964
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001965 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001966 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1967 if (!ddc_node) {
1968 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001969 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001970 }
Inki Daee2a562d2014-05-09 16:46:10 +09001971
1972out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001973 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1974 if (!hdata->ddc_adpt) {
1975 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001976 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001977 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001978
Inki Daee2a562d2014-05-09 16:46:10 +09001979 phy_node = hdmi_legacy_phy_dt_binding(dev);
1980 if (phy_node)
1981 goto out_get_phy_port;
1982
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001983 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001984 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1985 if (!phy_node) {
1986 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1987 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001988 goto err_ddc;
1989 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001990
Inki Daee2a562d2014-05-09 16:46:10 +09001991out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001992 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001993 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1994 if (!hdata->regs_hdmiphy) {
1995 DRM_ERROR("failed to ioremap hdmi phy\n");
1996 ret = -ENOMEM;
1997 goto err_ddc;
1998 }
1999 } else {
2000 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2001 if (!hdata->hdmiphy_port) {
2002 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002003 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002004 goto err_ddc;
2005 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002006 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002007
Sean Paul724fd142014-05-09 15:05:10 +09002008 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2009
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002010 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002011 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002012 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002013 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002014 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002015 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002016 goto err_hdmiphy;
2017 }
2018
Rahul Sharma049d34e2014-05-20 10:36:05 +05302019 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
2020 "samsung,syscon-phandle");
2021 if (IS_ERR(hdata->pmureg)) {
2022 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09002023 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05302024 goto err_hdmiphy;
2025 }
2026
Sean Paulaf65c802014-01-30 16:19:27 -05002027 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002028
Inki Daedf5225b2014-05-29 18:28:02 +09002029 ret = component_add(&pdev->dev, &hdmi_component_ops);
2030 if (ret)
2031 goto err_disable_pm_runtime;
2032
2033 return ret;
2034
2035err_disable_pm_runtime:
2036 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002037
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002038err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002039 if (hdata->hdmiphy_port)
2040 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002041err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002042 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002043
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002044 return ret;
2045}
2046
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002047static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002048{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002049 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002050
Sean Paul724fd142014-05-09 15:05:10 +09002051 cancel_delayed_work_sync(&hdata->hotplug_work);
2052
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002053 component_del(&pdev->dev, &hdmi_component_ops);
2054
2055 pm_runtime_disable(&pdev->dev);
2056
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02002057 if (!IS_ERR(hdata->reg_hdmi_en))
2058 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002059
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002060 if (hdata->hdmiphy_port)
2061 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002062
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002063 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002064
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002065 return 0;
2066}
2067
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002068#ifdef CONFIG_PM
2069static int exynos_hdmi_suspend(struct device *dev)
2070{
2071 struct hdmi_context *hdata = dev_get_drvdata(dev);
2072
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002073 hdmi_clk_disable_gates(hdata);
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002074
2075 return 0;
2076}
2077
2078static int exynos_hdmi_resume(struct device *dev)
2079{
2080 struct hdmi_context *hdata = dev_get_drvdata(dev);
2081 int ret;
2082
Andrzej Hajda9be7e982016-01-14 14:22:47 +09002083 ret = hdmi_clk_enable_gates(hdata);
2084 if (ret < 0)
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002085 return ret;
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002086
2087 return 0;
2088}
2089#endif
2090
2091static const struct dev_pm_ops exynos_hdmi_pm_ops = {
2092 SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
2093};
2094
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002095struct platform_driver hdmi_driver = {
2096 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002097 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002098 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302099 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002100 .owner = THIS_MODULE,
Gustavo Padovanf28464c2015-11-02 20:39:18 +09002101 .pm = &exynos_hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302102 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002103 },
2104};