aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-02-21 08:32:02 -0500
committerTom Rini <trini@konsulko.com>2022-02-21 08:32:02 -0500
commit24b628a8f844868adca897aae40af6f98cdbc26d (patch)
tree43572009123231107d618dce3a4f84d7e2c536d6 /drivers
parent55e9cef1432ffd42559874b2a469729f20b627d9 (diff)
parent9bd4232f958b94fdd700e44897fb61bdc898b787 (diff)
downloadu-boot-24b628a8f844868adca897aae40af6f98cdbc26d.zip
u-boot-24b628a8f844868adca897aae40af6f98cdbc26d.tar.gz
u-boot-24b628a8f844868adca897aae40af6f98cdbc26d.tar.bz2
Merge tag 'xilinx-for-v2022.04-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-microblaze
Xilinx changes for v2022.04-rc3 microblaze: - Fix exception handler zynqmp: - Show information about secure images - DT changes (som u-boot file removal) - Fix zynqmp_pm_cfg_obj_convert.py - Fix platform boot xilinx: - Fix bootm_size calculation - Remove GPIO_EXTRA_HEADER selection power: - Add zynqmp power management driver scsi: - Add phy support to ceva driver zynq qspi: - Fix unaligned accesses and check baudrate setup - Add support for spi memory operations net: - Fix 64bit calculation in axi_emac video: - Add missing gpio dependency for seps driver
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/sata_ceva.c44
-rw-r--r--drivers/firmware/firmware-zynqmp.c71
-rw-r--r--drivers/net/xilinx_axi_emac.c4
-rw-r--r--drivers/phy/phy-zynqmp.c30
-rw-r--r--drivers/power/domain/Kconfig9
-rw-r--r--drivers/power/domain/Makefile1
-rw-r--r--drivers/power/domain/zynqmp-power-domain.c89
-rw-r--r--drivers/spi/zynq_qspi.c91
-rw-r--r--drivers/video/Kconfig2
9 files changed, 328 insertions, 13 deletions
diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c
index b71f102..43bcc59 100644
--- a/drivers/ata/sata_ceva.c
+++ b/drivers/ata/sata_ceva.c
@@ -6,9 +6,12 @@
#include <common.h>
#include <dm.h>
#include <ahci.h>
+#include <generic-phy.h>
#include <log.h>
+#include <reset.h>
#include <scsi.h>
#include <asm/io.h>
+#include <dm/device_compat.h>
#include <linux/ioport.h>
/* Vendor Specific Register Offsets */
@@ -181,6 +184,47 @@ static int sata_ceva_bind(struct udevice *dev)
static int sata_ceva_probe(struct udevice *dev)
{
struct ceva_sata_priv *priv = dev_get_priv(dev);
+ struct phy phy;
+ int ret;
+ struct reset_ctl_bulk resets;
+
+ ret = generic_phy_get_by_index(dev, 0, &phy);
+ if (!ret) {
+ dev_dbg(dev, "Perform PHY initialization\n");
+ ret = generic_phy_init(&phy);
+ if (ret)
+ return ret;
+ } else if (ret != -ENOENT) {
+ dev_dbg(dev, "could not get phy (err %d)\n", ret);
+ return ret;
+ }
+
+ /* reset is optional */
+ ret = reset_get_bulk(dev, &resets);
+ if (ret && ret != -ENOTSUPP && ret != -ENOENT) {
+ dev_dbg(dev, "Getting reset fails (err %d)\n", ret);
+ return ret;
+ }
+
+ /* Just trigger reset when reset is specified */
+ if (!ret) {
+ dev_dbg(dev, "Perform IP reset\n");
+ ret = reset_deassert_bulk(&resets);
+ if (ret) {
+ dev_dbg(dev, "Reset fails (err %d)\n", ret);
+ reset_release_bulk(&resets);
+ return ret;
+ }
+ }
+
+ if (phy.dev) {
+ dev_dbg(dev, "Perform PHY power on\n");
+ ret = generic_phy_power_on(&phy);
+ if (ret) {
+ dev_dbg(dev, "PHY power on failed (err %d)\n", ret);
+ return ret;
+ }
+ }
ceva_init_sata(priv);
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 839203e..8d8492d 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <cpu_func.h>
#include <dm.h>
+#include <dm/lists.h>
#include <log.h>
#include <zynqmp_firmware.h>
#include <asm/cache.h>
@@ -27,6 +28,57 @@ struct zynqmp_power {
struct mbox_chan rx_chan;
} zynqmp_power;
+#define NODE_ID_LOCATION 5
+
+static unsigned int xpm_configobject[] = {
+ /**********************************************************************/
+ /* HEADER */
+ 2, /* Number of remaining words in the header */
+ 1, /* Number of sections included in config object */
+ PM_CONFIG_OBJECT_TYPE_OVERLAY, /* Type of Config object as overlay */
+ /**********************************************************************/
+ /* SLAVE SECTION */
+
+ PM_CONFIG_SLAVE_SECTION_ID, /* Section ID */
+ 1, /* Number of slaves */
+
+ 0, /* Node ID which will be changed below */
+ PM_SLAVE_FLAG_IS_SHAREABLE,
+ PM_CONFIG_IPI_PSU_CORTEXA53_0_MASK |
+ PM_CONFIG_IPI_PSU_CORTEXR5_0_MASK |
+ PM_CONFIG_IPI_PSU_CORTEXR5_1_MASK, /* IPI Mask */
+};
+
+static unsigned int xpm_configobject_close[] = {
+ /**********************************************************************/
+ /* HEADER */
+ 2, /* Number of remaining words in the header */
+ 1, /* Number of sections included in config object */
+ PM_CONFIG_OBJECT_TYPE_OVERLAY, /* Type of Config object as overlay */
+ /**********************************************************************/
+ /* SET CONFIG SECTION */
+ PM_CONFIG_SET_CONFIG_SECTION_ID,
+ 0U, /* Loading permission to Overlay config object */
+};
+
+int zynqmp_pmufw_config_close(void)
+{
+ zynqmp_pmufw_load_config_object(xpm_configobject_close,
+ sizeof(xpm_configobject_close));
+ return 0;
+}
+
+int zynqmp_pmufw_node(u32 id)
+{
+ /* Record power domain id */
+ xpm_configobject[NODE_ID_LOCATION] = id;
+
+ zynqmp_pmufw_load_config_object(xpm_configobject,
+ sizeof(xpm_configobject));
+
+ return 0;
+}
+
static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
{
struct zynqmp_ipi_msg msg;
@@ -226,8 +278,27 @@ static const struct udevice_id zynqmp_firmware_ids[] = {
{ }
};
+static int zynqmp_firmware_bind(struct udevice *dev)
+{
+ int ret;
+ struct udevice *child;
+
+ if (IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN)) {
+ ret = device_bind_driver_to_node(dev, "zynqmp_power_domain",
+ "zynqmp_power_domain",
+ dev_ofnode(dev), &child);
+ if (ret) {
+ printf("zynqmp power domain driver is not bound: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return dm_scan_fdt_dev(dev);
+}
+
U_BOOT_DRIVER(zynqmp_firmware) = {
.id = UCLASS_FIRMWARE,
.name = "zynqmp_firmware",
.of_match = zynqmp_firmware_ids,
+ .bind = zynqmp_firmware_bind,
};
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c
index 2ec76d0..f21addb 100644
--- a/drivers/net/xilinx_axi_emac.c
+++ b/drivers/net/xilinx_axi_emac.c
@@ -832,8 +832,8 @@ static int axi_emac_of_to_plat(struct udevice *dev)
printf("%s: axistream is not found\n", __func__);
return -EINVAL;
}
- plat->dmatx = (struct axidma_reg *)fdtdec_get_addr(gd->fdt_blob,
- offset, "reg");
+ plat->dmatx = (struct axidma_reg *)fdtdec_get_addr_size_auto_parent
+ (gd->fdt_blob, 0, offset, "reg", 0, NULL, false);
if (!plat->dmatx) {
printf("%s: axi_dma register space not found\n", __func__);
return -EINVAL;
diff --git a/drivers/phy/phy-zynqmp.c b/drivers/phy/phy-zynqmp.c
index 9dc3d42..08c1b6e 100644
--- a/drivers/phy/phy-zynqmp.c
+++ b/drivers/phy/phy-zynqmp.c
@@ -373,6 +373,29 @@ static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy)
xpsgtr_write_phy(gtr_phy, L0_TX_DIG_61, L0_TM_DISABLE_SCRAMBLE_ENCODER);
}
+/* DP-specific initialization. */
+static void xpsgtr_phy_init_dp(struct xpsgtr_phy *gtr_phy)
+{
+ xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_45,
+ L0_TXPMD_TM_45_OVER_DP_MAIN |
+ L0_TXPMD_TM_45_ENABLE_DP_MAIN |
+ L0_TXPMD_TM_45_OVER_DP_POST1 |
+ L0_TXPMD_TM_45_OVER_DP_POST2 |
+ L0_TXPMD_TM_45_ENABLE_DP_POST2);
+ xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_118,
+ L0_TX_ANA_TM_118_FORCE_17_0);
+}
+
+/* SATA-specific initialization. */
+static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
+{
+ struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
+
+ xpsgtr_bypass_scrambler_8b10b(gtr_phy);
+
+ writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
+}
+
/* SGMII-specific initialization. */
static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
{
@@ -427,9 +450,12 @@ static int xpsgtr_init(struct phy *x)
case ICM_PROTOCOL_SGMII:
xpsgtr_phy_init_sgmii(gtr_phy);
break;
- case ICM_PROTOCOL_DP:
case ICM_PROTOCOL_SATA:
- return -EINVAL;
+ xpsgtr_phy_init_sata(gtr_phy);
+ break;
+ case ICM_PROTOCOL_DP:
+ xpsgtr_phy_init_dp(gtr_phy);
+ break;
}
dev_dbg(gtr_dev->dev, "lane %u (type %u, protocol %u): init done\n",
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index 9aea5fc..93d2599 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -88,4 +88,13 @@ config TI_POWER_DOMAIN
help
Generic power domain implementation for TI K3 devices.
+config ZYNQMP_POWER_DOMAIN
+ bool "Enable the Xilinx ZynqMP Power domain driver"
+ depends on POWER_DOMAIN && ZYNQMP_FIRMWARE
+ help
+ Generic power domain implementation for Xilinx ZynqMP devices.
+ The driver should be enabled when system starts in very minimal
+ configuration and it is extended at run time. Then enabling
+ the driver will ensure that PMUFW enable access to requested IP.
+
endmenu
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 530ae35..7c8af67 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
+obj-$(CONFIG_ZYNQMP_POWER_DOMAIN) += zynqmp-power-domain.o
diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c
new file mode 100644
index 0000000..5383d09
--- /dev/null
+++ b/drivers/power/domain/zynqmp-power-domain.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, Xilinx. Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <misc.h>
+#include <power-domain-uclass.h>
+#include <linux/bitops.h>
+
+#include <zynqmp_firmware.h>
+
+#define NODE_ID_LOCATION 5
+
+static unsigned int xpm_configobject[] = {
+ /* HEADER */
+ 2, /* Number of remaining words in the header */
+ 1, /* Number of sections included in config object */
+ PM_CONFIG_OBJECT_TYPE_OVERLAY, /* Type of Config object as overlay */
+ /* SLAVE SECTION */
+
+ PM_CONFIG_SLAVE_SECTION_ID, /* Section ID */
+ 1, /* Number of slaves */
+
+ 0, /* Node ID which will be changed below */
+ PM_SLAVE_FLAG_IS_SHAREABLE,
+ PM_CONFIG_IPI_PSU_CORTEXA53_0_MASK |
+ PM_CONFIG_IPI_PSU_CORTEXR5_0_MASK |
+ PM_CONFIG_IPI_PSU_CORTEXR5_1_MASK, /* IPI Mask */
+};
+
+static int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
+ const u32 qos, const enum zynqmp_pm_request_ack ack)
+{
+ return xilinx_pm_request(PM_REQUEST_NODE, node, capabilities,
+ qos, ack, NULL);
+}
+
+static int zynqmp_power_domain_request(struct power_domain *power_domain)
+{
+ /* Record power domain id */
+ xpm_configobject[NODE_ID_LOCATION] = power_domain->id;
+
+ zynqmp_pmufw_load_config_object(xpm_configobject, sizeof(xpm_configobject));
+
+ return 0;
+}
+
+static int zynqmp_power_domain_free(struct power_domain *power_domain)
+{
+ /* nop now */
+ return 0;
+}
+
+static int zynqmp_power_domain_on(struct power_domain *power_domain)
+{
+ return zynqmp_pm_request_node(power_domain->id,
+ ZYNQMP_PM_CAPABILITY_ACCESS,
+ ZYNQMP_PM_MAX_QOS,
+ ZYNQMP_PM_REQUEST_ACK_BLOCKING);
+}
+
+static int zynqmp_power_domain_off(struct power_domain *power_domain)
+{
+ /* nop now */
+ return 0;
+}
+
+struct power_domain_ops zynqmp_power_domain_ops = {
+ .request = zynqmp_power_domain_request,
+ .rfree = zynqmp_power_domain_free,
+ .on = zynqmp_power_domain_on,
+ .off = zynqmp_power_domain_off,
+};
+
+static int zynqmp_power_domain_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+U_BOOT_DRIVER(zynqmp_power_domain) = {
+ .name = "zynqmp_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .probe = zynqmp_power_domain_probe,
+ .ops = &zynqmp_power_domain_ops,
+};
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
index cf6da53..b69d992 100644
--- a/drivers/spi/zynq_qspi.c
+++ b/drivers/spi/zynq_qspi.c
@@ -16,6 +16,7 @@
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/bitops.h>
+#include <spi-mem.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -49,6 +50,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define ZYNQ_QSPI_CR_BAUD_SHIFT 3 /* Baud rate divisor shift */
#define ZYNQ_QSPI_CR_SS_SHIFT 10 /* Slave select shift */
+#define ZYNQ_QSPI_MAX_BAUD_RATE 0x7
+#define ZYNQ_QSPI_DEFAULT_BAUD_RATE 0x2
+
#define ZYNQ_QSPI_FIFO_DEPTH 63
#define ZYNQ_QSPI_WAIT (CONFIG_SYS_HZ / 100) /* 10 ms */
@@ -230,12 +234,16 @@ static void zynq_qspi_read_data(struct zynq_qspi_priv *priv, u32 data, u8 size)
priv->rx_buf += 1;
break;
case 2:
- *((u16 *)priv->rx_buf) = data;
- priv->rx_buf += 2;
+ *((u8 *)priv->rx_buf) = data;
+ priv->rx_buf += 1;
+ *((u8 *)priv->rx_buf) = (u8)(data >> 8);
+ priv->rx_buf += 1;
break;
case 3:
- *((u16 *)priv->rx_buf) = data;
- priv->rx_buf += 2;
+ *((u8 *)priv->rx_buf) = data;
+ priv->rx_buf += 1;
+ *((u8 *)priv->rx_buf) = (u8)(data >> 8);
+ priv->rx_buf += 1;
byte3 = (u8)(data >> 16);
*((u8 *)priv->rx_buf) = byte3;
priv->rx_buf += 1;
@@ -272,13 +280,17 @@ static void zynq_qspi_write_data(struct zynq_qspi_priv *priv,
*data |= 0xFFFFFF00;
break;
case 2:
- *data = *((u16 *)priv->tx_buf);
- priv->tx_buf += 2;
+ *data = *((u8 *)priv->tx_buf);
+ priv->tx_buf += 1;
+ *data |= (*((u8 *)priv->tx_buf) << 8);
+ priv->tx_buf += 1;
*data |= 0xFFFF0000;
break;
case 3:
- *data = *((u16 *)priv->tx_buf);
- priv->tx_buf += 2;
+ *data = *((u8 *)priv->tx_buf);
+ priv->tx_buf += 1;
+ *data |= (*((u8 *)priv->tx_buf) << 8);
+ priv->tx_buf += 1;
*data |= (*((u8 *)priv->tx_buf) << 16);
priv->tx_buf += 1;
*data |= 0xFF000000;
@@ -613,6 +625,9 @@ static int zynq_qspi_set_speed(struct udevice *bus, uint speed)
(2 << baud_rate_val)) > speed))
baud_rate_val++;
+ if (baud_rate_val > ZYNQ_QSPI_MAX_BAUD_RATE)
+ baud_rate_val = ZYNQ_QSPI_DEFAULT_BAUD_RATE;
+
plat->speed_hz = speed / (2 << baud_rate_val);
}
confr &= ~ZYNQ_QSPI_CR_BAUD_MASK;
@@ -649,12 +664,72 @@ static int zynq_qspi_set_mode(struct udevice *bus, uint mode)
return 0;
}
+static int zynq_qspi_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ int op_len, pos = 0, ret, i;
+ unsigned int flag = 0;
+ const u8 *tx_buf = NULL;
+ u8 *rx_buf = NULL;
+
+ if (op->data.nbytes) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ rx_buf = op->data.buf.in;
+ else
+ tx_buf = op->data.buf.out;
+ }
+
+ op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+
+ u8 op_buf[op_len];
+
+ op_buf[pos++] = op->cmd.opcode;
+
+ if (op->addr.nbytes) {
+ for (i = 0; i < op->addr.nbytes; i++)
+ op_buf[pos + i] = op->addr.val >>
+ (8 * (op->addr.nbytes - i - 1));
+
+ pos += op->addr.nbytes;
+ }
+
+ if (op->dummy.nbytes)
+ memset(op_buf + pos, 0xff, op->dummy.nbytes);
+
+ /* 1st transfer: opcode + address + dummy cycles */
+ /* Make sure to set END bit if no tx or rx data messages follow */
+ if (!tx_buf && !rx_buf)
+ flag |= SPI_XFER_END;
+
+ ret = zynq_qspi_xfer(slave->dev, op_len * 8, op_buf, NULL,
+ flag | SPI_XFER_BEGIN);
+ if (ret)
+ return ret;
+
+ /* 2nd transfer: rx or tx data path */
+ if (tx_buf || rx_buf) {
+ ret = zynq_qspi_xfer(slave->dev, op->data.nbytes * 8, tx_buf,
+ rx_buf, flag | SPI_XFER_END);
+ if (ret)
+ return ret;
+ }
+
+ spi_release_bus(slave);
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops zynq_qspi_mem_ops = {
+ .exec_op = zynq_qspi_exec_op,
+};
+
static const struct dm_spi_ops zynq_qspi_ops = {
.claim_bus = zynq_qspi_claim_bus,
.release_bus = zynq_qspi_release_bus,
.xfer = zynq_qspi_xfer,
.set_speed = zynq_qspi_set_speed,
.set_mode = zynq_qspi_set_mode,
+ .mem_ops = &zynq_qspi_mem_ops,
};
static const struct udevice_id zynq_qspi_ids[] = {
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index cfa08b5..ff8e11f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -675,7 +675,7 @@ config VIDEO_NX
config VIDEO_SEPS525
bool "Enable video support for Seps525"
- depends on DM_VIDEO
+ depends on DM_VIDEO && DM_GPIO
help
Enable support for the Syncoam PM-OLED display driver (RGB 160x128).
Currently driver is supporting only SPI interface.