diff options
Diffstat (limited to 'arch/arm/mach-zynqmp')
-rw-r--r-- | arch/arm/mach-zynqmp/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/firmware-zynqmp.c | 203 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/include/mach/debug_ll.h | 31 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h | 80 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h | 21 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/zynqmp-bbu.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynqmp/zynqmp.c | 6 |
7 files changed, 214 insertions, 142 deletions
diff --git a/arch/arm/mach-zynqmp/Kconfig b/arch/arm/mach-zynqmp/Kconfig index 78cb901653..23d04926e6 100644 --- a/arch/arm/mach-zynqmp/Kconfig +++ b/arch/arm/mach-zynqmp/Kconfig @@ -1,5 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-or-later -if ARCH_ZYNQMP + +menu "ZynqMP Features" + depends on ARCH_ZYNQMP + +config MACH_XILINX_ZCU102 + bool "Xilinx Zynq UltraScale+ MPSoC ZCU102" + select ARM_USE_COMPRESSED_DTB + help + Say Y here if you are using the Xilinx Zynq UltraScale+ MPSoC ZCU102 + evaluation board. config MACH_XILINX_ZCU104 bool "Xilinx Zynq UltraScale+ MPSoC ZCU104" @@ -13,4 +22,4 @@ config MACH_XILINX_ZCU106 Say Y here if you are using the Xilinx Zynq UltraScale+ MPSoC ZCU106 evaluation board. -endif +endmenu diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c index c23b434031..039a46e767 100644 --- a/arch/arm/mach-zynqmp/firmware-zynqmp.c +++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c @@ -14,9 +14,17 @@ #include <common.h> #include <init.h> +#include <driver.h> +#include <param.h> #include <linux/arm-smccc.h> -#include <mach/firmware-zynqmp.h> +#include <mach/zynqmp/firmware-zynqmp.h> + +struct zynqmp_fw { + struct device *dev; + u32 ggs[4]; + u32 pggs[4]; +}; #define ZYNQMP_TZ_VERSION(MAJOR, MINOR) ((MAJOR << 16) | MINOR) @@ -40,6 +48,7 @@ enum pm_ret_status { enum pm_api_id { PM_GET_API_VERSION = 1, + PM_MMIO_WRITE = 19, PM_FPGA_LOAD = 22, PM_FPGA_GET_STATUS, PM_IOCTL = 34, @@ -504,6 +513,130 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, } /** + * zynqmp_pm_set_sd_tapdelay() - Set tap delay for the SD device + * + * @node_id: Node ID of the device + * @type: Type of tap delay to set (input/output) + * @value: Value to set fot the tap delay + * + * This function sets input/output tap delay for the SD device. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) +{ + u32 reg = (type == PM_TAPDELAY_INPUT) ? SD_ITAPDLY : SD_OTAPDLYSEL; + u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16); + + if (value) { + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, + IOCTL_SET_SD_TAPDELAY, + type, value, NULL); + } + + /* + * Work around completely misdesigned firmware API on Xilinx ZynqMP. + * The IOCTL_SET_SD_TAPDELAY firmware call allows the caller to only + * ever set IOU_SLCR SD_ITAPDLY Register SD0_ITAPDLYENA/SD1_ITAPDLYENA + * bits, but there is no matching call to clear those bits. If those + * bits are not cleared, SDMMC tuning may fail. + * + * Luckily, there are PM_MMIO_READ/PM_MMIO_WRITE calls which seem to + * allow complete unrestricted access to all address space, including + * IOU_SLCR SD_ITAPDLY Register and all the other registers, access + * to which was supposed to be protected by the current firmware API. + * + * Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter + * part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits. + */ + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); + +/** + * zynqmp_pm_sd_dll_reset() - Reset DLL logic + * + * @node_id: Node ID of the device + * @type: Reset type + * + * This function resets DLL logic for the SD device. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SD_DLL_RESET, + type, 0, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset); + +/* + * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs) + * @index: GGS register index + * @value: Register value to be written + * + * This function writes value to GGS register. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_write_ggs(u32 index, u32 value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS, + index, value, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs); + +/** + * zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs) + * @index: GGS register index + * @value: Register value to be written + * + * This function returns GGS register value. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_read_ggs(u32 index, u32 *value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS, + index, 0, value); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs); + +/** + * zynqmp_pm_write_pggs() - PM API for writing persistent global general + * storage (pggs) + * @index: PGGS register index + * @value: Register value to be written + * + * This function writes value to PGGS register. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_write_pggs(u32 index, u32 value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value, + NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs); + +/** + * zynqmp_pm_read_pggs() - PM API for reading persistent global general + * storage (pggs) + * @index: PGGS register index + * @value: Register value to be written + * + * This function returns PGGS register value. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_read_pggs(u32 index, u32 *value) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0, + value); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs); + +/** * zynqmp_pm_fpga_load - Perform the fpga load * @address: Address to write to * @size: pl bitstream size @@ -576,12 +709,59 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) } EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); +static bool parse_reg(const char *reg, unsigned *idx) +{ + bool pggs = reg[0] == 'p'; + kstrtouint(reg + pggs + sizeof("ggs") - 1, 10, idx); + return pggs; +} -static int zynqmp_firmware_probe(struct device_d *dev) +static int ggs_set(struct param_d *p, void *_val) +{ + u32 *val = _val; + unsigned idx; + + if (parse_reg(p->name, &idx)) + return zynqmp_pm_write_pggs(idx, *val); + else + return zynqmp_pm_write_ggs(idx, *val); +} +static int ggs_get(struct param_d *p, void *_val) { + u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 *val = _val; + unsigned idx; + int ret; + + if (parse_reg(p->name, &idx)) + ret = zynqmp_pm_read_pggs(idx, ret_payload); + else + ret = zynqmp_pm_read_ggs(idx, ret_payload); + + if (ret) + return ret; + + *val = ret_payload[1]; + + return 0; +} + +static inline void dev_add_param_ggs(struct zynqmp_fw *fw, const char *str, u32 *value) +{ + dev_add_param_uint32(fw->dev, str, ggs_set, ggs_get, value, "0x%x", value); +} + +static int zynqmp_firmware_probe(struct device *dev) +{ + + struct zynqmp_fw *fw; int ret; - ret = get_set_conduit_method(dev->device_node); + fw = xzalloc(sizeof(*fw)); + + dev_add_alias(dev, "zynqmp_fw"); + + ret = get_set_conduit_method(dev->of_node); if (ret) goto out; @@ -619,7 +799,19 @@ static int zynqmp_firmware_probe(struct device_d *dev) dev_dbg(dev, "Trustzone version v%d.%d\n", pm_tz_version >> 16, pm_tz_version & 0xFFFF); - of_platform_populate(dev->device_node, NULL, dev); + of_platform_populate(dev->of_node, NULL, dev); + + fw->dev = dev; + + dev_add_param_ggs(fw, "ggs0", &fw->ggs[0]); + dev_add_param_ggs(fw, "ggs1", &fw->ggs[1]); + dev_add_param_ggs(fw, "ggs2", &fw->ggs[2]); + dev_add_param_ggs(fw, "ggs3", &fw->ggs[3]); + + dev_add_param_ggs(fw, "pggs0", &fw->pggs[0]); + dev_add_param_ggs(fw, "pggs1", &fw->pggs[1]); + dev_add_param_ggs(fw, "pggs2", &fw->pggs[2]); + dev_add_param_ggs(fw, "pggs3", &fw->pggs[3]); out: if (ret) do_fw_call = do_fw_call_fail; @@ -630,8 +822,9 @@ static struct of_device_id zynqmp_firmware_id_table[] = { { .compatible = "xlnx,zynqmp-firmware", }, {} }; +MODULE_DEVICE_TABLE(of, zynqmp_firmware_id_table); -static struct driver_d zynqmp_firmware_driver = { +static struct driver zynqmp_firmware_driver = { .name = "zynqmp_firmware", .probe = zynqmp_firmware_probe, .of_compatible = DRV_OF_COMPAT(zynqmp_firmware_id_table), diff --git a/arch/arm/mach-zynqmp/include/mach/debug_ll.h b/arch/arm/mach-zynqmp/include/mach/debug_ll.h deleted file mode 100644 index 67571fe2e1..0000000000 --- a/arch/arm/mach-zynqmp/include/mach/debug_ll.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef __MACH_DEBUG_LL_H__ -#define __MACH_DEBUG_LL_H__ - -#include <io.h> - -#define ZYNQMP_UART0_BASE 0xFF000000 -#define ZYNQMP_UART1_BASE 0xFF010000 -#define ZYNQMP_UART_BASE ZYNQMP_UART0_BASE -#define ZYNQMP_DEBUG_LL_UART_BASE ZYNQMP_UART_BASE - -#define ZYNQMP_UART_RXTXFIFO 0x30 -#define ZYNQMP_UART_CHANNEL_STS 0x2C - -#define ZYNQMP_UART_STS_TFUL (1 << 4) -#define ZYNQMP_UART_TXDIS (1 << 5) - -static inline void PUTC_LL(int c) -{ - void __iomem *base = (void __iomem *)ZYNQMP_DEBUG_LL_UART_BASE; - - if (readl(base) & ZYNQMP_UART_TXDIS) - return; - - while ((readl(base + ZYNQMP_UART_CHANNEL_STS) & ZYNQMP_UART_STS_TFUL) != 0) - ; - - writel(c, base + 0x30); -} - -#endif diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h deleted file mode 100644 index a04482237d..0000000000 --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Xilinx Zynq MPSoC Firmware layer - * - * Copyright (c) 2018 Thomas Haemmerle <thomas.haemmerle@wolfvision.net> - * - * based on Linux xlnx-zynqmp - * - * Michal Simek <michal.simek@xilinx.com> - * Davorin Mista <davorin.mista@aggios.com> - * Jolly Shah <jollys@xilinx.com> - * Rajan Vaja <rajanv@xilinx.com> - */ - -#ifndef FIRMWARE_ZYNQMP_H_ -#define FIRMWARE_ZYNQMP_H_ - -#define PAYLOAD_ARG_CNT 4 - -#define ZYNQMP_PM_VERSION(MAJOR, MINOR) ((MAJOR << 16) | MINOR) - -#define ZYNQMP_FPGA_BIT_AUTH_DDR BIT(1) -#define ZYNQMP_FPGA_BIT_AUTH_OCM BIT(2) -#define ZYNQMP_FPGA_BIT_ENC_USR_KEY BIT(3) -#define ZYNQMP_FPGA_BIT_ENC_DEV_KEY BIT(4) -#define ZYNQMP_FPGA_BIT_ONLY_BIN BIT(5) - -#define ZYNQMP_PCAP_STATUS_FPGA_DONE BIT(3) - -enum pm_ioctl_id { - IOCTL_SET_PLL_FRAC_MODE = 8, - IOCTL_GET_PLL_FRAC_MODE, - IOCTL_SET_PLL_FRAC_DATA, - IOCTL_GET_PLL_FRAC_DATA, -}; - -enum pm_query_id { - PM_QID_INVALID, - PM_QID_CLOCK_GET_NAME, - PM_QID_CLOCK_GET_TOPOLOGY, - PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, - PM_QID_CLOCK_GET_PARENTS, - PM_QID_CLOCK_GET_ATTRIBUTES, - PM_QID_CLOCK_GET_NUM_CLOCKS = 12, -}; - -/** - * struct zynqmp_pm_query_data - PM query data - * @qid: query ID - * @arg1: Argument 1 of query data - * @arg2: Argument 2 of query data - * @arg3: Argument 3 of query data - */ -struct zynqmp_pm_query_data { - u32 qid; - u32 arg1; - u32 arg2; - u32 arg3; -}; - -struct zynqmp_eemi_ops { - int (*get_api_version)(u32 *version); - int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); - int (*clock_enable)(u32 clock_id); - int (*clock_disable)(u32 clock_id); - int (*clock_getstate)(u32 clock_id, u32 *state); - int (*clock_setdivider)(u32 clock_id, u32 divider); - int (*clock_getdivider)(u32 clock_id, u32 *divider); - int (*clock_setrate)(u32 clock_id, u64 rate); - int (*clock_getrate)(u32 clock_id, u64 *rate); - int (*clock_setparent)(u32 clock_id, u32 parent_id); - int (*clock_getparent)(u32 clock_id, u32 *parent_id); - int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out); - int (*fpga_getstatus)(u32 *status); - int (*fpga_load)(u64 address, u32 size, u32 flags); -}; - -const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void); - -#endif /* FIRMWARE_ZYNQMP_H_ */ diff --git a/arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h b/arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h deleted file mode 100644 index 8502791ee0..0000000000 --- a/arch/arm/mach-zynqmp/include/mach/zynqmp-bbu.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2020 Michael Tretter <m.tretter@pengutronix.de> - */ -#ifndef __MACH_ZYNQMP_BBU_H -#define __MACH_ZYNQMP_BBU_H - -#include <bbu.h> - -#ifdef CONFIG_BAREBOX_UPDATE -int zynqmp_bbu_register_handler(const char *name, char *devicefile, - unsigned long flags); -#else -static int zynqmp_bbu_register_handler(const char *name, char *devicefile, - unsigned long flags) -{ - return 0; -}; -#endif - -#endif /* __MACH_ZYNQMP_BBU_H */ diff --git a/arch/arm/mach-zynqmp/zynqmp-bbu.c b/arch/arm/mach-zynqmp/zynqmp-bbu.c index 7ac8c2b8a9..3c5e2fe885 100644 --- a/arch/arm/mach-zynqmp/zynqmp-bbu.c +++ b/arch/arm/mach-zynqmp/zynqmp-bbu.c @@ -4,7 +4,7 @@ */ #include <common.h> -#include <mach/zynqmp-bbu.h> +#include <mach/zynqmp/zynqmp-bbu.h> int zynqmp_bbu_register_handler(const char *name, char *devicefile, unsigned long flags) diff --git a/arch/arm/mach-zynqmp/zynqmp.c b/arch/arm/mach-zynqmp/zynqmp.c index 610d4bba6e..f86bda1693 100644 --- a/arch/arm/mach-zynqmp/zynqmp.c +++ b/arch/arm/mach-zynqmp/zynqmp.c @@ -147,9 +147,11 @@ static int zynqmp_init(void) enum bootsource boot_src; int boot_instance; + if (!of_machine_is_compatible("xlnx,zynqmp")) + return 0; + zynqmp_get_bootsource(&boot_src, &boot_instance); - bootsource_set(boot_src); - bootsource_set_instance(boot_instance); + bootsource_set_raw(boot_src, boot_instance); reset_source_set(zynqmp_get_reset_src()); |