summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-07-26 08:32:37 -0400
committerTom Rini <trini@konsulko.com>2022-07-26 08:32:37 -0400
commite5f6fecda4a606acd2417fb537f331e37c757fa5 (patch)
tree852732e3a6aed34836e1e6650eda62cbbe02eeb2 /drivers
parent6e15cda270a060cf87c6c643a1cc3da65ffb242d (diff)
parent2a75bc1303b34e88745fcecfeacbe94f2a4bd1e2 (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.c24
-rw-r--r--drivers/fpga/Kconfig27
-rw-r--r--drivers/fpga/fpga.c33
-rw-r--r--drivers/fpga/spartan2.c3
-rw-r--r--drivers/fpga/spartan3.c2
-rw-r--r--drivers/fpga/versalpl.c2
-rw-r--r--drivers/fpga/virtex2.c13
-rw-r--r--drivers/fpga/xilinx.c8
-rw-r--r--drivers/fpga/zynqmppl.c99
-rw-r--r--drivers/fpga/zynqpl.c2
-rw-r--r--drivers/mailbox/Kconfig2
-rw-r--r--drivers/mailbox/zynqmp-ipi.c2
-rw-r--r--drivers/mmc/zynq_sdhci.c4
-rw-r--r--drivers/reset/Kconfig6
-rw-r--r--drivers/reset/reset-zynqmp.c10
-rw-r--r--drivers/serial/serial_zynq.c2
-rw-r--r--drivers/spi/xilinx_spi.c236
-rw-r--r--drivers/spi/zynq_qspi.c73
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, &regs->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,
+ &regs->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(&regs->spicr) | SPICR_RXFIFO_RESEST | SPICR_TXFIFO_RESEST;
+ writel(reg, &regs->spicr);
writel(SPISSR_OFF, &regs->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(&regs->spicr) | SPICR_MASTER_INHIBIT;
+ writel(reg, &regs->spicr);
+ count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
+ /* Enable master transaction */
reg = readl(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
writel(reg, &regs->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(&regs->spisr, SPISR_TX_EMPTY, true,
+ XILINX_SPISR_TIMEOUT, false);
+ if (ret < 0) {
+ printf("XILSPI error: Xfer timeout\n");
+ return ret;
}
+
+ reg = readl(&regs->spicr) | SPICR_MASTER_INHIBIT;
+ writel(reg, &regs->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(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
- writel(reg, &regs->spicr);
- txbytes -= count;
- if (txp)
- txp += count;
+ spi_cs_activate(spi->dev, slave_plat->cs);
- ret = wait_for_bit_le32(&regs->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, &regs->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(&regs->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,
};