From: Stefan Herbrechtsmeier Date: Mon, 20 Jun 2022 16:36:43 +0000 (+0200) Subject: soc: xilinx: zynqmp: Add machine identification support X-Git-Url: http://git.dujemihanovic.xyz/login.html?a=commitdiff_plain;h=a1e618a1b925c43e70b2e72928f62f3d447fbf68;p=u-boot.git soc: xilinx: zynqmp: Add machine identification support Add machine identification support based on the zynqmp_get_silicon_idcode_name function and use the soc_get_machine function of the soc uclass to get silicon idcode name for the fpga init. Signed-off-by: Stefan Herbrechtsmeier Link: https://lore.kernel.org/r/20220620163650.18756-8-stefan.herbrechtsmeier-oss@weidmueller.com Signed-off-by: Michal Simek --- diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 1f18fb3473..06f6dbab18 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -44,274 +45,10 @@ #include "pm_cfg_obj.h" -#define ZYNQMP_VERSION_SIZE 7 -#define EFUSE_VCU_DIS_SHIFT 8 -#define EFUSE_VCU_DIS_MASK BIT(EFUSE_VCU_DIS_SHIFT) -#define EFUSE_GPU_DIS_SHIFT 5 -#define EFUSE_GPU_DIS_MASK BIT(EFUSE_GPU_DIS_SHIFT) -#define IDCODE_DEV_TYPE_MASK GENMASK(27, 0) -#define IDCODE2_PL_INIT_SHIFT 9 -#define IDCODE2_PL_INIT_MASK BIT(IDCODE2_PL_INIT_SHIFT) - DECLARE_GLOBAL_DATA_PTR; #if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC; - -enum { - ZYNQMP_VARIANT_EG = BIT(0U), - ZYNQMP_VARIANT_EV = BIT(1U), - ZYNQMP_VARIANT_CG = BIT(2U), - ZYNQMP_VARIANT_DR = BIT(3U), -}; - -struct zynqmp_device { - u32 id; - u8 device; - u8 variants; -}; - -static const struct zynqmp_device zynqmp_devices[] = { - { - .id = 0x04688093, - .device = 1, - .variants = ZYNQMP_VARIANT_EG, - }, - { - .id = 0x04711093, - .device = 2, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, - }, - { - .id = 0x04710093, - .device = 3, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, - }, - { - .id = 0x04721093, - .device = 4, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG | - ZYNQMP_VARIANT_EV, - }, - { - .id = 0x04720093, - .device = 5, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG | - ZYNQMP_VARIANT_EV, - }, - { - .id = 0x04739093, - .device = 6, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, - }, - { - .id = 0x04730093, - .device = 7, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG | - ZYNQMP_VARIANT_EV, - }, - { - .id = 0x04738093, - .device = 9, - .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, - }, - { - .id = 0x04740093, - .device = 11, - .variants = ZYNQMP_VARIANT_EG, - }, - { - .id = 0x04750093, - .device = 15, - .variants = ZYNQMP_VARIANT_EG, - }, - { - .id = 0x04759093, - .device = 17, - .variants = ZYNQMP_VARIANT_EG, - }, - { - .id = 0x04758093, - .device = 19, - .variants = ZYNQMP_VARIANT_EG, - }, - { - .id = 0x047E1093, - .device = 21, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047E3093, - .device = 23, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047E5093, - .device = 25, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047E4093, - .device = 27, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047E0093, - .device = 28, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047E2093, - .device = 29, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047E6093, - .device = 39, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047FD093, - .device = 43, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047F8093, - .device = 46, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047FF093, - .device = 47, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047FB093, - .device = 48, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x047FE093, - .device = 49, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x046d0093, - .device = 67, - .variants = ZYNQMP_VARIANT_DR, - }, - { - .id = 0x04714093, - .device = 24, - .variants = 0, - }, - { - .id = 0x04724093, - .device = 26, - .variants = 0, - }, -}; - -static const struct zynqmp_device *zynqmp_get_device(u32 idcode) -{ - idcode &= IDCODE_DEV_TYPE_MASK; - - for (int i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { - if (zynqmp_devices[i].id == idcode) - return &zynqmp_devices[i]; - } - - return NULL; -} - -static char *zynqmp_get_silicon_idcode_name(void) -{ - const struct zynqmp_device *device; - u32 idcode, idcode2; - char name[ZYNQMP_VERSION_SIZE]; - u32 ret_payload[PAYLOAD_ARG_CNT]; - int ret; - - ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); - if (ret) { - debug("%s: Getting chipid failed\n", __func__); - return "unknown"; - } - - /* - * Firmware returns: - * payload[0][31:0] = status of the operation - * payload[1]] = IDCODE - * payload[2][19:0] = Version - * payload[2][28:20] = EXTENDED_IDCODE - * payload[2][29] = PL_INIT - */ - - idcode = ret_payload[1]; - idcode2 = ret_payload[2] >> ZYNQMP_CSU_VERSION_EMPTY_SHIFT; - debug("%s, IDCODE: 0x%0x, IDCODE2: 0x%0x\r\n", __func__, idcode, - idcode2); - - device = zynqmp_get_device(idcode); - if (!device) - return "unknown"; - - /* Add device prefix to the name */ - ret = snprintf(name, ZYNQMP_VERSION_SIZE, "%s%d", - device->variants ? "zu" : "xck", device->device); - if (ret < 0) - return "unknown"; - - if (device->variants & ZYNQMP_VARIANT_EV) { - /* Devices with EV variant might be EG/CG/EV family */ - if (idcode2 & IDCODE2_PL_INIT_MASK) { - u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >> - EFUSE_VCU_DIS_SHIFT) << 1 | - ((idcode2 & EFUSE_GPU_DIS_MASK) >> - EFUSE_GPU_DIS_SHIFT); - - /* - * Get family name based on extended idcode values as - * determined on UG1087, EXTENDED_IDCODE register - * description - */ - switch (family) { - case 0x00: - strlcat(name, "ev", sizeof(name)); - break; - case 0x10: - strlcat(name, "eg", sizeof(name)); - break; - case 0x11: - strlcat(name, "cg", sizeof(name)); - break; - default: - /* Do not append family name*/ - break; - } - } else { - /* - * When PL powered down the VCU Disable efuse cannot be - * read. So, ignore the bit and just findout if it is CG - * or EG/EV variant. - */ - strlcat(name, (idcode2 & EFUSE_GPU_DIS_MASK) ? "cg" : - "e", sizeof(name)); - } - } else if (device->variants & ZYNQMP_VARIANT_CG) { - /* Devices with CG variant might be EG or CG family */ - strlcat(name, (idcode2 & EFUSE_GPU_DIS_MASK) ? "cg" : "eg", - sizeof(name)); - } else if (device->variants & ZYNQMP_VARIANT_EG) { - strlcat(name, "eg", sizeof(name)); - } else if (device->variants & ZYNQMP_VARIANT_DR) { - strlcat(name, "dr", sizeof(name)); - } else { - debug("Variant not identified\n"); - } - - return strdup(name); -} #endif int __maybe_unused psu_uboot_init(void) @@ -402,6 +139,11 @@ static void print_secure_boot(void) int board_init(void) { +#if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) + struct udevice *soc; + char name[SOC_MAX_STR_SIZE]; + int ret; +#endif #if defined(CONFIG_ZYNQMP_FIRMWARE) struct udevice *dev; @@ -428,10 +170,15 @@ int board_init(void) printf("EL Level:\tEL%d\n", current_el()); #if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) - zynqmppl.name = zynqmp_get_silicon_idcode_name(); - printf("Chip ID:\t%s\n", zynqmppl.name); - fpga_init(); - fpga_add(fpga_xilinx, &zynqmppl); + ret = soc_get(&soc); + if (!ret) { + ret = soc_get_machine(soc, name, sizeof(name)); + if (ret >= 0) { + zynqmppl.name = strdup(name); + fpga_init(); + fpga_add(fpga_xilinx, &zynqmppl); + } + } #endif /* display secure boot information */ diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c index 563d93da24..c10fc7d444 100644 --- a/drivers/soc/soc_xilinx_zynqmp.c +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -3,10 +3,15 @@ * Xilinx ZynqMP SOC driver * * Copyright (C) 2021 Xilinx, Inc. + * Michal Simek + * + * Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG + * Stefan Herbrechtsmeier */ #include #include +#include #include #include #include @@ -22,11 +27,257 @@ */ static const char zynqmp_family[] = "ZynqMP"; +#define EFUSE_VCU_DIS_SHIFT 8 +#define EFUSE_VCU_DIS_MASK BIT(EFUSE_VCU_DIS_SHIFT) +#define EFUSE_GPU_DIS_SHIFT 5 +#define EFUSE_GPU_DIS_MASK BIT(EFUSE_GPU_DIS_SHIFT) +#define IDCODE_DEV_TYPE_MASK GENMASK(27, 0) +#define IDCODE2_PL_INIT_SHIFT 9 +#define IDCODE2_PL_INIT_MASK BIT(IDCODE2_PL_INIT_SHIFT) + +#define ZYNQMP_VERSION_SIZE 7 + +enum { + ZYNQMP_VARIANT_EG = BIT(0), + ZYNQMP_VARIANT_EV = BIT(1), + ZYNQMP_VARIANT_CG = BIT(2), + ZYNQMP_VARIANT_DR = BIT(3), +}; + +struct zynqmp_device { + u32 id; + u8 device; + u8 variants; +}; + struct soc_xilinx_zynqmp_priv { const char *family; + char machine[ZYNQMP_VERSION_SIZE]; char revision; }; +static const struct zynqmp_device zynqmp_devices[] = { + { + .id = 0x04688093, + .device = 1, + .variants = ZYNQMP_VARIANT_EG, + }, + { + .id = 0x04711093, + .device = 2, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, + }, + { + .id = 0x04710093, + .device = 3, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, + }, + { + .id = 0x04721093, + .device = 4, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG | + ZYNQMP_VARIANT_EV, + }, + { + .id = 0x04720093, + .device = 5, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG | + ZYNQMP_VARIANT_EV, + }, + { + .id = 0x04739093, + .device = 6, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, + }, + { + .id = 0x04730093, + .device = 7, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG | + ZYNQMP_VARIANT_EV, + }, + { + .id = 0x04738093, + .device = 9, + .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, + }, + { + .id = 0x04740093, + .device = 11, + .variants = ZYNQMP_VARIANT_EG, + }, + { + .id = 0x04750093, + .device = 15, + .variants = ZYNQMP_VARIANT_EG, + }, + { + .id = 0x04759093, + .device = 17, + .variants = ZYNQMP_VARIANT_EG, + }, + { + .id = 0x04758093, + .device = 19, + .variants = ZYNQMP_VARIANT_EG, + }, + { + .id = 0x047E1093, + .device = 21, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047E3093, + .device = 23, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047E5093, + .device = 25, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047E4093, + .device = 27, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047E0093, + .device = 28, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047E2093, + .device = 29, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047E6093, + .device = 39, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FD093, + .device = 43, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047F8093, + .device = 46, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FF093, + .device = 47, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FB093, + .device = 48, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FE093, + .device = 49, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046d0093, + .device = 67, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x04714093, + .device = 24, + .variants = 0, + }, + { + .id = 0x04724093, + .device = 26, + .variants = 0, + }, +}; + +static const struct zynqmp_device *zynqmp_get_device(u32 idcode) +{ + idcode &= IDCODE_DEV_TYPE_MASK; + + for (int i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { + if (zynqmp_devices[i].id == idcode) + return &zynqmp_devices[i]; + } + + return NULL; +} + +static int soc_xilinx_zynqmp_detect_machine(struct udevice *dev, u32 idcode, + u32 idcode2) +{ + struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); + const struct zynqmp_device *device; + int ret; + + device = zynqmp_get_device(idcode); + if (!device) + return 0; + + /* Add device prefix to the name */ + ret = snprintf(priv->machine, sizeof(priv->machine), "%s%d", + device->variants ? "zu" : "xck", device->device); + if (ret < 0) + return ret; + + if (device->variants & ZYNQMP_VARIANT_EV) { + /* Devices with EV variant might be EG/CG/EV family */ + if (idcode2 & IDCODE2_PL_INIT_MASK) { + u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >> + EFUSE_VCU_DIS_SHIFT) << 1 | + ((idcode2 & EFUSE_GPU_DIS_MASK) >> + EFUSE_GPU_DIS_SHIFT); + + /* + * Get family name based on extended idcode values as + * determined on UG1087, EXTENDED_IDCODE register + * description + */ + switch (family) { + case 0x00: + strlcat(priv->machine, "ev", + sizeof(priv->machine)); + break; + case 0x10: + strlcat(priv->machine, "eg", + sizeof(priv->machine)); + break; + case 0x11: + strlcat(priv->machine, "cg", + sizeof(priv->machine)); + break; + default: + /* Do not append family name*/ + break; + } + } else { + /* + * When PL powered down the VCU Disable efuse cannot be + * read. So, ignore the bit and just findout if it is CG + * or EG/EV variant. + */ + strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ? + "cg" : "e", sizeof(priv->machine)); + } + } else if (device->variants & ZYNQMP_VARIANT_CG) { + /* Devices with CG variant might be EG or CG family */ + strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ? + "cg" : "eg", sizeof(priv->machine)); + } else if (device->variants & ZYNQMP_VARIANT_EG) { + strlcat(priv->machine, "eg", sizeof(priv->machine)); + } else if (device->variants & ZYNQMP_VARIANT_DR) { + strlcat(priv->machine, "dr", sizeof(priv->machine)); + } + + return 0; +} + static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size) { struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); @@ -34,6 +285,17 @@ static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size return snprintf(buf, size, "%s", priv->family); } +int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size) +{ + struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); + const char *machine = priv->machine; + + if (!machine[0]) + machine = "unknown"; + + return snprintf(buf, size, "%s", machine); +} + static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int size) { struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev); @@ -44,6 +306,7 @@ static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int si static const struct soc_ops soc_xilinx_zynqmp_ops = { .get_family = soc_xilinx_zynqmp_get_family, .get_revision = soc_xilinx_zynqmp_get_revision, + .get_machine = soc_xilinx_zynqmp_get_machine, }; static int soc_xilinx_zynqmp_probe(struct udevice *dev) @@ -64,6 +327,26 @@ static int soc_xilinx_zynqmp_probe(struct udevice *dev) priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK; + if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { + /* + * Firmware returns: + * payload[0][31:0] = status of the operation + * payload[1] = IDCODE + * payload[2][19:0] = Version + * payload[2][28:20] = EXTENDED_IDCODE + * payload[2][29] = PL_INIT + */ + u32 idcode = ret_payload[1]; + u32 idcode2 = ret_payload[2] >> + ZYNQMP_CSU_VERSION_EMPTY_SHIFT; + dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode, + idcode2); + + ret = soc_xilinx_zynqmp_detect_machine(dev, idcode, idcode2); + if (ret) + return ret; + } + return 0; }