Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/rockchip: dsi: add dual mipi support

Add the Rockchip-sepcific dual-dsi setup and hook it into the VOP as well.
As described in the general dual-dsi devicetree binding, the panel should
define two input ports and point each of them to one of the used dsi-
controllers, as well as declare one of them as clock-master.
This is used to determine the dual-dsi state and get access to both
controller instances.

v6:
handle master+slave component in dsi-attach
v5:
use driver-internal mechanism to find dual dsi slave
v4:
add component directly in probe when adding empty dsi slave controller

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181001123845.11818-8-heiko@sntech.de

authored by

Heiko Stuebner and committed by
Andrzej Hajda
cf6d100d 739838b5

+146
+137
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
··· 218 218 struct clk *grf_clk; 219 219 struct clk *phy_cfg_clk; 220 220 221 + /* dual-channel */ 222 + bool is_slave; 223 + struct dw_mipi_dsi_rockchip *slave; 224 + 221 225 unsigned int lane_mbps; /* per lane */ 222 226 u16 input_div; 223 227 u16 feedback_div; ··· 230 226 struct dw_mipi_dsi *dmd; 231 227 const struct rockchip_dw_dsi_chip_data *cdata; 232 228 struct dw_mipi_dsi_plat_data pdata; 229 + int devcnt; 233 230 }; 234 231 235 232 struct dphy_pll_parameter_map { ··· 607 602 } 608 603 609 604 s->output_type = DRM_MODE_CONNECTOR_DSI; 605 + if (dsi->slave) 606 + s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL; 610 607 611 608 return 0; 612 609 } ··· 624 617 return; 625 618 626 619 pm_runtime_get_sync(dsi->dev); 620 + if (dsi->slave) 621 + pm_runtime_get_sync(dsi->slave->dev); 627 622 628 623 /* 629 624 * For the RK3399, the clk of grf must be enabled before writing grf ··· 639 630 } 640 631 641 632 dw_mipi_dsi_rockchip_config(dsi, mux); 633 + if (dsi->slave) 634 + dw_mipi_dsi_rockchip_config(dsi->slave, mux); 642 635 643 636 clk_disable_unprepare(dsi->grf_clk); 644 637 } ··· 649 638 { 650 639 struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder); 651 640 641 + if (dsi->slave) 642 + pm_runtime_put(dsi->slave->dev); 652 643 pm_runtime_put(dsi->dev); 653 644 } 654 645 ··· 686 673 return 0; 687 674 } 688 675 676 + static struct device 677 + *dw_mipi_dsi_rockchip_find_second(struct dw_mipi_dsi_rockchip *dsi) 678 + { 679 + const struct of_device_id *match; 680 + struct device_node *node = NULL, *local; 681 + 682 + match = of_match_device(dsi->dev->driver->of_match_table, dsi->dev); 683 + 684 + local = of_graph_get_remote_node(dsi->dev->of_node, 1, 0); 685 + if (!local) 686 + return NULL; 687 + 688 + while ((node = of_find_compatible_node(node, NULL, 689 + match->compatible))) { 690 + struct device_node *remote; 691 + 692 + /* found ourself */ 693 + if (node == dsi->dev->of_node) 694 + continue; 695 + 696 + remote = of_graph_get_remote_node(node, 1, 0); 697 + if (!remote) 698 + continue; 699 + 700 + /* same display device in port1-ep0 for both */ 701 + if (remote == local) { 702 + struct dw_mipi_dsi_rockchip *dsi2; 703 + struct platform_device *pdev; 704 + 705 + pdev = of_find_device_by_node(node); 706 + 707 + /* 708 + * we have found the second, so will either return it 709 + * or return with an error. In any case won't need the 710 + * nodes anymore nor continue the loop. 711 + */ 712 + of_node_put(remote); 713 + of_node_put(node); 714 + of_node_put(local); 715 + 716 + if (!pdev) 717 + return ERR_PTR(-EPROBE_DEFER); 718 + 719 + dsi2 = platform_get_drvdata(pdev); 720 + if (!dsi2) { 721 + platform_device_put(pdev); 722 + return ERR_PTR(-EPROBE_DEFER); 723 + } 724 + 725 + return &pdev->dev; 726 + } 727 + 728 + of_node_put(remote); 729 + } 730 + 731 + of_node_put(local); 732 + 733 + return NULL; 734 + } 735 + 689 736 static int dw_mipi_dsi_rockchip_bind(struct device *dev, 690 737 struct device *master, 691 738 void *data) 692 739 { 693 740 struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev); 694 741 struct drm_device *drm_dev = data; 742 + struct device *second; 743 + bool master1, master2; 695 744 int ret; 745 + 746 + second = dw_mipi_dsi_rockchip_find_second(dsi); 747 + if (IS_ERR(second)) 748 + return PTR_ERR(second); 749 + 750 + if (second) { 751 + master1 = of_property_read_bool(dsi->dev->of_node, 752 + "clock-master"); 753 + master2 = of_property_read_bool(second->of_node, 754 + "clock-master"); 755 + 756 + if (master1 && master2) { 757 + DRM_DEV_ERROR(dsi->dev, "only one clock-master allowed\n"); 758 + return -EINVAL; 759 + } 760 + 761 + if (!master1 && !master2) { 762 + DRM_DEV_ERROR(dsi->dev, "no clock-master defined\n"); 763 + return -EINVAL; 764 + } 765 + 766 + /* we are the slave in dual-DSI */ 767 + if (!master1) { 768 + dsi->is_slave = true; 769 + return 0; 770 + } 771 + 772 + dsi->slave = dev_get_drvdata(second); 773 + if (!dsi->slave) { 774 + DRM_DEV_ERROR(dev, "could not get slaves data\n"); 775 + return -ENODEV; 776 + } 777 + 778 + dsi->slave->is_slave = true; 779 + dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd); 780 + put_device(second); 781 + } 696 782 697 783 ret = clk_prepare_enable(dsi->pllref_clk); 698 784 if (ret) { ··· 820 708 { 821 709 struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev); 822 710 711 + if (dsi->is_slave) 712 + return; 713 + 823 714 dw_mipi_dsi_unbind(dsi->dmd); 824 715 825 716 clk_disable_unprepare(dsi->pllref_clk); ··· 837 722 struct mipi_dsi_device *device) 838 723 { 839 724 struct dw_mipi_dsi_rockchip *dsi = priv_data; 725 + struct device *second; 840 726 int ret; 841 727 842 728 ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops); ··· 847 731 return ret; 848 732 } 849 733 734 + second = dw_mipi_dsi_rockchip_find_second(dsi); 735 + if (IS_ERR(second)) 736 + return PTR_ERR(second); 737 + if (second) { 738 + ret = component_add(second, &dw_mipi_dsi_rockchip_ops); 739 + if (ret) { 740 + DRM_DEV_ERROR(second, 741 + "Failed to register component: %d\n", 742 + ret); 743 + return ret; 744 + } 745 + } 746 + 850 747 return 0; 851 748 } 852 749 ··· 867 738 struct mipi_dsi_device *device) 868 739 { 869 740 struct dw_mipi_dsi_rockchip *dsi = priv_data; 741 + struct device *second; 742 + 743 + second = dw_mipi_dsi_rockchip_find_second(dsi); 744 + if (second && !IS_ERR(second)) 745 + component_del(second, &dw_mipi_dsi_rockchip_ops); 870 746 871 747 component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops); 872 748 ··· 979 845 static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev) 980 846 { 981 847 struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev); 848 + 849 + if (dsi->devcnt == 0) 850 + component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops); 982 851 983 852 dw_mipi_dsi_remove(dsi->dmd); 984 853
+1
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
··· 37 37 int output_type; 38 38 int output_mode; 39 39 int output_bpc; 40 + int output_flags; 40 41 }; 41 42 #define to_rockchip_crtc_state(s) \ 42 43 container_of(s, struct rockchip_crtc_state, base)
+3
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
··· 916 916 pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? 917 917 BIT(VSYNC_POSITIVE) : 0; 918 918 VOP_REG_SET(vop, output, pin_pol, pin_pol); 919 + VOP_REG_SET(vop, output, mipi_dual_channel_en, 0); 919 920 920 921 switch (s->output_type) { 921 922 case DRM_MODE_CONNECTOR_LVDS: ··· 934 933 case DRM_MODE_CONNECTOR_DSI: 935 934 VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol); 936 935 VOP_REG_SET(vop, output, mipi_en, 1); 936 + VOP_REG_SET(vop, output, mipi_dual_channel_en, 937 + !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL)); 937 938 break; 938 939 case DRM_MODE_CONNECTOR_DisplayPort: 939 940 pin_pol &= ~BIT(DCLK_INVERT);
+4
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
··· 60 60 struct vop_reg edp_en; 61 61 struct vop_reg hdmi_en; 62 62 struct vop_reg mipi_en; 63 + struct vop_reg mipi_dual_channel_en; 63 64 struct vop_reg rgb_en; 64 65 }; 65 66 ··· 214 213 #define ROCKCHIP_OUT_MODE_P565 2 215 214 /* for use special outface */ 216 215 #define ROCKCHIP_OUT_MODE_AAAA 15 216 + 217 + /* output flags */ 218 + #define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0) 217 219 218 220 enum alpha_mode { 219 221 ALPHA_STRAIGHT,
+1
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
··· 634 634 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), 635 635 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), 636 636 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), 637 + .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), 637 638 }; 638 639 639 640 static const struct vop_data rk3399_vop_big = {