This patch adds zynqmp afi config driver.This is useful for the configuration of the PS-PL interface on Zynq US+ MPSoC platform. Signed-off-by: Nava kishore Manne <nava.manne@xxxxxxxxxx> --- drivers/misc/Kconfig | 11 ++++++ drivers/misc/Makefile | 1 + drivers/misc/zynqmp-afi.c | 83 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 drivers/misc/zynqmp-afi.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 877b43b3377d..d1ea1eeb3ac1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -456,6 +456,17 @@ config ZYNQ_AFI between PS and PL, the AXI port data path should be configured with the proper Bus-width values +config ZYNQMP_AFI + tristate "Xilinx ZYNQMP AFI support" + help + ZynqMP AFI driver support for writing to the AFI registers for + configuring PS_PL Bus-width. Xilinx Zynq US+ MPSoC connect the + PS to the programmable logic (PL) through the AXI port. This AXI + port helps to establish the data path between the PS and PL. + In-order to establish the proper communication path between + PS and PL, the AXI port data path should be configured with + the proper Bus-width values + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e9b03843100f..54bd0edc511e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o obj-$(CONFIG_ZYNQ_AFI) += zynq-afi.o +obj-$(CONFIG_ZYNQMP_AFI) += zynqmp-afi.o diff --git a/drivers/misc/zynqmp-afi.c b/drivers/misc/zynqmp-afi.c new file mode 100644 index 000000000000..a318652576d2 --- /dev/null +++ b/drivers/misc/zynqmp-afi.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx FPGA AFI bridge. + * Copyright (c) 2018-2021 Xilinx Inc. + */ + +#include <linux/err.h> +#include <linux/firmware/xlnx-zynqmp.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/** + * struct zynqmp_afi_fpga - AFI register description + * @value: value to be written to the register + * @regid: Register id for the register to be written + */ +struct zynqmp_afi_fpga { + u32 value; + u32 regid; +}; + +static int zynqmp_afi_fpga_probe(struct platform_device *pdev) +{ + struct zynqmp_afi_fpga *zynqmp_afi_fpga; + struct device_node *np = pdev->dev.of_node; + int i, entries, ret; + u32 reg, val; + + zynqmp_afi_fpga = devm_kzalloc(&pdev->dev, + sizeof(*zynqmp_afi_fpga), GFP_KERNEL); + if (!zynqmp_afi_fpga) + return -ENOMEM; + platform_set_drvdata(pdev, zynqmp_afi_fpga); + + entries = of_property_count_u32_elems(np, "config-afi"); + if (!entries || (entries % 2)) { + dev_err(&pdev->dev, "Invalid number of registers\n"); + return -EINVAL; + } + + for (i = 0; i < entries / 2; i++) { + ret = of_property_read_u32_index(np, "config-afi", i * 2, ®); + if (ret) { + dev_err(&pdev->dev, "failed to read register\n"); + return -EINVAL; + } + ret = of_property_read_u32_index(np, "config-afi", i * 2 + 1, + &val); + if (ret) { + dev_err(&pdev->dev, "failed to read value\n"); + return -EINVAL; + } + ret = zynqmp_pm_afi(reg, val); + if (ret < 0) { + dev_err(&pdev->dev, "AFI register write error %d\n", + ret); + return ret; + } + } + return 0; +} + +static const struct of_device_id zynqmp_afi_fpga_ids[] = { + { .compatible = "xlnx,zynqmp-afi-fpga" }, + { }, +}; +MODULE_DEVICE_TABLE(of, zynqmp_afi_fpga_ids); + +static struct platform_driver zynqmp_afi_fpga_driver = { + .driver = { + .name = "zynqmp-afi-fpga", + .of_match_table = zynqmp_afi_fpga_ids, + }, + .probe = zynqmp_afi_fpga_probe, +}; +module_platform_driver(zynqmp_afi_fpga_driver); + +MODULE_DESCRIPTION("ZYNQMP FPGA afi module"); +MODULE_AUTHOR("Nava kishore Manne <nava.manne@xxxxxxxxxx>"); +MODULE_LICENSE("GPL v2"); -- 2.18.0