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

pinctrl: pinctrl-zynqmp: Add support for Versal platform

Add Pinctrl support for Xilinx Versal platform.
Driver checks for firmware support to retrieve the Pin information, if it
is supported then proceed further otherwise it returns error saying
operation not supported. Latest Xilinx Platform Management Firmware must
be used to make use of the Pinctrl driver for Versal platform.

Signed-off-by: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
Link: https://lore.kernel.org/20240906110113.3154327-4-sai.krishna.potthuri@amd.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Sai Krishna Potthuri and committed by
Linus Walleij
4c9e8da4 86b9ce0a

+92 -5
+92 -5
drivers/pinctrl/pinctrl-zynqmp.c
··· 10 10 11 11 #include <dt-bindings/pinctrl/pinctrl-zynqmp.h> 12 12 13 + #include <linux/bitfield.h> 13 14 #include <linux/bitmap.h> 14 15 #include <linux/init.h> 15 16 #include <linux/module.h> ··· 44 43 #define DRIVE_STRENGTH_4MA 4 45 44 #define DRIVE_STRENGTH_8MA 8 46 45 #define DRIVE_STRENGTH_12MA 12 46 + 47 + #define VERSAL_LPD_PIN_PREFIX "LPD_MIO" 48 + #define VERSAL_PMC_PIN_PREFIX "PMC_MIO" 49 + 50 + #define VERSAL_PINCTRL_ATTR_NODETYPE_MASK GENMASK(19, 14) 51 + #define VERSAL_PINCTRL_NODETYPE_LPD_MIO BIT(0) 47 52 48 53 /** 49 54 * struct zynqmp_pmux_function - a pinmux function ··· 100 93 }; 101 94 102 95 static struct pinctrl_desc zynqmp_desc; 96 + static u32 family_code; 97 + static u32 sub_family_code; 103 98 104 99 static int zynqmp_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 105 100 { ··· 605 596 if (!groups[resp[i]].name) 606 597 return -ENOMEM; 607 598 608 - for (pin = 0; pin < groups[resp[i]].npins; pin++) 609 - __set_bit(groups[resp[i]].pins[pin], used_pins); 599 + for (pin = 0; pin < groups[resp[i]].npins; pin++) { 600 + if (family_code == ZYNQMP_FAMILY_CODE) 601 + __set_bit(groups[resp[i]].pins[pin], used_pins); 602 + else 603 + __set_bit((u8)groups[resp[i]].pins[pin] - 1, used_pins); 604 + } 610 605 } 611 606 } 612 607 done: ··· 886 873 return 0; 887 874 } 888 875 876 + static int versal_pinctrl_get_attributes(u32 pin_idx, u32 *response) 877 + { 878 + struct zynqmp_pm_query_data qdata = {0}; 879 + u32 payload[PAYLOAD_ARG_CNT]; 880 + int ret; 881 + 882 + qdata.qid = PM_QID_PINCTRL_GET_ATTRIBUTES; 883 + qdata.arg1 = pin_idx; 884 + 885 + ret = zynqmp_pm_query_data(qdata, payload); 886 + if (ret) 887 + return ret; 888 + 889 + memcpy(response, &payload[1], sizeof(*response)); 890 + 891 + return 0; 892 + } 893 + 894 + static int versal_pinctrl_prepare_pin_desc(struct device *dev, 895 + const struct pinctrl_pin_desc **zynqmp_pins, 896 + unsigned int *npins) 897 + { 898 + u32 lpd_mio_pins = 0, attr, nodetype; 899 + struct pinctrl_pin_desc *pins, *pin; 900 + int ret, i; 901 + 902 + ret = zynqmp_pm_is_function_supported(PM_QUERY_DATA, PM_QID_PINCTRL_GET_ATTRIBUTES); 903 + if (ret) 904 + return ret; 905 + 906 + ret = zynqmp_pinctrl_get_num_pins(npins); 907 + if (ret) 908 + return ret; 909 + 910 + pins = devm_kzalloc(dev, sizeof(*pins) * *npins, GFP_KERNEL); 911 + if (!pins) 912 + return -ENOMEM; 913 + 914 + for (i = 0; i < *npins; i++) { 915 + ret = versal_pinctrl_get_attributes(i, &attr); 916 + if (ret) 917 + return ret; 918 + 919 + pin = &pins[i]; 920 + pin->number = attr; 921 + nodetype = FIELD_GET(VERSAL_PINCTRL_ATTR_NODETYPE_MASK, attr); 922 + if (nodetype == VERSAL_PINCTRL_NODETYPE_LPD_MIO) { 923 + pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", 924 + VERSAL_LPD_PIN_PREFIX, i); 925 + lpd_mio_pins++; 926 + } else { 927 + pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", 928 + VERSAL_PMC_PIN_PREFIX, i - lpd_mio_pins); 929 + } 930 + 931 + if (!pin->name) 932 + return -ENOMEM; 933 + } 934 + 935 + *zynqmp_pins = pins; 936 + 937 + return 0; 938 + } 939 + 889 940 static int zynqmp_pinctrl_probe(struct platform_device *pdev) 890 941 { 891 942 struct zynqmp_pinctrl *pctrl; ··· 959 882 if (!pctrl) 960 883 return -ENOMEM; 961 884 962 - ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev, 963 - &zynqmp_desc.pins, 964 - &zynqmp_desc.npins); 885 + ret = zynqmp_pm_get_family_info(&family_code, &sub_family_code); 886 + if (ret < 0) 887 + return ret; 888 + 889 + if (family_code == ZYNQMP_FAMILY_CODE) { 890 + ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins, 891 + &zynqmp_desc.npins); 892 + } else { 893 + ret = versal_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins, 894 + &zynqmp_desc.npins); 895 + } 896 + 965 897 if (ret) { 966 898 dev_err(&pdev->dev, "pin desc prepare fail with %d\n", ret); 967 899 return ret; ··· 993 907 994 908 static const struct of_device_id zynqmp_pinctrl_of_match[] = { 995 909 { .compatible = "xlnx,zynqmp-pinctrl" }, 910 + { .compatible = "xlnx,versal-pinctrl" }, 996 911 { } 997 912 }; 998 913 MODULE_DEVICE_TABLE(of, zynqmp_pinctrl_of_match);