blob: c5a0617c429d9753694691b6c727d043d682fd77 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030020#include <drm/drm_atomic_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090021
22#include "regs-hdmi.h"
23
24#include <linux/kernel.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090025#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
Andrzej Hajda2228b7c2015-09-25 14:48:24 +020033#include <linux/gpio/consumer.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090034#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053035#include <linux/io.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Andrzej Hajdacd240cd2015-07-09 16:28:09 +020037#include <linux/of_device.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Rahul Sharma049d34e2014-05-20 10:36:05 +053040#include <linux/mfd/syscon.h>
41#include <linux/regmap.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090042
43#include <drm/exynos_drm.h>
44
45#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090046#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050047#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090048
Sean Paul724fd142014-05-09 15:05:10 +090049#define HOTPLUG_DEBOUNCE_MS 1100
50
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053051/* AVI header and aspect ratio */
52#define HDMI_AVI_VERSION 0x02
53#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053054
55/* AUI header info */
56#define HDMI_AUI_VERSION 0x01
57#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053058#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
59#define AVI_4_3_CENTER_RATIO 0x9
60#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053061
Rahul Sharma5a325072012-10-04 20:48:54 +053062enum hdmi_type {
63 HDMI_TYPE13,
64 HDMI_TYPE14,
Andrzej Hajda633d00b2015-09-25 14:48:16 +020065 HDMI_TYPE_COUNT
66};
67
68#define HDMI_MAPPED_BASE 0xffff0000
69
70enum hdmi_mapped_regs {
71 HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
72 HDMI_PHY_RSTOUT,
73 HDMI_ACR_CON,
74};
75
76static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
77 { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
78 { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
79 { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
Rahul Sharma5a325072012-10-04 20:48:54 +053080};
81
Andrzej Hajda1ab739d2015-09-25 14:48:22 +020082static const char * const supply[] = {
83 "vdd",
84 "vdd_osc",
85 "vdd_pll",
86};
87
Inki Daebfe4e842014-03-06 14:18:17 +090088struct hdmi_driver_data {
89 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090090 const struct hdmiphy_config *phy_confs;
91 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090092 unsigned int is_apb_phy:1;
93};
94
Joonyoung Shim590f4182012-03-16 18:47:14 +090095struct hdmi_context {
Gustavo Padovan2b8376c2015-08-15 12:14:08 -030096 struct drm_encoder encoder;
Joonyoung Shim590f4182012-03-16 18:47:14 +090097 struct device *dev;
98 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -050099 struct drm_connector connector;
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900100 bool hpd;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900101 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900102 bool dvi_mode;
Sean Paul724fd142014-05-09 15:05:10 +0900103 struct delayed_work hotplug_work;
Rahul Sharmabfa48422014-04-03 20:41:04 +0530104 struct drm_display_mode current_mode;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200105 u8 cea_video_id;
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200106 const struct hdmi_driver_data *drv_data;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900107
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200108 void __iomem *regs;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900109 void __iomem *regs_hdmiphy;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200110 struct i2c_client *hdmiphy_port;
111 struct i2c_adapter *ddc_adpt;
112 struct gpio_desc *hpd_gpio;
113 int irq;
Rahul Sharma049d34e2014-05-20 10:36:05 +0530114 struct regmap *pmureg;
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +0200115 struct clk *hdmi;
116 struct clk *sclk_hdmi;
117 struct clk *sclk_pixel;
118 struct clk *sclk_hdmiphy;
119 struct clk *mout_hdmi;
120 struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
121 struct regulator *reg_hdmi_en;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900122};
123
Gustavo Padovan2b8376c2015-08-15 12:14:08 -0300124static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100125{
Gustavo Padovancf67cc92015-08-11 17:38:06 +0900126 return container_of(e, struct hdmi_context, encoder);
Andrzej Hajda0d8424f82014-11-17 09:54:21 +0100127}
128
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200129static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
130{
131 return container_of(c, struct hdmi_context, connector);
132}
133
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500134struct hdmiphy_config {
135 int pixel_clock;
136 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900137};
138
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900139/* list of phy config settings */
140static const struct hdmiphy_config hdmiphy_v13_configs[] = {
141 {
142 .pixel_clock = 27000000,
143 .conf = {
144 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
145 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
146 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200147 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900148 },
149 },
150 {
151 .pixel_clock = 27027000,
152 .conf = {
153 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
154 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
155 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200156 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900157 },
158 },
159 {
160 .pixel_clock = 74176000,
161 .conf = {
162 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
163 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
164 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200165 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166 },
167 },
168 {
169 .pixel_clock = 74250000,
170 .conf = {
171 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
172 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
173 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200174 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900175 },
176 },
177 {
178 .pixel_clock = 148500000,
179 .conf = {
180 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
181 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
182 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200183 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900184 },
185 },
186};
187
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500188static const struct hdmiphy_config hdmiphy_v14_configs[] = {
189 {
190 .pixel_clock = 25200000,
191 .conf = {
192 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
193 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
194 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
195 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
196 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900197 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500198 {
199 .pixel_clock = 27000000,
200 .conf = {
201 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
202 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
203 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
204 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
205 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900206 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500207 {
208 .pixel_clock = 27027000,
209 .conf = {
210 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
211 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
212 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200213 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500214 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900215 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500216 {
217 .pixel_clock = 36000000,
218 .conf = {
219 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
220 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
221 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
222 0x54, 0xab, 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 = 40000000,
227 .conf = {
228 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
229 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
230 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
231 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
232 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900233 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500234 {
235 .pixel_clock = 65000000,
236 .conf = {
237 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
238 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
239 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
240 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
241 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900242 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500243 {
Shirish Se1d883c2014-03-13 14:28:27 +0900244 .pixel_clock = 71000000,
245 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530246 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
247 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
248 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900249 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
250 },
251 },
252 {
253 .pixel_clock = 73250000,
254 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530255 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
256 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
257 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900258 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
259 },
260 },
261 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500262 .pixel_clock = 74176000,
263 .conf = {
264 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
265 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
266 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
267 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
268 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900269 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500270 {
271 .pixel_clock = 74250000,
272 .conf = {
273 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
274 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
275 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200276 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500277 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900278 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500279 {
280 .pixel_clock = 83500000,
281 .conf = {
282 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
283 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
284 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
285 0x54, 0x93, 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 = 106500000,
290 .conf = {
291 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
292 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
293 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
294 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
295 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900296 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500297 {
298 .pixel_clock = 108000000,
299 .conf = {
300 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
301 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
302 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
303 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
304 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900305 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500306 {
Shirish Se1d883c2014-03-13 14:28:27 +0900307 .pixel_clock = 115500000,
308 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530309 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
310 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
311 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900312 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
313 },
314 },
315 {
316 .pixel_clock = 119000000,
317 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530318 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
319 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
320 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900321 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
322 },
323 },
324 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 .pixel_clock = 146250000,
326 .conf = {
327 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
328 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
329 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
330 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
331 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900332 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500333 {
334 .pixel_clock = 148500000,
335 .conf = {
336 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
337 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
338 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Andrzej Hajda74a74ff2015-09-25 14:48:18 +0200339 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500340 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900341 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900342};
343
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530344static const struct hdmiphy_config hdmiphy_5420_configs[] = {
345 {
346 .pixel_clock = 25200000,
347 .conf = {
348 0x01, 0x52, 0x3F, 0x55, 0x40, 0x01, 0x00, 0xC8,
349 0x82, 0xC8, 0xBD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
350 0x06, 0x80, 0x01, 0x84, 0x05, 0x02, 0x24, 0x66,
351 0x54, 0xF4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
352 },
353 },
354 {
355 .pixel_clock = 27000000,
356 .conf = {
357 0x01, 0xD1, 0x22, 0x51, 0x40, 0x08, 0xFC, 0xE0,
358 0x98, 0xE8, 0xCB, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
359 0x06, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
360 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
361 },
362 },
363 {
364 .pixel_clock = 27027000,
365 .conf = {
366 0x01, 0xD1, 0x2D, 0x72, 0x40, 0x64, 0x12, 0xC8,
367 0x43, 0xE8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
368 0x26, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
369 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
370 },
371 },
372 {
373 .pixel_clock = 36000000,
374 .conf = {
375 0x01, 0x51, 0x2D, 0x55, 0x40, 0x40, 0x00, 0xC8,
376 0x02, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
377 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
378 0x54, 0xAB, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
379 },
380 },
381 {
382 .pixel_clock = 40000000,
383 .conf = {
384 0x01, 0xD1, 0x21, 0x31, 0x40, 0x3C, 0x28, 0xC8,
385 0x87, 0xE8, 0xC8, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
386 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
387 0x54, 0x9A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
388 },
389 },
390 {
391 .pixel_clock = 65000000,
392 .conf = {
393 0x01, 0xD1, 0x36, 0x34, 0x40, 0x0C, 0x04, 0xC8,
394 0x82, 0xE8, 0x45, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
395 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
396 0x54, 0xBD, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
397 },
398 },
399 {
400 .pixel_clock = 71000000,
401 .conf = {
402 0x01, 0xD1, 0x3B, 0x35, 0x40, 0x0C, 0x04, 0xC8,
403 0x85, 0xE8, 0x63, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
404 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
405 0x54, 0x57, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
406 },
407 },
408 {
409 .pixel_clock = 73250000,
410 .conf = {
411 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x78, 0x8D, 0xC8,
412 0x81, 0xE8, 0xB7, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
413 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
414 0x54, 0xA8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
415 },
416 },
417 {
418 .pixel_clock = 74176000,
419 .conf = {
420 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0xC8,
421 0x81, 0xE8, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
422 0x56, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
423 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
424 },
425 },
426 {
427 .pixel_clock = 74250000,
428 .conf = {
429 0x01, 0xD1, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
430 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
431 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
432 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
433 },
434 },
435 {
436 .pixel_clock = 83500000,
437 .conf = {
438 0x01, 0xD1, 0x23, 0x11, 0x40, 0x0C, 0xFB, 0xC8,
439 0x85, 0xE8, 0xD1, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
440 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
441 0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
442 },
443 },
444 {
445 .pixel_clock = 88750000,
446 .conf = {
447 0x01, 0xD1, 0x25, 0x11, 0x40, 0x18, 0xFF, 0xC8,
448 0x83, 0xE8, 0xDE, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
449 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
450 0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
451 },
452 },
453 {
454 .pixel_clock = 106500000,
455 .conf = {
456 0x01, 0xD1, 0x2C, 0x12, 0x40, 0x0C, 0x09, 0xC8,
457 0x84, 0xE8, 0x0A, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
458 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
459 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
460 },
461 },
462 {
463 .pixel_clock = 108000000,
464 .conf = {
465 0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
466 0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
467 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
468 0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
469 },
470 },
471 {
472 .pixel_clock = 115500000,
473 .conf = {
474 0x01, 0xD1, 0x30, 0x14, 0x40, 0x0C, 0x03, 0xC8,
475 0x88, 0xE8, 0x21, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
476 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
477 0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
478 },
479 },
480 {
481 .pixel_clock = 146250000,
482 .conf = {
483 0x01, 0xD1, 0x3D, 0x15, 0x40, 0x18, 0xFD, 0xC8,
484 0x83, 0xE8, 0x6E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
485 0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
486 0x54, 0x54, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
487 },
488 },
489 {
490 .pixel_clock = 148500000,
491 .conf = {
492 0x01, 0xD1, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
493 0x81, 0xE8, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
494 0x26, 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x66,
495 0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
496 },
497 },
498};
499
Sachin Kamat16337072014-05-22 10:32:56 +0530500static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +0530501 .type = HDMI_TYPE14,
502 .phy_confs = hdmiphy_5420_configs,
503 .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs),
504 .is_apb_phy = 1,
505};
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900506
Sachin Kamat16337072014-05-22 10:32:56 +0530507static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900508 .type = HDMI_TYPE14,
509 .phy_confs = hdmiphy_v14_configs,
510 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
511 .is_apb_phy = 0,
512};
513
Marek Szyprowskiff830c92014-07-01 10:10:07 +0200514static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
515 .type = HDMI_TYPE13,
516 .phy_confs = hdmiphy_v13_configs,
517 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
518 .is_apb_phy = 0,
519};
520
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200521static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
522{
523 if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
524 return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
525 return reg_id;
526}
527
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900528static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
529{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200530 return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900531}
532
533static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
534 u32 reg_id, u8 value)
535{
Andrzej Hajda1993c332015-09-25 14:48:19 +0200536 writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900537}
538
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200539static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
540 int bytes, u32 val)
541{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200542 reg_id = hdmi_map_reg(hdata, reg_id);
543
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200544 while (--bytes >= 0) {
Andrzej Hajda1993c332015-09-25 14:48:19 +0200545 writel(val & 0xff, hdata->regs + reg_id);
Andrzej Hajdaedb6e412015-07-09 16:28:11 +0200546 val >>= 8;
547 reg_id += 4;
548 }
549}
550
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900551static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
552 u32 reg_id, u32 value, u32 mask)
553{
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200554 u32 old;
555
556 reg_id = hdmi_map_reg(hdata, reg_id);
557 old = readl(hdata->regs + reg_id);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900558 value = (value & mask) | (old & ~mask);
559 writel(value, hdata->regs + reg_id);
560}
561
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900562static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
563 u32 reg_offset, const u8 *buf, u32 len)
564{
565 if ((reg_offset + len) > 32)
566 return -EINVAL;
567
568 if (hdata->hdmiphy_port) {
569 int ret;
570
571 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
572 if (ret == len)
573 return 0;
574 return ret;
575 } else {
576 int i;
577 for (i = 0; i < len; i++)
Andrzej Hajda1993c332015-09-25 14:48:19 +0200578 writel(buf[i], hdata->regs_hdmiphy +
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900579 ((reg_offset + i)<<2));
580 return 0;
581 }
582}
583
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900584static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900585{
586#define DUMPREG(reg_id) \
587 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
588 readl(hdata->regs + reg_id))
589 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
590 DUMPREG(HDMI_INTC_FLAG);
591 DUMPREG(HDMI_INTC_CON);
592 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900593 DUMPREG(HDMI_V13_PHY_RSTOUT);
594 DUMPREG(HDMI_V13_PHY_VPLL);
595 DUMPREG(HDMI_V13_PHY_CMU);
596 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900597
598 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
599 DUMPREG(HDMI_CON_0);
600 DUMPREG(HDMI_CON_1);
601 DUMPREG(HDMI_CON_2);
602 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900603 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900604 DUMPREG(HDMI_STATUS_EN);
605 DUMPREG(HDMI_HPD);
606 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900607 DUMPREG(HDMI_V13_HPD_GEN);
608 DUMPREG(HDMI_V13_DC_CONTROL);
609 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900610
611 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
612 DUMPREG(HDMI_H_BLANK_0);
613 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900614 DUMPREG(HDMI_V13_V_BLANK_0);
615 DUMPREG(HDMI_V13_V_BLANK_1);
616 DUMPREG(HDMI_V13_V_BLANK_2);
617 DUMPREG(HDMI_V13_H_V_LINE_0);
618 DUMPREG(HDMI_V13_H_V_LINE_1);
619 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900620 DUMPREG(HDMI_VSYNC_POL);
621 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900622 DUMPREG(HDMI_V13_V_BLANK_F_0);
623 DUMPREG(HDMI_V13_V_BLANK_F_1);
624 DUMPREG(HDMI_V13_V_BLANK_F_2);
625 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
626 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
627 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
628 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
629 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
630 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
631 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
632 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
633 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
634 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
635 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
636 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900637
638 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
639 DUMPREG(HDMI_TG_CMD);
640 DUMPREG(HDMI_TG_H_FSZ_L);
641 DUMPREG(HDMI_TG_H_FSZ_H);
642 DUMPREG(HDMI_TG_HACT_ST_L);
643 DUMPREG(HDMI_TG_HACT_ST_H);
644 DUMPREG(HDMI_TG_HACT_SZ_L);
645 DUMPREG(HDMI_TG_HACT_SZ_H);
646 DUMPREG(HDMI_TG_V_FSZ_L);
647 DUMPREG(HDMI_TG_V_FSZ_H);
648 DUMPREG(HDMI_TG_VSYNC_L);
649 DUMPREG(HDMI_TG_VSYNC_H);
650 DUMPREG(HDMI_TG_VSYNC2_L);
651 DUMPREG(HDMI_TG_VSYNC2_H);
652 DUMPREG(HDMI_TG_VACT_ST_L);
653 DUMPREG(HDMI_TG_VACT_ST_H);
654 DUMPREG(HDMI_TG_VACT_SZ_L);
655 DUMPREG(HDMI_TG_VACT_SZ_H);
656 DUMPREG(HDMI_TG_FIELD_CHG_L);
657 DUMPREG(HDMI_TG_FIELD_CHG_H);
658 DUMPREG(HDMI_TG_VACT_ST2_L);
659 DUMPREG(HDMI_TG_VACT_ST2_H);
660 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
661 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
662 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
663 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
664 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
665 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
666 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
667 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
668#undef DUMPREG
669}
670
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900671static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
672{
673 int i;
674
675#define DUMPREG(reg_id) \
676 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
677 readl(hdata->regs + reg_id))
678
679 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
680 DUMPREG(HDMI_INTC_CON);
681 DUMPREG(HDMI_INTC_FLAG);
682 DUMPREG(HDMI_HPD_STATUS);
683 DUMPREG(HDMI_INTC_CON_1);
684 DUMPREG(HDMI_INTC_FLAG_1);
685 DUMPREG(HDMI_PHY_STATUS_0);
686 DUMPREG(HDMI_PHY_STATUS_PLL);
687 DUMPREG(HDMI_PHY_CON_0);
Andrzej Hajda633d00b2015-09-25 14:48:16 +0200688 DUMPREG(HDMI_V14_PHY_RSTOUT);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900689 DUMPREG(HDMI_PHY_VPLL);
690 DUMPREG(HDMI_PHY_CMU);
691 DUMPREG(HDMI_CORE_RSTOUT);
692
693 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
694 DUMPREG(HDMI_CON_0);
695 DUMPREG(HDMI_CON_1);
696 DUMPREG(HDMI_CON_2);
697 DUMPREG(HDMI_SYS_STATUS);
698 DUMPREG(HDMI_PHY_STATUS_0);
699 DUMPREG(HDMI_STATUS_EN);
700 DUMPREG(HDMI_HPD);
701 DUMPREG(HDMI_MODE_SEL);
702 DUMPREG(HDMI_ENC_EN);
703 DUMPREG(HDMI_DC_CONTROL);
704 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
705
706 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
707 DUMPREG(HDMI_H_BLANK_0);
708 DUMPREG(HDMI_H_BLANK_1);
709 DUMPREG(HDMI_V2_BLANK_0);
710 DUMPREG(HDMI_V2_BLANK_1);
711 DUMPREG(HDMI_V1_BLANK_0);
712 DUMPREG(HDMI_V1_BLANK_1);
713 DUMPREG(HDMI_V_LINE_0);
714 DUMPREG(HDMI_V_LINE_1);
715 DUMPREG(HDMI_H_LINE_0);
716 DUMPREG(HDMI_H_LINE_1);
717 DUMPREG(HDMI_HSYNC_POL);
718
719 DUMPREG(HDMI_VSYNC_POL);
720 DUMPREG(HDMI_INT_PRO_MODE);
721 DUMPREG(HDMI_V_BLANK_F0_0);
722 DUMPREG(HDMI_V_BLANK_F0_1);
723 DUMPREG(HDMI_V_BLANK_F1_0);
724 DUMPREG(HDMI_V_BLANK_F1_1);
725
726 DUMPREG(HDMI_H_SYNC_START_0);
727 DUMPREG(HDMI_H_SYNC_START_1);
728 DUMPREG(HDMI_H_SYNC_END_0);
729 DUMPREG(HDMI_H_SYNC_END_1);
730
731 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
732 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
733 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
734 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
735
736 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
737 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
738 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
739 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
740
741 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
742 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
743 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
744 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
745
746 DUMPREG(HDMI_V_BLANK_F2_0);
747 DUMPREG(HDMI_V_BLANK_F2_1);
748 DUMPREG(HDMI_V_BLANK_F3_0);
749 DUMPREG(HDMI_V_BLANK_F3_1);
750 DUMPREG(HDMI_V_BLANK_F4_0);
751 DUMPREG(HDMI_V_BLANK_F4_1);
752 DUMPREG(HDMI_V_BLANK_F5_0);
753 DUMPREG(HDMI_V_BLANK_F5_1);
754
755 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
756 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
757 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
758 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
759 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
760 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
761 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
762 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
763
764 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
765 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
766 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
767 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
768 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
769 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
770 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
771 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
772
773 DUMPREG(HDMI_VACT_SPACE_1_0);
774 DUMPREG(HDMI_VACT_SPACE_1_1);
775 DUMPREG(HDMI_VACT_SPACE_2_0);
776 DUMPREG(HDMI_VACT_SPACE_2_1);
777 DUMPREG(HDMI_VACT_SPACE_3_0);
778 DUMPREG(HDMI_VACT_SPACE_3_1);
779 DUMPREG(HDMI_VACT_SPACE_4_0);
780 DUMPREG(HDMI_VACT_SPACE_4_1);
781 DUMPREG(HDMI_VACT_SPACE_5_0);
782 DUMPREG(HDMI_VACT_SPACE_5_1);
783 DUMPREG(HDMI_VACT_SPACE_6_0);
784 DUMPREG(HDMI_VACT_SPACE_6_1);
785
786 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
787 DUMPREG(HDMI_TG_CMD);
788 DUMPREG(HDMI_TG_H_FSZ_L);
789 DUMPREG(HDMI_TG_H_FSZ_H);
790 DUMPREG(HDMI_TG_HACT_ST_L);
791 DUMPREG(HDMI_TG_HACT_ST_H);
792 DUMPREG(HDMI_TG_HACT_SZ_L);
793 DUMPREG(HDMI_TG_HACT_SZ_H);
794 DUMPREG(HDMI_TG_V_FSZ_L);
795 DUMPREG(HDMI_TG_V_FSZ_H);
796 DUMPREG(HDMI_TG_VSYNC_L);
797 DUMPREG(HDMI_TG_VSYNC_H);
798 DUMPREG(HDMI_TG_VSYNC2_L);
799 DUMPREG(HDMI_TG_VSYNC2_H);
800 DUMPREG(HDMI_TG_VACT_ST_L);
801 DUMPREG(HDMI_TG_VACT_ST_H);
802 DUMPREG(HDMI_TG_VACT_SZ_L);
803 DUMPREG(HDMI_TG_VACT_SZ_H);
804 DUMPREG(HDMI_TG_FIELD_CHG_L);
805 DUMPREG(HDMI_TG_FIELD_CHG_H);
806 DUMPREG(HDMI_TG_VACT_ST2_L);
807 DUMPREG(HDMI_TG_VACT_ST2_H);
808 DUMPREG(HDMI_TG_VACT_ST3_L);
809 DUMPREG(HDMI_TG_VACT_ST3_H);
810 DUMPREG(HDMI_TG_VACT_ST4_L);
811 DUMPREG(HDMI_TG_VACT_ST4_H);
812 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
813 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
814 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
815 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
816 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
817 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
818 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
819 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
820 DUMPREG(HDMI_TG_3D);
821
822 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
823 DUMPREG(HDMI_AVI_CON);
824 DUMPREG(HDMI_AVI_HEADER0);
825 DUMPREG(HDMI_AVI_HEADER1);
826 DUMPREG(HDMI_AVI_HEADER2);
827 DUMPREG(HDMI_AVI_CHECK_SUM);
828 DUMPREG(HDMI_VSI_CON);
829 DUMPREG(HDMI_VSI_HEADER0);
830 DUMPREG(HDMI_VSI_HEADER1);
831 DUMPREG(HDMI_VSI_HEADER2);
832 for (i = 0; i < 7; ++i)
833 DUMPREG(HDMI_VSI_DATA(i));
834
835#undef DUMPREG
836}
837
838static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
839{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200840 if (hdata->drv_data->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900841 hdmi_v13_regs_dump(hdata, prefix);
842 else
843 hdmi_v14_regs_dump(hdata, prefix);
844}
845
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530846static u8 hdmi_chksum(struct hdmi_context *hdata,
847 u32 start, u8 len, u32 hdr_sum)
848{
849 int i;
850
851 /* hdr_sum : header0 + header1 + header2
852 * start : start address of packet byte1
853 * len : packet bytes - 1 */
854 for (i = 0; i < len; ++i)
855 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
856
857 /* return 2's complement of 8 bit hdr_sum */
858 return (u8)(~(hdr_sum & 0xff) + 1);
859}
860
861static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530862 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530863{
864 u32 hdr_sum;
865 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530866 u32 mod;
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200867 u8 ar;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530868
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530869 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
870 if (hdata->dvi_mode) {
871 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
872 HDMI_VSI_CON_DO_NOT_TRANSMIT);
873 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
874 HDMI_AVI_CON_DO_NOT_TRANSMIT);
875 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
876 return;
877 }
878
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530879 switch (infoframe->any.type) {
880 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530881 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530882 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
883 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
884 infoframe->any.version);
885 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
886 hdr_sum = infoframe->any.type + infoframe->any.version +
887 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530888
889 /* Output format zero hardcoded ,RGB YBCR selection */
890 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
891 AVI_ACTIVE_FORMAT_VALID |
892 AVI_UNDERSCANNED_DISPLAY_VALID);
893
Shirish S46154152014-03-13 10:58:28 +0530894 /*
895 * Set the aspect ratio as per the mode, mentioned in
896 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
897 */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200898 ar = hdata->current_mode.picture_aspect_ratio;
899 switch (ar) {
Shirish S46154152014-03-13 10:58:28 +0530900 case HDMI_PICTURE_ASPECT_4_3:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200901 ar |= AVI_4_3_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530902 break;
903 case HDMI_PICTURE_ASPECT_16_9:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200904 ar |= AVI_16_9_CENTER_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530905 break;
906 case HDMI_PICTURE_ASPECT_NONE:
907 default:
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200908 ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
Shirish S46154152014-03-13 10:58:28 +0530909 break;
910 }
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200911 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530912
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +0200913 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530914
915 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530916 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530917 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
918 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
919 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530920 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530921 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530922 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
923 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
924 infoframe->any.version);
925 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
926 hdr_sum = infoframe->any.type + infoframe->any.version +
927 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530928 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530929 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530930 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
931 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
932 break;
933 default:
934 break;
935 }
936}
937
Sean Pauld9716ee2014-01-30 16:19:29 -0500938static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
939 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500940{
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200941 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Paul45517892014-01-30 16:19:05 -0500942
Andrzej Hajda2228b7c2015-09-25 14:48:24 +0200943 if (gpiod_get_value(hdata->hpd_gpio))
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200944 return connector_status_connected;
Sean Paul5137c8c2014-04-03 20:41:03 +0530945
Andrzej Hajdaef6ce282015-07-09 16:28:07 +0200946 return connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500947}
948
Sean Pauld9716ee2014-01-30 16:19:29 -0500949static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900950{
Andrzej Hajdaad279312014-09-09 15:16:13 +0200951 drm_connector_unregister(connector);
952 drm_connector_cleanup(connector);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900953}
954
Sean Pauld9716ee2014-01-30 16:19:29 -0500955static struct drm_connector_funcs hdmi_connector_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300956 .dpms = drm_atomic_helper_connector_dpms,
Sean Pauld9716ee2014-01-30 16:19:29 -0500957 .fill_modes = drm_helper_probe_single_connector_modes,
958 .detect = hdmi_detect,
959 .destroy = hdmi_connector_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300960 .reset = drm_atomic_helper_connector_reset,
961 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
962 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Sean Pauld9716ee2014-01-30 16:19:29 -0500963};
964
965static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900966{
Andrzej Hajda185f22d2015-09-25 14:48:26 +0200967 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -0500968 struct edid *edid;
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200969 int ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970
Inki Dae8fa04aa2014-03-13 16:38:31 +0900971 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500972 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900973
Inki Dae8fa04aa2014-03-13 16:38:31 +0900974 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500975 if (!edid)
976 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977
Sean Pauld9716ee2014-01-30 16:19:29 -0500978 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500979 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
980 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500981 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500982
Sean Pauld9716ee2014-01-30 16:19:29 -0500983 drm_mode_connector_update_edid_property(connector, edid);
984
Andrzej Hajda64ebd892015-07-09 08:25:38 +0200985 ret = drm_add_edid_modes(connector, edid);
986
987 kfree(edid);
988
989 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900990}
991
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900992static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900993{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900994 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900995
Andrzej Hajdacd240cd2015-07-09 16:28:09 +0200996 for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
997 if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500998 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500999
1000 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
1001 return -EINVAL;
1002}
1003
Sean Pauld9716ee2014-01-30 16:19:29 -05001004static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -05001005 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001006{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001007 struct hdmi_context *hdata = connector_to_hdmi(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001008 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001009
Rahul Sharma16844fb2013-06-10 14:50:00 +05301010 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
1011 mode->hdisplay, mode->vdisplay, mode->vrefresh,
1012 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
1013 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001014
Sean Paulf041b252014-01-30 16:19:15 -05001015 ret = mixer_check_mode(mode);
1016 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -05001017 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -05001018
Rahul Sharma16844fb2013-06-10 14:50:00 +05301019 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001020 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -05001021 return MODE_BAD;
1022
1023 return MODE_OK;
1024}
1025
1026static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
1027{
Andrzej Hajda185f22d2015-09-25 14:48:26 +02001028 struct hdmi_context *hdata = connector_to_hdmi(connector);
Sean Pauld9716ee2014-01-30 16:19:29 -05001029
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001030 return &hdata->encoder;
Sean Pauld9716ee2014-01-30 16:19:29 -05001031}
1032
1033static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
1034 .get_modes = hdmi_get_modes,
1035 .mode_valid = hdmi_mode_valid,
1036 .best_encoder = hdmi_best_encoder,
1037};
1038
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001039static int hdmi_create_connector(struct drm_encoder *encoder)
Sean Pauld9716ee2014-01-30 16:19:29 -05001040{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001041 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001042 struct drm_connector *connector = &hdata->connector;
1043 int ret;
1044
Sean Pauld9716ee2014-01-30 16:19:29 -05001045 connector->interlace_allowed = true;
1046 connector->polled = DRM_CONNECTOR_POLL_HPD;
1047
1048 ret = drm_connector_init(hdata->drm_dev, connector,
1049 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
1050 if (ret) {
1051 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001052 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -05001053 }
1054
1055 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001056 drm_connector_register(connector);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001057 drm_mode_connector_attach_encoder(connector, encoder);
Sean Pauld9716ee2014-01-30 16:19:29 -05001058
1059 return 0;
1060}
1061
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001062static bool hdmi_mode_fixup(struct drm_encoder *encoder,
1063 const struct drm_display_mode *mode,
1064 struct drm_display_mode *adjusted_mode)
Sean Paulf041b252014-01-30 16:19:15 -05001065{
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001066 struct drm_device *dev = encoder->dev;
1067 struct drm_connector *connector;
Sean Paulf041b252014-01-30 16:19:15 -05001068 struct drm_display_mode *m;
1069 int mode_ok;
1070
Sean Paulf041b252014-01-30 16:19:15 -05001071 drm_mode_set_crtcinfo(adjusted_mode, 0);
1072
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001073 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1074 if (connector->encoder == encoder)
1075 break;
1076 }
1077
1078 if (connector->encoder != encoder)
1079 return true;
1080
Sean Pauld9716ee2014-01-30 16:19:29 -05001081 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -05001082
1083 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -05001084 if (mode_ok == MODE_OK)
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001085 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001086
1087 /*
1088 * otherwise, find the most suitable mode among modes and change it
1089 * to adjusted_mode.
1090 */
1091 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -05001092 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -05001093
Sean Pauld9716ee2014-01-30 16:19:29 -05001094 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001095 DRM_INFO("desired mode doesn't exist so\n");
1096 DRM_INFO("use the most suitable mode among modes.\n");
1097
1098 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1099 m->hdisplay, m->vdisplay, m->vrefresh);
1100
Sean Paul75626852014-01-30 16:19:16 -05001101 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001102 break;
1103 }
1104 }
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001105
1106 return true;
Sean Paulf041b252014-01-30 16:19:15 -05001107}
1108
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001109static void hdmi_set_acr(u32 freq, u8 *acr)
1110{
1111 u32 n, cts;
1112
1113 switch (freq) {
1114 case 32000:
1115 n = 4096;
1116 cts = 27000;
1117 break;
1118 case 44100:
1119 n = 6272;
1120 cts = 30000;
1121 break;
1122 case 88200:
1123 n = 12544;
1124 cts = 30000;
1125 break;
1126 case 176400:
1127 n = 25088;
1128 cts = 30000;
1129 break;
1130 case 48000:
1131 n = 6144;
1132 cts = 27000;
1133 break;
1134 case 96000:
1135 n = 12288;
1136 cts = 27000;
1137 break;
1138 case 192000:
1139 n = 24576;
1140 cts = 27000;
1141 break;
1142 default:
1143 n = 0;
1144 cts = 0;
1145 break;
1146 }
1147
1148 acr[1] = cts >> 16;
1149 acr[2] = cts >> 8 & 0xff;
1150 acr[3] = cts & 0xff;
1151
1152 acr[4] = n >> 16;
1153 acr[5] = n >> 8 & 0xff;
1154 acr[6] = n & 0xff;
1155}
1156
1157static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1158{
1159 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1160 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1161 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1162 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1163 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1164 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1165 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1166 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1167 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001168 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001169}
1170
1171static void hdmi_audio_init(struct hdmi_context *hdata)
1172{
Sachin Kamat7a9bf6e2014-07-02 09:33:07 +05301173 u32 sample_rate, bits_per_sample;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001174 u32 data_num, bit_ch, sample_frq;
1175 u32 val;
1176 u8 acr[7];
1177
1178 sample_rate = 44100;
1179 bits_per_sample = 16;
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001180
1181 switch (bits_per_sample) {
1182 case 20:
1183 data_num = 2;
1184 bit_ch = 1;
1185 break;
1186 case 24:
1187 data_num = 3;
1188 bit_ch = 1;
1189 break;
1190 default:
1191 data_num = 1;
1192 bit_ch = 0;
1193 break;
1194 }
1195
1196 hdmi_set_acr(sample_rate, acr);
1197 hdmi_reg_acr(hdata, acr);
1198
1199 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1200 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1201 | HDMI_I2S_MUX_ENABLE);
1202
1203 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1204 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1205
1206 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1207
1208 sample_frq = (sample_rate == 44100) ? 0 :
1209 (sample_rate == 48000) ? 2 :
1210 (sample_rate == 32000) ? 3 :
1211 (sample_rate == 96000) ? 0xa : 0x0;
1212
1213 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1214 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1215
1216 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1217 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1218
1219 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1220 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1221 | HDMI_I2S_SEL_LRCK(6));
1222 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1223 | HDMI_I2S_SEL_SDATA2(4));
1224 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1225 | HDMI_I2S_SEL_SDATA2(2));
1226 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1227
1228 /* I2S_CON_1 & 2 */
1229 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1230 | HDMI_I2S_L_CH_LOW_POL);
1231 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1232 | HDMI_I2S_SET_BIT_CH(bit_ch)
1233 | HDMI_I2S_SET_SDATA_BIT(data_num)
1234 | HDMI_I2S_BASIC_FORMAT);
1235
1236 /* Configure register related to CUV information */
1237 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1238 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1239 | HDMI_I2S_COPYRIGHT
1240 | HDMI_I2S_LINEAR_PCM
1241 | HDMI_I2S_CONSUMER_FORMAT);
1242 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1243 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1244 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1245 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1246 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1247 HDMI_I2S_ORG_SMP_FREQ_44_1
1248 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1249 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1250
1251 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1252}
1253
1254static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1255{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001256 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001257 return;
1258
1259 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1260 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1261 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1262}
1263
Rahul Sharmabfa48422014-04-03 20:41:04 +05301264static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001265{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301266 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001267
Rahul Sharmabfa48422014-04-03 20:41:04 +05301268 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1269 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001270
Rahul Sharmabfa48422014-04-03 20:41:04 +05301271 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1272 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001273}
1274
1275static void hdmi_conf_init(struct hdmi_context *hdata)
1276{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301277 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301278
Sean Paul77006a72013-01-16 10:17:20 -05001279 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001280 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1281 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001282
1283 /* choose HDMI mode */
1284 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1285 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
Shirish S9a8e1cb2014-02-14 13:04:57 +05301286 /* Apply Video preable and Guard band in HDMI mode only */
1287 hdmi_reg_writeb(hdata, HDMI_CON_2, 0);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001288 /* disable bluescreen */
1289 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001290
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001291 if (hdata->dvi_mode) {
1292 /* choose DVI mode */
1293 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1294 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1295 hdmi_reg_writeb(hdata, HDMI_CON_2,
1296 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1297 }
1298
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001299 if (hdata->drv_data->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001300 /* choose bluescreen (fecal) color */
1301 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1302 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1303 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1304
1305 /* enable AVI packet every vsync, fixes purple line problem */
1306 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1307 /* force RGB, look to CEA-861-D, table 7 for more detail */
1308 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1309 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1310
1311 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1312 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1313 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1314 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301315 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1316 infoframe.any.version = HDMI_AVI_VERSION;
1317 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301318 hdmi_reg_infoframe(hdata, &infoframe);
1319
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301320 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1321 infoframe.any.version = HDMI_AUI_VERSION;
1322 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301323 hdmi_reg_infoframe(hdata, &infoframe);
1324
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001325 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001326 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1327 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001328}
1329
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001330static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
1331{
1332 int tries;
1333
1334 for (tries = 0; tries < 10; ++tries) {
1335 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
1336
1337 if (val & HDMI_PHY_STATUS_READY) {
1338 DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
1339 return;
1340 }
1341 usleep_range(10, 20);
1342 }
1343
1344 DRM_ERROR("PLL could not reach steady state\n");
1345}
1346
Rahul Sharma16844fb2013-06-10 14:50:00 +05301347static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001348{
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001349 struct drm_display_mode *m = &hdata->current_mode;
1350 unsigned int val;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001351
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001352 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1353 hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
1354 (m->htotal << 12) | m->vtotal);
1355
1356 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1357 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
1358
1359 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1360 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
1361
1362 val = (m->hsync_start - m->hdisplay - 2);
1363 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1364 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1365 hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
1366
1367 /*
1368 * Quirk requirement for exynos HDMI IP design,
1369 * 2 pixels less than the actual calculation for hsync_start
1370 * and end.
1371 */
1372
1373 /* Following values & calculations differ for different type of modes */
1374 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1375 /* Interlaced Mode */
1376 val = ((m->vsync_end - m->vdisplay) / 2);
1377 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1378 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1379
1380 val = m->vtotal / 2;
1381 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1382 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1383
1384 val = (m->vtotal +
1385 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1386 val |= m->vtotal << 11;
1387 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
1388
1389 val = ((m->vtotal / 2) + 7);
1390 val |= ((m->vtotal / 2) + 2) << 12;
1391 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
1392
1393 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1394 val |= ((m->htotal / 2) +
1395 (m->hsync_start - m->hdisplay)) << 12;
1396 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
1397
1398 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1399 (m->vtotal - m->vdisplay) / 2);
1400 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1401
1402 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
1403 } else {
1404 /* Progressive Mode */
1405
1406 val = m->vtotal;
1407 val |= (m->vtotal - m->vdisplay) << 11;
1408 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
1409
1410 hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
1411
1412 val = (m->vsync_end - m->vdisplay);
1413 val |= ((m->vsync_start - m->vdisplay) << 12);
1414 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
1415
1416 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
1417 hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
1418 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1419 m->vtotal - m->vdisplay);
1420 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1421 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1422 }
1423
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001424 /* Timing generator registers */
Andrzej Hajdaedb6e412015-07-09 16:28:11 +02001425 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1426 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1427 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1428 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1429 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1430 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1431 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1432 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1433 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1434 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1435 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001436}
1437
Rahul Sharma16844fb2013-06-10 14:50:00 +05301438static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001439{
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001440 struct drm_display_mode *m = &hdata->current_mode;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001441
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001442 hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
1443 hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
1444 hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
1445 hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
1446 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1447 hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
1448 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1449 hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
1450 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1451
1452 /*
1453 * Quirk requirement for exynos 5 HDMI IP design,
1454 * 2 pixels less than the actual calculation for hsync_start
1455 * and end.
1456 */
1457
1458 /* Following values & calculations differ for different type of modes */
1459 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1460 /* Interlaced Mode */
1461 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1462 (m->vsync_end - m->vdisplay) / 2);
1463 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1464 (m->vsync_start - m->vdisplay) / 2);
1465 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
1466 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1467 (m->vtotal - m->vdisplay) / 2);
1468 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
1469 m->vtotal - m->vdisplay / 2);
1470 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
1471 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
1472 (m->vtotal / 2) + 7);
1473 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
1474 (m->vtotal / 2) + 2);
1475 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
1476 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1477 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
1478 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1479 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1480 (m->vtotal - m->vdisplay) / 2);
1481 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
1482 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
1483 m->vtotal - m->vdisplay / 2);
1484 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
1485 (m->vtotal / 2) + 1);
1486 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
1487 (m->vtotal / 2) + 1);
1488 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
1489 (m->vtotal / 2) + 1);
1490 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
1491 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
1492 } else {
1493 /* Progressive Mode */
1494 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
1495 m->vsync_end - m->vdisplay);
1496 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
1497 m->vsync_start - m->vdisplay);
1498 hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
1499 hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
1500 m->vtotal - m->vdisplay);
1501 hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
1502 hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
1503 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
1504 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
1505 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
1506 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
1507 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
1508 m->vtotal - m->vdisplay);
1509 hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
1510 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
1511 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
1512 hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
1513 hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
1514 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
1515 hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
1516 }
1517
1518 /* Following values & calculations are same irrespective of mode type */
1519 hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
1520 m->hsync_start - m->hdisplay - 2);
1521 hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
1522 m->hsync_end - m->hdisplay - 2);
1523 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
1524 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
1525 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
1526 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
1527 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
1528 hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
1529 hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
1530 hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
1531 hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
1532 hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
1533 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
1534 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
1535 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
1536 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
1537 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
1538 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
1539 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
1540 hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001541
1542 /* Timing generator registers */
Andrzej Hajda7b5102d2015-07-09 16:28:12 +02001543 hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
1544 hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
1545 hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
1546 hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
1547 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
1548 hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
1549 hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
1550 hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
1551 hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001552}
1553
Rahul Sharma16844fb2013-06-10 14:50:00 +05301554static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001555{
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001556 if (hdata->drv_data->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301557 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001558 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301559 hdmi_v14_mode_apply(hdata);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001560
1561 hdmiphy_wait_for_pll(hdata);
1562
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001563 clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
Andrzej Hajda8eb6d4e2015-09-25 14:48:17 +02001564
1565 /* enable HDMI and timing generator */
1566 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001567}
1568
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001569static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1570{
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001571 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001572
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001573 /* reset hdmiphy */
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001574 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001575 usleep_range(10000, 12000);
Andrzej Hajda633d00b2015-09-25 14:48:16 +02001576 hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001577 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001578}
1579
1580static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1581{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001582 int ret;
1583 int i;
1584
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001585 /* pixel clock */
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001586 i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001587 if (i < 0) {
1588 DRM_ERROR("failed to find hdmiphy conf\n");
1589 return;
1590 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001591
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001592 ret = hdmiphy_reg_write_buf(hdata, 0,
1593 hdata->drv_data->phy_confs[i].conf, 32);
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001594 if (ret) {
1595 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001596 return;
1597 }
1598
Sean Paul09760ea2013-01-14 17:03:20 -05001599 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001600}
1601
1602static void hdmi_conf_apply(struct hdmi_context *hdata)
1603{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001604 hdmiphy_conf_reset(hdata);
1605 hdmiphy_conf_apply(hdata);
1606
Rahul Sharmabfa48422014-04-03 20:41:04 +05301607 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001608 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001609
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001610 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001611
1612 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301613 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001614 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001615
1616 hdmi_regs_dump(hdata, "start");
1617}
1618
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001619static void hdmi_mode_set(struct drm_encoder *encoder,
1620 struct drm_display_mode *mode,
1621 struct drm_display_mode *adjusted_mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001622{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001623 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001624 struct drm_display_mode *m = adjusted_mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001625
YoungJun Chocbc4c332013-06-12 10:44:40 +09001626 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1627 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001628 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
Tobias Jakobi1e6d4592015-04-07 01:14:50 +02001629 "INTERLACED" : "PROGRESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001630
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001631 drm_mode_copy(&hdata->current_mode, m);
Andrzej Hajdac93aaeb2015-07-09 16:28:10 +02001632 hdata->cea_video_id = drm_match_cea_mode(mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001633}
1634
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001635static void hdmi_enable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001636{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001637 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001638
Andrzej Hajda882a0642015-07-09 16:28:08 +02001639 if (hdata->powered)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001640 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001641
1642 hdata->powered = true;
1643
Sean Paulaf65c802014-01-30 16:19:27 -05001644 pm_runtime_get_sync(hdata->dev);
1645
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001646 if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
Seung-Woo Kimad079452013-06-05 14:34:38 +09001647 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1648
Rahul Sharma049d34e2014-05-20 10:36:05 +05301649 /* set pmu hdmiphy control bit to enable hdmiphy */
1650 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1651 PMU_HDMI_PHY_ENABLE_BIT, 1);
1652
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001653 clk_prepare_enable(hdata->hdmi);
1654 clk_prepare_enable(hdata->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301655
Gustavo Padovanc2c099f2015-08-05 20:24:17 -03001656 hdmi_conf_apply(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001657}
1658
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001659static void hdmi_disable(struct drm_encoder *encoder)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001660{
Gustavo Padovancf67cc92015-08-11 17:38:06 +09001661 struct hdmi_context *hdata = encoder_to_hdmi(encoder);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001662 struct drm_crtc *crtc = encoder->crtc;
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001663 const struct drm_crtc_helper_funcs *funcs = NULL;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001664
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001665 if (!hdata->powered)
Andrzej Hajda882a0642015-07-09 16:28:08 +02001666 return;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001667
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001668 /*
1669 * The SFRs of VP and Mixer are updated by Vertical Sync of
1670 * Timing generator which is a part of HDMI so the sequence
1671 * to disable TV Subsystem should be as following,
1672 * VP -> Mixer -> HDMI
1673 *
1674 * Below codes will try to disable Mixer and VP(if used)
1675 * prior to disabling HDMI.
1676 */
1677 if (crtc)
1678 funcs = crtc->helper_private;
1679 if (funcs && funcs->disable)
1680 (*funcs->disable)(crtc);
1681
Rahul Sharmabfa48422014-04-03 20:41:04 +05301682 /* HDMI System Disable */
1683 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1684
Sean Paul724fd142014-05-09 15:05:10 +09001685 cancel_delayed_work(&hdata->hotplug_work);
1686
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001687 clk_disable_unprepare(hdata->sclk_hdmi);
1688 clk_disable_unprepare(hdata->hdmi);
Rahul Sharma049d34e2014-05-20 10:36:05 +05301689
1690 /* reset pmu hdmiphy control bit to disable hdmiphy */
1691 regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
1692 PMU_HDMI_PHY_ENABLE_BIT, 0);
1693
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001694 regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001695
Sean Paulaf65c802014-01-30 16:19:27 -05001696 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001697
1698 hdata->powered = false;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001699}
1700
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001701static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
Sean Paulf041b252014-01-30 16:19:15 -05001702 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001703 .mode_set = hdmi_mode_set,
Gustavo Padovanb6595dc2015-08-10 21:37:04 -03001704 .enable = hdmi_enable,
1705 .disable = hdmi_disable,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001706};
1707
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001708static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
1709 .destroy = drm_encoder_cleanup,
1710};
1711
Sean Paul724fd142014-05-09 15:05:10 +09001712static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001713{
Sean Paul724fd142014-05-09 15:05:10 +09001714 struct hdmi_context *hdata;
1715
1716 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001717
Sean Paul45517892014-01-30 16:19:05 -05001718 if (hdata->drm_dev)
1719 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001720}
1721
1722static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1723{
1724 struct hdmi_context *hdata = arg;
1725
1726 mod_delayed_work(system_wq, &hdata->hotplug_work,
1727 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001728
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001729 return IRQ_HANDLED;
1730}
1731
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001732static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001733{
1734 struct device *dev = hdata->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001735 int i, ret;
1736
1737 DRM_DEBUG_KMS("HDMI resource init\n");
1738
Andrzej Hajda2228b7c2015-09-25 14:48:24 +02001739 hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
1740 if (IS_ERR(hdata->hpd_gpio)) {
1741 DRM_ERROR("cannot get hpd gpio property\n");
1742 return PTR_ERR(hdata->hpd_gpio);
1743 }
1744
1745 hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
1746 if (hdata->irq < 0) {
1747 DRM_ERROR("failed to get GPIO irq\n");
1748 return hdata->irq;
1749 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001750 /* get clocks, power */
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001751 hdata->hdmi = devm_clk_get(dev, "hdmi");
1752 if (IS_ERR(hdata->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001753 DRM_ERROR("failed to get clock 'hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001754 ret = PTR_ERR(hdata->hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001755 goto fail;
1756 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001757 hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
1758 if (IS_ERR(hdata->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001759 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001760 ret = PTR_ERR(hdata->sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001761 goto fail;
1762 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001763 hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
1764 if (IS_ERR(hdata->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001765 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001766 ret = PTR_ERR(hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001767 goto fail;
1768 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001769 hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
1770 if (IS_ERR(hdata->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001771 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001772 ret = PTR_ERR(hdata->sclk_hdmiphy);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001773 goto fail;
1774 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001775 hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1776 if (IS_ERR(hdata->mout_hdmi)) {
Rahul Sharma59956d32013-06-11 12:24:03 +05301777 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001778 ret = PTR_ERR(hdata->mout_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301779 goto fail;
1780 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001781
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001782 clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001783
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001784 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001785 hdata->regul_bulk[i].supply = supply[i];
1786 hdata->regul_bulk[i].consumer = NULL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001787 }
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001788 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001789 if (ret) {
1790 DRM_ERROR("failed to get regulators\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001791 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001792 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001793
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001794 hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001795
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001796 if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001797 return 0;
1798
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001799 if (IS_ERR(hdata->reg_hdmi_en))
1800 return PTR_ERR(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001801
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02001802 ret = regulator_enable(hdata->reg_hdmi_en);
Andrzej Hajda498d5a32015-09-25 14:48:21 +02001803 if (ret)
1804 DRM_ERROR("failed to enable hdmi-en regulator\n");
Marek Szyprowski05fdf982014-07-01 10:10:06 +02001805
Inki Daedf5225b2014-05-29 18:28:02 +09001806 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001807fail:
1808 DRM_ERROR("HDMI resource init - failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001809 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001810}
1811
Rahul Sharma22c4f422012-10-04 20:48:55 +05301812static struct of_device_id hdmi_match_types[] = {
1813 {
Marek Szyprowskiff830c92014-07-01 10:10:07 +02001814 .compatible = "samsung,exynos4210-hdmi",
1815 .data = &exynos4210_hdmi_driver_data,
1816 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301817 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09001818 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301819 }, {
Rahul Sharmaa18a2dd2014-04-20 15:51:17 +05301820 .compatible = "samsung,exynos5420-hdmi",
1821 .data = &exynos5420_hdmi_driver_data,
1822 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301823 /* end node */
1824 }
1825};
Sjoerd Simons39b58a32014-07-18 22:36:41 +02001826MODULE_DEVICE_TABLE (of, hdmi_match_types);
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301827
Inki Daef37cd5e2014-05-09 14:25:20 +09001828static int hdmi_bind(struct device *dev, struct device *master, void *data)
1829{
1830 struct drm_device *drm_dev = data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001831 struct hdmi_context *hdata = dev_get_drvdata(dev);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001832 struct drm_encoder *encoder = &hdata->encoder;
1833 int ret, pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +09001834
Inki Daef37cd5e2014-05-09 14:25:20 +09001835 hdata->drm_dev = drm_dev;
1836
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001837 pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
1838 EXYNOS_DISPLAY_TYPE_HDMI);
1839 if (pipe < 0)
1840 return pipe;
Gustavo Padovana2986e82015-08-05 20:24:20 -03001841
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001842 encoder->possible_crtcs = 1 << pipe;
1843
1844 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
1845
1846 drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
1847 DRM_MODE_ENCODER_TMDS);
1848
1849 drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
1850
1851 ret = hdmi_create_connector(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001852 if (ret) {
1853 DRM_ERROR("failed to create connector ret = %d\n", ret);
Gustavo Padovan2b8376c2015-08-15 12:14:08 -03001854 drm_encoder_cleanup(encoder);
Gustavo Padovana2986e82015-08-05 20:24:20 -03001855 return ret;
1856 }
1857
1858 return 0;
Inki Daef37cd5e2014-05-09 14:25:20 +09001859}
1860
1861static void hdmi_unbind(struct device *dev, struct device *master, void *data)
1862{
Inki Daef37cd5e2014-05-09 14:25:20 +09001863}
1864
1865static const struct component_ops hdmi_component_ops = {
1866 .bind = hdmi_bind,
1867 .unbind = hdmi_unbind,
1868};
1869
Inki Daee2a562d2014-05-09 16:46:10 +09001870static struct device_node *hdmi_legacy_ddc_dt_binding(struct device *dev)
1871{
1872 const char *compatible_str = "samsung,exynos4210-hdmiddc";
1873 struct device_node *np;
1874
1875 np = of_find_compatible_node(NULL, NULL, compatible_str);
1876 if (np)
1877 return of_get_next_parent(np);
1878
1879 return NULL;
1880}
1881
1882static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
1883{
1884 const char *compatible_str = "samsung,exynos4212-hdmiphy";
1885
1886 return of_find_compatible_node(NULL, NULL, compatible_str);
1887}
1888
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001889static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001890{
Inki Daef37cd5e2014-05-09 14:25:20 +09001891 struct device_node *ddc_node, *phy_node;
Inki Daef37cd5e2014-05-09 14:25:20 +09001892 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001893 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001894 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001895 struct resource *res;
1896 int ret;
1897
Andrzej Hajda930865f2014-11-17 09:54:20 +01001898 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
1899 if (!hdata)
1900 return -ENOMEM;
1901
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001902 match = of_match_device(hdmi_match_types, dev);
1903 if (!match)
1904 return -ENODEV;
1905
1906 hdata->drv_data = match->data;
Andrzej Hajda930865f2014-11-17 09:54:20 +01001907
Andrzej Hajda930865f2014-11-17 09:54:20 +01001908 platform_set_drvdata(pdev, hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001909
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001910 hdata->dev = dev;
1911
1912 ret = hdmi_resources_init(hdata);
1913 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301914 DRM_ERROR("hdmi_resources_init failed\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001915 return ret;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001916 }
1917
1918 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001919 hdata->regs = devm_ioremap_resource(dev, res);
Inki Daedf5225b2014-05-29 18:28:02 +09001920 if (IS_ERR(hdata->regs)) {
1921 ret = PTR_ERR(hdata->regs);
Andrzej Hajda86650402015-06-11 23:23:37 +09001922 return ret;
Inki Daedf5225b2014-05-29 18:28:02 +09001923 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001924
Inki Daee2a562d2014-05-09 16:46:10 +09001925 ddc_node = hdmi_legacy_ddc_dt_binding(dev);
1926 if (ddc_node)
1927 goto out_get_ddc_adpt;
1928
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001929 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001930 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
1931 if (!ddc_node) {
1932 DRM_ERROR("Failed to find ddc node in device tree\n");
Andrzej Hajda86650402015-06-11 23:23:37 +09001933 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001934 }
Inki Daee2a562d2014-05-09 16:46:10 +09001935
1936out_get_ddc_adpt:
Inki Dae8fa04aa2014-03-13 16:38:31 +09001937 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
1938 if (!hdata->ddc_adpt) {
1939 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001940 return -EPROBE_DEFER;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001941 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001942
Inki Daee2a562d2014-05-09 16:46:10 +09001943 phy_node = hdmi_legacy_phy_dt_binding(dev);
1944 if (phy_node)
1945 goto out_get_phy_port;
1946
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001947 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09001948 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
1949 if (!phy_node) {
1950 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
1951 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952 goto err_ddc;
1953 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001954
Inki Daee2a562d2014-05-09 16:46:10 +09001955out_get_phy_port:
Andrzej Hajdacd240cd2015-07-09 16:28:09 +02001956 if (hdata->drv_data->is_apb_phy) {
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001957 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
1958 if (!hdata->regs_hdmiphy) {
1959 DRM_ERROR("failed to ioremap hdmi phy\n");
1960 ret = -ENOMEM;
1961 goto err_ddc;
1962 }
1963 } else {
1964 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
1965 if (!hdata->hdmiphy_port) {
1966 DRM_ERROR("Failed to get hdmi phy i2c client\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001967 ret = -EPROBE_DEFER;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001968 goto err_ddc;
1969 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09001970 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001971
Sean Paul724fd142014-05-09 15:05:10 +09001972 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
1973
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001974 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001975 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001976 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05001977 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001978 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001979 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001980 goto err_hdmiphy;
1981 }
1982
Rahul Sharma049d34e2014-05-20 10:36:05 +05301983 hdata->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
1984 "samsung,syscon-phandle");
1985 if (IS_ERR(hdata->pmureg)) {
1986 DRM_ERROR("syscon regmap lookup failed.\n");
Inki Daedf5225b2014-05-29 18:28:02 +09001987 ret = -EPROBE_DEFER;
Rahul Sharma049d34e2014-05-20 10:36:05 +05301988 goto err_hdmiphy;
1989 }
1990
Sean Paulaf65c802014-01-30 16:19:27 -05001991 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001992
Inki Daedf5225b2014-05-29 18:28:02 +09001993 ret = component_add(&pdev->dev, &hdmi_component_ops);
1994 if (ret)
1995 goto err_disable_pm_runtime;
1996
1997 return ret;
1998
1999err_disable_pm_runtime:
2000 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002001
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002002err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002003 if (hdata->hdmiphy_port)
2004 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002005err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002006 put_device(&hdata->ddc_adpt->dev);
Inki Daedf5225b2014-05-29 18:28:02 +09002007
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002008 return ret;
2009}
2010
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002011static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002012{
Andrzej Hajda930865f2014-11-17 09:54:20 +01002013 struct hdmi_context *hdata = platform_get_drvdata(pdev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002014
Sean Paul724fd142014-05-09 15:05:10 +09002015 cancel_delayed_work_sync(&hdata->hotplug_work);
2016
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002017 component_del(&pdev->dev, &hdmi_component_ops);
2018
2019 pm_runtime_disable(&pdev->dev);
2020
Andrzej Hajdaaf1f7c22015-09-25 14:48:25 +02002021 if (!IS_ERR(hdata->reg_hdmi_en))
2022 regulator_disable(hdata->reg_hdmi_en);
Marek Szyprowski05fdf982014-07-01 10:10:06 +02002023
Seung-Woo Kim9d1e25c2014-07-28 17:15:22 +09002024 if (hdata->hdmiphy_port)
2025 put_device(&hdata->hdmiphy_port->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002026
Andrzej Hajda2445c4a2015-09-25 14:48:20 +02002027 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002028
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002029 return 0;
2030}
2031
2032struct platform_driver hdmi_driver = {
2033 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002034 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002035 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302036 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002037 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302038 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002039 },
2040};