| .. | .. |
|---|
| 7 | 7 | |
|---|
| 8 | 8 | #include <drm/drm_atomic_helper.h> |
|---|
| 9 | 9 | #include <drm/drm_bridge.h> |
|---|
| 10 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 10 | +#include <drm/drm_drv.h> |
|---|
| 11 | 11 | #include <drm/drm_mipi_dsi.h> |
|---|
| 12 | 12 | #include <drm/drm_panel.h> |
|---|
| 13 | +#include <drm/drm_probe_helper.h> |
|---|
| 13 | 14 | #include <video/mipi_display.h> |
|---|
| 14 | 15 | |
|---|
| 15 | 16 | #include <linux/clk.h> |
|---|
| 17 | +#include <linux/interrupt.h> |
|---|
| 16 | 18 | #include <linux/iopoll.h> |
|---|
| 17 | 19 | #include <linux/module.h> |
|---|
| 18 | 20 | #include <linux/of_address.h> |
|---|
| .. | .. |
|---|
| 20 | 22 | #include <linux/platform_device.h> |
|---|
| 21 | 23 | #include <linux/pm_runtime.h> |
|---|
| 22 | 24 | #include <linux/reset.h> |
|---|
| 25 | + |
|---|
| 26 | +#include <linux/phy/phy.h> |
|---|
| 27 | +#include <linux/phy/phy-mipi-dphy.h> |
|---|
| 23 | 28 | |
|---|
| 24 | 29 | #define IP_CONF 0x0 |
|---|
| 25 | 30 | #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26) |
|---|
| .. | .. |
|---|
| 419 | 424 | #define DSI_NULL_FRAME_OVERHEAD 6 |
|---|
| 420 | 425 | #define DSI_EOT_PKT_SIZE 4 |
|---|
| 421 | 426 | |
|---|
| 422 | | -#define REG_WAKEUP_TIME_NS 800 |
|---|
| 423 | | -#define DPHY_PLL_RATE_HZ 108000000 |
|---|
| 424 | | - |
|---|
| 425 | | -/* DPHY registers */ |
|---|
| 426 | | -#define DPHY_PMA_CMN(reg) (reg) |
|---|
| 427 | | -#define DPHY_PMA_LCLK(reg) (0x100 + (reg)) |
|---|
| 428 | | -#define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg)) |
|---|
| 429 | | -#define DPHY_PMA_RCLK(reg) (0x600 + (reg)) |
|---|
| 430 | | -#define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg)) |
|---|
| 431 | | -#define DPHY_PCS(reg) (0xb00 + (reg)) |
|---|
| 432 | | - |
|---|
| 433 | | -#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20) |
|---|
| 434 | | -#define DPHY_CMN_SSM_EN BIT(0) |
|---|
| 435 | | -#define DPHY_CMN_TX_MODE_EN BIT(9) |
|---|
| 436 | | - |
|---|
| 437 | | -#define DPHY_CMN_PWM DPHY_PMA_CMN(0x40) |
|---|
| 438 | | -#define DPHY_CMN_PWM_DIV(x) ((x) << 20) |
|---|
| 439 | | -#define DPHY_CMN_PWM_LOW(x) ((x) << 10) |
|---|
| 440 | | -#define DPHY_CMN_PWM_HIGH(x) (x) |
|---|
| 441 | | - |
|---|
| 442 | | -#define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c) |
|---|
| 443 | | -#define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22)) |
|---|
| 444 | | -#define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21)) |
|---|
| 445 | | - |
|---|
| 446 | | -#define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50) |
|---|
| 447 | | -#define DPHY_CMN_IPDIV_FROM_REG BIT(0) |
|---|
| 448 | | -#define DPHY_CMN_IPDIV(x) ((x) << 1) |
|---|
| 449 | | -#define DPHY_CMN_OPDIV_FROM_REG BIT(6) |
|---|
| 450 | | -#define DPHY_CMN_OPDIV(x) ((x) << 7) |
|---|
| 451 | | - |
|---|
| 452 | | -#define DPHY_PSM_CFG DPHY_PCS(0x4) |
|---|
| 453 | | -#define DPHY_PSM_CFG_FROM_REG BIT(0) |
|---|
| 454 | | -#define DPHY_PSM_CLK_DIV(x) ((x) << 1) |
|---|
| 455 | | - |
|---|
| 456 | 427 | struct cdns_dsi_output { |
|---|
| 457 | 428 | struct mipi_dsi_device *dev; |
|---|
| 458 | 429 | struct drm_panel *panel; |
|---|
| 459 | 430 | struct drm_bridge *bridge; |
|---|
| 431 | + union phy_configure_opts phy_opts; |
|---|
| 460 | 432 | }; |
|---|
| 461 | 433 | |
|---|
| 462 | 434 | enum cdns_dsi_input_id { |
|---|
| .. | .. |
|---|
| 465 | 437 | CDNS_DSC_INPUT, |
|---|
| 466 | 438 | }; |
|---|
| 467 | 439 | |
|---|
| 468 | | -struct cdns_dphy_cfg { |
|---|
| 469 | | - u8 pll_ipdiv; |
|---|
| 470 | | - u8 pll_opdiv; |
|---|
| 471 | | - u16 pll_fbdiv; |
|---|
| 472 | | - unsigned long lane_bps; |
|---|
| 473 | | - unsigned int nlanes; |
|---|
| 474 | | -}; |
|---|
| 475 | | - |
|---|
| 476 | 440 | struct cdns_dsi_cfg { |
|---|
| 477 | 441 | unsigned int hfp; |
|---|
| 478 | 442 | unsigned int hsa; |
|---|
| 479 | 443 | unsigned int hbp; |
|---|
| 480 | 444 | unsigned int hact; |
|---|
| 481 | 445 | unsigned int htotal; |
|---|
| 482 | | -}; |
|---|
| 483 | | - |
|---|
| 484 | | -struct cdns_dphy; |
|---|
| 485 | | - |
|---|
| 486 | | -enum cdns_dphy_clk_lane_cfg { |
|---|
| 487 | | - DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0, |
|---|
| 488 | | - DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1, |
|---|
| 489 | | - DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2, |
|---|
| 490 | | - DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3, |
|---|
| 491 | | -}; |
|---|
| 492 | | - |
|---|
| 493 | | -struct cdns_dphy_ops { |
|---|
| 494 | | - int (*probe)(struct cdns_dphy *dphy); |
|---|
| 495 | | - void (*remove)(struct cdns_dphy *dphy); |
|---|
| 496 | | - void (*set_psm_div)(struct cdns_dphy *dphy, u8 div); |
|---|
| 497 | | - void (*set_clk_lane_cfg)(struct cdns_dphy *dphy, |
|---|
| 498 | | - enum cdns_dphy_clk_lane_cfg cfg); |
|---|
| 499 | | - void (*set_pll_cfg)(struct cdns_dphy *dphy, |
|---|
| 500 | | - const struct cdns_dphy_cfg *cfg); |
|---|
| 501 | | - unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); |
|---|
| 502 | | -}; |
|---|
| 503 | | - |
|---|
| 504 | | -struct cdns_dphy { |
|---|
| 505 | | - struct cdns_dphy_cfg cfg; |
|---|
| 506 | | - void __iomem *regs; |
|---|
| 507 | | - struct clk *psm_clk; |
|---|
| 508 | | - struct clk *pll_ref_clk; |
|---|
| 509 | | - const struct cdns_dphy_ops *ops; |
|---|
| 510 | 446 | }; |
|---|
| 511 | 447 | |
|---|
| 512 | 448 | struct cdns_dsi_input { |
|---|
| .. | .. |
|---|
| 526 | 462 | struct reset_control *dsi_p_rst; |
|---|
| 527 | 463 | struct clk *dsi_sys_clk; |
|---|
| 528 | 464 | bool link_initialized; |
|---|
| 529 | | - struct cdns_dphy *dphy; |
|---|
| 465 | + struct phy *dphy; |
|---|
| 530 | 466 | }; |
|---|
| 531 | 467 | |
|---|
| 532 | 468 | static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) |
|---|
| .. | .. |
|---|
| 545 | 481 | return container_of(bridge, struct cdns_dsi_input, bridge); |
|---|
| 546 | 482 | } |
|---|
| 547 | 483 | |
|---|
| 548 | | -static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, |
|---|
| 549 | | - struct cdns_dphy_cfg *cfg, |
|---|
| 550 | | - unsigned int dpi_htotal, |
|---|
| 551 | | - unsigned int dpi_bpp, |
|---|
| 552 | | - unsigned int dpi_hz, |
|---|
| 553 | | - unsigned int dsi_htotal, |
|---|
| 554 | | - unsigned int dsi_nlanes, |
|---|
| 555 | | - unsigned int *dsi_hfp_ext) |
|---|
| 484 | +static unsigned int mode_to_dpi_hfp(const struct drm_display_mode *mode, |
|---|
| 485 | + bool mode_valid_check) |
|---|
| 556 | 486 | { |
|---|
| 557 | | - u64 dlane_bps, dlane_bps_max, fbdiv, fbdiv_max, adj_dsi_htotal; |
|---|
| 558 | | - unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk); |
|---|
| 487 | + if (mode_valid_check) |
|---|
| 488 | + return mode->hsync_start - mode->hdisplay; |
|---|
| 559 | 489 | |
|---|
| 560 | | - memset(cfg, 0, sizeof(*cfg)); |
|---|
| 561 | | - |
|---|
| 562 | | - cfg->nlanes = dsi_nlanes; |
|---|
| 563 | | - |
|---|
| 564 | | - if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000) |
|---|
| 565 | | - return -EINVAL; |
|---|
| 566 | | - else if (pll_ref_hz < 19200000) |
|---|
| 567 | | - cfg->pll_ipdiv = 1; |
|---|
| 568 | | - else if (pll_ref_hz < 38400000) |
|---|
| 569 | | - cfg->pll_ipdiv = 2; |
|---|
| 570 | | - else if (pll_ref_hz < 76800000) |
|---|
| 571 | | - cfg->pll_ipdiv = 4; |
|---|
| 572 | | - else |
|---|
| 573 | | - cfg->pll_ipdiv = 8; |
|---|
| 574 | | - |
|---|
| 575 | | - /* |
|---|
| 576 | | - * Make sure DSI htotal is aligned on a lane boundary when calculating |
|---|
| 577 | | - * the expected data rate. This is done by extending HFP in case of |
|---|
| 578 | | - * misalignment. |
|---|
| 579 | | - */ |
|---|
| 580 | | - adj_dsi_htotal = dsi_htotal; |
|---|
| 581 | | - if (dsi_htotal % dsi_nlanes) |
|---|
| 582 | | - adj_dsi_htotal += dsi_nlanes - (dsi_htotal % dsi_nlanes); |
|---|
| 583 | | - |
|---|
| 584 | | - dlane_bps = (u64)dpi_hz * adj_dsi_htotal; |
|---|
| 585 | | - |
|---|
| 586 | | - /* data rate in bytes/sec is not an integer, refuse the mode. */ |
|---|
| 587 | | - if (do_div(dlane_bps, dsi_nlanes * dpi_htotal)) |
|---|
| 588 | | - return -EINVAL; |
|---|
| 589 | | - |
|---|
| 590 | | - /* data rate was in bytes/sec, convert to bits/sec. */ |
|---|
| 591 | | - dlane_bps *= 8; |
|---|
| 592 | | - |
|---|
| 593 | | - if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL) |
|---|
| 594 | | - return -EINVAL; |
|---|
| 595 | | - else if (dlane_bps >= 1250000000) |
|---|
| 596 | | - cfg->pll_opdiv = 1; |
|---|
| 597 | | - else if (dlane_bps >= 630000000) |
|---|
| 598 | | - cfg->pll_opdiv = 2; |
|---|
| 599 | | - else if (dlane_bps >= 320000000) |
|---|
| 600 | | - cfg->pll_opdiv = 4; |
|---|
| 601 | | - else if (dlane_bps >= 160000000) |
|---|
| 602 | | - cfg->pll_opdiv = 8; |
|---|
| 603 | | - |
|---|
| 604 | | - /* |
|---|
| 605 | | - * Allow a deviation of 0.2% on the per-lane data rate to try to |
|---|
| 606 | | - * recover a potential mismatch between DPI and PPI clks. |
|---|
| 607 | | - */ |
|---|
| 608 | | - dlane_bps_max = dlane_bps + DIV_ROUND_DOWN_ULL(dlane_bps, 500); |
|---|
| 609 | | - fbdiv_max = DIV_ROUND_DOWN_ULL(dlane_bps_max * 2 * |
|---|
| 610 | | - cfg->pll_opdiv * cfg->pll_ipdiv, |
|---|
| 611 | | - pll_ref_hz); |
|---|
| 612 | | - fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv * |
|---|
| 613 | | - cfg->pll_ipdiv, |
|---|
| 614 | | - pll_ref_hz); |
|---|
| 615 | | - |
|---|
| 616 | | - /* |
|---|
| 617 | | - * Iterate over all acceptable fbdiv and try to find an adjusted DSI |
|---|
| 618 | | - * htotal length providing an exact match. |
|---|
| 619 | | - * |
|---|
| 620 | | - * Note that we could do something even trickier by relying on the fact |
|---|
| 621 | | - * that a new line is not necessarily aligned on a lane boundary, so, |
|---|
| 622 | | - * by making adj_dsi_htotal non aligned on a dsi_lanes we can improve a |
|---|
| 623 | | - * bit the precision. With this, the step would be |
|---|
| 624 | | - * |
|---|
| 625 | | - * pll_ref_hz / (2 * opdiv * ipdiv * nlanes) |
|---|
| 626 | | - * |
|---|
| 627 | | - * instead of |
|---|
| 628 | | - * |
|---|
| 629 | | - * pll_ref_hz / (2 * opdiv * ipdiv) |
|---|
| 630 | | - * |
|---|
| 631 | | - * The drawback of this approach is that we would need to make sure the |
|---|
| 632 | | - * number or lines is a multiple of the realignment periodicity which is |
|---|
| 633 | | - * a function of the number of lanes and the original misalignment. For |
|---|
| 634 | | - * example, for NLANES = 4 and HTOTAL % NLANES = 3, it takes 4 lines |
|---|
| 635 | | - * to realign on a lane: |
|---|
| 636 | | - * LINE 0: expected number of bytes, starts emitting first byte of |
|---|
| 637 | | - * LINE 1 on LANE 3 |
|---|
| 638 | | - * LINE 1: expected number of bytes, starts emitting first 2 bytes of |
|---|
| 639 | | - * LINE 2 on LANES 2 and 3 |
|---|
| 640 | | - * LINE 2: expected number of bytes, starts emitting first 3 bytes of |
|---|
| 641 | | - * of LINE 3 on LANES 1, 2 and 3 |
|---|
| 642 | | - * LINE 3: one byte less, now things are realigned on LANE 0 for LINE 4 |
|---|
| 643 | | - * |
|---|
| 644 | | - * I figured this extra complexity was not worth the benefit, but if |
|---|
| 645 | | - * someone really has unfixable mismatch, that would be something to |
|---|
| 646 | | - * investigate. |
|---|
| 647 | | - */ |
|---|
| 648 | | - for (; fbdiv <= fbdiv_max; fbdiv++) { |
|---|
| 649 | | - u32 rem; |
|---|
| 650 | | - |
|---|
| 651 | | - adj_dsi_htotal = (u64)fbdiv * pll_ref_hz * dsi_nlanes * |
|---|
| 652 | | - dpi_htotal; |
|---|
| 653 | | - |
|---|
| 654 | | - /* |
|---|
| 655 | | - * Do the division in 2 steps to avoid an overflow on the |
|---|
| 656 | | - * divider. |
|---|
| 657 | | - */ |
|---|
| 658 | | - rem = do_div(adj_dsi_htotal, dpi_hz); |
|---|
| 659 | | - if (rem) |
|---|
| 660 | | - continue; |
|---|
| 661 | | - |
|---|
| 662 | | - rem = do_div(adj_dsi_htotal, |
|---|
| 663 | | - cfg->pll_opdiv * cfg->pll_ipdiv * 2 * 8); |
|---|
| 664 | | - if (rem) |
|---|
| 665 | | - continue; |
|---|
| 666 | | - |
|---|
| 667 | | - cfg->pll_fbdiv = fbdiv; |
|---|
| 668 | | - *dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; |
|---|
| 669 | | - break; |
|---|
| 670 | | - } |
|---|
| 671 | | - |
|---|
| 672 | | - /* No match, let's just reject the display mode. */ |
|---|
| 673 | | - if (!cfg->pll_fbdiv) |
|---|
| 674 | | - return -EINVAL; |
|---|
| 675 | | - |
|---|
| 676 | | - dlane_bps = DIV_ROUND_DOWN_ULL((u64)dpi_hz * adj_dsi_htotal * 8, |
|---|
| 677 | | - dsi_nlanes * dpi_htotal); |
|---|
| 678 | | - cfg->lane_bps = dlane_bps; |
|---|
| 679 | | - |
|---|
| 680 | | - return 0; |
|---|
| 681 | | -} |
|---|
| 682 | | - |
|---|
| 683 | | -static int cdns_dphy_setup_psm(struct cdns_dphy *dphy) |
|---|
| 684 | | -{ |
|---|
| 685 | | - unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk); |
|---|
| 686 | | - unsigned long psm_div; |
|---|
| 687 | | - |
|---|
| 688 | | - if (!psm_clk_hz || psm_clk_hz > 100000000) |
|---|
| 689 | | - return -EINVAL; |
|---|
| 690 | | - |
|---|
| 691 | | - psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000); |
|---|
| 692 | | - if (dphy->ops->set_psm_div) |
|---|
| 693 | | - dphy->ops->set_psm_div(dphy, psm_div); |
|---|
| 694 | | - |
|---|
| 695 | | - return 0; |
|---|
| 696 | | -} |
|---|
| 697 | | - |
|---|
| 698 | | -static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy, |
|---|
| 699 | | - enum cdns_dphy_clk_lane_cfg cfg) |
|---|
| 700 | | -{ |
|---|
| 701 | | - if (dphy->ops->set_clk_lane_cfg) |
|---|
| 702 | | - dphy->ops->set_clk_lane_cfg(dphy, cfg); |
|---|
| 703 | | -} |
|---|
| 704 | | - |
|---|
| 705 | | -static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy, |
|---|
| 706 | | - const struct cdns_dphy_cfg *cfg) |
|---|
| 707 | | -{ |
|---|
| 708 | | - if (dphy->ops->set_pll_cfg) |
|---|
| 709 | | - dphy->ops->set_pll_cfg(dphy, cfg); |
|---|
| 710 | | -} |
|---|
| 711 | | - |
|---|
| 712 | | -static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy) |
|---|
| 713 | | -{ |
|---|
| 714 | | - return dphy->ops->get_wakeup_time_ns(dphy); |
|---|
| 490 | + return mode->crtc_hsync_start - mode->crtc_hdisplay; |
|---|
| 715 | 491 | } |
|---|
| 716 | 492 | |
|---|
| 717 | 493 | static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, |
|---|
| .. | .. |
|---|
| 731 | 507 | static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, |
|---|
| 732 | 508 | const struct drm_display_mode *mode, |
|---|
| 733 | 509 | struct cdns_dsi_cfg *dsi_cfg, |
|---|
| 734 | | - struct cdns_dphy_cfg *dphy_cfg, |
|---|
| 735 | 510 | bool mode_valid_check) |
|---|
| 736 | 511 | { |
|---|
| 737 | | - unsigned long dsi_htotal = 0, dsi_hss_hsa_hse_hbp = 0; |
|---|
| 738 | 512 | struct cdns_dsi_output *output = &dsi->output; |
|---|
| 739 | | - unsigned int dsi_hfp_ext = 0, dpi_hfp, tmp; |
|---|
| 513 | + unsigned int tmp; |
|---|
| 740 | 514 | bool sync_pulse = false; |
|---|
| 741 | | - int bpp, nlanes, ret; |
|---|
| 515 | + int bpp; |
|---|
| 742 | 516 | |
|---|
| 743 | 517 | memset(dsi_cfg, 0, sizeof(*dsi_cfg)); |
|---|
| 744 | 518 | |
|---|
| .. | .. |
|---|
| 746 | 520 | sync_pulse = true; |
|---|
| 747 | 521 | |
|---|
| 748 | 522 | bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); |
|---|
| 749 | | - nlanes = output->dev->lanes; |
|---|
| 750 | 523 | |
|---|
| 751 | 524 | if (mode_valid_check) |
|---|
| 752 | 525 | tmp = mode->htotal - |
|---|
| .. | .. |
|---|
| 757 | 530 | mode->crtc_hsync_end : mode->crtc_hsync_start); |
|---|
| 758 | 531 | |
|---|
| 759 | 532 | dsi_cfg->hbp = dpi_to_dsi_timing(tmp, bpp, DSI_HBP_FRAME_OVERHEAD); |
|---|
| 760 | | - dsi_htotal += dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; |
|---|
| 761 | | - dsi_hss_hsa_hse_hbp += dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; |
|---|
| 762 | 533 | |
|---|
| 763 | 534 | if (sync_pulse) { |
|---|
| 764 | 535 | if (mode_valid_check) |
|---|
| .. | .. |
|---|
| 768 | 539 | |
|---|
| 769 | 540 | dsi_cfg->hsa = dpi_to_dsi_timing(tmp, bpp, |
|---|
| 770 | 541 | DSI_HSA_FRAME_OVERHEAD); |
|---|
| 771 | | - dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; |
|---|
| 772 | | - dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; |
|---|
| 773 | 542 | } |
|---|
| 774 | 543 | |
|---|
| 775 | 544 | dsi_cfg->hact = dpi_to_dsi_timing(mode_valid_check ? |
|---|
| 776 | 545 | mode->hdisplay : mode->crtc_hdisplay, |
|---|
| 777 | 546 | bpp, 0); |
|---|
| 547 | + dsi_cfg->hfp = dpi_to_dsi_timing(mode_to_dpi_hfp(mode, mode_valid_check), |
|---|
| 548 | + bpp, DSI_HFP_FRAME_OVERHEAD); |
|---|
| 549 | + |
|---|
| 550 | + return 0; |
|---|
| 551 | +} |
|---|
| 552 | + |
|---|
| 553 | +static int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi, |
|---|
| 554 | + struct cdns_dsi_cfg *dsi_cfg, |
|---|
| 555 | + struct phy_configure_opts_mipi_dphy *phy_cfg, |
|---|
| 556 | + const struct drm_display_mode *mode, |
|---|
| 557 | + bool mode_valid_check) |
|---|
| 558 | +{ |
|---|
| 559 | + struct cdns_dsi_output *output = &dsi->output; |
|---|
| 560 | + unsigned long long dlane_bps; |
|---|
| 561 | + unsigned long adj_dsi_htotal; |
|---|
| 562 | + unsigned long dsi_htotal; |
|---|
| 563 | + unsigned long dpi_htotal; |
|---|
| 564 | + unsigned long dpi_hz; |
|---|
| 565 | + unsigned int dsi_hfp_ext; |
|---|
| 566 | + unsigned int lanes = output->dev->lanes; |
|---|
| 567 | + |
|---|
| 568 | + dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; |
|---|
| 569 | + if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) |
|---|
| 570 | + dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; |
|---|
| 571 | + |
|---|
| 778 | 572 | dsi_htotal += dsi_cfg->hact; |
|---|
| 779 | | - |
|---|
| 780 | | - if (mode_valid_check) |
|---|
| 781 | | - dpi_hfp = mode->hsync_start - mode->hdisplay; |
|---|
| 782 | | - else |
|---|
| 783 | | - dpi_hfp = mode->crtc_hsync_start - mode->crtc_hdisplay; |
|---|
| 784 | | - |
|---|
| 785 | | - dsi_cfg->hfp = dpi_to_dsi_timing(dpi_hfp, bpp, DSI_HFP_FRAME_OVERHEAD); |
|---|
| 786 | 573 | dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD; |
|---|
| 787 | 574 | |
|---|
| 788 | | - if (mode_valid_check) |
|---|
| 789 | | - ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, |
|---|
| 790 | | - mode->htotal, bpp, |
|---|
| 791 | | - mode->clock * 1000, |
|---|
| 792 | | - dsi_htotal, nlanes, |
|---|
| 793 | | - &dsi_hfp_ext); |
|---|
| 794 | | - else |
|---|
| 795 | | - ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, |
|---|
| 796 | | - mode->crtc_htotal, bpp, |
|---|
| 797 | | - mode->crtc_clock * 1000, |
|---|
| 798 | | - dsi_htotal, nlanes, |
|---|
| 799 | | - &dsi_hfp_ext); |
|---|
| 575 | + /* |
|---|
| 576 | + * Make sure DSI htotal is aligned on a lane boundary when calculating |
|---|
| 577 | + * the expected data rate. This is done by extending HFP in case of |
|---|
| 578 | + * misalignment. |
|---|
| 579 | + */ |
|---|
| 580 | + adj_dsi_htotal = dsi_htotal; |
|---|
| 581 | + if (dsi_htotal % lanes) |
|---|
| 582 | + adj_dsi_htotal += lanes - (dsi_htotal % lanes); |
|---|
| 800 | 583 | |
|---|
| 584 | + dpi_hz = (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000; |
|---|
| 585 | + dlane_bps = (unsigned long long)dpi_hz * adj_dsi_htotal; |
|---|
| 586 | + |
|---|
| 587 | + /* data rate in bytes/sec is not an integer, refuse the mode. */ |
|---|
| 588 | + dpi_htotal = mode_valid_check ? mode->htotal : mode->crtc_htotal; |
|---|
| 589 | + if (do_div(dlane_bps, lanes * dpi_htotal)) |
|---|
| 590 | + return -EINVAL; |
|---|
| 591 | + |
|---|
| 592 | + /* data rate was in bytes/sec, convert to bits/sec. */ |
|---|
| 593 | + phy_cfg->hs_clk_rate = dlane_bps * 8; |
|---|
| 594 | + |
|---|
| 595 | + dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; |
|---|
| 596 | + dsi_cfg->hfp += dsi_hfp_ext; |
|---|
| 597 | + dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; |
|---|
| 598 | + |
|---|
| 599 | + return 0; |
|---|
| 600 | +} |
|---|
| 601 | + |
|---|
| 602 | +static int cdns_dsi_check_conf(struct cdns_dsi *dsi, |
|---|
| 603 | + const struct drm_display_mode *mode, |
|---|
| 604 | + struct cdns_dsi_cfg *dsi_cfg, |
|---|
| 605 | + bool mode_valid_check) |
|---|
| 606 | +{ |
|---|
| 607 | + struct cdns_dsi_output *output = &dsi->output; |
|---|
| 608 | + struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; |
|---|
| 609 | + unsigned long dsi_hss_hsa_hse_hbp; |
|---|
| 610 | + unsigned int nlanes = output->dev->lanes; |
|---|
| 611 | + int ret; |
|---|
| 612 | + |
|---|
| 613 | + ret = cdns_dsi_mode2cfg(dsi, mode, dsi_cfg, mode_valid_check); |
|---|
| 801 | 614 | if (ret) |
|---|
| 802 | 615 | return ret; |
|---|
| 803 | 616 | |
|---|
| 804 | | - dsi_cfg->hfp += dsi_hfp_ext; |
|---|
| 805 | | - dsi_htotal += dsi_hfp_ext; |
|---|
| 806 | | - dsi_cfg->htotal = dsi_htotal; |
|---|
| 617 | + phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000, |
|---|
| 618 | + mipi_dsi_pixel_format_to_bpp(output->dev->format), |
|---|
| 619 | + nlanes, phy_cfg); |
|---|
| 620 | + |
|---|
| 621 | + ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check); |
|---|
| 622 | + if (ret) |
|---|
| 623 | + return ret; |
|---|
| 624 | + |
|---|
| 625 | + ret = phy_validate(dsi->dphy, PHY_MODE_MIPI_DPHY, 0, &output->phy_opts); |
|---|
| 626 | + if (ret) |
|---|
| 627 | + return ret; |
|---|
| 628 | + |
|---|
| 629 | + dsi_hss_hsa_hse_hbp = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; |
|---|
| 630 | + if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) |
|---|
| 631 | + dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; |
|---|
| 807 | 632 | |
|---|
| 808 | 633 | /* |
|---|
| 809 | 634 | * Make sure DPI(HFP) > DSI(HSS+HSA+HSE+HBP) to guarantee that the FIFO |
|---|
| 810 | 635 | * is empty before we start a receiving a new line on the DPI |
|---|
| 811 | 636 | * interface. |
|---|
| 812 | 637 | */ |
|---|
| 813 | | - if ((u64)dphy_cfg->lane_bps * dpi_hfp * nlanes < |
|---|
| 638 | + if ((u64)phy_cfg->hs_clk_rate * |
|---|
| 639 | + mode_to_dpi_hfp(mode, mode_valid_check) * nlanes < |
|---|
| 814 | 640 | (u64)dsi_hss_hsa_hse_hbp * |
|---|
| 815 | 641 | (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000) |
|---|
| 816 | 642 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 818 | 644 | return 0; |
|---|
| 819 | 645 | } |
|---|
| 820 | 646 | |
|---|
| 821 | | -static int cdns_dsi_bridge_attach(struct drm_bridge *bridge) |
|---|
| 647 | +static int cdns_dsi_bridge_attach(struct drm_bridge *bridge, |
|---|
| 648 | + enum drm_bridge_attach_flags flags) |
|---|
| 822 | 649 | { |
|---|
| 823 | 650 | struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); |
|---|
| 824 | 651 | struct cdns_dsi *dsi = input_to_dsi(input); |
|---|
| .. | .. |
|---|
| 830 | 657 | return -ENOTSUPP; |
|---|
| 831 | 658 | } |
|---|
| 832 | 659 | |
|---|
| 833 | | - return drm_bridge_attach(bridge->encoder, output->bridge, bridge); |
|---|
| 660 | + return drm_bridge_attach(bridge->encoder, output->bridge, bridge, |
|---|
| 661 | + flags); |
|---|
| 834 | 662 | } |
|---|
| 835 | 663 | |
|---|
| 836 | 664 | static enum drm_mode_status |
|---|
| 837 | 665 | cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, |
|---|
| 666 | + const struct drm_display_info *info, |
|---|
| 838 | 667 | const struct drm_display_mode *mode) |
|---|
| 839 | 668 | { |
|---|
| 840 | 669 | struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); |
|---|
| 841 | 670 | struct cdns_dsi *dsi = input_to_dsi(input); |
|---|
| 842 | 671 | struct cdns_dsi_output *output = &dsi->output; |
|---|
| 843 | | - struct cdns_dphy_cfg dphy_cfg; |
|---|
| 844 | 672 | struct cdns_dsi_cfg dsi_cfg; |
|---|
| 845 | | - int bpp, nlanes, ret; |
|---|
| 673 | + int bpp, ret; |
|---|
| 846 | 674 | |
|---|
| 847 | 675 | /* |
|---|
| 848 | 676 | * VFP_DSI should be less than VFP_DPI and VFP_DSI should be at |
|---|
| .. | .. |
|---|
| 860 | 688 | if ((mode->hdisplay * bpp) % 32) |
|---|
| 861 | 689 | return MODE_H_ILLEGAL; |
|---|
| 862 | 690 | |
|---|
| 863 | | - nlanes = output->dev->lanes; |
|---|
| 864 | | - |
|---|
| 865 | | - ret = cdns_dsi_mode2cfg(dsi, mode, &dsi_cfg, &dphy_cfg, true); |
|---|
| 691 | + ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, true); |
|---|
| 866 | 692 | if (ret) |
|---|
| 867 | | - return MODE_CLOCK_RANGE; |
|---|
| 693 | + return MODE_BAD; |
|---|
| 868 | 694 | |
|---|
| 869 | 695 | return MODE_OK; |
|---|
| 870 | 696 | } |
|---|
| .. | .. |
|---|
| 885 | 711 | pm_runtime_put(dsi->base.dev); |
|---|
| 886 | 712 | } |
|---|
| 887 | 713 | |
|---|
| 888 | | -static void cdns_dsi_hs_init(struct cdns_dsi *dsi, |
|---|
| 889 | | - const struct cdns_dphy_cfg *dphy_cfg) |
|---|
| 714 | +static void cdns_dsi_hs_init(struct cdns_dsi *dsi) |
|---|
| 890 | 715 | { |
|---|
| 716 | + struct cdns_dsi_output *output = &dsi->output; |
|---|
| 891 | 717 | u32 status; |
|---|
| 892 | 718 | |
|---|
| 893 | 719 | /* |
|---|
| .. | .. |
|---|
| 898 | 724 | DPHY_CMN_PDN | DPHY_PLL_PDN, |
|---|
| 899 | 725 | dsi->regs + MCTL_DPHY_CFG0); |
|---|
| 900 | 726 | |
|---|
| 901 | | - /* |
|---|
| 902 | | - * Configure the internal PSM clk divider so that the DPHY has a |
|---|
| 903 | | - * 1MHz clk (or something close). |
|---|
| 904 | | - */ |
|---|
| 905 | | - WARN_ON_ONCE(cdns_dphy_setup_psm(dsi->dphy)); |
|---|
| 906 | | - |
|---|
| 907 | | - /* |
|---|
| 908 | | - * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes |
|---|
| 909 | | - * and 8 data lanes, each clk lane can be attache different set of |
|---|
| 910 | | - * data lanes. The 2 groups are named 'left' and 'right', so here we |
|---|
| 911 | | - * just say that we want the 'left' clk lane to drive the 'left' data |
|---|
| 912 | | - * lanes. |
|---|
| 913 | | - */ |
|---|
| 914 | | - cdns_dphy_set_clk_lane_cfg(dsi->dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT); |
|---|
| 915 | | - |
|---|
| 916 | | - /* |
|---|
| 917 | | - * Configure the DPHY PLL that will be used to generate the TX byte |
|---|
| 918 | | - * clk. |
|---|
| 919 | | - */ |
|---|
| 920 | | - cdns_dphy_set_pll_cfg(dsi->dphy, dphy_cfg); |
|---|
| 921 | | - |
|---|
| 922 | | - /* Start TX state machine. */ |
|---|
| 923 | | - writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, |
|---|
| 924 | | - dsi->dphy->regs + DPHY_CMN_SSM); |
|---|
| 727 | + phy_init(dsi->dphy); |
|---|
| 728 | + phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY); |
|---|
| 729 | + phy_configure(dsi->dphy, &output->phy_opts); |
|---|
| 730 | + phy_power_on(dsi->dphy); |
|---|
| 925 | 731 | |
|---|
| 926 | 732 | /* Activate the PLL and wait until it's locked. */ |
|---|
| 927 | 733 | writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR); |
|---|
| .. | .. |
|---|
| 931 | 737 | status & PLL_LOCKED, 100, 100)); |
|---|
| 932 | 738 | /* De-assert data and clock reset lines. */ |
|---|
| 933 | 739 | writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN | |
|---|
| 934 | | - DPHY_D_RSTB(dphy_cfg->nlanes) | DPHY_C_RSTB, |
|---|
| 740 | + DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB, |
|---|
| 935 | 741 | dsi->regs + MCTL_DPHY_CFG0); |
|---|
| 936 | 742 | } |
|---|
| 937 | 743 | |
|---|
| .. | .. |
|---|
| 977 | 783 | struct cdns_dsi *dsi = input_to_dsi(input); |
|---|
| 978 | 784 | struct cdns_dsi_output *output = &dsi->output; |
|---|
| 979 | 785 | struct drm_display_mode *mode; |
|---|
| 980 | | - struct cdns_dphy_cfg dphy_cfg; |
|---|
| 786 | + struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; |
|---|
| 981 | 787 | unsigned long tx_byte_period; |
|---|
| 982 | 788 | struct cdns_dsi_cfg dsi_cfg; |
|---|
| 983 | 789 | u32 tmp, reg_wakeup, div; |
|---|
| 984 | | - int bpp, nlanes; |
|---|
| 790 | + int nlanes; |
|---|
| 985 | 791 | |
|---|
| 986 | 792 | if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) |
|---|
| 987 | 793 | return; |
|---|
| 988 | 794 | |
|---|
| 989 | 795 | mode = &bridge->encoder->crtc->state->adjusted_mode; |
|---|
| 990 | | - bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); |
|---|
| 991 | 796 | nlanes = output->dev->lanes; |
|---|
| 992 | 797 | |
|---|
| 993 | | - WARN_ON_ONCE(cdns_dsi_mode2cfg(dsi, mode, &dsi_cfg, &dphy_cfg, false)); |
|---|
| 798 | + WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); |
|---|
| 994 | 799 | |
|---|
| 995 | | - cdns_dsi_hs_init(dsi, &dphy_cfg); |
|---|
| 800 | + cdns_dsi_hs_init(dsi); |
|---|
| 996 | 801 | cdns_dsi_init_link(dsi); |
|---|
| 997 | 802 | |
|---|
| 998 | 803 | writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa), |
|---|
| .. | .. |
|---|
| 1028 | 833 | tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes); |
|---|
| 1029 | 834 | |
|---|
| 1030 | 835 | tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8, |
|---|
| 1031 | | - dphy_cfg.lane_bps); |
|---|
| 1032 | | - reg_wakeup = cdns_dphy_get_wakeup_time_ns(dsi->dphy) / |
|---|
| 1033 | | - tx_byte_period; |
|---|
| 836 | + phy_cfg->hs_clk_rate); |
|---|
| 837 | + reg_wakeup = (phy_cfg->hs_prepare + phy_cfg->hs_zero) / tx_byte_period; |
|---|
| 1034 | 838 | writel(REG_WAKEUP_TIME(reg_wakeup) | REG_LINE_DURATION(tmp), |
|---|
| 1035 | 839 | dsi->regs + VID_DPHY_TIME); |
|---|
| 1036 | 840 | |
|---|
| .. | .. |
|---|
| 1153 | 957 | |
|---|
| 1154 | 958 | panel = of_drm_find_panel(np); |
|---|
| 1155 | 959 | if (!IS_ERR(panel)) { |
|---|
| 1156 | | - bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI); |
|---|
| 960 | + bridge = drm_panel_bridge_add_typed(panel, |
|---|
| 961 | + DRM_MODE_CONNECTOR_DSI); |
|---|
| 1157 | 962 | } else { |
|---|
| 1158 | 963 | bridge = of_drm_find_bridge(dev->dev.of_node); |
|---|
| 1159 | 964 | if (!bridge) |
|---|
| .. | .. |
|---|
| 1223 | 1028 | struct mipi_dsi_packet packet; |
|---|
| 1224 | 1029 | int ret, i, tx_len, rx_len; |
|---|
| 1225 | 1030 | |
|---|
| 1226 | | - ret = pm_runtime_get_sync(host->dev); |
|---|
| 1031 | + ret = pm_runtime_resume_and_get(host->dev); |
|---|
| 1227 | 1032 | if (ret < 0) |
|---|
| 1228 | 1033 | return ret; |
|---|
| 1229 | 1034 | |
|---|
| .. | .. |
|---|
| 1344 | 1149 | reset_control_deassert(dsi->dsi_p_rst); |
|---|
| 1345 | 1150 | clk_prepare_enable(dsi->dsi_p_clk); |
|---|
| 1346 | 1151 | clk_prepare_enable(dsi->dsi_sys_clk); |
|---|
| 1347 | | - clk_prepare_enable(dsi->dphy->psm_clk); |
|---|
| 1348 | | - clk_prepare_enable(dsi->dphy->pll_ref_clk); |
|---|
| 1349 | 1152 | |
|---|
| 1350 | 1153 | return 0; |
|---|
| 1351 | 1154 | } |
|---|
| .. | .. |
|---|
| 1354 | 1157 | { |
|---|
| 1355 | 1158 | struct cdns_dsi *dsi = dev_get_drvdata(dev); |
|---|
| 1356 | 1159 | |
|---|
| 1357 | | - clk_disable_unprepare(dsi->dphy->pll_ref_clk); |
|---|
| 1358 | | - clk_disable_unprepare(dsi->dphy->psm_clk); |
|---|
| 1359 | 1160 | clk_disable_unprepare(dsi->dsi_sys_clk); |
|---|
| 1360 | 1161 | clk_disable_unprepare(dsi->dsi_p_clk); |
|---|
| 1361 | 1162 | reset_control_assert(dsi->dsi_p_rst); |
|---|
| .. | .. |
|---|
| 1365 | 1166 | |
|---|
| 1366 | 1167 | static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, |
|---|
| 1367 | 1168 | NULL); |
|---|
| 1368 | | - |
|---|
| 1369 | | -static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy) |
|---|
| 1370 | | -{ |
|---|
| 1371 | | - /* Default wakeup time is 800 ns (in a simulated environment). */ |
|---|
| 1372 | | - return 800; |
|---|
| 1373 | | -} |
|---|
| 1374 | | - |
|---|
| 1375 | | -static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy, |
|---|
| 1376 | | - const struct cdns_dphy_cfg *cfg) |
|---|
| 1377 | | -{ |
|---|
| 1378 | | - u32 fbdiv_low, fbdiv_high; |
|---|
| 1379 | | - |
|---|
| 1380 | | - fbdiv_low = (cfg->pll_fbdiv / 4) - 2; |
|---|
| 1381 | | - fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2; |
|---|
| 1382 | | - |
|---|
| 1383 | | - writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG | |
|---|
| 1384 | | - DPHY_CMN_IPDIV(cfg->pll_ipdiv) | |
|---|
| 1385 | | - DPHY_CMN_OPDIV(cfg->pll_opdiv), |
|---|
| 1386 | | - dphy->regs + DPHY_CMN_OPIPDIV); |
|---|
| 1387 | | - writel(DPHY_CMN_FBDIV_FROM_REG | |
|---|
| 1388 | | - DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high), |
|---|
| 1389 | | - dphy->regs + DPHY_CMN_FBDIV); |
|---|
| 1390 | | - writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) | |
|---|
| 1391 | | - DPHY_CMN_PWM_DIV(0x8), |
|---|
| 1392 | | - dphy->regs + DPHY_CMN_PWM); |
|---|
| 1393 | | -} |
|---|
| 1394 | | - |
|---|
| 1395 | | -static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div) |
|---|
| 1396 | | -{ |
|---|
| 1397 | | - writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div), |
|---|
| 1398 | | - dphy->regs + DPHY_PSM_CFG); |
|---|
| 1399 | | -} |
|---|
| 1400 | | - |
|---|
| 1401 | | -/* |
|---|
| 1402 | | - * This is the reference implementation of DPHY hooks. Specific integration of |
|---|
| 1403 | | - * this IP may have to re-implement some of them depending on how they decided |
|---|
| 1404 | | - * to wire things in the SoC. |
|---|
| 1405 | | - */ |
|---|
| 1406 | | -static const struct cdns_dphy_ops ref_dphy_ops = { |
|---|
| 1407 | | - .get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns, |
|---|
| 1408 | | - .set_pll_cfg = cdns_dphy_ref_set_pll_cfg, |
|---|
| 1409 | | - .set_psm_div = cdns_dphy_ref_set_psm_div, |
|---|
| 1410 | | -}; |
|---|
| 1411 | | - |
|---|
| 1412 | | -static const struct of_device_id cdns_dphy_of_match[] = { |
|---|
| 1413 | | - { .compatible = "cdns,dphy", .data = &ref_dphy_ops }, |
|---|
| 1414 | | - { /* sentinel */ }, |
|---|
| 1415 | | -}; |
|---|
| 1416 | | - |
|---|
| 1417 | | -static struct cdns_dphy *cdns_dphy_probe(struct platform_device *pdev) |
|---|
| 1418 | | -{ |
|---|
| 1419 | | - const struct of_device_id *match; |
|---|
| 1420 | | - struct cdns_dphy *dphy; |
|---|
| 1421 | | - struct of_phandle_args args; |
|---|
| 1422 | | - struct resource res; |
|---|
| 1423 | | - int ret; |
|---|
| 1424 | | - |
|---|
| 1425 | | - ret = of_parse_phandle_with_args(pdev->dev.of_node, "phys", |
|---|
| 1426 | | - "#phy-cells", 0, &args); |
|---|
| 1427 | | - if (ret) |
|---|
| 1428 | | - return ERR_PTR(-ENOENT); |
|---|
| 1429 | | - |
|---|
| 1430 | | - match = of_match_node(cdns_dphy_of_match, args.np); |
|---|
| 1431 | | - if (!match || !match->data) |
|---|
| 1432 | | - return ERR_PTR(-EINVAL); |
|---|
| 1433 | | - |
|---|
| 1434 | | - dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); |
|---|
| 1435 | | - if (!dphy) |
|---|
| 1436 | | - return ERR_PTR(-ENOMEM); |
|---|
| 1437 | | - |
|---|
| 1438 | | - dphy->ops = match->data; |
|---|
| 1439 | | - |
|---|
| 1440 | | - ret = of_address_to_resource(args.np, 0, &res); |
|---|
| 1441 | | - if (ret) |
|---|
| 1442 | | - return ERR_PTR(ret); |
|---|
| 1443 | | - |
|---|
| 1444 | | - dphy->regs = devm_ioremap_resource(&pdev->dev, &res); |
|---|
| 1445 | | - if (IS_ERR(dphy->regs)) |
|---|
| 1446 | | - return ERR_CAST(dphy->regs); |
|---|
| 1447 | | - |
|---|
| 1448 | | - dphy->psm_clk = of_clk_get_by_name(args.np, "psm"); |
|---|
| 1449 | | - if (IS_ERR(dphy->psm_clk)) |
|---|
| 1450 | | - return ERR_CAST(dphy->psm_clk); |
|---|
| 1451 | | - |
|---|
| 1452 | | - dphy->pll_ref_clk = of_clk_get_by_name(args.np, "pll_ref"); |
|---|
| 1453 | | - if (IS_ERR(dphy->pll_ref_clk)) { |
|---|
| 1454 | | - ret = PTR_ERR(dphy->pll_ref_clk); |
|---|
| 1455 | | - goto err_put_psm_clk; |
|---|
| 1456 | | - } |
|---|
| 1457 | | - |
|---|
| 1458 | | - if (dphy->ops->probe) { |
|---|
| 1459 | | - ret = dphy->ops->probe(dphy); |
|---|
| 1460 | | - if (ret) |
|---|
| 1461 | | - goto err_put_pll_ref_clk; |
|---|
| 1462 | | - } |
|---|
| 1463 | | - |
|---|
| 1464 | | - return dphy; |
|---|
| 1465 | | - |
|---|
| 1466 | | -err_put_pll_ref_clk: |
|---|
| 1467 | | - clk_put(dphy->pll_ref_clk); |
|---|
| 1468 | | - |
|---|
| 1469 | | -err_put_psm_clk: |
|---|
| 1470 | | - clk_put(dphy->psm_clk); |
|---|
| 1471 | | - |
|---|
| 1472 | | - return ERR_PTR(ret); |
|---|
| 1473 | | -} |
|---|
| 1474 | | - |
|---|
| 1475 | | -static void cdns_dphy_remove(struct cdns_dphy *dphy) |
|---|
| 1476 | | -{ |
|---|
| 1477 | | - if (dphy->ops->remove) |
|---|
| 1478 | | - dphy->ops->remove(dphy); |
|---|
| 1479 | | - |
|---|
| 1480 | | - clk_put(dphy->pll_ref_clk); |
|---|
| 1481 | | - clk_put(dphy->psm_clk); |
|---|
| 1482 | | -} |
|---|
| 1483 | 1169 | |
|---|
| 1484 | 1170 | static int cdns_dsi_drm_probe(struct platform_device *pdev) |
|---|
| 1485 | 1171 | { |
|---|
| .. | .. |
|---|
| 1519 | 1205 | if (irq < 0) |
|---|
| 1520 | 1206 | return irq; |
|---|
| 1521 | 1207 | |
|---|
| 1522 | | - dsi->dphy = cdns_dphy_probe(pdev); |
|---|
| 1208 | + dsi->dphy = devm_phy_get(&pdev->dev, "dphy"); |
|---|
| 1523 | 1209 | if (IS_ERR(dsi->dphy)) |
|---|
| 1524 | 1210 | return PTR_ERR(dsi->dphy); |
|---|
| 1525 | 1211 | |
|---|
| 1526 | 1212 | ret = clk_prepare_enable(dsi->dsi_p_clk); |
|---|
| 1527 | 1213 | if (ret) |
|---|
| 1528 | | - goto err_remove_dphy; |
|---|
| 1214 | + return ret; |
|---|
| 1529 | 1215 | |
|---|
| 1530 | 1216 | val = readl(dsi->regs + ID_REG); |
|---|
| 1531 | 1217 | if (REV_VENDOR_ID(val) != 0xcad) { |
|---|
| .. | .. |
|---|
| 1583 | 1269 | err_disable_pclk: |
|---|
| 1584 | 1270 | clk_disable_unprepare(dsi->dsi_p_clk); |
|---|
| 1585 | 1271 | |
|---|
| 1586 | | -err_remove_dphy: |
|---|
| 1587 | | - cdns_dphy_remove(dsi->dphy); |
|---|
| 1588 | | - |
|---|
| 1589 | 1272 | return ret; |
|---|
| 1590 | 1273 | } |
|---|
| 1591 | 1274 | |
|---|
| .. | .. |
|---|
| 1595 | 1278 | |
|---|
| 1596 | 1279 | mipi_dsi_host_unregister(&dsi->base); |
|---|
| 1597 | 1280 | pm_runtime_disable(&pdev->dev); |
|---|
| 1598 | | - cdns_dphy_remove(dsi->dphy); |
|---|
| 1599 | 1281 | |
|---|
| 1600 | 1282 | return 0; |
|---|
| 1601 | 1283 | } |
|---|
| .. | .. |
|---|
| 1604 | 1286 | { .compatible = "cdns,dsi" }, |
|---|
| 1605 | 1287 | { }, |
|---|
| 1606 | 1288 | }; |
|---|
| 1289 | +MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); |
|---|
| 1607 | 1290 | |
|---|
| 1608 | 1291 | static struct platform_driver cdns_dsi_platform_driver = { |
|---|
| 1609 | 1292 | .probe = cdns_dsi_drm_probe, |
|---|