aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/bridge/cdns-dsi.c
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@bootlin.com>2019-01-21 10:45:54 -0500
committerMaxime Ripard <maxime.ripard@bootlin.com>2019-02-07 03:48:40 -0500
commitfced5a364dee9d3a3ed1e3290ea3b83984b78007 (patch)
tree36ad3b7471308c09fd09970e7d643d8700328813 /drivers/gpu/drm/bridge/cdns-dsi.c
parent4dad3e7f12f702980f42033cf8f93525f95d8db9 (diff)
drm/bridge: cdns: Convert to phy framework
Now that we have everything we need in the phy framework to allow to tune the phy parameters, let's convert the Cadence DSI bridge to that API instead of creating a ad-hoc driver for its phy. Acked-by: Sean Paul <sean@poorly.run> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/8772ad061f07cd91fa48bb05880095b25eccec08.1548085432.git-series.maxime.ripard@bootlin.com
Diffstat (limited to 'drivers/gpu/drm/bridge/cdns-dsi.c')
-rw-r--r--drivers/gpu/drm/bridge/cdns-dsi.c485
1 files changed, 59 insertions, 426 deletions
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
458struct cdns_dsi_output { 427struct 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
464enum cdns_dsi_input_id { 434enum 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
470struct 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
478struct cdns_dsi_cfg { 440struct 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
486struct cdns_dphy;
487
488enum 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
495struct 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
506struct 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
514struct cdns_dsi_input { 448struct 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
534static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) 468static 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
559static 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
694static 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
709static 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
716static 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
723static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy)
724{
725 return dphy->ops->get_wakeup_time_ns(dphy);
726}
727
728static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, 493static 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
789static int cdns_dphy_validate(struct cdns_dsi *dsi, 554static 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,
833static int cdns_dsi_check_conf(struct cdns_dsi *dsi, 603static 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
935static void cdns_dsi_hs_init(struct cdns_dsi *dsi, 712static 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)
1413static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, 1165static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume,
1414 NULL); 1166 NULL);
1415 1167
1416static 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
1422static 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
1442static 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 */
1453static 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
1459static const struct of_device_id cdns_dphy_of_match[] = {
1460 { .compatible = "cdns,dphy", .data = &ref_dphy_ops },
1461 { /* sentinel */ },
1462};
1463
1464static 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
1513err_put_pll_ref_clk:
1514 clk_put(dphy->pll_ref_clk);
1515
1516err_put_psm_clk:
1517 clk_put(dphy->psm_clk);
1518
1519 return ERR_PTR(ret);
1520}
1521
1522static 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
1531static int cdns_dsi_drm_probe(struct platform_device *pdev) 1168static 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:
1630err_disable_pclk: 1267err_disable_pclk:
1631 clk_disable_unprepare(dsi->dsi_p_clk); 1268 clk_disable_unprepare(dsi->dsi_p_clk);
1632 1269
1633err_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}