Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / msm / hdmi / hdmi_connector.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013 Red Hat
4  * Author: Rob Clark <robdclark@gmail.com>
5  */
6
7 #include <linux/delay.h>
8 #include <linux/gpio/consumer.h>
9 #include <linux/pinctrl/consumer.h>
10
11 #include "msm_kms.h"
12 #include "hdmi.h"
13
14 struct hdmi_connector {
15         struct drm_connector base;
16         struct hdmi *hdmi;
17         struct work_struct hpd_work;
18 };
19 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
20
21 static void msm_hdmi_phy_reset(struct hdmi *hdmi)
22 {
23         unsigned int val;
24
25         val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
26
27         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
28                 /* pull low */
29                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
30                                 val & ~HDMI_PHY_CTRL_SW_RESET);
31         } else {
32                 /* pull high */
33                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
34                                 val | HDMI_PHY_CTRL_SW_RESET);
35         }
36
37         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
38                 /* pull low */
39                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
40                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
41         } else {
42                 /* pull high */
43                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
44                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
45         }
46
47         msleep(100);
48
49         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
50                 /* pull high */
51                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
52                                 val | HDMI_PHY_CTRL_SW_RESET);
53         } else {
54                 /* pull low */
55                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
56                                 val & ~HDMI_PHY_CTRL_SW_RESET);
57         }
58
59         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
60                 /* pull high */
61                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
62                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
63         } else {
64                 /* pull low */
65                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
66                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
67         }
68 }
69
70 static int gpio_config(struct hdmi *hdmi, bool on)
71 {
72         const struct hdmi_platform_config *config = hdmi->config;
73         int i;
74
75         if (on) {
76                 for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
77                         struct hdmi_gpio_data gpio = config->gpios[i];
78
79                         if (gpio.gpiod) {
80                                 if (gpio.output) {
81                                         gpiod_direction_output(gpio.gpiod,
82                                                                gpio.value);
83                                 } else {
84                                         gpiod_direction_input(gpio.gpiod);
85                                         gpiod_set_value_cansleep(gpio.gpiod,
86                                                                  gpio.value);
87                                 }
88                         }
89                 }
90
91                 DBG("gpio on");
92         } else {
93                 for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
94                         struct hdmi_gpio_data gpio = config->gpios[i];
95
96                         if (!gpio.gpiod)
97                                 continue;
98
99                         if (gpio.output) {
100                                 int value = gpio.value ? 0 : 1;
101
102                                 gpiod_set_value_cansleep(gpio.gpiod, value);
103                         }
104                 };
105
106                 DBG("gpio off");
107         }
108
109         return 0;
110 }
111
112 static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
113 {
114         const struct hdmi_platform_config *config = hdmi->config;
115         struct device *dev = &hdmi->pdev->dev;
116         int i, ret;
117
118         if (enable) {
119                 for (i = 0; i < config->hpd_clk_cnt; i++) {
120                         if (config->hpd_freq && config->hpd_freq[i]) {
121                                 ret = clk_set_rate(hdmi->hpd_clks[i],
122                                                    config->hpd_freq[i]);
123                                 if (ret)
124                                         dev_warn(dev,
125                                                  "failed to set clk %s (%d)\n",
126                                                  config->hpd_clk_names[i], ret);
127                         }
128
129                         ret = clk_prepare_enable(hdmi->hpd_clks[i]);
130                         if (ret) {
131                                 DRM_DEV_ERROR(dev,
132                                         "failed to enable hpd clk: %s (%d)\n",
133                                         config->hpd_clk_names[i], ret);
134                         }
135                 }
136         } else {
137                 for (i = config->hpd_clk_cnt - 1; i >= 0; i--)
138                         clk_disable_unprepare(hdmi->hpd_clks[i]);
139         }
140 }
141
142 int msm_hdmi_hpd_enable(struct drm_connector *connector)
143 {
144         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
145         struct hdmi *hdmi = hdmi_connector->hdmi;
146         const struct hdmi_platform_config *config = hdmi->config;
147         struct device *dev = &hdmi->pdev->dev;
148         uint32_t hpd_ctrl;
149         int i, ret;
150         unsigned long flags;
151
152         for (i = 0; i < config->hpd_reg_cnt; i++) {
153                 ret = regulator_enable(hdmi->hpd_regs[i]);
154                 if (ret) {
155                         DRM_DEV_ERROR(dev, "failed to enable hpd regulator: %s (%d)\n",
156                                         config->hpd_reg_names[i], ret);
157                         goto fail;
158                 }
159         }
160
161         ret = pinctrl_pm_select_default_state(dev);
162         if (ret) {
163                 DRM_DEV_ERROR(dev, "pinctrl state chg failed: %d\n", ret);
164                 goto fail;
165         }
166
167         ret = gpio_config(hdmi, true);
168         if (ret) {
169                 DRM_DEV_ERROR(dev, "failed to configure GPIOs: %d\n", ret);
170                 goto fail;
171         }
172
173         pm_runtime_get_sync(dev);
174         enable_hpd_clocks(hdmi, true);
175
176         msm_hdmi_set_mode(hdmi, false);
177         msm_hdmi_phy_reset(hdmi);
178         msm_hdmi_set_mode(hdmi, true);
179
180         hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
181
182         /* enable HPD events: */
183         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
184                         HDMI_HPD_INT_CTRL_INT_CONNECT |
185                         HDMI_HPD_INT_CTRL_INT_EN);
186
187         /* set timeout to 4.1ms (max) for hardware debounce */
188         spin_lock_irqsave(&hdmi->reg_lock, flags);
189         hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
190         hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
191
192         /* Toggle HPD circuit to trigger HPD sense */
193         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
194                         ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
195         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
196                         HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
197         spin_unlock_irqrestore(&hdmi->reg_lock, flags);
198
199         return 0;
200
201 fail:
202         return ret;
203 }
204
205 static void hdp_disable(struct hdmi_connector *hdmi_connector)
206 {
207         struct hdmi *hdmi = hdmi_connector->hdmi;
208         const struct hdmi_platform_config *config = hdmi->config;
209         struct device *dev = &hdmi->pdev->dev;
210         int i, ret = 0;
211
212         /* Disable HPD interrupt */
213         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
214
215         msm_hdmi_set_mode(hdmi, false);
216
217         enable_hpd_clocks(hdmi, false);
218         pm_runtime_put_autosuspend(dev);
219
220         ret = gpio_config(hdmi, false);
221         if (ret)
222                 dev_warn(dev, "failed to unconfigure GPIOs: %d\n", ret);
223
224         ret = pinctrl_pm_select_sleep_state(dev);
225         if (ret)
226                 dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
227
228         for (i = 0; i < config->hpd_reg_cnt; i++) {
229                 ret = regulator_disable(hdmi->hpd_regs[i]);
230                 if (ret)
231                         dev_warn(dev, "failed to disable hpd regulator: %s (%d)\n",
232                                         config->hpd_reg_names[i], ret);
233         }
234 }
235
236 static void
237 msm_hdmi_hotplug_work(struct work_struct *work)
238 {
239         struct hdmi_connector *hdmi_connector =
240                 container_of(work, struct hdmi_connector, hpd_work);
241         struct drm_connector *connector = &hdmi_connector->base;
242         drm_helper_hpd_irq_event(connector->dev);
243 }
244
245 void msm_hdmi_connector_irq(struct drm_connector *connector)
246 {
247         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
248         struct hdmi *hdmi = hdmi_connector->hdmi;
249         uint32_t hpd_int_status, hpd_int_ctrl;
250
251         /* Process HPD: */
252         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
253         hpd_int_ctrl   = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
254
255         if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) &&
256                         (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
257                 bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
258
259                 /* ack & disable (temporarily) HPD events: */
260                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
261                         HDMI_HPD_INT_CTRL_INT_ACK);
262
263                 DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
264
265                 /* detect disconnect if we are connected or visa versa: */
266                 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
267                 if (!detected)
268                         hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
269                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
270
271                 queue_work(hdmi->workq, &hdmi_connector->hpd_work);
272         }
273 }
274
275 static enum drm_connector_status detect_reg(struct hdmi *hdmi)
276 {
277         uint32_t hpd_int_status;
278
279         pm_runtime_get_sync(&hdmi->pdev->dev);
280         enable_hpd_clocks(hdmi, true);
281
282         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
283
284         enable_hpd_clocks(hdmi, false);
285         pm_runtime_put_autosuspend(&hdmi->pdev->dev);
286
287         return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
288                         connector_status_connected : connector_status_disconnected;
289 }
290
291 #define HPD_GPIO_INDEX  2
292 static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
293 {
294         const struct hdmi_platform_config *config = hdmi->config;
295         struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
296
297         return gpiod_get_value(hpd_gpio.gpiod) ?
298                         connector_status_connected :
299                         connector_status_disconnected;
300 }
301
302 static enum drm_connector_status hdmi_connector_detect(
303                 struct drm_connector *connector, bool force)
304 {
305         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
306         struct hdmi *hdmi = hdmi_connector->hdmi;
307         const struct hdmi_platform_config *config = hdmi->config;
308         struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
309         enum drm_connector_status stat_gpio, stat_reg;
310         int retry = 20;
311
312         /*
313          * some platforms may not have hpd gpio. Rely only on the status
314          * provided by REG_HDMI_HPD_INT_STATUS in this case.
315          */
316         if (!hpd_gpio.gpiod)
317                 return detect_reg(hdmi);
318
319         do {
320                 stat_gpio = detect_gpio(hdmi);
321                 stat_reg  = detect_reg(hdmi);
322
323                 if (stat_gpio == stat_reg)
324                         break;
325
326                 mdelay(10);
327         } while (--retry);
328
329         /* the status we get from reading gpio seems to be more reliable,
330          * so trust that one the most if we didn't manage to get hdmi and
331          * gpio status to agree:
332          */
333         if (stat_gpio != stat_reg) {
334                 DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg);
335                 DBG("hpd gpio tells us: %d", stat_gpio);
336         }
337
338         return stat_gpio;
339 }
340
341 static void hdmi_connector_destroy(struct drm_connector *connector)
342 {
343         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
344
345         hdp_disable(hdmi_connector);
346
347         drm_connector_cleanup(connector);
348
349         kfree(hdmi_connector);
350 }
351
352 static int msm_hdmi_connector_get_modes(struct drm_connector *connector)
353 {
354         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
355         struct hdmi *hdmi = hdmi_connector->hdmi;
356         struct edid *edid;
357         uint32_t hdmi_ctrl;
358         int ret = 0;
359
360         hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
361         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
362
363         edid = drm_get_edid(connector, hdmi->i2c);
364
365         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
366
367         hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
368         drm_connector_update_edid_property(connector, edid);
369
370         if (edid) {
371                 ret = drm_add_edid_modes(connector, edid);
372                 kfree(edid);
373         }
374
375         return ret;
376 }
377
378 static int msm_hdmi_connector_mode_valid(struct drm_connector *connector,
379                                  struct drm_display_mode *mode)
380 {
381         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
382         struct hdmi *hdmi = hdmi_connector->hdmi;
383         const struct hdmi_platform_config *config = hdmi->config;
384         struct msm_drm_private *priv = connector->dev->dev_private;
385         struct msm_kms *kms = priv->kms;
386         long actual, requested;
387
388         requested = 1000 * mode->clock;
389         actual = kms->funcs->round_pixclk(kms,
390                         requested, hdmi_connector->hdmi->encoder);
391
392         /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
393          * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
394          * instead):
395          */
396         if (config->pwr_clk_cnt > 0)
397                 actual = clk_round_rate(hdmi->pwr_clks[0], actual);
398
399         DBG("requested=%ld, actual=%ld", requested, actual);
400
401         if (actual != requested)
402                 return MODE_CLOCK_RANGE;
403
404         return 0;
405 }
406
407 static const struct drm_connector_funcs hdmi_connector_funcs = {
408         .detect = hdmi_connector_detect,
409         .fill_modes = drm_helper_probe_single_connector_modes,
410         .destroy = hdmi_connector_destroy,
411         .reset = drm_atomic_helper_connector_reset,
412         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
413         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
414 };
415
416 static const struct drm_connector_helper_funcs msm_hdmi_connector_helper_funcs = {
417         .get_modes = msm_hdmi_connector_get_modes,
418         .mode_valid = msm_hdmi_connector_mode_valid,
419 };
420
421 /* initialize connector */
422 struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi)
423 {
424         struct drm_connector *connector = NULL;
425         struct hdmi_connector *hdmi_connector;
426
427         hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL);
428         if (!hdmi_connector)
429                 return ERR_PTR(-ENOMEM);
430
431         hdmi_connector->hdmi = hdmi;
432         INIT_WORK(&hdmi_connector->hpd_work, msm_hdmi_hotplug_work);
433
434         connector = &hdmi_connector->base;
435
436         drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
437                         DRM_MODE_CONNECTOR_HDMIA);
438         drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs);
439
440         connector->polled = DRM_CONNECTOR_POLL_CONNECT |
441                         DRM_CONNECTOR_POLL_DISCONNECT;
442
443         connector->interlace_allowed = 0;
444         connector->doublescan_allowed = 0;
445
446         drm_connector_attach_encoder(connector, hdmi->encoder);
447
448         return connector;
449 }