2 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
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.
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>
20 #include <drm/drm_of.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>
27 #include "rockchip_drm_drv.h"
28 #include "rockchip_drm_vop.h"
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)))
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)
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))
49 #define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
51 struct rockchip_hdmi {
53 struct regmap *regmap;
54 void __iomem *hdmiphy;
55 struct drm_encoder encoder;
56 enum dw_hdmi_devtype dev_type;
64 #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
67 inno_dw_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data,
68 struct drm_display_mode *mode)
70 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
72 return phy_power_on(hdmi->phy);
75 static void inno_dw_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data)
77 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
79 phy_power_off(hdmi->phy);
82 static enum drm_connector_status
83 inno_dw_hdmi_phy_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
85 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
86 enum drm_connector_status status;
88 status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
90 if (hdmi->dev_type == RK3228_HDMI)
93 if (status == connector_status_connected)
94 regmap_write(hdmi->regmap,
98 regmap_write(hdmi->regmap,
100 RK3328_IO_3V_DOMAIN);
104 static int inno_dw_hdmi_init(struct rockchip_hdmi *hdmi)
108 ret = clk_prepare_enable(hdmi->grf_clk);
110 dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret);
111 return -EPROBE_DEFER;
113 if (hdmi->dev_type == RK3328_HDMI) {
114 /* Map HPD pin to 3V io */
115 regmap_write(hdmi->regmap,
117 RK3328_IO_3V_DOMAIN |
119 /* Map ddc pin to 5V io */
120 regmap_write(hdmi->regmap,
122 RK3328_IO_CTRL_BY_HDMI);
123 regmap_write(hdmi->regmap,
128 regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON2,
130 regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON6,
131 RK3228_IO_3V_DOMAIN);
133 clk_disable_unprepare(hdmi->grf_clk);
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
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, },
159 { .tmds = 0, .n_32k = 0, .n_44k1 = 0, .n_48k = 0, },
162 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
250 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
251 /* pixelclk bpp8 bpp10 bpp12 */
253 600000000, { 0x0000, 0x0000, 0x0000 },
255 ~0UL, { 0x0000, 0x0000, 0x0000},
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}
268 static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi,
274 if (phy_table_size > ARRAY_SIZE(rockchip_phy_config)) {
275 dev_err(hdmi->dev, "phy table array number is out of range\n");
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];
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];
292 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
294 struct device_node *np = hdmi->dev->of_node;
295 int ret, val, phy_table_size;
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);
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);
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);
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);
334 ret = clk_prepare_enable(hdmi->vpll_clk);
336 dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret);
340 ret = clk_prepare_enable(hdmi->hclk_vio);
342 dev_err(hdmi->dev, "Failed to eanble HDMI hclk_vio: %d\n",
347 if (of_get_property(np, "rockchip,phy-table", &val)) {
348 phy_config = kmalloc(val, GFP_KERNEL);
350 /* use default table when kmalloc failed. */
351 dev_err(hdmi->dev, "kmalloc phy table failed\n");
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,
366 dev_dbg(hdmi->dev, "use default hdmi phy table\n");
372 static enum drm_mode_status
373 dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
374 struct drm_display_mode *mode)
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;
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.
387 if (mode->clock > INT_MAX / 1000)
390 * If sink max TMDS clock < 340MHz, we should check the mode pixel
391 * clock > 340MHz is YCbCr420 or not.
393 if (mode->clock > 340000 &&
394 connector->display_info.max_tmds_clock < 340000 &&
395 !(mode->flags & DRM_MODE_FLAG_420_MASK))
399 const struct drm_connector_helper_funcs *funcs;
401 funcs = connector->helper_private;
402 if (funcs->atomic_best_encoder)
403 encoder = funcs->atomic_best_encoder(connector,
406 encoder = funcs->best_encoder(connector);
409 if (!encoder || !encoder->possible_crtcs)
412 * ensure all drm display mode can work, if someone want support more
413 * resolutions, please limit the possible_crtc, only connect to
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];
421 if (!(encoder->possible_crtcs & drm_crtc_mask(crtc)))
423 if (!funcs || !funcs->mode_valid)
426 status = funcs->mode_valid(crtc, mode,
427 DRM_MODE_CONNECTOR_HDMIA);
428 if (status != MODE_OK)
435 static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
436 .destroy = drm_encoder_cleanup,
439 static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
443 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
445 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
446 struct drm_crtc *crtc = encoder->crtc;
447 u32 lcdsel_grf_reg, lcdsel_mask;
452 if (WARN_ON(!crtc || !crtc->state))
455 clk_set_rate(hdmi->vpll_clk,
456 crtc->state->adjusted_mode.crtc_clock * 1000);
458 switch (hdmi->dev_type) {
460 lcdsel_grf_reg = RK3288_GRF_SOC_CON6;
461 lcdsel_mask = RK3288_HDMI_LCDC_SEL;
464 lcdsel_grf_reg = RK3399_GRF_SOC_CON20;
465 lcdsel_mask = RK3399_HDMI_LCDC_SEL;
471 mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
473 val = HIWORD_UPDATE(lcdsel_mask, lcdsel_mask);
475 val = HIWORD_UPDATE(0, lcdsel_mask);
477 ret = clk_prepare_enable(hdmi->grf_clk);
479 dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret);
483 regmap_write(hdmi->regmap, lcdsel_grf_reg, val);
484 dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
485 (mux) ? "LIT" : "BIG");
487 clk_disable_unprepare(hdmi->grf_clk);
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)
495 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
496 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
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);
505 phy_set_bus_width(hdmi->phy, 8);
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;
513 s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
514 s->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
516 s->output_type = DRM_MODE_CONNECTOR_HDMIA;
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,
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,
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,
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,
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,
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,
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,
572 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
573 { .compatible = "rockchip,rk3228-dw-hdmi",
574 .data = &rk3228_hdmi_drv_data
576 { .compatible = "rockchip,rk3288-dw-hdmi",
577 .data = &rk3288_hdmi_drv_data
580 .compatible = "rockchip,rk3328-dw-hdmi",
581 .data = &rk3328_hdmi_drv_data
584 .compatible = "rockchip,rk3368-dw-hdmi",
585 .data = &rk3368_hdmi_drv_data
587 { .compatible = "rockchip,rk3399-dw-hdmi",
588 .data = &rk3399_hdmi_drv_data
592 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
594 static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
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;
607 if (!pdev->dev.of_node)
610 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
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;
620 irq = platform_get_irq(pdev, 0);
624 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
628 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
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.
635 if (encoder->possible_crtcs == 0)
636 return -EPROBE_DEFER;
638 ret = rockchip_hdmi_parse_dt(hdmi);
640 dev_err(hdmi->dev, "Unable to parse OF data\n");
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);
651 plat_data->phy_data = hdmi;
652 ret = inno_dw_hdmi_init(hdmi);
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);
661 ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
664 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
665 * which would have called the encoder cleanup. Do it manually.
668 drm_encoder_cleanup(encoder);
673 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
676 return dw_hdmi_unbind(dev, master, data);
679 static const struct component_ops dw_hdmi_rockchip_ops = {
680 .bind = dw_hdmi_rockchip_bind,
681 .unbind = dw_hdmi_rockchip_unbind,
684 static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
686 pm_runtime_enable(&pdev->dev);
687 pm_runtime_get_sync(&pdev->dev);
689 return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
692 static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
694 component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
695 pm_runtime_disable(&pdev->dev);
700 static int dw_hdmi_rockchip_suspend(struct device *dev)
702 dw_hdmi_suspend(dev);
703 pm_runtime_put_sync(dev);
708 static int dw_hdmi_rockchip_resume(struct device *dev)
710 pm_runtime_get_sync(dev);
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)
721 static struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
722 .probe = dw_hdmi_rockchip_probe,
723 .remove = dw_hdmi_rockchip_remove,
725 .name = "dwhdmi-rockchip",
726 .of_match_table = dw_hdmi_rockchip_dt_ids,
727 .pm = &dw_hdmi_pm_ops,
731 module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
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");