|
147 | 147 | #define TF_PORT_TO_ADDR_MT8173 BIT(18) |
148 | 148 | #define INT_ID_PORT_WIDTH_6 BIT(19) |
149 | 149 | #define CFG_IFA_MASTER_IN_ATF BIT(20) |
| 150 | +#define DL_WITH_MULTI_LARB BIT(21) |
150 | 151 |
|
151 | 152 | #define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask) \ |
152 | 153 | ((((pdata)->flags) & (mask)) == (_x)) |
@@ -865,49 +866,78 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev) |
865 | 866 | struct mtk_iommu_data *data = dev_iommu_priv_get(dev); |
866 | 867 | struct device_link *link; |
867 | 868 | struct device *larbdev; |
| 869 | + unsigned long larbid_msk = 0; |
868 | 870 | unsigned int larbid, larbidx, i; |
869 | 871 |
|
870 | 872 | if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) |
871 | 873 | return &data->iommu; |
872 | 874 |
|
873 | 875 | /* |
874 | 876 | * Link the consumer device with the smi-larb device(supplier). |
875 | | - * The device that connects with each a larb is a independent HW. |
876 | | - * All the ports in each a device should be in the same larbs. |
| 877 | + * w/DL_WITH_MULTI_LARB: the master may connect with multi larbs, |
| 878 | + * we should create device link with each larb. |
| 879 | + * w/o DL_WITH_MULTI_LARB: the master must connect with one larb, |
| 880 | + * otherwise fail. |
877 | 881 | */ |
878 | 882 | larbid = MTK_M4U_TO_LARB(fwspec->ids[0]); |
879 | 883 | if (larbid >= MTK_LARB_NR_MAX) |
880 | 884 | return ERR_PTR(-EINVAL); |
881 | 885 |
|
| 886 | + larbid_msk |= BIT(larbid); |
| 887 | + |
882 | 888 | for (i = 1; i < fwspec->num_ids; i++) { |
883 | 889 | larbidx = MTK_M4U_TO_LARB(fwspec->ids[i]); |
884 | | - if (larbid != larbidx) { |
| 890 | + if (MTK_IOMMU_HAS_FLAG(data->plat_data, DL_WITH_MULTI_LARB)) { |
| 891 | + larbid_msk |= BIT(larbidx); |
| 892 | + } else if (larbid != larbidx) { |
885 | 893 | dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n", |
886 | 894 | larbid, larbidx); |
887 | 895 | return ERR_PTR(-EINVAL); |
888 | 896 | } |
889 | 897 | } |
890 | | - larbdev = data->larb_imu[larbid].dev; |
891 | | - if (!larbdev) |
892 | | - return ERR_PTR(-EINVAL); |
893 | 898 |
|
894 | | - link = device_link_add(dev, larbdev, |
895 | | - DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); |
896 | | - if (!link) |
897 | | - dev_err(dev, "Unable to link %s\n", dev_name(larbdev)); |
| 899 | + for_each_set_bit(larbid, &larbid_msk, 32) { |
| 900 | + larbdev = data->larb_imu[larbid].dev; |
| 901 | + if (!larbdev) |
| 902 | + return ERR_PTR(-EINVAL); |
| 903 | + |
| 904 | + link = device_link_add(dev, larbdev, |
| 905 | + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); |
| 906 | + if (!link) { |
| 907 | + dev_err(dev, "Unable to link %s\n", dev_name(larbdev)); |
| 908 | + goto link_remove; |
| 909 | + } |
| 910 | + } |
| 911 | + |
898 | 912 | return &data->iommu; |
| 913 | + |
| 914 | +link_remove: |
| 915 | + for_each_set_bit(i, &larbid_msk, larbid) { |
| 916 | + larbdev = data->larb_imu[i].dev; |
| 917 | + device_link_remove(dev, larbdev); |
| 918 | + } |
| 919 | + |
| 920 | + return ERR_PTR(-ENODEV); |
899 | 921 | } |
900 | 922 |
|
901 | 923 | static void mtk_iommu_release_device(struct device *dev) |
902 | 924 | { |
903 | 925 | struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
904 | 926 | struct mtk_iommu_data *data; |
905 | 927 | struct device *larbdev; |
906 | | - unsigned int larbid; |
| 928 | + unsigned int larbid, i; |
| 929 | + unsigned long larbid_msk = 0; |
907 | 930 |
|
908 | 931 | data = dev_iommu_priv_get(dev); |
909 | | - if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { |
910 | | - larbid = MTK_M4U_TO_LARB(fwspec->ids[0]); |
| 932 | + if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) |
| 933 | + return; |
| 934 | + |
| 935 | + for (i = 0; i < fwspec->num_ids; i++) { |
| 936 | + larbid = MTK_M4U_TO_LARB(fwspec->ids[i]); |
| 937 | + larbid_msk |= BIT(larbid); |
| 938 | + } |
| 939 | + |
| 940 | + for_each_set_bit(larbid, &larbid_msk, 32) { |
911 | 941 | larbdev = data->larb_imu[larbid].dev; |
912 | 942 | device_link_remove(dev, larbdev); |
913 | 943 | } |
|
0 commit comments