diff options
-rw-r--r-- | drivers/gpu/drm/bridge/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/cdns-dsi.c | 485 |
2 files changed, 60 insertions, 426 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 2fee47b0d50b..8840f396a7b6 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig | |||
@@ -30,6 +30,7 @@ config DRM_CDNS_DSI | |||
30 | select DRM_KMS_HELPER | 30 | select DRM_KMS_HELPER |
31 | select DRM_MIPI_DSI | 31 | select DRM_MIPI_DSI |
32 | select DRM_PANEL_BRIDGE | 32 | select DRM_PANEL_BRIDGE |
33 | select GENERIC_PHY_MIPI_DPHY | ||
33 | depends on OF | 34 | depends on OF |
34 | help | 35 | help |
35 | Support Cadence DPI to DSI bridge. This is an internal | 36 | Support Cadence DPI to DSI bridge. This is an internal |
diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 0f5bb3dca828..6166dca6be81 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
24 | #include <linux/reset.h> | 24 | #include <linux/reset.h> |
25 | 25 | ||
26 | #include <linux/phy/phy.h> | ||
27 | #include <linux/phy/phy-mipi-dphy.h> | ||
28 | |||
26 | #define IP_CONF 0x0 | 29 | #define IP_CONF 0x0 |
27 | #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26) | 30 | #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26) |
28 | #define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21) | 31 | #define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21) |
@@ -421,44 +424,11 @@ | |||
421 | #define DSI_NULL_FRAME_OVERHEAD 6 | 424 | #define DSI_NULL_FRAME_OVERHEAD 6 |
422 | #define DSI_EOT_PKT_SIZE 4 | 425 | #define DSI_EOT_PKT_SIZE 4 |
423 | 426 | ||
424 | #define REG_WAKEUP_TIME_NS 800 | ||
425 | #define DPHY_PLL_RATE_HZ 108000000 | ||
426 | |||
427 | /* DPHY registers */ | ||
428 | #define DPHY_PMA_CMN(reg) (reg) | ||
429 | #define DPHY_PMA_LCLK(reg) (0x100 + (reg)) | ||
430 | #define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg)) | ||
431 | #define DPHY_PMA_RCLK(reg) (0x600 + (reg)) | ||
432 | #define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg)) | ||
433 | #define DPHY_PCS(reg) (0xb00 + (reg)) | ||
434 | |||
435 | #define DPHY_CMN_SSM DPHY_PMA_CMN(0x20) | ||
436 | #define DPHY_CMN_SSM_EN BIT(0) | ||
437 | #define DPHY_CMN_TX_MODE_EN BIT(9) | ||
438 | |||
439 | #define DPHY_CMN_PWM DPHY_PMA_CMN(0x40) | ||
440 | #define DPHY_CMN_PWM_DIV(x) ((x) << 20) | ||
441 | #define DPHY_CMN_PWM_LOW(x) ((x) << 10) | ||
442 | #define DPHY_CMN_PWM_HIGH(x) (x) | ||
443 | |||
444 | #define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c) | ||
445 | #define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22)) | ||
446 | #define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21)) | ||
447 | |||
448 | #define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50) | ||
449 | #define DPHY_CMN_IPDIV_FROM_REG BIT(0) | ||
450 | #define DPHY_CMN_IPDIV(x) ((x) << 1) | ||
451 | #define DPHY_CMN_OPDIV_FROM_REG BIT(6) | ||
452 | #define DPHY_CMN_OPDIV(x) ((x) << 7) | ||
453 | |||
454 | #define DPHY_PSM_CFG DPHY_PCS(0x4) | ||
455 | #define DPHY_PSM_CFG_FROM_REG BIT(0) | ||
456 | #define DPHY_PSM_CLK_DIV(x) ((x) << 1) | ||
457 | |||
458 | struct cdns_dsi_output { | 427 | struct cdns_dsi_output { |
459 | struct mipi_dsi_device *dev; | 428 | struct mipi_dsi_device *dev; |
460 | struct drm_panel *panel; | 429 | struct drm_panel *panel; |
461 | struct drm_bridge *bridge; | 430 | struct drm_bridge *bridge; |
431 | union phy_configure_opts phy_opts; | ||
462 | }; | 432 | }; |
463 | 433 | ||
464 | enum cdns_dsi_input_id { | 434 | enum cdns_dsi_input_id { |
@@ -467,14 +437,6 @@ enum cdns_dsi_input_id { | |||
467 | CDNS_DSC_INPUT, | 437 | CDNS_DSC_INPUT, |
468 | }; | 438 | }; |
469 | 439 | ||
470 | struct cdns_dphy_cfg { | ||
471 | u8 pll_ipdiv; | ||
472 | u8 pll_opdiv; | ||
473 | u16 pll_fbdiv; | ||
474 | unsigned long lane_bps; | ||
475 | unsigned int nlanes; | ||
476 | }; | ||
477 | |||
478 | struct cdns_dsi_cfg { | 440 | struct cdns_dsi_cfg { |
479 | unsigned int hfp; | 441 | unsigned int hfp; |
480 | unsigned int hsa; | 442 | unsigned int hsa; |
@@ -483,34 +445,6 @@ struct cdns_dsi_cfg { | |||
483 | unsigned int htotal; | 445 | unsigned int htotal; |
484 | }; | 446 | }; |
485 | 447 | ||
486 | struct cdns_dphy; | ||
487 | |||
488 | enum cdns_dphy_clk_lane_cfg { | ||
489 | DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0, | ||
490 | DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1, | ||
491 | DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2, | ||
492 | DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3, | ||
493 | }; | ||
494 | |||
495 | struct cdns_dphy_ops { | ||
496 | int (*probe)(struct cdns_dphy *dphy); | ||
497 | void (*remove)(struct cdns_dphy *dphy); | ||
498 | void (*set_psm_div)(struct cdns_dphy *dphy, u8 div); | ||
499 | void (*set_clk_lane_cfg)(struct cdns_dphy *dphy, | ||
500 | enum cdns_dphy_clk_lane_cfg cfg); | ||
501 | void (*set_pll_cfg)(struct cdns_dphy *dphy, | ||
502 | const struct cdns_dphy_cfg *cfg); | ||
503 | unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); | ||
504 | }; | ||
505 | |||
506 | struct cdns_dphy { | ||
507 | struct cdns_dphy_cfg cfg; | ||
508 | void __iomem *regs; | ||
509 | struct clk *psm_clk; | ||
510 | struct clk *pll_ref_clk; | ||
511 | const struct cdns_dphy_ops *ops; | ||
512 | }; | ||
513 | |||
514 | struct cdns_dsi_input { | 448 | struct cdns_dsi_input { |
515 | enum cdns_dsi_input_id id; | 449 | enum cdns_dsi_input_id id; |
516 | struct drm_bridge bridge; | 450 | struct drm_bridge bridge; |
@@ -528,7 +462,7 @@ struct cdns_dsi { | |||
528 | struct reset_control *dsi_p_rst; | 462 | struct reset_control *dsi_p_rst; |
529 | struct clk *dsi_sys_clk; | 463 | struct clk *dsi_sys_clk; |
530 | bool link_initialized; | 464 | bool link_initialized; |
531 | struct cdns_dphy *dphy; | 465 | struct phy *dphy; |
532 | }; | 466 | }; |
533 | 467 | ||
534 | static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) | 468 | static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) |
@@ -556,175 +490,6 @@ static unsigned int mode_to_dpi_hfp(const struct drm_display_mode *mode, | |||
556 | return mode->crtc_hsync_start - mode->crtc_hdisplay; | 490 | return mode->crtc_hsync_start - mode->crtc_hdisplay; |
557 | } | 491 | } |
558 | 492 | ||
559 | static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, | ||
560 | struct cdns_dphy_cfg *cfg, | ||
561 | unsigned int dpi_htotal, | ||
562 | unsigned int dpi_bpp, | ||
563 | unsigned int dpi_hz, | ||
564 | unsigned int dsi_htotal, | ||
565 | unsigned int dsi_nlanes, | ||
566 | unsigned int *dsi_hfp_ext) | ||
567 | { | ||
568 | u64 dlane_bps, dlane_bps_max, fbdiv, fbdiv_max, adj_dsi_htotal; | ||
569 | unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk); | ||
570 | |||
571 | memset(cfg, 0, sizeof(*cfg)); | ||
572 | |||
573 | cfg->nlanes = dsi_nlanes; | ||
574 | |||
575 | if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000) | ||
576 | return -EINVAL; | ||
577 | else if (pll_ref_hz < 19200000) | ||
578 | cfg->pll_ipdiv = 1; | ||
579 | else if (pll_ref_hz < 38400000) | ||
580 | cfg->pll_ipdiv = 2; | ||
581 | else if (pll_ref_hz < 76800000) | ||
582 | cfg->pll_ipdiv = 4; | ||
583 | else | ||
584 | cfg->pll_ipdiv = 8; | ||
585 | |||
586 | /* | ||
587 | * Make sure DSI htotal is aligned on a lane boundary when calculating | ||
588 | * the expected data rate. This is done by extending HFP in case of | ||
589 | * misalignment. | ||
590 | */ | ||
591 | adj_dsi_htotal = dsi_htotal; | ||
592 | if (dsi_htotal % dsi_nlanes) | ||
593 | adj_dsi_htotal += dsi_nlanes - (dsi_htotal % dsi_nlanes); | ||
594 | |||
595 | dlane_bps = (u64)dpi_hz * adj_dsi_htotal; | ||
596 | |||
597 | /* data rate in bytes/sec is not an integer, refuse the mode. */ | ||
598 | if (do_div(dlane_bps, dsi_nlanes * dpi_htotal)) | ||
599 | return -EINVAL; | ||
600 | |||
601 | /* data rate was in bytes/sec, convert to bits/sec. */ | ||
602 | dlane_bps *= 8; | ||
603 | |||
604 | if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL) | ||
605 | return -EINVAL; | ||
606 | else if (dlane_bps >= 1250000000) | ||
607 | cfg->pll_opdiv = 1; | ||
608 | else if (dlane_bps >= 630000000) | ||
609 | cfg->pll_opdiv = 2; | ||
610 | else if (dlane_bps >= 320000000) | ||
611 | cfg->pll_opdiv = 4; | ||
612 | else if (dlane_bps >= 160000000) | ||
613 | cfg->pll_opdiv = 8; | ||
614 | |||
615 | /* | ||
616 | * Allow a deviation of 0.2% on the per-lane data rate to try to | ||
617 | * recover a potential mismatch between DPI and PPI clks. | ||
618 | */ | ||
619 | dlane_bps_max = dlane_bps + DIV_ROUND_DOWN_ULL(dlane_bps, 500); | ||
620 | fbdiv_max = DIV_ROUND_DOWN_ULL(dlane_bps_max * 2 * | ||
621 | cfg->pll_opdiv * cfg->pll_ipdiv, | ||
622 | pll_ref_hz); | ||
623 | fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv * | ||
624 | cfg->pll_ipdiv, | ||
625 | pll_ref_hz); | ||
626 | |||
627 | /* | ||
628 | * Iterate over all acceptable fbdiv and try to find an adjusted DSI | ||
629 | * htotal length providing an exact match. | ||
630 | * | ||
631 | * Note that we could do something even trickier by relying on the fact | ||
632 | * that a new line is not necessarily aligned on a lane boundary, so, | ||
633 | * by making adj_dsi_htotal non aligned on a dsi_lanes we can improve a | ||
634 | * bit the precision. With this, the step would be | ||
635 | * | ||
636 | * pll_ref_hz / (2 * opdiv * ipdiv * nlanes) | ||
637 | * | ||
638 | * instead of | ||
639 | * | ||
640 | * pll_ref_hz / (2 * opdiv * ipdiv) | ||
641 | * | ||
642 | * The drawback of this approach is that we would need to make sure the | ||
643 | * number or lines is a multiple of the realignment periodicity which is | ||
644 | * a function of the number of lanes and the original misalignment. For | ||
645 | * example, for NLANES = 4 and HTOTAL % NLANES = 3, it takes 4 lines | ||
646 | * to realign on a lane: | ||
647 | * LINE 0: expected number of bytes, starts emitting first byte of | ||
648 | * LINE 1 on LANE 3 | ||
649 | * LINE 1: expected number of bytes, starts emitting first 2 bytes of | ||
650 | * LINE 2 on LANES 2 and 3 | ||
651 | * LINE 2: expected number of bytes, starts emitting first 3 bytes of | ||
652 | * of LINE 3 on LANES 1, 2 and 3 | ||
653 | * LINE 3: one byte less, now things are realigned on LANE 0 for LINE 4 | ||
654 | * | ||
655 | * I figured this extra complexity was not worth the benefit, but if | ||
656 | * someone really has unfixable mismatch, that would be something to | ||
657 | * investigate. | ||
658 | */ | ||
659 | for (; fbdiv <= fbdiv_max; fbdiv++) { | ||
660 | u32 rem; | ||
661 | |||
662 | adj_dsi_htotal = (u64)fbdiv * pll_ref_hz * dsi_nlanes * | ||
663 | dpi_htotal; | ||
664 | |||
665 | /* | ||
666 | * Do the division in 2 steps to avoid an overflow on the | ||
667 | * divider. | ||
668 | */ | ||
669 | rem = do_div(adj_dsi_htotal, dpi_hz); | ||
670 | if (rem) | ||
671 | continue; | ||
672 | |||
673 | rem = do_div(adj_dsi_htotal, | ||
674 | cfg->pll_opdiv * cfg->pll_ipdiv * 2 * 8); | ||
675 | if (rem) | ||
676 | continue; | ||
677 | |||
678 | cfg->pll_fbdiv = fbdiv; | ||
679 | *dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; | ||
680 | break; | ||
681 | } | ||
682 | |||
683 | /* No match, let's just reject the display mode. */ | ||
684 | if (!cfg->pll_fbdiv) | ||
685 | return -EINVAL; | ||
686 | |||
687 | dlane_bps = DIV_ROUND_DOWN_ULL((u64)dpi_hz * adj_dsi_htotal * 8, | ||
688 | dsi_nlanes * dpi_htotal); | ||
689 | cfg->lane_bps = dlane_bps; | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int cdns_dphy_setup_psm(struct cdns_dphy *dphy) | ||
695 | { | ||
696 | unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk); | ||
697 | unsigned long psm_div; | ||
698 | |||
699 | if (!psm_clk_hz || psm_clk_hz > 100000000) | ||
700 | return -EINVAL; | ||
701 | |||
702 | psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000); | ||
703 | if (dphy->ops->set_psm_div) | ||
704 | dphy->ops->set_psm_div(dphy, psm_div); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy, | ||
710 | enum cdns_dphy_clk_lane_cfg cfg) | ||
711 | { | ||
712 | if (dphy->ops->set_clk_lane_cfg) | ||
713 | dphy->ops->set_clk_lane_cfg(dphy, cfg); | ||
714 | } | ||
715 | |||
716 | static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy, | ||
717 | const struct cdns_dphy_cfg *cfg) | ||
718 | { | ||
719 | if (dphy->ops->set_pll_cfg) | ||
720 | dphy->ops->set_pll_cfg(dphy, cfg); | ||
721 | } | ||
722 | |||
723 | static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy) | ||
724 | { | ||
725 | return dphy->ops->get_wakeup_time_ns(dphy); | ||
726 | } | ||
727 | |||
728 | static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, | 493 | static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, |
729 | unsigned int dpi_bpp, | 494 | unsigned int dpi_bpp, |
730 | unsigned int dsi_pkt_overhead) | 495 | unsigned int dsi_pkt_overhead) |
@@ -786,17 +551,20 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, | |||
786 | return 0; | 551 | return 0; |
787 | } | 552 | } |
788 | 553 | ||
789 | static int cdns_dphy_validate(struct cdns_dsi *dsi, | 554 | static int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi, |
790 | struct cdns_dsi_cfg *dsi_cfg, | 555 | struct cdns_dsi_cfg *dsi_cfg, |
791 | struct cdns_dphy_cfg *dphy_cfg, | 556 | struct phy_configure_opts_mipi_dphy *phy_cfg, |
792 | const struct drm_display_mode *mode, | 557 | const struct drm_display_mode *mode, |
793 | bool mode_valid_check) | 558 | bool mode_valid_check) |
794 | { | 559 | { |
795 | struct cdns_dsi_output *output = &dsi->output; | 560 | struct cdns_dsi_output *output = &dsi->output; |
561 | unsigned long long dlane_bps; | ||
562 | unsigned long adj_dsi_htotal; | ||
796 | unsigned long dsi_htotal; | 563 | unsigned long dsi_htotal; |
797 | unsigned int dsi_hfp_ext = 0; | 564 | unsigned long dpi_htotal; |
798 | 565 | unsigned long dpi_hz; | |
799 | int ret; | 566 | unsigned int dsi_hfp_ext; |
567 | unsigned int lanes = output->dev->lanes; | ||
800 | 568 | ||
801 | dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; | 569 | dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; |
802 | if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) | 570 | if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) |
@@ -805,25 +573,27 @@ static int cdns_dphy_validate(struct cdns_dsi *dsi, | |||
805 | dsi_htotal += dsi_cfg->hact; | 573 | dsi_htotal += dsi_cfg->hact; |
806 | dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD; | 574 | dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD; |
807 | 575 | ||
808 | if (mode_valid_check) | 576 | /* |
809 | ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, | 577 | * Make sure DSI htotal is aligned on a lane boundary when calculating |
810 | mode->htotal, | 578 | * the expected data rate. This is done by extending HFP in case of |
811 | mipi_dsi_pixel_format_to_bpp(output->dev->format), | 579 | * misalignment. |
812 | mode->clock * 1000, | 580 | */ |
813 | dsi_htotal, | 581 | adj_dsi_htotal = dsi_htotal; |
814 | output->dev->lanes, | 582 | if (dsi_htotal % lanes) |
815 | &dsi_hfp_ext); | 583 | adj_dsi_htotal += lanes - (dsi_htotal % lanes); |
816 | else | 584 | |
817 | ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, | 585 | dpi_hz = (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000; |
818 | mode->crtc_htotal, | 586 | dlane_bps = (unsigned long long)dpi_hz * adj_dsi_htotal; |
819 | mipi_dsi_pixel_format_to_bpp(output->dev->format), | 587 | |
820 | mode->crtc_clock * 1000, | 588 | /* data rate in bytes/sec is not an integer, refuse the mode. */ |
821 | dsi_htotal, | 589 | dpi_htotal = mode_valid_check ? mode->htotal : mode->crtc_htotal; |
822 | output->dev->lanes, | 590 | if (do_div(dlane_bps, lanes * dpi_htotal)) |
823 | &dsi_hfp_ext); | 591 | return -EINVAL; |
824 | if (ret) | ||
825 | return ret; | ||
826 | 592 | ||
593 | /* data rate was in bytes/sec, convert to bits/sec. */ | ||
594 | phy_cfg->hs_clk_rate = dlane_bps * 8; | ||
595 | |||
596 | dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; | ||
827 | dsi_cfg->hfp += dsi_hfp_ext; | 597 | dsi_cfg->hfp += dsi_hfp_ext; |
828 | dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; | 598 | dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; |
829 | 599 | ||
@@ -833,10 +603,10 @@ static int cdns_dphy_validate(struct cdns_dsi *dsi, | |||
833 | static int cdns_dsi_check_conf(struct cdns_dsi *dsi, | 603 | static int cdns_dsi_check_conf(struct cdns_dsi *dsi, |
834 | const struct drm_display_mode *mode, | 604 | const struct drm_display_mode *mode, |
835 | struct cdns_dsi_cfg *dsi_cfg, | 605 | struct cdns_dsi_cfg *dsi_cfg, |
836 | struct cdns_dphy_cfg *dphy_cfg, | ||
837 | bool mode_valid_check) | 606 | bool mode_valid_check) |
838 | { | 607 | { |
839 | struct cdns_dsi_output *output = &dsi->output; | 608 | struct cdns_dsi_output *output = &dsi->output; |
609 | struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; | ||
840 | unsigned long dsi_hss_hsa_hse_hbp; | 610 | unsigned long dsi_hss_hsa_hse_hbp; |
841 | unsigned int nlanes = output->dev->lanes; | 611 | unsigned int nlanes = output->dev->lanes; |
842 | int ret; | 612 | int ret; |
@@ -845,7 +615,15 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi, | |||
845 | if (ret) | 615 | if (ret) |
846 | return ret; | 616 | return ret; |
847 | 617 | ||
848 | ret = cdns_dphy_validate(dsi, dsi_cfg, dphy_cfg, mode, mode_valid_check); | 618 | phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000, |
619 | mipi_dsi_pixel_format_to_bpp(output->dev->format), | ||
620 | nlanes, phy_cfg); | ||
621 | |||
622 | ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check); | ||
623 | if (ret) | ||
624 | return ret; | ||
625 | |||
626 | ret = phy_validate(dsi->dphy, PHY_MODE_MIPI_DPHY, 0, &output->phy_opts); | ||
849 | if (ret) | 627 | if (ret) |
850 | return ret; | 628 | return ret; |
851 | 629 | ||
@@ -858,7 +636,7 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi, | |||
858 | * is empty before we start a receiving a new line on the DPI | 636 | * is empty before we start a receiving a new line on the DPI |
859 | * interface. | 637 | * interface. |
860 | */ | 638 | */ |
861 | if ((u64)dphy_cfg->lane_bps * | 639 | if ((u64)phy_cfg->hs_clk_rate * |
862 | mode_to_dpi_hfp(mode, mode_valid_check) * nlanes < | 640 | mode_to_dpi_hfp(mode, mode_valid_check) * nlanes < |
863 | (u64)dsi_hss_hsa_hse_hbp * | 641 | (u64)dsi_hss_hsa_hse_hbp * |
864 | (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000) | 642 | (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000) |
@@ -889,7 +667,6 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, | |||
889 | struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); | 667 | struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); |
890 | struct cdns_dsi *dsi = input_to_dsi(input); | 668 | struct cdns_dsi *dsi = input_to_dsi(input); |
891 | struct cdns_dsi_output *output = &dsi->output; | 669 | struct cdns_dsi_output *output = &dsi->output; |
892 | struct cdns_dphy_cfg dphy_cfg; | ||
893 | struct cdns_dsi_cfg dsi_cfg; | 670 | struct cdns_dsi_cfg dsi_cfg; |
894 | int bpp, ret; | 671 | int bpp, ret; |
895 | 672 | ||
@@ -909,7 +686,7 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, | |||
909 | if ((mode->hdisplay * bpp) % 32) | 686 | if ((mode->hdisplay * bpp) % 32) |
910 | return MODE_H_ILLEGAL; | 687 | return MODE_H_ILLEGAL; |
911 | 688 | ||
912 | ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, &dphy_cfg, true); | 689 | ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, true); |
913 | if (ret) | 690 | if (ret) |
914 | return MODE_BAD; | 691 | return MODE_BAD; |
915 | 692 | ||
@@ -932,9 +709,9 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge) | |||
932 | pm_runtime_put(dsi->base.dev); | 709 | pm_runtime_put(dsi->base.dev); |
933 | } | 710 | } |
934 | 711 | ||
935 | static void cdns_dsi_hs_init(struct cdns_dsi *dsi, | 712 | static void cdns_dsi_hs_init(struct cdns_dsi *dsi) |
936 | const struct cdns_dphy_cfg *dphy_cfg) | ||
937 | { | 713 | { |
714 | struct cdns_dsi_output *output = &dsi->output; | ||
938 | u32 status; | 715 | u32 status; |
939 | 716 | ||
940 | /* | 717 | /* |
@@ -945,30 +722,10 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi, | |||
945 | DPHY_CMN_PDN | DPHY_PLL_PDN, | 722 | DPHY_CMN_PDN | DPHY_PLL_PDN, |
946 | dsi->regs + MCTL_DPHY_CFG0); | 723 | dsi->regs + MCTL_DPHY_CFG0); |
947 | 724 | ||
948 | /* | 725 | phy_init(dsi->dphy); |
949 | * Configure the internal PSM clk divider so that the DPHY has a | 726 | phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY); |
950 | * 1MHz clk (or something close). | 727 | phy_configure(dsi->dphy, &output->phy_opts); |
951 | */ | 728 | phy_power_on(dsi->dphy); |
952 | WARN_ON_ONCE(cdns_dphy_setup_psm(dsi->dphy)); | ||
953 | |||
954 | /* | ||
955 | * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes | ||
956 | * and 8 data lanes, each clk lane can be attache different set of | ||
957 | * data lanes. The 2 groups are named 'left' and 'right', so here we | ||
958 | * just say that we want the 'left' clk lane to drive the 'left' data | ||
959 | * lanes. | ||
960 | */ | ||
961 | cdns_dphy_set_clk_lane_cfg(dsi->dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT); | ||
962 | |||
963 | /* | ||
964 | * Configure the DPHY PLL that will be used to generate the TX byte | ||
965 | * clk. | ||
966 | */ | ||
967 | cdns_dphy_set_pll_cfg(dsi->dphy, dphy_cfg); | ||
968 | |||
969 | /* Start TX state machine. */ | ||
970 | writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, | ||
971 | dsi->dphy->regs + DPHY_CMN_SSM); | ||
972 | 729 | ||
973 | /* Activate the PLL and wait until it's locked. */ | 730 | /* Activate the PLL and wait until it's locked. */ |
974 | writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR); | 731 | writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR); |
@@ -978,7 +735,7 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi, | |||
978 | status & PLL_LOCKED, 100, 100)); | 735 | status & PLL_LOCKED, 100, 100)); |
979 | /* De-assert data and clock reset lines. */ | 736 | /* De-assert data and clock reset lines. */ |
980 | writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN | | 737 | writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN | |
981 | DPHY_D_RSTB(dphy_cfg->nlanes) | DPHY_C_RSTB, | 738 | DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB, |
982 | dsi->regs + MCTL_DPHY_CFG0); | 739 | dsi->regs + MCTL_DPHY_CFG0); |
983 | } | 740 | } |
984 | 741 | ||
@@ -1024,7 +781,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) | |||
1024 | struct cdns_dsi *dsi = input_to_dsi(input); | 781 | struct cdns_dsi *dsi = input_to_dsi(input); |
1025 | struct cdns_dsi_output *output = &dsi->output; | 782 | struct cdns_dsi_output *output = &dsi->output; |
1026 | struct drm_display_mode *mode; | 783 | struct drm_display_mode *mode; |
1027 | struct cdns_dphy_cfg dphy_cfg; | 784 | struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; |
1028 | unsigned long tx_byte_period; | 785 | unsigned long tx_byte_period; |
1029 | struct cdns_dsi_cfg dsi_cfg; | 786 | struct cdns_dsi_cfg dsi_cfg; |
1030 | u32 tmp, reg_wakeup, div; | 787 | u32 tmp, reg_wakeup, div; |
@@ -1037,9 +794,9 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) | |||
1037 | bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); | 794 | bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); |
1038 | nlanes = output->dev->lanes; | 795 | nlanes = output->dev->lanes; |
1039 | 796 | ||
1040 | WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, &dphy_cfg, false)); | 797 | WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); |
1041 | 798 | ||
1042 | cdns_dsi_hs_init(dsi, &dphy_cfg); | 799 | cdns_dsi_hs_init(dsi); |
1043 | cdns_dsi_init_link(dsi); | 800 | cdns_dsi_init_link(dsi); |
1044 | 801 | ||
1045 | writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa), | 802 | writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa), |
@@ -1075,9 +832,8 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) | |||
1075 | tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes); | 832 | tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes); |
1076 | 833 | ||
1077 | tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8, | 834 | tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8, |
1078 | dphy_cfg.lane_bps); | 835 | phy_cfg->hs_clk_rate); |
1079 | reg_wakeup = cdns_dphy_get_wakeup_time_ns(dsi->dphy) / | 836 | reg_wakeup = (phy_cfg->hs_prepare + phy_cfg->hs_zero) / tx_byte_period; |
1080 | tx_byte_period; | ||
1081 | writel(REG_WAKEUP_TIME(reg_wakeup) | REG_LINE_DURATION(tmp), | 837 | writel(REG_WAKEUP_TIME(reg_wakeup) | REG_LINE_DURATION(tmp), |
1082 | dsi->regs + VID_DPHY_TIME); | 838 | dsi->regs + VID_DPHY_TIME); |
1083 | 839 | ||
@@ -1391,8 +1147,6 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev) | |||
1391 | reset_control_deassert(dsi->dsi_p_rst); | 1147 | reset_control_deassert(dsi->dsi_p_rst); |
1392 | clk_prepare_enable(dsi->dsi_p_clk); | 1148 | clk_prepare_enable(dsi->dsi_p_clk); |
1393 | clk_prepare_enable(dsi->dsi_sys_clk); | 1149 | clk_prepare_enable(dsi->dsi_sys_clk); |
1394 | clk_prepare_enable(dsi->dphy->psm_clk); | ||
1395 | clk_prepare_enable(dsi->dphy->pll_ref_clk); | ||
1396 | 1150 | ||
1397 | return 0; | 1151 | return 0; |
1398 | } | 1152 | } |
@@ -1401,8 +1155,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev) | |||
1401 | { | 1155 | { |
1402 | struct cdns_dsi *dsi = dev_get_drvdata(dev); | 1156 | struct cdns_dsi *dsi = dev_get_drvdata(dev); |
1403 | 1157 | ||
1404 | clk_disable_unprepare(dsi->dphy->pll_ref_clk); | ||
1405 | clk_disable_unprepare(dsi->dphy->psm_clk); | ||
1406 | clk_disable_unprepare(dsi->dsi_sys_clk); | 1158 | clk_disable_unprepare(dsi->dsi_sys_clk); |
1407 | clk_disable_unprepare(dsi->dsi_p_clk); | 1159 | clk_disable_unprepare(dsi->dsi_p_clk); |
1408 | reset_control_assert(dsi->dsi_p_rst); | 1160 | reset_control_assert(dsi->dsi_p_rst); |
@@ -1413,121 +1165,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev) | |||
1413 | static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, | 1165 | static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, |
1414 | NULL); | 1166 | NULL); |
1415 | 1167 | ||
1416 | static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy) | ||
1417 | { | ||
1418 | /* Default wakeup time is 800 ns (in a simulated environment). */ | ||
1419 | return 800; | ||
1420 | } | ||
1421 | |||
1422 | static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy, | ||
1423 | const struct cdns_dphy_cfg *cfg) | ||
1424 | { | ||
1425 | u32 fbdiv_low, fbdiv_high; | ||
1426 | |||
1427 | fbdiv_low = (cfg->pll_fbdiv / 4) - 2; | ||
1428 | fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2; | ||
1429 | |||
1430 | writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG | | ||
1431 | DPHY_CMN_IPDIV(cfg->pll_ipdiv) | | ||
1432 | DPHY_CMN_OPDIV(cfg->pll_opdiv), | ||
1433 | dphy->regs + DPHY_CMN_OPIPDIV); | ||
1434 | writel(DPHY_CMN_FBDIV_FROM_REG | | ||
1435 | DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high), | ||
1436 | dphy->regs + DPHY_CMN_FBDIV); | ||
1437 | writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) | | ||
1438 | DPHY_CMN_PWM_DIV(0x8), | ||
1439 | dphy->regs + DPHY_CMN_PWM); | ||
1440 | } | ||
1441 | |||
1442 | static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div) | ||
1443 | { | ||
1444 | writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div), | ||
1445 | dphy->regs + DPHY_PSM_CFG); | ||
1446 | } | ||
1447 | |||
1448 | /* | ||
1449 | * This is the reference implementation of DPHY hooks. Specific integration of | ||
1450 | * this IP may have to re-implement some of them depending on how they decided | ||
1451 | * to wire things in the SoC. | ||
1452 | */ | ||
1453 | static const struct cdns_dphy_ops ref_dphy_ops = { | ||
1454 | .get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns, | ||
1455 | .set_pll_cfg = cdns_dphy_ref_set_pll_cfg, | ||
1456 | .set_psm_div = cdns_dphy_ref_set_psm_div, | ||
1457 | }; | ||
1458 | |||
1459 | static const struct of_device_id cdns_dphy_of_match[] = { | ||
1460 | { .compatible = "cdns,dphy", .data = &ref_dphy_ops }, | ||
1461 | { /* sentinel */ }, | ||
1462 | }; | ||
1463 | |||
1464 | static struct cdns_dphy *cdns_dphy_probe(struct platform_device *pdev) | ||
1465 | { | ||
1466 | const struct of_device_id *match; | ||
1467 | struct cdns_dphy *dphy; | ||
1468 | struct of_phandle_args args; | ||
1469 | struct resource res; | ||
1470 | int ret; | ||
1471 | |||
1472 | ret = of_parse_phandle_with_args(pdev->dev.of_node, "phys", | ||
1473 | "#phy-cells", 0, &args); | ||
1474 | if (ret) | ||
1475 | return ERR_PTR(-ENOENT); | ||
1476 | |||
1477 | match = of_match_node(cdns_dphy_of_match, args.np); | ||
1478 | if (!match || !match->data) | ||
1479 | return ERR_PTR(-EINVAL); | ||
1480 | |||
1481 | dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); | ||
1482 | if (!dphy) | ||
1483 | return ERR_PTR(-ENOMEM); | ||
1484 | |||
1485 | dphy->ops = match->data; | ||
1486 | |||
1487 | ret = of_address_to_resource(args.np, 0, &res); | ||
1488 | if (ret) | ||
1489 | return ERR_PTR(ret); | ||
1490 | |||
1491 | dphy->regs = devm_ioremap_resource(&pdev->dev, &res); | ||
1492 | if (IS_ERR(dphy->regs)) | ||
1493 | return ERR_CAST(dphy->regs); | ||
1494 | |||
1495 | dphy->psm_clk = of_clk_get_by_name(args.np, "psm"); | ||
1496 | if (IS_ERR(dphy->psm_clk)) | ||
1497 | return ERR_CAST(dphy->psm_clk); | ||
1498 | |||
1499 | dphy->pll_ref_clk = of_clk_get_by_name(args.np, "pll_ref"); | ||
1500 | if (IS_ERR(dphy->pll_ref_clk)) { | ||
1501 | ret = PTR_ERR(dphy->pll_ref_clk); | ||
1502 | goto err_put_psm_clk; | ||
1503 | } | ||
1504 | |||
1505 | if (dphy->ops->probe) { | ||
1506 | ret = dphy->ops->probe(dphy); | ||
1507 | if (ret) | ||
1508 | goto err_put_pll_ref_clk; | ||
1509 | } | ||
1510 | |||
1511 | return dphy; | ||
1512 | |||
1513 | err_put_pll_ref_clk: | ||
1514 | clk_put(dphy->pll_ref_clk); | ||
1515 | |||
1516 | err_put_psm_clk: | ||
1517 | clk_put(dphy->psm_clk); | ||
1518 | |||
1519 | return ERR_PTR(ret); | ||
1520 | } | ||
1521 | |||
1522 | static void cdns_dphy_remove(struct cdns_dphy *dphy) | ||
1523 | { | ||
1524 | if (dphy->ops->remove) | ||
1525 | dphy->ops->remove(dphy); | ||
1526 | |||
1527 | clk_put(dphy->pll_ref_clk); | ||
1528 | clk_put(dphy->psm_clk); | ||
1529 | } | ||
1530 | |||
1531 | static int cdns_dsi_drm_probe(struct platform_device *pdev) | 1168 | static int cdns_dsi_drm_probe(struct platform_device *pdev) |
1532 | { | 1169 | { |
1533 | struct cdns_dsi *dsi; | 1170 | struct cdns_dsi *dsi; |
@@ -1566,13 +1203,13 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev) | |||
1566 | if (irq < 0) | 1203 | if (irq < 0) |
1567 | return irq; | 1204 | return irq; |
1568 | 1205 | ||
1569 | dsi->dphy = cdns_dphy_probe(pdev); | 1206 | dsi->dphy = devm_phy_get(&pdev->dev, "dphy"); |
1570 | if (IS_ERR(dsi->dphy)) | 1207 | if (IS_ERR(dsi->dphy)) |
1571 | return PTR_ERR(dsi->dphy); | 1208 | return PTR_ERR(dsi->dphy); |
1572 | 1209 | ||
1573 | ret = clk_prepare_enable(dsi->dsi_p_clk); | 1210 | ret = clk_prepare_enable(dsi->dsi_p_clk); |
1574 | if (ret) | 1211 | if (ret) |
1575 | goto err_remove_dphy; | 1212 | return ret; |
1576 | 1213 | ||
1577 | val = readl(dsi->regs + ID_REG); | 1214 | val = readl(dsi->regs + ID_REG); |
1578 | if (REV_VENDOR_ID(val) != 0xcad) { | 1215 | if (REV_VENDOR_ID(val) != 0xcad) { |
@@ -1630,9 +1267,6 @@ err_disable_runtime_pm: | |||
1630 | err_disable_pclk: | 1267 | err_disable_pclk: |
1631 | clk_disable_unprepare(dsi->dsi_p_clk); | 1268 | clk_disable_unprepare(dsi->dsi_p_clk); |
1632 | 1269 | ||
1633 | err_remove_dphy: | ||
1634 | cdns_dphy_remove(dsi->dphy); | ||
1635 | |||
1636 | return ret; | 1270 | return ret; |
1637 | } | 1271 | } |
1638 | 1272 | ||
@@ -1642,7 +1276,6 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev) | |||
1642 | 1276 | ||
1643 | mipi_dsi_host_unregister(&dsi->base); | 1277 | mipi_dsi_host_unregister(&dsi->base); |
1644 | pm_runtime_disable(&pdev->dev); | 1278 | pm_runtime_disable(&pdev->dev); |
1645 | cdns_dphy_remove(dsi->dphy); | ||
1646 | 1279 | ||
1647 | return 0; | 1280 | return 0; |
1648 | } | 1281 | } |