UPSTREAM: drm/rockchip: Avoid race with vblank count increment
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / dw_hdmi-rockchip.c
1 /*
2  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9
10 #include <linux/clk.h>
11 #include <linux/clk-provider.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/rockchip/cpu.h>
16 #include <linux/regmap.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/phy/phy.h>
19
20 #include <drm/drm_of.h>
21 #include <drm/drmP.h>
22 #include <drm/drm_crtc_helper.h>
23 #include <drm/drm_edid.h>
24 #include <drm/drm_encoder_slave.h>
25 #include <drm/bridge/dw_hdmi.h>
26
27 #include "rockchip_drm_drv.h"
28 #include "rockchip_drm_vop.h"
29
30 #define RK3228_GRF_SOC_CON2             0x0408
31 #define RK3228_DDC_MASK_EN              ((3 << 13) | (3 << (13 + 16)))
32 #define RK3228_GRF_SOC_CON6             0x0418
33 #define RK3228_IO_3V_DOMAIN             ((7 << 4) | (7 << (4 + 16)))
34
35 #define RK3288_GRF_SOC_CON6             0x025C
36 #define RK3288_HDMI_LCDC_SEL            BIT(4)
37 #define RK3399_GRF_SOC_CON20            0x6250
38 #define RK3399_HDMI_LCDC_SEL            BIT(6)
39
40 #define RK3328_GRF_SOC_CON2             0x0408
41 #define RK3328_DDC_MASK_EN              ((3 << 10) | (3 << (10 + 16)))
42 #define RK3328_GRF_SOC_CON3             0x040c
43 #define RK3328_IO_CTRL_BY_HDMI          (0xf0000000 | BIT(13) | BIT(12))
44 #define RK3328_GRF_SOC_CON4             0x0410
45 #define RK3328_IO_3V_DOMAIN             (7 << (9 + 16))
46 #define RK3328_IO_5V_DOMAIN             ((7 << 9) | (3 << (9 + 16)))
47 #define RK3328_HPD_3V                   (BIT(8 + 16) | BIT(13 + 16))
48
49 #define HIWORD_UPDATE(val, mask)        (val | (mask) << 16)
50
51 struct rockchip_hdmi {
52         struct device *dev;
53         struct regmap *regmap;
54         void __iomem *hdmiphy;
55         struct drm_encoder encoder;
56         enum dw_hdmi_devtype dev_type;
57         struct clk *vpll_clk;
58         struct clk *grf_clk;
59         struct clk *hclk_vio;
60
61         struct phy *phy;
62 };
63
64 #define to_rockchip_hdmi(x)     container_of(x, struct rockchip_hdmi, x)
65
66 static int
67 inno_dw_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data,
68                       struct drm_display_mode *mode)
69 {
70         struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
71
72         return phy_power_on(hdmi->phy);
73 }
74
75 static void inno_dw_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data)
76 {
77         struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
78
79         phy_power_off(hdmi->phy);
80 }
81
82 static enum drm_connector_status
83 inno_dw_hdmi_phy_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
84 {
85         struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
86         enum drm_connector_status status;
87
88         status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
89
90         if (hdmi->dev_type == RK3228_HDMI)
91                 return status;
92
93         if (status == connector_status_connected)
94                 regmap_write(hdmi->regmap,
95                              RK3328_GRF_SOC_CON4,
96                              RK3328_IO_5V_DOMAIN);
97         else
98                 regmap_write(hdmi->regmap,
99                              RK3328_GRF_SOC_CON4,
100                              RK3328_IO_3V_DOMAIN);
101         return status;
102 }
103
104 static int inno_dw_hdmi_init(struct rockchip_hdmi *hdmi)
105 {
106         int ret;
107
108         ret = clk_prepare_enable(hdmi->grf_clk);
109         if (ret < 0) {
110                 dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret);
111                 return -EPROBE_DEFER;
112         }
113         if (hdmi->dev_type == RK3328_HDMI) {
114                 /* Map HPD pin to 3V io */
115                 regmap_write(hdmi->regmap,
116                              RK3328_GRF_SOC_CON4,
117                              RK3328_IO_3V_DOMAIN |
118                              RK3328_HPD_3V);
119                 /* Map ddc pin to 5V io */
120                 regmap_write(hdmi->regmap,
121                              RK3328_GRF_SOC_CON3,
122                              RK3328_IO_CTRL_BY_HDMI);
123                 regmap_write(hdmi->regmap,
124                              RK3328_GRF_SOC_CON2,
125                              RK3328_DDC_MASK_EN |
126                              BIT(18));
127         } else {
128                 regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON2,
129                              RK3228_DDC_MASK_EN);
130                 regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON6,
131                              RK3228_IO_3V_DOMAIN);
132         }
133         clk_disable_unprepare(hdmi->grf_clk);
134         return 0;
135 }
136
137 /*
138  * There are some rates that would be ranged for better clock jitter at
139  * Chrome OS tree, like 25.175Mhz would range to 25.170732Mhz. But due
140  * to the clock is aglined to KHz in struct drm_display_mode, this would
141  * bring some inaccurate error if we still run the compute_n math, so
142  * let's just code an const table for it until we can actually get the
143  * right clock rate.
144  */
145 static const struct dw_hdmi_audio_tmds_n rockchip_werid_tmds_n_table[] = {
146         /* 25176471 for 25.175 MHz = 428000000 / 17. */
147         { .tmds = 25177000, .n_32k = 4352, .n_44k1 = 14994, .n_48k = 6528, },
148         /* 57290323 for 57.284 MHz */
149         { .tmds = 57291000, .n_32k = 3968, .n_44k1 = 4557, .n_48k = 5952, },
150         /* 74437500 for 74.44 MHz = 297750000 / 4 */
151         { .tmds = 74438000, .n_32k = 8192, .n_44k1 = 18816, .n_48k = 4096, },
152         /* 118666667 for 118.68 MHz */
153         { .tmds = 118667000, .n_32k = 4224, .n_44k1 = 5292, .n_48k = 6336, },
154         /* 121714286 for 121.75 MHz */
155         { .tmds = 121715000, .n_32k = 4480, .n_44k1 = 6174, .n_48k = 6272, },
156         /* 136800000 for 136.75 MHz */
157         { .tmds = 136800000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },
158         /* End of table */
159         { .tmds = 0,         .n_32k = 0,    .n_44k1 = 0,    .n_48k = 0, },
160 };
161
162 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
163         {
164                 30666000, {
165                         { 0x00b3, 0x0000 },
166                         { 0x2153, 0x0000 },
167                         { 0x40f3, 0x0000 },
168                 },
169         },  {
170                 36800000, {
171                         { 0x00b3, 0x0000 },
172                         { 0x2153, 0x0000 },
173                         { 0x40a2, 0x0001 },
174                 },
175         },  {
176                 46000000, {
177                         { 0x00b3, 0x0000 },
178                         { 0x2142, 0x0001 },
179                         { 0x40a2, 0x0001 },
180                 },
181         },  {
182                 61333000, {
183                         { 0x0072, 0x0001 },
184                         { 0x2142, 0x0001 },
185                         { 0x40a2, 0x0001 },
186                 },
187         },  {
188                 73600000, {
189                         { 0x0072, 0x0001 },
190                         { 0x2142, 0x0001 },
191                         { 0x4061, 0x0002 },
192                 },
193         },  {
194                 92000000, {
195                         { 0x0072, 0x0001 },
196                         { 0x2145, 0x0002 },
197                         { 0x4061, 0x0002 },
198                 },
199         },  {
200                 122666000, {
201                         { 0x0051, 0x0002 },
202                         { 0x2145, 0x0002 },
203                         { 0x4061, 0x0002 },
204                 },
205         },  {
206                 147200000, {
207                         { 0x0051, 0x0002 },
208                         { 0x2145, 0x0002 },
209                         { 0x4064, 0x0003 },
210                 },
211         },  {
212                 184000000, {
213                         { 0x0051, 0x0002 },
214                         { 0x214c, 0x0003 },
215                         { 0x4064, 0x0003 },
216                 },
217         },  {
218                 226666000, {
219                         { 0x0040, 0x0003 },
220                         { 0x214c, 0x0003 },
221                         { 0x4064, 0x0003 },
222                 },
223         },  {
224                 272000000, {
225                         { 0x0040, 0x0003 },
226                         { 0x214c, 0x0003 },
227                         { 0x5a64, 0x0003 },
228                 },
229         },  {
230                 340000000, {
231                         { 0x0040, 0x0003 },
232                         { 0x3b4c, 0x0003 },
233                         { 0x5a64, 0x0003 },
234                 },
235         },  {
236                 600000000, {
237                         { 0x1a40, 0x0003 },
238                         { 0x3b4c, 0x0003 },
239                         { 0x5a64, 0x0003 },
240                 },
241         },  {
242                 ~0UL, {
243                         { 0x0000, 0x0000 },
244                         { 0x0000, 0x0000 },
245                         { 0x0000, 0x0000 },
246                 },
247         }
248 };
249
250 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
251         /*      pixelclk    bpp8    bpp10   bpp12 */
252         {
253                 600000000, { 0x0000, 0x0000, 0x0000 },
254         },  {
255                 ~0UL,      { 0x0000, 0x0000, 0x0000},
256         }
257 };
258
259 static struct dw_hdmi_phy_config rockchip_phy_config[] = {
260         /*pixelclk   symbol   term   vlev*/
261         { 74250000,  0x8009, 0x0004, 0x0272},
262         { 165000000, 0x802b, 0x0004, 0x0209},
263         { 297000000, 0x8039, 0x0005, 0x028d},
264         { 594000000, 0x8039, 0x0000, 0x019d},
265         { ~0UL,      0x0000, 0x0000, 0x0000}
266 };
267
268 static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi,
269                                           u32 *config,
270                                           int phy_table_size)
271 {
272         int i;
273
274         if (phy_table_size > ARRAY_SIZE(rockchip_phy_config)) {
275                 dev_err(hdmi->dev, "phy table array number is out of range\n");
276                 return -E2BIG;
277         }
278
279         for (i = 0; i < phy_table_size; i++) {
280                 if (config[i * 4] != 0)
281                         rockchip_phy_config[i].mpixelclock = (u64)config[i * 4];
282                 else
283                         rockchip_phy_config[i].mpixelclock = ~0UL;
284                 rockchip_phy_config[i].term = (u16)config[i * 4 + 1];
285                 rockchip_phy_config[i].sym_ctr = (u16)config[i * 4 + 2];
286                 rockchip_phy_config[i].vlev_ctr = (u16)config[i * 4 + 3];
287         }
288
289         return 0;
290 }
291
292 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
293 {
294         struct device_node *np = hdmi->dev->of_node;
295         int ret, val, phy_table_size;
296         u32 *phy_config;
297
298         hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
299         if (IS_ERR(hdmi->regmap)) {
300                 dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
301                 return PTR_ERR(hdmi->regmap);
302         }
303
304         hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
305         if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
306                 hdmi->vpll_clk = NULL;
307         } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
308                 return -EPROBE_DEFER;
309         } else if (IS_ERR(hdmi->vpll_clk)) {
310                 dev_err(hdmi->dev, "failed to get grf clock\n");
311                 return PTR_ERR(hdmi->vpll_clk);
312         }
313
314         hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
315         if (PTR_ERR(hdmi->grf_clk) == -ENOENT) {
316                 hdmi->grf_clk = NULL;
317         } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) {
318                 return -EPROBE_DEFER;
319         } else if (IS_ERR(hdmi->grf_clk)) {
320                 dev_err(hdmi->dev, "failed to get grf clock\n");
321                 return PTR_ERR(hdmi->grf_clk);
322         }
323
324         hdmi->hclk_vio = devm_clk_get(hdmi->dev, "hclk_vio");
325         if (PTR_ERR(hdmi->hclk_vio) == -ENOENT) {
326                 hdmi->hclk_vio = NULL;
327         } else if (PTR_ERR(hdmi->hclk_vio) == -EPROBE_DEFER) {
328                 return -EPROBE_DEFER;
329         } else if (IS_ERR(hdmi->hclk_vio)) {
330                 dev_err(hdmi->dev, "failed to get hclk_vio clock\n");
331                 return PTR_ERR(hdmi->hclk_vio);
332         }
333
334         ret = clk_prepare_enable(hdmi->vpll_clk);
335         if (ret) {
336                 dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret);
337                 return ret;
338         }
339
340         ret = clk_prepare_enable(hdmi->hclk_vio);
341         if (ret) {
342                 dev_err(hdmi->dev, "Failed to eanble HDMI hclk_vio: %d\n",
343                         ret);
344                 return ret;
345         }
346
347         if (of_get_property(np, "rockchip,phy-table", &val)) {
348                 phy_config = kmalloc(val, GFP_KERNEL);
349                 if (!phy_config) {
350                         /* use default table when kmalloc failed. */
351                         dev_err(hdmi->dev, "kmalloc phy table failed\n");
352
353                         return -ENOMEM;
354                 }
355                 phy_table_size = val / 16;
356                 of_property_read_u32_array(np, "rockchip,phy-table",
357                                            phy_config, val / sizeof(u32));
358                 ret = rockchip_hdmi_update_phy_table(hdmi, phy_config,
359                                                      phy_table_size);
360                 if (ret) {
361                         kfree(phy_config);
362                         return ret;
363                 }
364                 kfree(phy_config);
365         } else {
366                 dev_dbg(hdmi->dev, "use default hdmi phy table\n");
367         }
368
369         return 0;
370 }
371
372 static enum drm_mode_status
373 dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
374                             struct drm_display_mode *mode)
375 {
376         struct drm_encoder *encoder = connector->encoder;
377         enum drm_mode_status status = MODE_OK;
378         struct drm_device *dev = connector->dev;
379         struct rockchip_drm_private *priv = dev->dev_private;
380         struct drm_crtc *crtc;
381
382         /*
383          * Pixel clocks we support are always < 2GHz and so fit in an
384          * int.  We should make sure source rate does too so we don't get
385          * overflow when we multiply by 1000.
386          */
387         if (mode->clock > INT_MAX / 1000)
388                 return MODE_BAD;
389         /*
390          * If sink max TMDS clock < 340MHz, we should check the mode pixel
391          * clock > 340MHz is YCbCr420 or not.
392          */
393         if (mode->clock > 340000 &&
394             connector->display_info.max_tmds_clock < 340000 &&
395             !(mode->flags & DRM_MODE_FLAG_420_MASK))
396                 return MODE_BAD;
397
398         if (!encoder) {
399                 const struct drm_connector_helper_funcs *funcs;
400
401                 funcs = connector->helper_private;
402                 if (funcs->atomic_best_encoder)
403                         encoder = funcs->atomic_best_encoder(connector,
404                                                              connector->state);
405                 else
406                         encoder = funcs->best_encoder(connector);
407         }
408
409         if (!encoder || !encoder->possible_crtcs)
410                 return MODE_BAD;
411         /*
412          * ensure all drm display mode can work, if someone want support more
413          * resolutions, please limit the possible_crtc, only connect to
414          * needed crtc.
415          */
416         drm_for_each_crtc(crtc, connector->dev) {
417                 int pipe = drm_crtc_index(crtc);
418                 const struct rockchip_crtc_funcs *funcs =
419                                                 priv->crtc_funcs[pipe];
420
421                 if (!(encoder->possible_crtcs & drm_crtc_mask(crtc)))
422                         continue;
423                 if (!funcs || !funcs->mode_valid)
424                         continue;
425
426                 status = funcs->mode_valid(crtc, mode,
427                                            DRM_MODE_CONNECTOR_HDMIA);
428                 if (status != MODE_OK)
429                         return status;
430         }
431
432         return status;
433 }
434
435 static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
436         .destroy = drm_encoder_cleanup,
437 };
438
439 static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
440 {
441 }
442
443 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
444 {
445         struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
446         struct drm_crtc *crtc = encoder->crtc;
447         u32 lcdsel_grf_reg, lcdsel_mask;
448         u32 val;
449         int mux;
450         int ret;
451
452         if (WARN_ON(!crtc || !crtc->state))
453                 return;
454
455         clk_set_rate(hdmi->vpll_clk,
456                      crtc->state->adjusted_mode.crtc_clock * 1000);
457
458         switch (hdmi->dev_type) {
459         case RK3288_HDMI:
460                 lcdsel_grf_reg = RK3288_GRF_SOC_CON6;
461                 lcdsel_mask = RK3288_HDMI_LCDC_SEL;
462                 break;
463         case RK3399_HDMI:
464                 lcdsel_grf_reg = RK3399_GRF_SOC_CON20;
465                 lcdsel_mask = RK3399_HDMI_LCDC_SEL;
466                 break;
467         default:
468                 return;
469         };
470
471         mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
472         if (mux)
473                 val = HIWORD_UPDATE(lcdsel_mask, lcdsel_mask);
474         else
475                 val = HIWORD_UPDATE(0, lcdsel_mask);
476
477         ret = clk_prepare_enable(hdmi->grf_clk);
478         if (ret < 0) {
479                 dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret);
480                 return;
481         }
482
483         regmap_write(hdmi->regmap, lcdsel_grf_reg, val);
484         dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
485                 (mux) ? "LIT" : "BIG");
486
487         clk_disable_unprepare(hdmi->grf_clk);
488 }
489
490 static int
491 dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
492                                       struct drm_crtc_state *crtc_state,
493                                       struct drm_connector_state *conn_state)
494 {
495         struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
496         struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
497
498         if (hdmi->phy) {
499                 if (drm_match_cea_mode(&crtc_state->mode) > 94 &&
500                     crtc_state->mode.crtc_clock > 340000 &&
501                     !(crtc_state->mode.flags & DRM_MODE_FLAG_420_MASK)) {
502                         crtc_state->mode.flags |= DRM_MODE_FLAG_420;
503                         phy_set_bus_width(hdmi->phy, 4);
504                 } else {
505                         phy_set_bus_width(hdmi->phy, 8);
506                 }
507         }
508
509         if (crtc_state->mode.flags & DRM_MODE_FLAG_420_MASK) {
510                 s->output_mode = ROCKCHIP_OUT_MODE_YUV420;
511                 s->bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
512         } else {
513                 s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
514                 s->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
515         }
516         s->output_type = DRM_MODE_CONNECTOR_HDMIA;
517
518         return 0;
519 }
520
521 static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
522         .enable     = dw_hdmi_rockchip_encoder_enable,
523         .disable    = dw_hdmi_rockchip_encoder_disable,
524         .atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
525 };
526
527 static const struct dw_hdmi_phy_ops inno_dw_hdmi_phy_ops = {
528         .init           = inno_dw_hdmi_phy_init,
529         .disable        = inno_dw_hdmi_phy_disable,
530         .read_hpd       = inno_dw_hdmi_phy_read_hpd,
531 };
532
533 static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
534         .mode_valid = dw_hdmi_rockchip_mode_valid,
535         .phy_ops    = &inno_dw_hdmi_phy_ops,
536         .phy_name   = "inno_dw_hdmi_phy",
537         .dev_type   = RK3228_HDMI,
538 };
539
540 static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
541         .mode_valid = dw_hdmi_rockchip_mode_valid,
542         .mpll_cfg   = rockchip_mpll_cfg,
543         .cur_ctr    = rockchip_cur_ctr,
544         .phy_config = rockchip_phy_config,
545         .dev_type   = RK3288_HDMI,
546         .tmds_n_table = rockchip_werid_tmds_n_table,
547 };
548
549 static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
550         .mode_valid = dw_hdmi_rockchip_mode_valid,
551         .phy_ops    = &inno_dw_hdmi_phy_ops,
552         .phy_name   = "inno_dw_hdmi_phy2",
553         .dev_type   = RK3328_HDMI,
554 };
555
556 static const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = {
557         .mode_valid = dw_hdmi_rockchip_mode_valid,
558         .mpll_cfg   = rockchip_mpll_cfg,
559         .cur_ctr    = rockchip_cur_ctr,
560         .phy_config = rockchip_phy_config,
561         .dev_type   = RK3368_HDMI,
562 };
563
564 static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
565         .mode_valid = dw_hdmi_rockchip_mode_valid,
566         .mpll_cfg   = rockchip_mpll_cfg,
567         .cur_ctr    = rockchip_cur_ctr,
568         .phy_config = rockchip_phy_config,
569         .dev_type   = RK3399_HDMI,
570 };
571
572 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
573         { .compatible = "rockchip,rk3228-dw-hdmi",
574           .data = &rk3228_hdmi_drv_data
575         },
576         { .compatible = "rockchip,rk3288-dw-hdmi",
577           .data = &rk3288_hdmi_drv_data
578         },
579         {
580           .compatible = "rockchip,rk3328-dw-hdmi",
581           .data = &rk3328_hdmi_drv_data
582         },
583         {
584          .compatible = "rockchip,rk3368-dw-hdmi",
585          .data = &rk3368_hdmi_drv_data
586         },
587         { .compatible = "rockchip,rk3399-dw-hdmi",
588           .data = &rk3399_hdmi_drv_data
589         },
590         {},
591 };
592 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
593
594 static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
595                                  void *data)
596 {
597         struct platform_device *pdev = to_platform_device(dev);
598         struct dw_hdmi_plat_data *plat_data;
599         const struct of_device_id *match;
600         struct drm_device *drm = data;
601         struct drm_encoder *encoder;
602         struct rockchip_hdmi *hdmi;
603         struct resource *iores;
604         int irq;
605         int ret;
606
607         if (!pdev->dev.of_node)
608                 return -ENODEV;
609
610         hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
611         if (!hdmi)
612                 return -ENOMEM;
613
614         match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
615         plat_data = (struct dw_hdmi_plat_data *)match->data;
616         hdmi->dev = &pdev->dev;
617         hdmi->dev_type = plat_data->dev_type;
618         encoder = &hdmi->encoder;
619
620         irq = platform_get_irq(pdev, 0);
621         if (irq < 0)
622                 return irq;
623
624         iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
625         if (!iores)
626                 return -ENXIO;
627
628         encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
629         /*
630          * If we failed to find the CRTC(s) which this encoder is
631          * supposed to be connected to, it's because the CRTC has
632          * not been registered yet.  Defer probing, and hope that
633          * the required CRTC is added later.
634          */
635         if (encoder->possible_crtcs == 0)
636                 return -EPROBE_DEFER;
637
638         ret = rockchip_hdmi_parse_dt(hdmi);
639         if (ret) {
640                 dev_err(hdmi->dev, "Unable to parse OF data\n");
641                 return ret;
642         }
643
644         if (hdmi->dev_type == RK3328_HDMI || hdmi->dev_type == RK3228_HDMI) {
645                 hdmi->phy = devm_phy_get(dev, "hdmi_phy");
646                 if (IS_ERR(hdmi->phy)) {
647                         ret = PTR_ERR(hdmi->phy);
648                         dev_err(dev, "failed to get phy: %d\n", ret);
649                         return ret;
650                 }
651                 plat_data->phy_data = hdmi;
652                 ret = inno_dw_hdmi_init(hdmi);
653                 if (ret < 0)
654                         return ret;
655         }
656
657         drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
658         drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
659                          DRM_MODE_ENCODER_TMDS, NULL);
660
661         ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
662
663         /*
664          * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
665          * which would have called the encoder cleanup.  Do it manually.
666          */
667         if (ret)
668                 drm_encoder_cleanup(encoder);
669
670         return ret;
671 }
672
673 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
674                                     void *data)
675 {
676         return dw_hdmi_unbind(dev, master, data);
677 }
678
679 static const struct component_ops dw_hdmi_rockchip_ops = {
680         .bind   = dw_hdmi_rockchip_bind,
681         .unbind = dw_hdmi_rockchip_unbind,
682 };
683
684 static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
685 {
686         pm_runtime_enable(&pdev->dev);
687         pm_runtime_get_sync(&pdev->dev);
688
689         return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
690 }
691
692 static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
693 {
694         component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
695         pm_runtime_disable(&pdev->dev);
696
697         return 0;
698 }
699
700 static int dw_hdmi_rockchip_suspend(struct device *dev)
701 {
702         dw_hdmi_suspend(dev);
703         pm_runtime_put_sync(dev);
704
705         return 0;
706 }
707
708 static int dw_hdmi_rockchip_resume(struct device *dev)
709 {
710         pm_runtime_get_sync(dev);
711         dw_hdmi_resume(dev);
712
713         return  0;
714 }
715
716 static const struct dev_pm_ops dw_hdmi_pm_ops = {
717         SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_rockchip_suspend,
718                                 dw_hdmi_rockchip_resume)
719 };
720
721 static struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
722         .probe  = dw_hdmi_rockchip_probe,
723         .remove = dw_hdmi_rockchip_remove,
724         .driver = {
725                 .name = "dwhdmi-rockchip",
726                 .of_match_table = dw_hdmi_rockchip_dt_ids,
727                 .pm = &dw_hdmi_pm_ops,
728         },
729 };
730
731 module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
732
733 MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
734 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
735 MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
736 MODULE_LICENSE("GPL");
737 MODULE_ALIAS("platform:dwhdmi-rockchip");