diff options
author | Tom Rini <trini@konsulko.com> | 2022-07-26 08:32:37 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-07-26 08:32:37 -0400 |
commit | e5f6fecda4a606acd2417fb537f331e37c757fa5 (patch) | |
tree | 852732e3a6aed34836e1e6650eda62cbbe02eeb2 /drivers | |
parent | 6e15cda270a060cf87c6c643a1cc3da65ffb242d (diff) | |
parent | 2a75bc1303b34e88745fcecfeacbe94f2a4bd1e2 (diff) |
Merge tag 'xilinx-for-v2022.10-rc2' of https://source.denx.de/u-boot/custodians/u-boot-microblaze
Xilinx changes for v2022.10-rc2
fpga:
- Convert SYS_FPGA_CHECK_CTRLC and SYS_FPGA_PROG_FEEDBACK to Kconfig
- Add support for secure bitstream loading
spi:
- xilinx_spi: Add support for memopers and supports_op
- zynq_qspi: Add support for supports_op/child_pre_probe
- zynq_qspi: Fix dummy cycle and qspi speed calculations
xilinx:
- Get rid of #stream-id-cells
- Use fixed partitions for SOM
- Add support for UUID reading from FRU
- Use strlcpy instead of strncpy
- Add reset driver support for ZynqMP and Versal
- Enable power domain driver in ZynqMP and Versal
zynqmp:
- Do no place BSS at 0 which have issue with NULL pointer
- Enable SLG gpio driver
- Disable LMB for mini configurations
- Remove duplicate PMIO_NODE_ID_BASE macro
versal:
- Add xlnx-versal-resets.h header
mmc:
- zynq_sdhci: Fix macro for MMC HS
relocate-rela:
- Fix support for BE hosts
- Define all macros for e_machine and reloc types
misc:
- Get rid of guard macros from ARM and RISC-V
lmb:
- Add support for disabling LMB
serial:
- zynq: Fix baudrate calculation
tests:
- Mark bind tests to run only on sandbox
- List also dm uclass and devres
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firmware/firmware-zynqmp.c | 24 | ||||
-rw-r--r-- | drivers/fpga/Kconfig | 27 | ||||
-rw-r--r-- | drivers/fpga/fpga.c | 33 | ||||
-rw-r--r-- | drivers/fpga/spartan2.c | 3 | ||||
-rw-r--r-- | drivers/fpga/spartan3.c | 2 | ||||
-rw-r--r-- | drivers/fpga/versalpl.c | 2 | ||||
-rw-r--r-- | drivers/fpga/virtex2.c | 13 | ||||
-rw-r--r-- | drivers/fpga/xilinx.c | 8 | ||||
-rw-r--r-- | drivers/fpga/zynqmppl.c | 99 | ||||
-rw-r--r-- | drivers/fpga/zynqpl.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mailbox/zynqmp-ipi.c | 2 | ||||
-rw-r--r-- | drivers/mmc/zynq_sdhci.c | 4 | ||||
-rw-r--r-- | drivers/reset/Kconfig | 6 | ||||
-rw-r--r-- | drivers/reset/reset-zynqmp.c | 10 | ||||
-rw-r--r-- | drivers/serial/serial_zynq.c | 2 | ||||
-rw-r--r-- | drivers/spi/xilinx_spi.c | 236 | ||||
-rw-r--r-- | drivers/spi/zynq_qspi.c | 73 |
18 files changed, 408 insertions, 140 deletions
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index b0cd647aa51..76ddc6b4f40 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -70,11 +70,20 @@ int zynqmp_pmufw_config_close(void) int zynqmp_pmufw_node(u32 id) { + static bool skip_config; + int ret; + + if (skip_config) + return 0; + /* Record power domain id */ xpm_configobject[NODE_ID_LOCATION] = id; - zynqmp_pmufw_load_config_object(xpm_configobject, - sizeof(xpm_configobject)); + ret = zynqmp_pmufw_load_config_object(xpm_configobject, + sizeof(xpm_configobject)); + + if (ret && id == NODE_APU_0) + skip_config = true; return 0; } @@ -227,7 +236,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) * @cfg_obj: Pointer to the configuration object * @size: Size of @cfg_obj in bytes */ -void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) +int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) { int err; u32 ret_payload[PAYLOAD_ARG_CNT]; @@ -241,12 +250,12 @@ void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) 0, ret_payload); if (err == XST_PM_NO_ACCESS) { printf("PMUFW no permission to change config object\n"); - return; + return -EACCES; } if (err == XST_PM_ALREADY_CONFIGURED) { debug("PMUFW Node is already configured\n"); - return; + return -ENODEV; } if (err) @@ -257,6 +266,8 @@ void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) if ((err || ret_payload[0]) && IS_ENABLED(CONFIG_SPL_BUILD)) panic("PMUFW config object loading failed in EL3\n"); + + return 0; } static int zynqmp_power_probe(struct udevice *dev) @@ -282,6 +293,9 @@ static int zynqmp_power_probe(struct udevice *dev) ret >> ZYNQMP_PM_VERSION_MAJOR_SHIFT, ret & ZYNQMP_PM_VERSION_MINOR_MASK); + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) + zynqmp_pmufw_node(NODE_APU_0); + return 0; }; diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 76719517f54..e07a9cf80ea 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -91,4 +91,31 @@ config FPGA_ZYNQPL Enable FPGA driver for loading bitstream in BIT and BIN format on Xilinx Zynq devices. +config SYS_FPGA_CHECK_CTRLC + bool "Allow Control-C to interrupt FPGA configuration" + depends on FPGA + help + User can interrupt FPGA configuration by pressing CTRL+C. + +config SYS_FPGA_PROG_FEEDBACK + bool "Progress output during FPGA configuration" + depends on FPGA + default y if FPGA_VIRTEX2 + help + Enable printing of hash marks during FPGA configuration. + +config FPGA_LOAD_SECURE + bool "Enable loading secure bitstreams" + depends on FPGA + help + Enables the fpga loads() functions that are used to load secure + (authenticated or encrypted or both) bitstreams on to FPGA. + +config SPL_FPGA_LOAD_SECURE + bool "Enable loading secure bitstreams for SPL" + depends on SPL_FPGA + help + Enables the fpga loads() functions that are used to load secure + (authenticated or encrypted or both) bitstreams on to FPGA. + endmenu diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c index fe3dfa12335..4db5c0a91e9 100644 --- a/drivers/fpga/fpga.c +++ b/drivers/fpga/fpga.c @@ -220,7 +220,7 @@ int fpga_fsload(int devnum, const void *buf, size_t size, } #endif -#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) int fpga_loads(int devnum, const void *buf, size_t size, struct fpga_secure_info *fpga_sec_info) { @@ -252,7 +252,8 @@ int fpga_loads(int devnum, const void *buf, size_t size, /* * Generic multiplexing code */ -int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype) +int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype, + int flags) { int ret_val = FPGA_FAIL; /* assume failure */ const fpga_desc *desc = fpga_validate(devnum, buf, bsize, @@ -263,7 +264,7 @@ int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype) case fpga_xilinx: #if defined(CONFIG_FPGA_XILINX) ret_val = xilinx_load(desc->devdesc, buf, bsize, - bstype); + bstype, flags); #else fpga_no_sup((char *)__func__, "Xilinx devices"); #endif @@ -356,3 +357,29 @@ int fpga_info(int devnum) return fpga_dev_info(devnum); } + +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) +int fpga_compatible2flag(int devnum, const char *compatible) +{ + const fpga_desc * const desc = fpga_get_desc(devnum); + + if (!desc) + return 0; + + switch (desc->devtype) { +#if defined(CONFIG_FPGA_XILINX) + case fpga_xilinx: + { + xilinx_desc *xdesc = (xilinx_desc *)desc->devdesc; + + if (xdesc->operations && xdesc->operations->str2flag) + return xdesc->operations->str2flag(xdesc, compatible); + } +#endif + default: + break; + } + + return 0; +} +#endif diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c index 3435400e58b..47692e32076 100644 --- a/drivers/fpga/spartan2.c +++ b/drivers/fpga/spartan2.c @@ -15,7 +15,6 @@ #endif #undef CONFIG_SYS_FPGA_CHECK_BUSY -#undef CONFIG_SYS_FPGA_PROG_FEEDBACK /* Note: The assumption is that we cannot possibly run fast enough to * overrun the device (the Slave Parallel mode can free run at 50MHz). @@ -41,7 +40,7 @@ static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); /* ------------------------------------------------------------------------- */ /* Spartan-II Generic Implementation */ static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { int ret_val = FPGA_FAIL; diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c index 4850c99352d..918f6db5065 100644 --- a/drivers/fpga/spartan3.c +++ b/drivers/fpga/spartan3.c @@ -45,7 +45,7 @@ static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); /* ------------------------------------------------------------------------- */ /* Spartan-II Generic Implementation */ static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { int ret_val = FPGA_FAIL; diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c index c44a7d34557..d3876a8f541 100644 --- a/drivers/fpga/versalpl.c +++ b/drivers/fpga/versalpl.c @@ -27,7 +27,7 @@ static ulong versal_align_dma_buffer(ulong *buf, u32 len) } static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { ulong bin_buf; int ret; diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c index b3e0537bab0..51b8d312056 100644 --- a/drivers/fpga/virtex2.c +++ b/drivers/fpga/virtex2.c @@ -41,17 +41,6 @@ #define CONFIG_FPGA_DELAY() #endif -#ifndef CONFIG_SYS_FPGA_PROG_FEEDBACK -#define CONFIG_SYS_FPGA_PROG_FEEDBACK -#endif - -/* - * Don't allow config cycle to be interrupted - */ -#ifndef CONFIG_SYS_FPGA_CHECK_CTRLC -#undef CONFIG_SYS_FPGA_CHECK_CTRLC -#endif - /* * Check for errors during configuration by default */ @@ -94,7 +83,7 @@ static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize); static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize); static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { int ret_val = FPGA_FAIL; diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index cbebefb55fe..8170c3368ef 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -135,11 +135,11 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, dataptr += 4; printf(" bytes in bitstream = %d\n", swapsize); - return fpga_load(devnum, dataptr, swapsize, bstype); + return fpga_load(devnum, dataptr, swapsize, bstype, 0); } int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { if (!xilinx_validate (desc, (char *)__FUNCTION__)) { printf ("%s: Invalid device descriptor\n", __FUNCTION__); @@ -151,7 +151,7 @@ int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize, return FPGA_FAIL; } - return desc->operations->load(desc, buf, bsize, bstype); + return desc->operations->load(desc, buf, bsize, bstype, flags); } #if defined(CONFIG_CMD_FPGA_LOADFS) @@ -172,7 +172,7 @@ int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, } #endif -#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) int xilinx_loads(xilinx_desc *desc, const void *buf, size_t bsize, struct fpga_secure_info *fpga_sec_info) { diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index 6b394869dbf..d1491da02c3 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -9,6 +9,7 @@ #include <common.h> #include <compiler.h> #include <cpu_func.h> +#include <fpga.h> #include <log.h> #include <zynqmppl.h> #include <zynqmp_firmware.h> @@ -199,53 +200,106 @@ static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf, return 0; } +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) +static int zynqmp_check_compatible(xilinx_desc *desc, int flags) +{ + /* + * If no flags set, the image may be legacy, but we need to + * signal caller this situation with specific error code. + */ + if (!flags) + return -ENODATA; + + /* For legacy bitstream images no need for other methods exist */ + if ((flags & desc->flags) && flags == FPGA_LEGACY) + return 0; + + /* + * Other images are handled in secure callback loads(). Check + * callback existence besides image type support. + */ + if (desc->operations->loads && (flags & desc->flags)) + return 0; + + return -ENODEV; +} +#endif + static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1); u32 swap = 0; ulong bin_buf; int ret; u32 buf_lo, buf_hi; + u32 bsize_req = (u32)bsize; u32 ret_payload[PAYLOAD_ARG_CNT]; - bool xilfpga_old = false; +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) + struct fpga_secure_info info = { 0 }; + + ret = zynqmp_check_compatible(desc, flags); + if (ret) { + if (ret != -ENODATA) { + puts("Missing loads() operation or unsupported bitstream type\n"); + return FPGA_FAIL; + } + /* If flags is not set, the image treats as legacy */ + flags = FPGA_LEGACY; + } + + switch (flags) { + case FPGA_LEGACY: + break; /* Handle the legacy image later in this function */ +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) + case FPGA_XILINX_ZYNQMP_DDRAUTH: + /* DDR authentication */ + info.authflag = ZYNQMP_FPGA_AUTH_DDR; + info.encflag = FPGA_NO_ENC_OR_NO_AUTH; + return desc->operations->loads(desc, buf, bsize, &info); + case FPGA_XILINX_ZYNQMP_ENC: + /* Encryption using device key */ + info.authflag = FPGA_NO_ENC_OR_NO_AUTH; + info.encflag = FPGA_ENC_DEV_KEY; + return desc->operations->loads(desc, buf, bsize, &info); +#endif + default: + printf("Unsupported bitstream type %d\n", flags); + return FPGA_FAIL; + } +#endif if (zynqmp_firmware_version() <= PMUFW_V1_0) { puts("WARN: PMUFW v1.0 or less is detected\n"); puts("WARN: Not all bitstream formats are supported\n"); puts("WARN: Please upgrade PMUFW\n"); - xilfpga_old = true; if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap)) return FPGA_FAIL; bsizeptr = (u32 *)&bsize; flush_dcache_range((ulong)bsizeptr, (ulong)bsizeptr + sizeof(size_t)); + bsize_req = (u32)(uintptr_t)bsizeptr; bstype |= BIT(ZYNQMP_FPGA_BIT_NS); + } else { + bstype = 0; } bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap); - debug("%s called!\n", __func__); flush_dcache_range(bin_buf, bin_buf + bsize); buf_lo = (u32)bin_buf; buf_hi = upper_32_bits(bin_buf); - if (xilfpga_old) - ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, - buf_hi, (u32)(uintptr_t)bsizeptr, - bstype, ret_payload); - else - ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, - buf_hi, (u32)bsize, 0, ret_payload); - + ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, + bsize_req, bstype, ret_payload); if (ret) printf("PL FPGA LOAD failed with err: 0x%08x\n", ret); return ret; } -#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize, struct fpga_secure_info *fpga_sec_info) { @@ -304,10 +358,25 @@ static int zynqmp_pcap_info(xilinx_desc *desc) return ret; } +static int __maybe_unused zynqmp_str2flag(xilinx_desc *desc, const char *str) +{ + if (!strncmp(str, "u-boot,fpga-legacy", 18)) + return FPGA_LEGACY; +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) + if (!strncmp(str, "u-boot,zynqmp-fpga-ddrauth", 26)) + return FPGA_XILINX_ZYNQMP_DDRAUTH; + + if (!strncmp(str, "u-boot,zynqmp-fpga-enc", 22)) + return FPGA_XILINX_ZYNQMP_ENC; +#endif + return 0; +} + struct xilinx_fpga_op zynqmp_op = { .load = zynqmp_load, -#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) && !defined(CONFIG_SPL_BUILD) + .info = zynqmp_pcap_info, +#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE) .loads = zynqmp_loads, + .str2flag = zynqmp_str2flag, #endif - .info = zynqmp_pcap_info, }; diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index 2de40109a81..d8ebd542abd 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -371,7 +371,7 @@ static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf, } static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize, - bitstream_type bstype) + bitstream_type bstype, int flags) { unsigned long ts; /* Timestamp */ u32 isr_status, swap; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 73db2af0b81..acbdce11b7c 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -54,7 +54,7 @@ config K3_SEC_PROXY config ZYNQMP_IPI bool "Xilinx ZynqMP IPI controller support" - depends on DM_MAILBOX && ARCH_ZYNQMP + depends on DM_MAILBOX && (ARCH_ZYNQMP || ARCH_VERSAL) help This enables support for the Xilinx ZynqMP Inter Processor Interrupt communication controller. diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c index 959cce923c5..3e4ec47389f 100644 --- a/drivers/mailbox/zynqmp-ipi.c +++ b/drivers/mailbox/zynqmp-ipi.c @@ -11,10 +11,10 @@ #include <dm.h> #include <mailbox-uclass.h> #include <dm/device_compat.h> -#include <mach/sys_proto.h> #include <linux/ioport.h> #include <linux/io.h> #include <wait_bit.h> +#include <zynqmp_firmware.h> /* IPI bitmasks, register base */ /* TODO: move reg base to DT */ diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index e978b679885..8f4071c8c28 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -101,8 +101,8 @@ static const u8 mode2timing[] = { [MMC_LEGACY] = MMC_TIMING_LEGACY, [MMC_HS] = MMC_TIMING_MMC_HS, [SD_HS] = MMC_TIMING_SD_HS, - [MMC_HS_52] = MMC_TIMING_UHS_SDR50, - [MMC_DDR_52] = MMC_TIMING_UHS_DDR50, + [MMC_HS_52] = MMC_TIMING_MMC_HS, + [MMC_DDR_52] = MMC_TIMING_MMC_DDR52, [UHS_SDR12] = MMC_TIMING_UHS_SDR12, [UHS_SDR25] = MMC_TIMING_UHS_SDR25, [UHS_SDR50] = MMC_TIMING_UHS_SDR50, diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index b57714111b5..69a7b4ccbad 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -199,11 +199,11 @@ config RESET_SCMI protocol communication with a SCMI server. config RESET_ZYNQMP - bool "Reset Driver for Xilinx ZynqMP SoC's" + bool "Reset Driver for Xilinx ZynqMP & Versal SoC's" depends on DM_RESET && ZYNQMP_FIRMWARE help - Support for reset controller on Xilinx ZynqMP SoC. Driver is only - passing request via Xilinx firmware interface to TF-A and PMU + Support for reset controller on Xilinx ZynqMP & Versal SoC's. Driver + is only passing request via Xilinx firmware interface to TF-A and PMU firmware. config RESET_DRA7 diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index 4e3f907980f..52c08c4722d 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -53,7 +53,7 @@ static int zynqmp_reset_request(struct reset_ctl *rst) dev_dbg(rst->dev, "%s(rst=%p) (id=%lu) (nr_reset=%d)\n", __func__, rst, rst->id, priv->nr_reset); - if (rst->id > priv->nr_reset) + if (priv->nr_reset && rst->id > priv->nr_reset) return -EINVAL; return 0; @@ -63,8 +63,11 @@ static int zynqmp_reset_probe(struct udevice *dev) { struct zynqmp_reset_priv *priv = dev_get_priv(dev); - priv->reset_id = ZYNQMP_RESET_ID; - priv->nr_reset = ZYNQMP_NR_RESETS; + if (device_is_compatible(dev, "xlnx,zynqmp-reset")) { + priv->reset_id = ZYNQMP_RESET_ID; + priv->nr_reset = ZYNQMP_NR_RESETS; + } + return 0; } @@ -76,6 +79,7 @@ const struct reset_ops zynqmp_reset_ops = { static const struct udevice_id zynqmp_reset_ids[] = { { .compatible = "xlnx,zynqmp-reset" }, + { .compatible = "xlnx,versal-reset" }, { } }; diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 83adfb5fb98..295337a8176 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -75,7 +75,7 @@ static void _uart_zynq_serial_setbrg(struct uart_zynq *regs, * Find acceptable values for baud generation. */ for (bdiv = 4; bdiv < 255; bdiv++) { - bgen = clock / (baud * (bdiv + 1)); + bgen = DIV_ROUND_CLOSEST(clock, baud * (bdiv + 1)); if (bgen < 2 || bgen > 65535) continue; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index b892cdae9ba..4e9115dafee 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -19,6 +19,7 @@ #include <log.h> #include <malloc.h> #include <spi.h> +#include <spi-mem.h> #include <asm/io.h> #include <wait_bit.h> #include <linux/bitops.h> @@ -73,7 +74,7 @@ #define XILSPI_MAX_XFER_BITS 8 #define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | SPICR_MASTER_MODE | \ - SPICR_SPE) + SPICR_SPE | SPICR_MASTER_INHIBIT) #define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS) #define XILINX_SPI_IDLE_VAL GENMASK(7, 0) @@ -119,6 +120,15 @@ static int xilinx_spi_probe(struct udevice *bus) writel(SPISSR_RESET_VALUE, ®s->srr); + /* + * Reset RX & TX FIFO + * Enable Manual Slave Select Assertion, + * Set SPI controller into master mode, and enable it + */ + writel(SPICR_RXFIFO_RESEST | SPICR_TXFIFO_RESEST | + SPICR_MANUAL_SS | SPICR_MASTER_MODE | SPICR_SPE, + ®s->spicr); + return 0; } @@ -136,7 +146,10 @@ static void spi_cs_deactivate(struct udevice *dev) struct udevice *bus = dev_get_parent(dev); struct xilinx_spi_priv *priv = dev_get_priv(bus); struct xilinx_spi_regs *regs = priv->regs; + u32 reg; + reg = readl(®s->spicr) | SPICR_RXFIFO_RESEST | SPICR_TXFIFO_RESEST; + writel(reg, ®s->spicr); writel(SPISSR_OFF, ®s->spissr); } @@ -205,70 +218,75 @@ static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes) return i; } -static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes, - const void *dout, void *din) +static int start_transfer(struct spi_slave *spi, const void *dout, void *din, u32 len) { - struct udevice *bus = dev_get_parent(dev); + struct udevice *bus = spi->dev->parent; struct xilinx_spi_priv *priv = dev_get_priv(bus); struct xilinx_spi_regs *regs = priv->regs; - struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - const unsigned char *txp = dout; - unsigned char *rxp = din; - u32 reg; - u32 txbytes = bytes; - u32 rxbytes = bytes; - - /* - * This loop runs two times. First time to send the command. - * Second time to transfer data. After transferring data, - * it sets txp to the initial value for the normal operation. - */ - for ( ; priv->startup < 2; priv->startup++) { - xilinx_spi_fill_txfifo(bus, txp, txbytes); + u32 count, txbytes, rxbytes; + int reg, ret; + const unsigned char *txp = (const unsigned char *)dout; + unsigned char *rxp = (unsigned char *)din; + + txbytes = len; + rxbytes = len; + while (txbytes || rxbytes) { + /* Disable master transaction */ + reg = readl(®s->spicr) | SPICR_MASTER_INHIBIT; + writel(reg, ®s->spicr); + count = xilinx_spi_fill_txfifo(bus, txp, txbytes); + /* Enable master transaction */ reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT; writel(reg, ®s->spicr); - xilinx_spi_read_rxfifo(bus, rxp, rxbytes); - txp = din; + txbytes -= count; + if (txp) + txp += count; - if (priv->startup) { - spi_cs_deactivate(dev); - spi_cs_activate(dev, slave_plat->cs); - txp = dout; + ret = wait_for_bit_le32(®s->spisr, SPISR_TX_EMPTY, true, + XILINX_SPISR_TIMEOUT, false); + if (ret < 0) { + printf("XILSPI error: Xfer timeout\n"); + return ret; } + + reg = readl(®s->spicr) | SPICR_MASTER_INHIBIT; + writel(reg, ®s->spicr); + count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes); + rxbytes -= count; + if (rxp) + rxp += count; } + + return 0; } -static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static void xilinx_spi_startup_block(struct spi_slave *spi) { - struct udevice *bus = dev_get_parent(dev); - struct xilinx_spi_priv *priv = dev_get_priv(bus); - struct xilinx_spi_regs *regs = priv->regs; - struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - /* assume spi core configured to do 8 bit transfers */ - unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS; - const unsigned char *txp = dout; - unsigned char *rxp = din; - u32 txbytes = bytes; - u32 rxbytes = bytes; - u32 reg, count; - int ret; - - debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", - dev_seq(bus), slave_plat->cs, bitlen, bytes, flags); - - if (bitlen == 0) - goto done; - - if (bitlen % XILSPI_MAX_XFER_BITS) { - printf("XILSPI warning: Not a multiple of %d bits\n", - XILSPI_MAX_XFER_BITS); - flags |= SPI_XFER_END; - goto done; - } + struct dm_spi_slave_plat *slave_plat = + dev_get_parent_plat(spi->dev); + unsigned char txp; + unsigned char rxp[8]; - if (flags & SPI_XFER_BEGIN) - spi_cs_activate(dev, slave_plat->cs); + /* + * Perform a dummy read as a work around for + * the startup block issue. + */ + spi_cs_activate(spi->dev, slave_plat->cs); + txp = 0x9f; + start_transfer(spi, (void *)&txp, NULL, 1); + + start_transfer(spi, NULL, (void *)rxp, 6); + + spi_cs_deactivate(spi->dev); +} + +static int xilinx_spi_mem_exec_op(struct spi_slave *spi, + const struct spi_mem_op *op) +{ + struct dm_spi_slave_plat *slave_plat = + dev_get_parent_plat(spi->dev); + static u32 startup; + u32 dummy_len, ret; /* * This is the work around for the startup block issue in @@ -276,36 +294,95 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, * block to FLASH. STARTUP block don't provide clock as soon * as QSPI provides command. So first command fails. */ - xilinx_spi_startup_block(dev, bytes, dout, din); + if (!startup) { + xilinx_spi_startup_block(spi); + startup++; + } - while (txbytes && rxbytes) { - count = xilinx_spi_fill_txfifo(bus, txp, txbytes); - reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT; - writel(reg, ®s->spicr); - txbytes -= count; - if (txp) - txp += count; + spi_cs_activate(spi->dev, slave_plat->cs); - ret = wait_for_bit_le32(®s->spisr, SPISR_TX_EMPTY, true, - XILINX_SPISR_TIMEOUT, false); - if (ret < 0) { - printf("XILSPI error: Xfer timeout\n"); - return ret; + if (op->cmd.opcode) { + ret = start_transfer(spi, (void *)&op->cmd.opcode, NULL, 1); + if (ret) + goto done; + } + if (op->addr.nbytes) { + int i; + u8 addr_buf[4]; + + for (i = 0; i < op->addr.nbytes; i++) + addr_buf[i] = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + + ret = start_transfer(spi, (void *)addr_buf, NULL, + op->addr.nbytes); + if (ret) + goto done; + } + if (op->dummy.nbytes) { + dummy_len = (op->dummy.nbytes * op->data.buswidth) / + op->dummy.buswidth; + + ret = start_transfer(spi, NULL, NULL, dummy_len); + if (ret) + goto done; + } + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) { + ret = start_transfer(spi, NULL, + op->data.buf.in, op->data.nbytes); + } else { + ret = start_transfer(spi, op->data.buf.out, + NULL, op->data.nbytes); } + if (ret) + goto done; + } +done: + spi_cs_deactivate(spi->dev); - debug("txbytes:0x%x,txp:0x%p\n", txbytes, txp); - count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes); - rxbytes -= count; - if (rxp) - rxp += count; - debug("rxbytes:0x%x rxp:0x%p\n", rxbytes, rxp); + return ret; +} + +static int xilinx_qspi_check_buswidth(struct spi_slave *slave, u8 width) +{ + u32 mode = slave->mode; + + switch (width) { + case 1: + return 0; + case 2: + if (mode & SPI_RX_DUAL) + return 0; + break; + case 4: + if (mode & SPI_RX_QUAD) + return 0; + break; } - done: - if (flags & SPI_XFER_END) - spi_cs_deactivate(dev); + return -EOPNOTSUPP; +} - return 0; +bool xilinx_qspi_mem_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + if (xilinx_qspi_check_buswidth(slave, op->cmd.buswidth)) + return false; + + if (op->addr.nbytes && + xilinx_qspi_check_buswidth(slave, op->addr.buswidth)) + return false; + + if (op->dummy.nbytes && + xilinx_qspi_check_buswidth(slave, op->dummy.buswidth)) + return false; + + if (op->data.dir != SPI_MEM_NO_DATA && + xilinx_qspi_check_buswidth(slave, op->data.buswidth)) + return false; + + return true; } static int xilinx_spi_set_speed(struct udevice *bus, uint speed) @@ -343,12 +420,17 @@ static int xilinx_spi_set_mode(struct udevice *bus, uint mode) return 0; } +static const struct spi_controller_mem_ops xilinx_spi_mem_ops = { + .exec_op = xilinx_spi_mem_exec_op, + .supports_op = xilinx_qspi_mem_exec_op, +}; + static const struct dm_spi_ops xilinx_spi_ops = { .claim_bus = xilinx_spi_claim_bus, .release_bus = xilinx_spi_release_bus, - .xfer = xilinx_spi_xfer, .set_speed = xilinx_spi_set_speed, .set_mode = xilinx_spi_set_mode, + .mem_ops = &xilinx_spi_mem_ops, }; static const struct udevice_id xilinx_spi_ids[] = { diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index b69d992b28a..00e3ffcd1df 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -94,6 +94,7 @@ struct zynq_qspi_priv { u8 mode; u8 fifo_depth; u32 freq; /* required frequency */ + u32 max_hz; const void *tx_buf; void *rx_buf; unsigned len; @@ -174,6 +175,16 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); } +static int zynq_qspi_child_pre_probe(struct udevice *bus) +{ + struct spi_slave *slave = dev_get_parent_priv(bus); + struct zynq_qspi_priv *priv = dev_get_priv(bus->parent); + + priv->max_hz = slave->max_hz; + + return 0; +} + static int zynq_qspi_probe(struct udevice *bus) { struct zynq_qspi_plat *plat = dev_get_plat(bus); @@ -611,15 +622,12 @@ static int zynq_qspi_set_speed(struct udevice *bus, uint speed) uint32_t confr; u8 baud_rate_val = 0; - if (speed > plat->frequency) - speed = plat->frequency; + if (!speed || speed > priv->max_hz) + speed = priv->max_hz; /* Set the clock frequency */ confr = readl(®s->cr); - if (speed == 0) { - /* Set baudrate x8, if the freq is 0 */ - baud_rate_val = 0x2; - } else if (plat->speed_hz != speed) { + if (plat->speed_hz != speed) { while ((baud_rate_val < ZYNQ_QSPI_CR_BAUD_MAX) && ((plat->frequency / (2 << baud_rate_val)) > speed)) @@ -668,6 +676,7 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { int op_len, pos = 0, ret, i; + u32 dummy_bytes = 0; unsigned int flag = 0; const u8 *tx_buf = NULL; u8 *rx_buf = NULL; @@ -680,6 +689,11 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, } op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; + if (op->dummy.nbytes) { + op_len = op->cmd.nbytes + op->addr.nbytes + + op->dummy.nbytes / op->dummy.buswidth; + dummy_bytes = op->dummy.nbytes / op->dummy.buswidth; + } u8 op_buf[op_len]; @@ -693,8 +707,8 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, pos += op->addr.nbytes; } - if (op->dummy.nbytes) - memset(op_buf + pos, 0xff, op->dummy.nbytes); + if (dummy_bytes) + memset(op_buf + pos, 0xff, dummy_bytes); /* 1st transfer: opcode + address + dummy cycles */ /* Make sure to set END bit if no tx or rx data messages follow */ @@ -719,8 +733,50 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, return 0; } +static int zynq_qspi_check_buswidth(struct spi_slave *slave, u8 width) +{ + u32 mode = slave->mode; + + switch (width) { + case 1: + return 0; + case 2: + if (mode & SPI_RX_DUAL) + return 0; + break; + case 4: + if (mode & SPI_RX_QUAD) + return 0; + break; + } + + return -EOPNOTSUPP; +} + +bool zynq_qspi_mem_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + if (zynq_qspi_check_buswidth(slave, op->cmd.buswidth)) + return false; + + if (op->addr.nbytes && + zynq_qspi_check_buswidth(slave, op->addr.buswidth)) + return false; + + if (op->dummy.nbytes && + zynq_qspi_check_buswidth(slave, op->dummy.buswidth)) + return false; + + if (op->data.dir != SPI_MEM_NO_DATA && + zynq_qspi_check_buswidth(slave, op->data.buswidth)) + return false; + + return true; +} + static const struct spi_controller_mem_ops zynq_qspi_mem_ops = { .exec_op = zynq_qspi_exec_op, + .supports_op = zynq_qspi_mem_exec_op, }; static const struct dm_spi_ops zynq_qspi_ops = { @@ -746,4 +802,5 @@ U_BOOT_DRIVER(zynq_qspi) = { .plat_auto = sizeof(struct zynq_qspi_plat), .priv_auto = sizeof(struct zynq_qspi_priv), .probe = zynq_qspi_probe, + .child_pre_probe = zynq_qspi_child_pre_probe, }; |