* [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading
@ 2025-06-16 9:44 Casey Connolly
2025-06-16 9:44 ` [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig Casey Connolly
` (8 more replies)
0 siblings, 9 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
The GENI block on Qualcomm platforms contains many Serial Engines (SEs),
these are general purpose hardware blocks capable of implementing any
low speed protocol (UART, SPI, I2C, etc).
The protocol implementation is provided in the form of firmware which is
programmed in to the peripheral, typically by the EDK2 bootloader. Up
until now we have primarily been chainloading U-Boot, and therefore
haven't had to deal with this problem.
However, when running U-Boot as the primary bootloader it is necessary
to handle loading and writing the firmware.
Support for doing this in Linux is also in progress [1], this series is
largely based on that one, however the Linux patches expect the firmware
to be provided in /lib/firmware, and will only exist on newer kernels.
Since we may want to use peripheral (e.g. EEPROM) inside U-Boot it is
still useful to implement firmware loading in U-Boot.
The approach taken here is to bind all peripheral devices which don't
need firmware loading (e.g. the serial port), then wait until
EVT_LAST_STAGE_INIT to handle loading the firmware from storage and
probing the remaining peripherals. We forcefully probe them so that they
will trigger firmware loading and will be available to Linux.
For testing on the RB3 Gen 2 [2] is needed so that the i2c peripherals
can be probed.
[1]: https://lore.kernel.org/linux-arm-msm/20250303124349.3474185-1-quic_vdadhani@quicinc.com/
[2]: https://lore.kernel.org/u-boot/20250314-sc7280-more-clocks-v1-0-ead54487c38e@linaro.org/
---
Changes in v4:
- Regenerate qcom_ipq5424_mmc_defconfig
- Adjust Kconfig so that peripheral drivers express their dependency on QCOM_GENI for firmware loading and update the defconfig
- Add fw loading for UART (e.g. bluetooth) and SPI
- Link to v3: https://lore.kernel.org/r/20250613-geni-load-fw-v3-0-be778b3b101b@linaro.org
Changes in v3:
- Replace printf() with pr_XXX() in geni SE driver
- Add firmware loading for UART as well
- Link to v2: https://lore.kernel.org/r/20250610-geni-load-fw-v2-0-7cad6bc18db0@linaro.org
Changes in v2:
- Use GENI_SE_INVALID_PROTO in geni_i2c instead of 0xff
- Fix typo
- Link to v1: https://lore.kernel.org/r/20250314-geni-load-fw-v1-0-587f25f2812f@linaro.org
---
Casey Connolly (9):
configs: run savedefconfig on qcom_ipq5424_mmc_defconfig
i2c: geni: fix error message wording in clk_disable
misc: introduce Qcom GENI wrapper
i2c: geni: load firmware if required
clk/qcom: sc7280: add uart7 clocks
serial: msm-geni: implement firmware loading
WIP: rb3gen2: describe micro-usb port
spi: geni: load firmware if required
configs: qcom_*: enable QCOM_GENI where needed
configs/chromebook_trogdor_defconfig | 2 +-
configs/qcom_defconfig | 3 +-
configs/qcom_ipq5424_mmc_defconfig | 69 +--
configs/qcom_ipq9574_mmc_defconfig | 2 +
drivers/clk/qcom/clock-sc7280.c | 6 +
drivers/i2c/Kconfig | 2 +-
drivers/i2c/geni_i2c.c | 14 +-
drivers/misc/Kconfig | 9 +
drivers/misc/Makefile | 1 +
drivers/misc/qcom_geni.c | 578 ++++++++++++++++++++++++
drivers/serial/Kconfig | 1 +
drivers/serial/serial_msm_geni.c | 81 ++--
drivers/spi/Kconfig | 2 +-
drivers/spi/spi-geni-qcom.c | 8 +
dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts | 17 +
include/soc/qcom/geni-se.h | 36 ++
include/soc/qcom/qup-fw-load.h | 178 ++++++++
17 files changed, 904 insertions(+), 105 deletions(-)
---
base-commit: 9805321dfdeb5225fe5c5e0721abf49c0875637e
change-id: 20250314-geni-load-fw-0eca432f489c
Casey Connolly <casey.connolly@linaro.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 16:21 ` Tom Rini
2025-06-16 9:44 ` [PATCH v4 2/9] i2c: geni: fix error message wording in clk_disable Casey Connolly
` (7 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Regenerate this defconfig since it seems to have been hand-made
originally. Some options like SCSI were enabled in the defconfig but not
in the final config, it seems like disabling SCSI is the correct thing
here, so no functional changes.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
configs/qcom_ipq5424_mmc_defconfig | 67 ++++++++++++--------------------------
1 file changed, 21 insertions(+), 46 deletions(-)
diff --git a/configs/qcom_ipq5424_mmc_defconfig b/configs/qcom_ipq5424_mmc_defconfig
index 0dd46680b0fc80b10a6975aaddf36e97d8b9be84..81c3865193d73e3f1fc85bd342e3f1d25534c81d 100644
--- a/configs/qcom_ipq5424_mmc_defconfig
+++ b/configs/qcom_ipq5424_mmc_defconfig
@@ -2,82 +2,57 @@ CONFIG_ARM=y
CONFIG_SKIP_LOWLEVEL_INIT=y
CONFIG_POSITION_INDEPENDENT=y
CONFIG_SYS_INIT_SP_BSS_OFFSET=1572864
CONFIG_ARCH_SNAPDRAGON=y
+CONFIG_TEXT_BASE=0x8a380000
CONFIG_NR_DRAM_BANKS=24
+CONFIG_ENV_SIZE=0x40000
+CONFIG_ENV_OFFSET=0
CONFIG_DEFAULT_DEVICE_TREE="qcom/ipq5424-rdp466"
CONFIG_SYS_LOAD_ADDR=0x50000000
+CONFIG_DEBUG_UART_BASE=0x1a84000
+CONFIG_DEBUG_UART_CLOCK=14745600
+CONFIG_DEBUG_UART=y
+CONFIG_REMAKE_ELF=y
+# CONFIG_EFI_LOADER is not set
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
-# CONFIG_EFI_LOADER is not set
-# CONFIG_EFI_BINARY_EXEC is not set
-# CONFIG_EFI_VARIABLE_FILE_STORE is not set
-# CONFIG_PXE_UTILS is not set
# CONFIG_BOOTSTD is not set
-# CONFIG_BOOTMETH_VBE is not set
-CONFIG_BOOTDELAY=2
CONFIG_OF_BOARD_SETUP=y
CONFIG_USE_PREBOOT=y
-CONFIG_LOG_MAX_LEVEL=9
-CONFIG_LOG_DEFAULT_LEVEL=4
+CONFIG_SYS_PBSIZE=1024
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_HUSH_PARSER=y
CONFIG_CMD_MMC=y
-CONFIG_CMD_USB=y
CONFIG_CMD_PART=y
+CONFIG_EFI_PARTITION=y
CONFIG_OF_LIVE=y
+CONFIG_ENV_IS_IN_MMC=y
CONFIG_USE_DEFAULT_ENV_FILE=y
CONFIG_DEFAULT_ENV_FILE="board/qualcomm/default.env"
CONFIG_CLK=y
CONFIG_CLK_QCOM_IPQ5424=y
-CONFIG_DFU_MMC=y
-CONFIG_DFU_SCSI=y
-CONFIG_SYS_DFU_DATA_BUF_SIZE=0x200000
CONFIG_MSM_GPIO=y
-CONFIG_PINCTRL=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_QCOM_IPQ5424=y
+# CONFIG_I2C is not set
+# CONFIG_INPUT is not set
+CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ADMA=y
CONFIG_MMC_SDHCI_MSM=y
-CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MTD=y
CONFIG_DM_MDIO=y
CONFIG_DM_ETH_PHY=y
CONFIG_DWC_ETH_QOS=y
CONFIG_DWC_ETH_QOS_QCOM=y
CONFIG_RGMII=y
CONFIG_PHY=y
CONFIG_PHY_QCOM_QMP_UFS=y
CONFIG_PHY_QCOM_QUSB2=y
-CONFIG_SCSI=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_QCOM_IPQ5424=y
+CONFIG_DEBUG_UART_MSM_GENI=y
+CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_MSM_SERIAL=y
CONFIG_MSM_GENI_SERIAL=y
CONFIG_SOC_QCOM=y
-CONFIG_DEBUG_UART=y
-CONFIG_DEBUG_UART_ANNOUNCE=y
-CONFIG_DEBUG_UART_BASE=0x1a84000
-CONFIG_DEBUG_UART_MSM_GENI=y
-CONFIG_DEBUG_UART_CLOCK=14745600
-CONFIG_TEXT_BASE=0x8a380000
-CONFIG_REMAKE_ELF=y
-CONFIG_FIT=y
-CONFIG_FIT_VERBOSE=y
-CONFIG_BOOTSTD_FULL=y
-CONFIG_SYS_CBSIZE=1024
-CONFIG_SYS_PBSIZE=1024
-CONFIG_OF_LIVE=y
-CONFIG_MSM_SERIAL=y
-CONFIG_DM_EVENT=y
-CONFIG_ENV_IS_IN_MMC=y
-CONFIG_ENV_SIZE=0x40000
-CONFIG_ENV_OFFSET=0
-CONFIG_PARTITIONS=y
-CONFIG_PARTITION_UUIDS=y
-CONFIG_MTD=y
-CONFIG_MTD_PARTS=y
-CONFIG_HUSH_PARSER=y
-CONFIG_PARTITIONS=y
-CONFIG_EFI_PARTITION=y
-# CONFIG_I2C is not set
-# CONFIG_INPUT is not set
-# CONFIG_SCSI is not set
-# CONFIG_SPMI is not set
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 2/9] i2c: geni: fix error message wording in clk_disable
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
2025-06-16 9:44 ` [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 3/9] misc: introduce Qcom GENI wrapper Casey Connolly
` (6 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Correct the error messages so they accurately describe that we failed to
disable the clocks, not to enable them.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
---
drivers/i2c/geni_i2c.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c
index eabf5c76c21c2bc12c80dbb9fb498a0080928248..4eb41ba852f7790ca646c8ba38f29fdb727fa804 100644
--- a/drivers/i2c/geni_i2c.c
+++ b/drivers/i2c/geni_i2c.c
@@ -330,17 +330,15 @@ static int geni_i2c_disable_clocks(struct udevice *dev, struct geni_i2c_priv *ge
if (geni->is_master_hub) {
ret = clk_disable(&geni->core);
if (ret) {
- dev_err(dev, "clk_enable core failed %d\n", ret);
- return ret;
+ dev_err(dev, "clk_disable core failed %d\n", ret);
}
}
ret = clk_disable(&geni->se);
if (ret) {
- dev_err(dev, "clk_enable se failed %d\n", ret);
- return ret;
+ dev_err(dev, "clk_disable se failed %d\n", ret);
}
return 0;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 3/9] misc: introduce Qcom GENI wrapper
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
2025-06-16 9:44 ` [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig Casey Connolly
2025-06-16 9:44 ` [PATCH v4 2/9] i2c: geni: fix error message wording in clk_disable Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 4/9] i2c: geni: load firmware if required Casey Connolly
` (5 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Qualcomm peripherals like UART, SPI, I2C, etc are all exposed under a
common GENI Serial Engine wrapper device. Replace the stub driver we use
for this currently with a full-on misc device and implement support for
loading peripheral firmware.
Each of the peripherals has it's own protocol-specific firmware, this is
stored on the internal storage of the device with a well-known partition
type GUID.
To support this, GENI will bind peripherals in two stages. First the
ones that already have firmware loaded (such as the serial port) are
bound in the typical way. But devices that require firmware loading are
deferred until EVT_LAST_STAGE_INIT. At this point we can be sure that
the storage device is available, so we load the firmware and then bind
and probe the remaining children.
Child devices are expected to determine if firmware loading is necessary
and call qcom_geni_load_firmware().
Since Linux currently doesn't support loading firmware (and firmware may
not be available), we probe all GENI peripherals to ensure that they
always load firmware if necessary.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
drivers/i2c/Kconfig | 2 +-
drivers/misc/Kconfig | 9 +
drivers/misc/Makefile | 1 +
drivers/misc/qcom_geni.c | 578 +++++++++++++++++++++++++++++++++++++++
drivers/serial/Kconfig | 1 +
drivers/serial/serial_msm_geni.c | 13 -
drivers/spi/Kconfig | 2 +-
include/soc/qcom/geni-se.h | 36 +++
include/soc/qcom/qup-fw-load.h | 178 ++++++++++++
9 files changed, 805 insertions(+), 15 deletions(-)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 146bc621c7e41d004508ac0737807d223db2d47e..255270a9c81ab9867d87fd29b4fc3ca1b8fc0443 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -655,9 +655,9 @@ config SYS_I2C_QUP
Peripherals Engine (QUP)".
config SYS_I2C_GENI
bool "Qualcomm Generic Interface (GENI) I2C controller"
- depends on ARCH_SNAPDRAGON
+ depends on ARCH_SNAPDRAGON && QCOM_GENI
help
Support for the Qualcomm Generic Interface (GENI) I2C interface.
The Generic Interface (GENI) is a firmware based Qualcomm Universal
Peripherals (QUP) Serial Engine (SE) Wrapper which can support multiple
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index ffc5868c0dd3e884fddb98b10f4b878d3f08b43a..78aaf003852aab96450963d93678787d30892f1b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -82,8 +82,17 @@ config GATEWORKS_SC
Enable access for the Gateworks System Controller used on Gateworks
boards to provide a boot watchdog, power control, temperature monitor,
voltage ADCs, and EEPROM.
+config QCOM_GENI
+ bool "Qualcomm Generic Interface (GENI) driver"
+ depends on MISC
+ select PARTITION_TYPE_GUID
+ help
+ Enable support for Qualcomm GENI and it's peripherals. GENI is responseible
+ for providing a common interface for various peripherals like UART, I2C, SPI,
+ etc.
+
config ROCKCHIP_EFUSE
bool "Rockchip e-fuse support"
depends on MISC
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 248068d5b4369bfe6d23216e92de4ee32bdfd081..627eef29af33fe06f44506467721e7121f64d502 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -68,8 +68,9 @@ obj-$(CONFIG_QFW_PIO) += qfw_pio.o
obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o
obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o
obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
endif
+obj-$(CONFIG_QCOM_GENI) += qcom_geni.o
obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o
obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c
new file mode 100644
index 0000000000000000000000000000000000000000..aa1999bfab320b8a11278cbc3d9903f3e554f055
--- /dev/null
+++ b/drivers/misc/qcom_geni.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2025, Linaro Ltd.
+ */
+
+#define pr_fmt(fmt) "GENI-SE: " fmt
+
+#include <blk.h>
+#include <part.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <elf.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <misc.h>
+#include <linux/printk.h>
+#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
+#include <dm/device_compat.h>
+
+struct qup_se_rsc {
+ phys_addr_t base;
+ phys_addr_t wrapper_base;
+ struct udevice *dev;
+
+ enum geni_se_xfer_mode mode;
+ enum geni_se_protocol_type protocol;
+};
+
+struct geni_se_plat {
+ bool need_firmware_load;
+};
+
+/**
+ * geni_enable_interrupts() Enable interrupts.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ *
+ * Enable the required interrupts during the firmware load process.
+ *
+ * Return: None.
+ */
+static void geni_enable_interrupts(struct qup_se_rsc *rsc)
+{
+ u32 reg_value;
+
+ /* Enable required interrupts. */
+ writel_relaxed(M_COMMON_GENI_M_IRQ_EN, rsc->base + GENI_M_IRQ_ENABLE);
+
+ reg_value = S_CMD_OVERRUN_EN | S_ILLEGAL_CMD_EN |
+ S_CMD_CANCEL_EN | S_CMD_ABORT_EN |
+ S_GP_IRQ_0_EN | S_GP_IRQ_1_EN |
+ S_GP_IRQ_2_EN | S_GP_IRQ_3_EN |
+ S_RX_FIFO_WR_ERR_EN | S_RX_FIFO_RD_ERR_EN;
+ writel_relaxed(reg_value, rsc->base + GENI_S_IRQ_ENABLE);
+
+ /* DMA mode configuration. */
+ reg_value = DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK |
+ DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK |
+ DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;
+ writel_relaxed(reg_value, rsc->base + DMA_TX_IRQ_EN_SET);
+ reg_value = DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK |
+ DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK |
+ DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK |
+ DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;
+ writel_relaxed(reg_value, rsc->base + DMA_RX_IRQ_EN_SET);
+}
+
+/**
+ * geni_flash_fw_revision() - Flash the firmware revision.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ * @hdr: Pointer to the ELF header of the Serial Engine.
+ *
+ * Flash the firmware revision and protocol into the respective register.
+ *
+ * Return: None.
+ */
+static void geni_flash_fw_revision(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr)
+{
+ u32 reg_value;
+
+ /* Flash firmware revision register. */
+ reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) |
+ (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT);
+ writel_relaxed(reg_value, rsc->base + SE_GENI_FW_REVISION);
+
+ reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) |
+ (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT);
+
+ writel_relaxed(reg_value, rsc->base + SE_S_FW_REVISION);
+}
+
+/**
+ * geni_configure_xfer_mode() - Set the transfer mode.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ *
+ * Set the transfer mode to either FIFO or DMA according to the mode specified by the protocol
+ * driver.
+ *
+ * Return: 0 if successful, otherwise return an error value.
+ */
+static int geni_configure_xfer_mode(struct qup_se_rsc *rsc)
+{
+ /* Configure SE FIFO, DMA or GSI mode. */
+ switch (rsc->mode) {
+ case GENI_GPI_DMA:
+ geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN,
+ GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);
+ writel_relaxed(0x0, rsc->base + SE_IRQ_EN);
+ writel_relaxed(SE_GSI_EVENT_EN_BMSK, rsc->base + SE_GSI_EVENT_EN);
+ break;
+
+ case GENI_SE_FIFO:
+ geni_clrbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN,
+ GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);
+ writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN);
+ writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN);
+ break;
+
+ case GENI_SE_DMA:
+ geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN,
+ GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);
+ writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN);
+ writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN);
+ break;
+
+ default:
+ dev_err(rsc->dev, "invalid se mode: %d\n", rsc->mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * geni_config_common_control() - Configure common CGC and disable high priority interrupt.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ *
+ * Configure the common CGC and disable high priority interrupts until the current low priority
+ * interrupts are handled.
+ *
+ * Return: None.
+ */
+static void geni_config_common_control(struct qup_se_rsc *rsc)
+{
+ /*
+ * Disable high priority interrupt until current low priority interrupts are handled.
+ */
+ geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CFG,
+ FAST_SWITCH_TO_HIGH_DISABLE_BMASK);
+
+ /*
+ * Set AHB_M_CLK_CGC_ON to indicate hardware controls se-wrapper cgc clock.
+ */
+ geni_setbits32(rsc->wrapper_base + QUPV3_SE_AHB_M_CFG,
+ AHB_M_CLK_CGC_ON_BMASK);
+
+ /* Let hardware to control common cgc. */
+ geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CGC_CTRL,
+ COMMON_CSR_SLV_CLK_CGC_ON_BMASK);
+}
+
+static int load_se_firmware(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr)
+{
+ const u32 *fw_val_arr, *cfg_val_arr;
+ const u8 *cfg_idx_arr;
+ u32 i, reg_value, mask, ramn_cnt;
+ int ret;
+
+ fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset);
+ cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset;
+ cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset);
+
+ geni_config_common_control(rsc);
+
+ /* Allows to drive corresponding data according to hardware value. */
+ writel_relaxed(0x0, rsc->base + GENI_OUTPUT_CTRL);
+
+ /* Set SCLK and HCLK to program RAM */
+ geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+ writel_relaxed(0x0, rsc->base + SE_GENI_CLK_CTRL);
+ geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+
+ /* Enable required clocks for DMA CSR, TX and RX. */
+ reg_value = DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK |
+ DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK |
+ DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK |
+ DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK;
+
+ geni_setbits32(rsc->base + DMA_GENERAL_CFG, reg_value);
+
+ /* Let hardware control CGC by default. */
+ writel_relaxed(DEFAULT_CGC_EN, rsc->base + GENI_CGC_CTRL);
+
+ /* Set version of the configuration register part of firmware. */
+ writel_relaxed(hdr->cfg_version, rsc->base + GENI_INIT_CFG_REVISION);
+ writel_relaxed(hdr->cfg_version, rsc->base + GENI_S_INIT_CFG_REVISION);
+
+ /* Configure GENI primitive table. */
+ for (i = 0; i < hdr->cfg_size_in_items; i++)
+ writel_relaxed(cfg_val_arr[i],
+ rsc->base + GENI_CFG_REG0 + (cfg_idx_arr[i] * sizeof(u32)));
+
+ /* Configure condition for assertion of RX_RFR_WATERMARK condition. */
+ reg_value = readl_relaxed(rsc->base + QUPV3_SE_HW_PARAM_1);
+ mask = (reg_value >> RX_FIFO_WIDTH_BIT) & RX_FIFO_WIDTH_MASK;
+ writel_relaxed(mask - 2, rsc->base + GENI_RX_RFR_WATERMARK_REG);
+
+ /* Let hardware control CGC */
+ geni_setbits32(rsc->base + GENI_OUTPUT_CTRL, DEFAULT_IO_OUTPUT_CTRL_MSK);
+
+ ret = geni_configure_xfer_mode(rsc);
+ if (ret) {
+ dev_err(rsc->dev, "failed to configure xfer mode: %d\n", ret);
+ return ret;
+ }
+
+ geni_enable_interrupts(rsc);
+
+ geni_flash_fw_revision(rsc, hdr);
+
+ ramn_cnt = hdr->fw_size_in_items;
+ if (hdr->fw_size_in_items % 2 != 0)
+ ramn_cnt++;
+
+ if (ramn_cnt >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(rsc->dev, "firmware size is too large\n");
+ return -EINVAL;
+ }
+
+ /* Program RAM address space. */
+ for (i = 0; i < hdr->fw_size_in_items; i++)
+ writel_relaxed(fw_val_arr[i], rsc->base + SE_GENI_CFG_RAMN + i * sizeof(u32));
+
+ /* Put default values on GENI's output pads. */
+ writel_relaxed(0x1, rsc->base + GENI_FORCE_DEFAULT_REG);
+
+ /* High to low SCLK and HCLK to finish RAM. */
+ geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+ geni_setbits32(rsc->base + SE_GENI_CLK_CTRL, GENI_CLK_CTRL_SER_CLK_SEL_BMSK);
+ geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+
+ /* Serial engine DMA interface is enabled. */
+ geni_setbits32(rsc->base + SE_DMA_IF_EN, DMA_IF_EN_DMA_IF_EN_BMSK);
+
+ /* Enable or disable FIFO interface of the serial engine. */
+ if (rsc->mode == GENI_SE_FIFO)
+ geni_clrbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE);
+ else
+ geni_setbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE);
+
+ return 0;
+}
+
+/**
+ * elf_phdr_valid() - Validate an ELF header.
+ * @phdr: Pointer to the ELF header.
+ *
+ * Validate the ELF header by comparing the fields stored in p_flags and the payload type.
+ *
+ * Return: true if the validation is successful, false otherwise.
+ */
+static bool elf_phdr_valid(const Elf32_Phdr *phdr)
+{
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ return false;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) == MI_PBT_NON_PAGED_SEGMENT &&
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) != MI_PBT_HASH_SEGMENT &&
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) != MI_PBT_NOTUSED_SEGMENT &&
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) != MI_PBT_SHARED_SEGMENT)
+ return true;
+
+ return false;
+}
+
+/**
+ * valid_seg_size() - Validate the segment size.
+ * @pelfseg: Pointer to the ELF header.
+ * @p_filesz: Pointer to the file size.
+ *
+ * Validate the ELF segment size by comparing the file size.
+ *
+ * Return: true if the segment is valid, false if the segment is invalid.
+ */
+static bool valid_seg_size(struct elf_se_hdr *pelfseg, Elf32_Word p_filesz)
+{
+ if (p_filesz >= pelfseg->fw_offset + pelfseg->fw_size_in_items * sizeof(u32) &&
+ p_filesz >= pelfseg->cfg_idx_offset + pelfseg->cfg_size_in_items * sizeof(u8) &&
+ p_filesz >= pelfseg->cfg_val_offset + pelfseg->cfg_size_in_items * sizeof(u32))
+ return true;
+ return false;
+}
+
+/**
+ * read_elf() - Read an ELF file.
+ * @rsc: Pointer to the SE resources structure.
+ * @fw: Pointer to the firmware buffer.
+ * @pelfseg: Pointer to the SE-specific ELF header.
+ * @phdr: Pointer to one of the valid headers from the list in the firmware buffer.
+ *
+ * Read the ELF file and output a pointer to the header data, which contains the firmware data and
+ * any other details.
+ *
+ * Return: 0 if successful, otherwise return an error value.
+ */
+static int read_elf(struct qup_se_rsc *rsc, const void *fw,
+ struct elf_se_hdr **pelfseg)
+{
+ Elf32_Phdr *phdr;
+ const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)fw;
+ Elf32_Phdr *phdrs = (Elf32_Phdr *)(ehdr + 1);
+ const u8 *addr;
+ int i;
+
+ ehdr = (Elf32_Ehdr *)fw;
+
+ if (ehdr->e_phnum < 2)
+ return -EINVAL;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+ if (!elf_phdr_valid(phdr))
+ continue;
+
+ if (phdr->p_filesz >= sizeof(struct elf_se_hdr)) {
+ addr = fw + phdr->p_offset;
+ *pelfseg = (struct elf_se_hdr *)addr;
+
+ if ((*pelfseg)->magic == MAGIC_NUM_SE &&
+ (*pelfseg)->version == 1 &&
+ valid_seg_size(*pelfseg, phdr->p_filesz) &&
+ (*pelfseg)->serial_protocol == rsc->protocol &&
+ (*pelfseg)->serial_protocol != GENI_SE_NONE)
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+int qcom_geni_load_firmware(phys_addr_t qup_base,
+ struct udevice *dev)
+{
+ struct qup_se_rsc rsc;
+ struct elf_se_hdr *hdr;
+ int ret;
+ void *fw;
+
+ rsc.dev = dev;
+ rsc.base = qup_base;
+ rsc.wrapper_base = dev_read_addr(dev->parent);
+
+ /* FIXME: GSI DMA mode if device has property qcom,gsi-dma-allowed */
+ rsc.mode = GENI_SE_FIFO;
+
+ switch (device_get_uclass_id(dev)) {
+ case UCLASS_I2C:
+ rsc.protocol = GENI_SE_I2C;
+ break;
+ case UCLASS_SPI:
+ rsc.protocol = GENI_SE_SPI;
+ break;
+ case UCLASS_SERIAL:
+ rsc.protocol = GENI_SE_UART;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* The firmware blob is the private data of the GENI wrapper (parent) */
+ fw = dev_get_priv(dev->parent);
+
+ ret = read_elf(&rsc, fw, &hdr);
+ if (ret) {
+ dev_err(dev, "Failed to read ELF: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "Loading QUP firmware...\n");
+
+ return load_se_firmware(&rsc, hdr);
+}
+
+/*
+ * We need to determine if firmware loading is necessary. Best way to do that is to check the FW
+ * revision of each QUP and see if it has already been loaded.
+ */
+static int geni_se_of_to_plat(struct udevice *dev)
+{
+ ofnode child;
+ struct resource res;
+ u32 proto;
+ struct geni_se_plat *plat = dev_get_plat(dev);
+
+ plat->need_firmware_load = false;
+
+ dev_for_each_subnode(child, dev) {
+ if (!ofnode_is_enabled(child))
+ continue;
+
+ if (ofnode_read_resource(child, 0, &res))
+ continue;
+
+ proto = readl(res.start + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+
+ if (proto == GENI_SE_INVALID_PROTO) {
+ plat->need_firmware_load = true;
+ } else {
+ /* Bind any devices that don't need firmware loading now. */
+ lists_bind_fdt(dev, child, NULL, NULL, false);
+ }
+ }
+
+ return 0;
+}
+
+#define QUPFW_PART_TYPE_GUID "21d1219f-2ed1-4ab4-930a-41a16ae75f7f"
+
+static int find_qupfw_part(struct udevice **blk_dev, struct disk_partition *part_info)
+{
+ struct blk_desc *desc;
+ int ret, partnum;
+
+ uclass_foreach_dev_probe(UCLASS_BLK, *blk_dev) {
+ if (device_get_uclass_id(*blk_dev) != UCLASS_BLK)
+ continue;
+
+ desc = dev_get_uclass_plat(*blk_dev);
+ if (!desc || desc->part_type == PART_TYPE_UNKNOWN)
+ continue;
+ for (partnum = 1;; partnum++) {
+ ret = part_get_info(desc, partnum, part_info);
+ if (ret)
+ break;
+ if (!strcmp(part_info->type_guid, QUPFW_PART_TYPE_GUID))
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int probe_children_load_firmware(struct udevice *dev)
+{
+ struct geni_se_plat *plat;
+ ofnode child;
+ struct udevice *child_dev;
+ struct resource res;
+ u32 proto;
+
+ plat = dev_get_plat(dev);
+
+ dev_for_each_subnode(child, dev) {
+ if (!ofnode_is_enabled(child))
+ continue;
+
+ if (ofnode_read_resource(child, 0, &res))
+ continue;
+
+ proto = readl(res.start + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+
+ if (proto != GENI_SE_INVALID_PROTO)
+ continue;
+
+ /*
+ * Now we're ready, bind and probe the child, this will trigger firmware loading.
+ */
+ lists_bind_fdt(dev, child, &child_dev, NULL, false);
+ debug("Probing child %s for fw loading\n", child_dev->name);
+ device_probe(child_dev);
+ }
+
+ return 0;
+}
+
+#define MAX_FW_BUF_SIZE (128 * 1024)
+
+/*
+ * Load firmware for QCOM GENI peripherals from the dedicated partition on storage and bind/probe
+ * all the peripheral devices that need firmware to be loaded.
+ */
+static int qcom_geni_fw_initialise(void)
+{
+ debug("Loading firmware for QCOM GENI SE\n");
+ struct udevice *geni_wrapper, *blk_dev;
+ struct disk_partition part_info;
+ int ret;
+ void *fw_buf;
+ size_t fw_size = MAX_FW_BUF_SIZE;
+ struct geni_se_plat *plat;
+
+ /* Find the first GENI SE wrapper that needs fw loading */
+ for (uclass_first_device(UCLASS_MISC, &geni_wrapper);
+ geni_wrapper;
+ uclass_next_device(&geni_wrapper)) {
+ if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC &&
+ !strcmp(geni_wrapper->driver->name, "geni-se-qup")) {
+ plat = dev_get_plat(geni_wrapper);
+ if (plat->need_firmware_load)
+ break;
+ }
+ }
+ if (!geni_wrapper) {
+ pr_err("GENI SE wrapper not found\n");
+ return 0;
+ }
+
+ ret = find_qupfw_part(&blk_dev, &part_info);
+ if (ret) {
+ pr_err("QUP firmware partition not found\n");
+ return 0;
+ }
+
+ if (part_info.size * part_info.blksz > MAX_FW_BUF_SIZE) {
+ pr_err("Firmware partition too large\n");
+ return -EINVAL;
+ }
+ fw_size = part_info.size * part_info.blksz;
+
+ fw_buf = malloc(fw_size);
+ if (!fw_buf) {
+ pr_err("Failed to allocate buffer for firmware\n");
+ return -ENOMEM;
+ }
+ memset(fw_buf, 0, fw_size);
+
+ ret = blk_read(blk_dev, part_info.start, part_info.size, fw_buf);
+ if (ret < 0) {
+ pr_err("Failed to read firmware from partition\n");
+ free(fw_buf);
+ return 0;
+ }
+
+ /*
+ * OK! Firmware is loaded, now bind and probe remaining children. They will attempt to load
+ * firmware during probe. Do this for each GENI SE wrapper that needs firmware loading.
+ */
+ for (; geni_wrapper;
+ uclass_next_device(&geni_wrapper)) {
+ if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC &&
+ !strcmp(geni_wrapper->driver->name, "geni-se-qup")) {
+ plat = dev_get_plat(geni_wrapper);
+ if (plat->need_firmware_load) {
+ dev_set_priv(geni_wrapper, fw_buf);
+ probe_children_load_firmware(geni_wrapper);
+ }
+ }
+ }
+
+ return 0;
+}
+
+EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qcom_geni_fw_initialise);
+
+static const struct udevice_id geni_ids[] = {
+ { .compatible = "qcom,geni-se-qup" },
+ {}
+};
+
+U_BOOT_DRIVER(sifive_otp) = {
+ .name = "geni-se-qup",
+ .id = UCLASS_MISC,
+ .of_match = geni_ids,
+ .of_to_plat = geni_se_of_to_plat,
+ .plat_auto = sizeof(struct geni_se_plat),
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 589b526381ffceb40913b7a304e277b6c9a8fdfd..fec3bee7522396704f27eb8ca40988523cba568c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1003,8 +1003,9 @@ config MSM_SERIAL
Single baudrate is supported in current implementation (115200).
config MSM_GENI_SERIAL
bool "Qualcomm on-chip GENI UART"
+ depends on QCOM_GENI
help
Support UART based on Generic Interface (GENI) Serial Engine (SE),
used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs
with Qualcomm Universal Peripheral (QUP) Wrapper cores,
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index 620cb9a59343bd50df639dd342271f1da19d9cee..35e0029144be7948eb5ab0da5a2d1317a08fb0c5 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -602,21 +602,8 @@ U_BOOT_DRIVER(serial_msm_geni) = {
.ops = &msm_serial_ops,
.flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
};
-static const struct udevice_id geniqup_ids[] = {
- { .compatible = "qcom,geni-se-qup" },
- { }
-};
-
-U_BOOT_DRIVER(geni_se_qup) = {
- .name = "geni-se-qup",
- .id = UCLASS_NOP,
- .of_match = geniqup_ids,
- .bind = dm_scan_fdt_dev,
- .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
-};
-
#ifdef CONFIG_DEBUG_UART_MSM_GENI
static struct msm_serial_data init_serial_data = {
.base = CONFIG_VAL(DEBUG_UART_BASE)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 9bdfc4c892043b705a70198790c07c122c40b75c..a8efbd74c7af5316132c2a121f7b5305545e4e5c 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -431,9 +431,9 @@ config SPI_QUP
data path from 4 bits to 32 bits and numerous protocol variants.
config SPI_GENI_QCOM
bool "Qualcomm Generic Interface (GENI) SPI controller"
- depends on ARCH_SNAPDRAGON
+ depends on ARCH_SNAPDRAGON && QCOM_GENI
help
Support for the Qualcomm Generic Interface (GENI) SPI controller.
The Generic Interface (GENI) is a firmware based Qualcomm Universal
Peripherals (QUP) Serial Engine (SE) Wrapper which can support multiple
diff --git a/include/soc/qcom/geni-se.h b/include/soc/qcom/geni-se.h
index 698a9256d2656d3fd207cb48a9f4918afc365a1b..fc9a8e82cd88a63cd50dcfb0647fa28b53adad37 100644
--- a/include/soc/qcom/geni-se.h
+++ b/include/soc/qcom/geni-se.h
@@ -5,16 +5,24 @@
#ifndef _QCOM_GENI_SE
#define _QCOM_GENI_SE
+enum geni_se_xfer_mode {
+ GENI_SE_INVALID,
+ GENI_SE_FIFO,
+ GENI_SE_DMA,
+ GENI_GPI_DMA,
+};
+
/* Protocols supported by GENI Serial Engines */
enum geni_se_protocol_type {
GENI_SE_NONE,
GENI_SE_SPI,
GENI_SE_UART,
GENI_SE_I2C,
GENI_SE_I3C,
GENI_SE_SPI_SLAVE,
+ GENI_SE_INVALID_PROTO = 255,
};
#define QUP_HW_VER_REG 0x4
@@ -28,8 +36,9 @@ enum geni_se_protocol_type {
#define GENI_SER_M_CLK_CFG 0x48
#define GENI_SER_S_CLK_CFG 0x4c
#define GENI_IF_DISABLE_RO 0x64
#define GENI_FW_REVISION_RO 0x68
+#define GENI_DFS_IF_CFG 0x80
#define SE_GENI_CLK_SEL 0x7c
#define SE_GENI_CFG_SEQ_START 0x84
#define SE_GENI_BYTE_GRAN 0x254
#define SE_GENI_DMA_MODE_EN 0x258
@@ -56,17 +65,26 @@ enum geni_se_protocol_type {
#define SE_GENI_RX_RFR_WATERMARK_REG 0x814
#define SE_GENI_IOS 0x908
#define SE_DMA_TX_IRQ_STAT 0xc40
#define SE_DMA_TX_IRQ_CLR 0xc44
+#define SE_DMA_TX_IRQ_EN_SET 0xc4c
#define SE_DMA_TX_FSM_RST 0xc58
#define SE_DMA_RX_IRQ_STAT 0xd40
#define SE_DMA_RX_IRQ_CLR 0xd44
+#define SE_DMA_RX_IRQ_EN_SET 0xd4c
#define SE_DMA_RX_LEN_IN 0xd54
#define SE_DMA_RX_FSM_RST 0xd58
#define SE_GSI_EVENT_EN 0xe18
#define SE_IRQ_EN 0xe1c
#define SE_HW_PARAM_0 0xe24
#define SE_HW_PARAM_1 0xe28
+#define SE_DMA_GENERAL_CFG 0xe30
+
+/* GENI_DFS_IF_CFG fields */
+#define DFS_IF_EN BIT(0)
+
+/* SE_DMA_RX_IRQ_EN_SET fields */
+#define RESET_DONE_EN_SET BIT(3)
/* GENI_FORCE_DEFAULT_REG fields */
#define FORCE_DEFAULT BIT(0)
@@ -261,5 +279,23 @@ enum geni_se_protocol_type {
/* QUP SE VERSION value for major number 2 and minor number 5 */
#define QUP_SE_VERSION_2_5 0x20050000
+/* SE_DMA_GENERAL_CFG */
+#define DMA_RX_CLK_CGC_ON BIT(0)
+#define DMA_TX_CLK_CGC_ON BIT(1)
+#define DMA_AHB_SLV_CFG_ON BIT(2)
+#define AHB_SEC_SLV_CLK_CGC_ON BIT(3)
+#define DUMMY_RX_NON_BUFFERABLE BIT(4)
+#define RX_DMA_ZERO_PADDING_EN BIT(5)
+#define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6)
+#define RX_DMA_IRQ_DELAY_SHFT 6
+
+#define GENI_SE_DMA_DONE_EN BIT(0)
+#define GENI_SE_DMA_EOT_EN BIT(1)
+#define GENI_SE_DMA_AHB_ERR_EN BIT(2)
+
+#define GENI_SE_DMA_EOT_BUF BIT(0)
+
+#define GENI_DMA_MODE_EN BIT(0)
+
#endif
diff --git a/include/soc/qcom/qup-fw-load.h b/include/soc/qcom/qup-fw-load.h
new file mode 100644
index 0000000000000000000000000000000000000000..a67a93c72a4b705eff5bd29b185a4172c19ae1d7
--- /dev/null
+++ b/include/soc/qcom/qup-fw-load.h
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#ifndef _LINUX_QCOM_QUP_FW_LOAD
+#define _LINUX_QCOM_QUP_FW_LOAD
+
+#include <linux/kernel.h>
+
+/*Magic numbers*/
+#define MAGIC_NUM_SE 0x57464553
+
+/* Common SE registers*/
+#define GENI_INIT_CFG_REVISION 0x0
+#define GENI_S_INIT_CFG_REVISION 0x4
+#define GENI_FORCE_DEFAULT_REG 0x20
+#define GENI_CGC_CTRL 0x28
+#define GENI_CFG_REG0 0x100
+
+#define QUPV3_SE_HW_PARAM_1 0xE28
+#define RX_FIFO_WIDTH_BIT 24
+#define RX_FIFO_WIDTH_MASK 0x3F
+
+/*Same registers as GENI_DMA_MODE_EN*/
+#define QUPV3_SE_GENI_DMA_MODE_EN 0x258
+#define GENI_M_IRQ_ENABLE 0x614
+#define GENI_S_IRQ_ENABLE 0x644
+#define GENI_RX_RFR_WATERMARK_REG 0x814
+#define DMA_TX_IRQ_EN_SET 0xC4C
+#define DMA_RX_IRQ_EN_SET 0xD4C
+#define DMA_GENERAL_CFG 0xE30
+#define SE_GENI_FW_REVISION 0x1000
+#define SE_S_FW_REVISION 0x1004
+#define SE_GENI_CFG_RAMN 0x1010
+#define SE_GENI_CLK_CTRL 0x2000
+#define SE_DMA_IF_EN 0x2004
+#define SE_FIFO_IF_DISABLE 0x2008
+
+#define MAX_GENI_CFG_RAMn_CNT 455
+
+#define MI_PBT_NON_PAGED_SEGMENT 0x0
+#define MI_PBT_HASH_SEGMENT 0x2
+#define MI_PBT_NOTUSED_SEGMENT 0x3
+#define MI_PBT_SHARED_SEGMENT 0x4
+#define MI_PBT_FLAG_PAGE_MODE_MASK 0x100000
+#define MI_PBT_FLAG_PAGE_MODE_SHIFT 0x14
+#define MI_PBT_FLAG_SEGMENT_TYPE_MASK 0x7000000
+#define MI_PBT_FLAG_SEGMENT_TYPE_SHIFT 0x18
+#define MI_PBT_FLAG_ACCESS_TYPE_MASK 0xE00000
+#define MI_PBT_FLAG_ACCESS_TYPE_SHIFT 0x15
+
+#define MI_PBT_PAGE_MODE_VALUE(x) \
+ (((x) & MI_PBT_FLAG_PAGE_MODE_MASK) >> \
+ MI_PBT_FLAG_PAGE_MODE_SHIFT)
+
+#define MI_PBT_SEGMENT_TYPE_VALUE(x) \
+ (((x) & MI_PBT_FLAG_SEGMENT_TYPE_MASK) >> \
+ MI_PBT_FLAG_SEGMENT_TYPE_SHIFT)
+
+#define MI_PBT_ACCESS_TYPE_VALUE(x) \
+ (((x) & MI_PBT_FLAG_ACCESS_TYPE_MASK) >> \
+ MI_PBT_FLAG_ACCESS_TYPE_SHIFT)
+
+/* GENI_FORCE_DEFAULT_REG fields */
+#define FORCE_DEFAULT BIT(0)
+
+/* FW_REVISION_RO fields */
+#define FW_REV_PROTOCOL_SHFT 8
+#define FW_REV_VERSION_SHFT 0
+
+#define GENI_FW_REVISION_RO 0x68
+#define GENI_S_FW_REVISION_RO 0x6C
+
+/* SE_GENI_DMA_MODE_EN */
+#define GENI_DMA_MODE_EN BIT(0)
+
+/* GENI_M_IRQ_EN fields */
+#define M_CMD_DONE_EN BIT(0)
+#define M_IO_DATA_DEASSERT_EN BIT(22)
+#define M_IO_DATA_ASSERT_EN BIT(23)
+#define M_RX_FIFO_RD_ERR_EN BIT(24)
+#define M_RX_FIFO_WR_ERR_EN BIT(25)
+#define M_RX_FIFO_WATERMARK_EN BIT(26)
+#define M_RX_FIFO_LAST_EN BIT(27)
+#define M_TX_FIFO_RD_ERR_EN BIT(28)
+#define M_TX_FIFO_WR_ERR_EN BIT(29)
+#define M_TX_FIFO_WATERMARK_EN BIT(30)
+#define M_COMMON_GENI_M_IRQ_EN (GENMASK(6, 1) | \
+ M_IO_DATA_DEASSERT_EN | \
+ M_IO_DATA_ASSERT_EN | M_RX_FIFO_RD_ERR_EN | \
+ M_RX_FIFO_WR_ERR_EN | M_TX_FIFO_RD_ERR_EN | \
+ M_TX_FIFO_WR_ERR_EN)
+
+/* GENI_S_IRQ_EN fields */
+#define S_CMD_OVERRUN_EN BIT(1)
+#define S_ILLEGAL_CMD_EN BIT(2)
+#define S_CMD_CANCEL_EN BIT(4)
+#define S_CMD_ABORT_EN BIT(5)
+#define S_GP_IRQ_0_EN BIT(9)
+#define S_GP_IRQ_1_EN BIT(10)
+#define S_GP_IRQ_2_EN BIT(11)
+#define S_GP_IRQ_3_EN BIT(12)
+#define S_RX_FIFO_RD_ERR_EN BIT(24)
+#define S_RX_FIFO_WR_ERR_EN BIT(25)
+#define S_COMMON_GENI_S_IRQ_EN (GENMASK(5, 1) | GENMASK(13, 9) | \
+ S_RX_FIFO_RD_ERR_EN | S_RX_FIFO_WR_ERR_EN)
+
+#define GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK 0x00000200
+#define GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK 0x00000100
+
+#define GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK 0x00000001
+
+#define DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK 0x00000008
+#define DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK 0x00000004
+#define DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK 0x00000001
+
+#define DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK 0x00000010
+#define DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK 0x00000008
+#define DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK 0x00000004
+#define DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK 0x00000001
+
+#define DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK 0x00000008
+#define DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK 0x00000004
+#define DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK 0x00000002
+#define DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK 0x00000001
+
+#define GENI_CLK_CTRL_SER_CLK_SEL_BMSK 0x00000001
+#define DMA_IF_EN_DMA_IF_EN_BMSK 0x00000001
+#define SE_GSI_EVENT_EN_BMSK 0x0000000f
+#define SE_IRQ_EN_RMSK 0x0000000f
+
+#define QUPV3_COMMON_CFG 0x0120
+#define FAST_SWITCH_TO_HIGH_DISABLE_BMASK 0x00000001
+
+#define QUPV3_SE_AHB_M_CFG 0x0118
+#define AHB_M_CLK_CGC_ON_BMASK 0x00000001
+
+#define QUPV3_COMMON_CGC_CTRL 0x021C
+#define COMMON_CSR_SLV_CLK_CGC_ON_BMASK 0x00000001
+
+/* access ports */
+#define geni_setbits32(_addr, _v) writel_relaxed(readl_relaxed(_addr) | (_v), (_addr))
+#define geni_clrbits32(_addr, _v) writel_relaxed(readl_relaxed(_addr) & ~(_v), (_addr))
+
+/**
+ * struct elf_se_hdr - firmware configurations
+ *
+ * @magic: set to 'SEFW'
+ * @version: A 32-bit value indicating the structure’s version number
+ * @core_version: QUPV3_HW_VERSION
+ * @serial_protocol: Programmed into GENI_FW_REVISION
+ * @fw_version: Programmed into GENI_FW_REVISION
+ * @cfg_version: Programmed into GENI_INIT_CFG_REVISION
+ * @fw_size_in_items: Number of (uint32_t) GENI_FW_RAM words
+ * @fw_offset: Byte offset of GENI_FW_RAM array
+ * @cfg_size_in_items: Number of GENI_FW_CFG index/value pairs
+ * @cfg_idx_offset: Byte offset of GENI_FW_CFG index array
+ * @cfg_val_offset: Byte offset of GENI_FW_CFG values array
+ */
+struct elf_se_hdr {
+ u32 magic;
+ u32 version;
+ u32 core_version;
+ u16 serial_protocol;
+ u16 fw_version;
+ u16 cfg_version;
+ u16 fw_size_in_items;
+ u16 fw_offset;
+ u16 cfg_size_in_items;
+ u16 cfg_idx_offset;
+ u16 cfg_val_offset;
+};
+
+struct udevice;
+
+int qcom_geni_load_firmware(phys_addr_t qup_base, struct udevice *dev);
+
+#endif /* _LINUX_QCOM_QUP_FW_LOAD */
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 4/9] i2c: geni: load firmware if required
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
` (2 preceding siblings ...)
2025-06-16 9:44 ` [PATCH v4 3/9] misc: introduce Qcom GENI wrapper Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 5/9] clk/qcom: sc7280: add uart7 clocks Casey Connolly
` (4 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Load firmware for the peripheral if necessary.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
---
drivers/i2c/geni_i2c.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c
index 4eb41ba852f7790ca646c8ba38f29fdb727fa804..d29e00fdf41df1d7a95d8d9b3b98f784f5b2a3e1 100644
--- a/drivers/i2c/geni_i2c.c
+++ b/drivers/i2c/geni_i2c.c
@@ -21,8 +21,9 @@
#include <clk.h>
#include <reset.h>
#include <time.h>
#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
#define SE_I2C_TX_TRANS_LEN 0x26c
#define SE_I2C_RX_TRANS_LEN 0x270
#define SE_I2C_SCL_COUNTERS 0x278
@@ -498,8 +499,15 @@ static int geni_i2c_probe(struct udevice *dev)
proto = readl(geni->base + GENI_FW_REVISION_RO);
proto &= FW_REV_PROTOCOL_MSK;
proto >>= FW_REV_PROTOCOL_SHFT;
+ if (proto == GENI_SE_INVALID_PROTO) {
+ qcom_geni_load_firmware(geni->base, dev);
+ proto = readl(geni->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+ }
+
if (proto != GENI_SE_I2C) {
dev_err(dev, "Invalid proto %d\n", proto);
geni_i2c_disable_clocks(dev, geni);
return -ENXIO;
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 5/9] clk/qcom: sc7280: add uart7 clocks
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
` (3 preceding siblings ...)
2025-06-16 9:44 ` [PATCH v4 4/9] i2c: geni: load firmware if required Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 6/9] serial: msm-geni: implement firmware loading Casey Connolly
` (3 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Allow us to power up UART7 so we can load the QUP firmware, this is used
for bluetooth on RB3 Gen 2 and possibly other boards.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
drivers/clk/qcom/clock-sc7280.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index bf3c6c4ae647a46f7f96b10c0e3ed76a2f2ebee1..55a233df39450e511aebf7892214967c284a603e 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -67,8 +67,13 @@ static ulong sc7280_set_rate(struct clk *clk, ulong rate)
freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate);
clk_rcg_set_rate_mnd(priv->base, 0x17600,
freq->pre_div, freq->m, freq->n, freq->src, 16);
return freq->freq;
+ case GCC_QUPV3_WRAP0_S7_CLK: /* UART7 */
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, 0x17860,
+ freq->pre_div, freq->m, freq->n, freq->src, 16);
+ return freq->freq;
case GCC_USB30_PRIM_MASTER_CLK:
freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate);
clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
freq->pre_div, freq->m, freq->n, freq->src, 8);
@@ -128,8 +133,9 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)),
GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)),
GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)),
GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(15)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x52008, BIT(17)),
GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)),
GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)),
GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)),
GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7705c, BIT(0)),
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 6/9] serial: msm-geni: implement firmware loading
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
` (4 preceding siblings ...)
2025-06-16 9:44 ` [PATCH v4 5/9] clk/qcom: sc7280: add uart7 clocks Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port Casey Connolly
` (2 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Teach the GENI UART driver to load firmware, similar to i2c.
This is primarily intended for non-debug UARTs, but since we don't
support using these as the console we abort probe for now.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
drivers/serial/serial_msm_geni.c | 68 ++++++++++++++++++----------------------
1 file changed, 30 insertions(+), 38 deletions(-)
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index 35e0029144be7948eb5ab0da5a2d1317a08fb0c5..ad8b183edf5763486c9bd30be1458a1b332c2fee 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -9,22 +9,23 @@
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <errno.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <misc.h>
#include <serial.h>
+#include <soc/qcom/qup-fw-load.h>
+#include <soc/qcom/geni-se.h>
#define UART_OVERSAMPLING 32
#define STALE_TIMEOUT 160
/* Registers*/
#define GENI_FORCE_DEFAULT_REG 0x20
#define GENI_SER_M_CLK_CFG 0x48
-#define GENI_SER_S_CLK_CFG 0x4C
-#define SE_HW_PARAM_0 0xE24
#define SE_GENI_STATUS 0x40
#define SE_GENI_S_CMD0 0x630
#define SE_GENI_S_CMD_CTRL_REG 0x634
#define SE_GENI_S_IRQ_CLEAR 0x648
@@ -38,9 +39,8 @@
#define SE_GENI_TX_FIFOn 0x700
#define SE_GENI_RX_FIFOn 0x780
#define SE_GENI_TX_FIFO_STATUS 0x800
#define SE_GENI_RX_FIFO_STATUS 0x804
-#define SE_GENI_TX_WATERMARK_REG 0x80C
#define SE_GENI_TX_PACKING_CFG0 0x260
#define SE_GENI_TX_PACKING_CFG1 0x264
#define SE_GENI_RX_PACKING_CFG0 0x284
#define SE_GENI_RX_PACKING_CFG1 0x288
@@ -53,61 +53,26 @@
#define SE_UART_TX_PARITY_CFG 0x2a4
#define SE_UART_RX_TRANS_CFG 0x280
#define SE_UART_RX_PARITY_CFG 0x2a8
-#define M_TX_FIFO_WATERMARK_EN (BIT(30))
#define DEF_TX_WM 2
/* GENI_FORCE_DEFAULT_REG fields */
-#define FORCE_DEFAULT (BIT(0))
-
-#define S_CMD_ABORT_EN (BIT(5))
#define UART_START_READ 0x1
-/* GENI_M_CMD_CTRL_REG */
-#define M_GENI_CMD_CANCEL (BIT(2))
-#define M_GENI_CMD_ABORT (BIT(1))
-#define M_GENI_DISABLE (BIT(0))
-
-#define M_CMD_ABORT_EN (BIT(5))
-#define M_CMD_DONE_EN (BIT(0))
#define M_CMD_DONE_DISABLE_MASK (~M_CMD_DONE_EN)
-#define S_GENI_CMD_ABORT (BIT(1))
-
-/* GENI_S_CMD0 fields */
-#define S_OPCODE_MSK (GENMASK(31, 27))
-#define S_PARAMS_MSK (GENMASK(26, 0))
-
-/* GENI_STATUS fields */
-#define M_GENI_CMD_ACTIVE (BIT(0))
-#define S_GENI_CMD_ACTIVE (BIT(12))
-#define M_CMD_DONE_EN (BIT(0))
-#define S_CMD_DONE_EN (BIT(0))
-
#define M_OPCODE_SHIFT 27
#define S_OPCODE_SHIFT 27
-#define M_TX_FIFO_WATERMARK_EN (BIT(30))
#define UART_START_TX 0x1
#define UART_CTS_MASK (BIT(1))
-#define M_SEC_IRQ_EN (BIT(31))
#define TX_FIFO_WC_MSK (GENMASK(27, 0))
-#define RX_FIFO_WC_MSK (GENMASK(24, 0))
-
-#define S_RX_FIFO_WATERMARK_EN (BIT(26))
-#define S_RX_FIFO_LAST_EN (BIT(27))
-#define M_RX_FIFO_WATERMARK_EN (BIT(26))
-#define M_RX_FIFO_LAST_EN (BIT(27))
/* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */
-#define SER_CLK_EN (BIT(0))
-#define CLK_DIV_MSK (GENMASK(15, 4))
#define CLK_DIV_SHFT 4
/* SE_HW_PARAM_0 fields */
-#define TX_FIFO_WIDTH_MSK (GENMASK(29, 24))
#define TX_FIFO_WIDTH_SHFT 24
-#define TX_FIFO_DEPTH_MSK (GENMASK(21, 16))
#define TX_FIFO_DEPTH_SHFT 16
/* GENI SE QUP Registers */
#define QUP_HW_VER_REG 0x4
@@ -548,16 +513,42 @@ static inline void geni_serial_init(struct udevice *dev)
static int msm_serial_probe(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
int ret;
+ u32 proto;
struct clk *clk;
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
priv->se = clk;
+ /* Try enable clock */
ret = clk_enable(clk);
+
+ /* Check if firmware loading is needed (BT UART) */
+ proto = readl(priv->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+
+ if (proto == GENI_SE_INVALID_PROTO) {
+ qcom_geni_load_firmware(priv->base, dev);
+ proto = readl(priv->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+ }
+
+ if (proto != GENI_SE_UART) {
+ dev_err(dev, "Invalid proto %d\n", proto);
+ clk_disable(clk);
+ return -ENXIO;
+ }
+
+ /* Don't actually probe non-debug UARTs */
+ if (ofnode_device_is_compatible(dev_ofnode(dev), "qcom,geni-uart"))
+ return -ENOENT;
+
+ /* Now handle clock enable return value */
if (ret)
return ret;
ret = geni_set_oversampling(dev);
@@ -588,8 +579,9 @@ static int msm_serial_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id msm_serial_ids[] = {
{ .compatible = "qcom,geni-debug-uart" },
+ { .compatible = "qcom,geni-uart" },
{ }
};
U_BOOT_DRIVER(serial_msm_geni) = {
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
` (5 preceding siblings ...)
2025-06-16 9:44 ` [PATCH v4 6/9] serial: msm-geni: implement firmware loading Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-17 9:49 ` Sumit Garg
2025-06-16 9:44 ` [PATCH v4 8/9] spi: geni: load firmware if required Casey Connolly
2025-06-16 9:44 ` [PATCH v4 9/9] configs: qcom_*: enable QCOM_GENI where needed Casey Connolly
8 siblings, 1 reply; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts b/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
index 7a36c90ad4ec8b52f30b22b1621404857d6ef336..a9689f126cc7f94a01921fe2dc70efb83774610a 100644
--- a/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
+++ b/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
@@ -881,8 +881,25 @@
status = "okay";
};
+&usb_2 {
+ status = "okay";
+};
+
+&usb_2_dwc3 {
+ dr_mode = "peripheral";
+ /delete-property/ usb-role-switch;
+};
+
+&usb_2_hsphy {
+ vdda-pll-supply = <&vreg_l10c_0p88>;
+ vdda18-supply = <&vreg_l1c_1p8>;
+ vdda33-supply = <&vreg_l2b_3p072>;
+
+ status = "okay";
+};
+
&usb_dp_qmpphy_out {
remote-endpoint = <&redriver_phy_con_ss>;
};
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 8/9] spi: geni: load firmware if required
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
` (6 preceding siblings ...)
2025-06-16 9:44 ` [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 9/9] configs: qcom_*: enable QCOM_GENI where needed Casey Connolly
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Attempt to load GENI peripheral firmware if we don't have a protocol
loaded.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
drivers/spi/spi-geni-qcom.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 940f88115184992a088626fbb7053274f91cc3dd..48354c335385258bca95f637138ea7f4d6a30fef 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -17,8 +17,9 @@
#include <linux/err.h>
#include <linux/bitops.h>
#include <time.h>
#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
/* SPI SE specific registers and respective register fields */
#define SE_SPI_CPHA 0x224
#define CPHA BIT(0)
@@ -535,8 +536,15 @@ static int geni_spi_probe(struct udevice *dev)
proto = readl(priv->base + GENI_FW_REVISION_RO);
proto &= FW_REV_PROTOCOL_MSK;
proto >>= FW_REV_PROTOCOL_SHFT;
+ if (proto == GENI_SE_INVALID_PROTO) {
+ qcom_geni_load_firmware(priv->base, dev);
+ proto = readl(priv->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+ }
+
if (proto != GENI_SE_SPI) {
dev_err(dev, "Invalid proto %d\n", proto);
clk_disable(&priv->clk);
return -ENXIO;
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v4 9/9] configs: qcom_*: enable QCOM_GENI where needed
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
` (7 preceding siblings ...)
2025-06-16 9:44 ` [PATCH v4 8/9] spi: geni: load firmware if required Casey Connolly
@ 2025-06-16 9:44 ` Casey Connolly
8 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-16 9:44 UTC (permalink / raw)
To: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
Sumit Garg, Casey Connolly
Cc: u-boot, u-boot-qcom, Casey Connolly
Enable the GENI MISC driver which is required for many Qualcomm
platforms.
Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
---
configs/chromebook_trogdor_defconfig | 2 +-
configs/qcom_defconfig | 3 ++-
configs/qcom_ipq5424_mmc_defconfig | 2 ++
configs/qcom_ipq9574_mmc_defconfig | 2 ++
4 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/configs/chromebook_trogdor_defconfig b/configs/chromebook_trogdor_defconfig
index c90dc946494c7f1a25051da84b010e01bd4f9518..81853a6b86fb160021e4db775164311e2cdf8af5 100644
--- a/configs/chromebook_trogdor_defconfig
+++ b/configs/chromebook_trogdor_defconfig
@@ -74,9 +74,8 @@ CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_CMD_LOG=y
-CONFIG_PARTITION_TYPE_GUID=y
CONFIG_OF_LIVE=y
# CONFIG_OF_TAG_MIGRATE is not set
CONFIG_DM_WARN=y
# CONFIG_OFNODE_MULTI_TREE is not set
@@ -89,8 +88,9 @@ CONFIG_DM_I2C=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SYS_I2C_GENI=y
CONFIG_CROS_EC_KEYB=y
CONFIG_MISC=y
+CONFIG_QCOM_GENI=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_SPI=y
# CONFIG_MMC_PCI is not set
CONFIG_MMC_SDHCI_MSM=y
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
index 2afb930e103cac5801bea05f531f98ed046113a0..e53bd7fba484153e2334f1d2e016a173373b84c7 100644
--- a/configs/qcom_defconfig
+++ b/configs/qcom_defconfig
@@ -87,8 +87,9 @@ CONFIG_BUTTON_KEYBOARD=y
CONFIG_IOMMU=y
CONFIG_QCOM_HYP_SMMU=y
CONFIG_MISC=y
CONFIG_NVMEM=y
+CONFIG_QCOM_GENI=y
CONFIG_I2C_EEPROM=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ADMA=y
CONFIG_MMC_SDHCI_MSM=y
@@ -150,8 +151,8 @@ CONFIG_VIDEO=y
CONFIG_VIDEO_FONT_16X32=y
CONFIG_SYS_WHITE_ON_BLACK=y
CONFIG_NO_FB_CLEAR=y
CONFIG_VIDEO_SIMPLE=y
-CONFIG_WDT_QCOM=y
CONFIG_WDT=y
+CONFIG_WDT_QCOM=y
# CONFIG_BINMAN_FDT is not set
CONFIG_BINMAN_DTB="./arch/arm/dts/qcom-binman.dtb"
diff --git a/configs/qcom_ipq5424_mmc_defconfig b/configs/qcom_ipq5424_mmc_defconfig
index 81c3865193d73e3f1fc85bd342e3f1d25534c81d..cbd154f81c396b0b10c3c208efe52ff4077e0b54 100644
--- a/configs/qcom_ipq5424_mmc_defconfig
+++ b/configs/qcom_ipq5424_mmc_defconfig
@@ -34,8 +34,10 @@ CONFIG_CLK=y
CONFIG_CLK_QCOM_IPQ5424=y
CONFIG_MSM_GPIO=y
# CONFIG_I2C is not set
# CONFIG_INPUT is not set
+CONFIG_MISC=y
+CONFIG_QCOM_GENI=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ADMA=y
CONFIG_MMC_SDHCI_MSM=y
diff --git a/configs/qcom_ipq9574_mmc_defconfig b/configs/qcom_ipq9574_mmc_defconfig
index 00abc8430596dadd574d5d2b7353ecfdef01e2b4..a14129d1e9b96118503a7e9c9ef8bcf2559981a7 100644
--- a/configs/qcom_ipq9574_mmc_defconfig
+++ b/configs/qcom_ipq9574_mmc_defconfig
@@ -33,8 +33,10 @@ CONFIG_CLK=y
CONFIG_CLK_QCOM_IPQ9574=y
CONFIG_MSM_GPIO=y
# CONFIG_I2C is not set
# CONFIG_INPUT is not set
+CONFIG_MISC=y
+CONFIG_QCOM_GENI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ADMA=y
CONFIG_MMC_SDHCI_MSM=y
CONFIG_MTD=y
--
2.49.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig
2025-06-16 9:44 ` [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig Casey Connolly
@ 2025-06-16 16:21 ` Tom Rini
0 siblings, 0 replies; 13+ messages in thread
From: Tom Rini @ 2025-06-16 16:21 UTC (permalink / raw)
To: Casey Connolly
Cc: Heiko Schocher, Rayagonda Kokatanur, Neil Armstrong, Sumit Garg,
u-boot, u-boot-qcom
[-- Attachment #1: Type: text/plain, Size: 798 bytes --]
On Mon, Jun 16, 2025 at 11:44:43AM +0200, Casey Connolly wrote:
> Regenerate this defconfig since it seems to have been hand-made
> originally. Some options like SCSI were enabled in the defconfig but not
> in the final config, it seems like disabling SCSI is the correct thing
> here, so no functional changes.
>
> Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
> ---
> configs/qcom_ipq5424_mmc_defconfig | 67 ++++++++++++--------------------------
> 1 file changed, 21 insertions(+), 46 deletions(-)
This is fine to do, but also please note that generally I re-generate
all configs from time to time (nominally before each -rc, but I do
forget) so these errors are cleaned up over time. I assume this is
needed for a later part of the series, so JFYI.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port
2025-06-16 9:44 ` [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port Casey Connolly
@ 2025-06-17 9:49 ` Sumit Garg
2025-06-18 18:05 ` Casey Connolly
0 siblings, 1 reply; 13+ messages in thread
From: Sumit Garg @ 2025-06-17 9:49 UTC (permalink / raw)
To: Casey Connolly
Cc: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
u-boot, u-boot-qcom
Hi Casey,
On Mon, Jun 16, 2025 at 11:44:49AM +0200, Casey Connolly wrote:
> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> ---
> dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
I suppose this is an unrelated change to the patch-set and I don't think
this patch as it is applied upstream since the manual patch isn't
allowed for dts/upstream subtree. You can rather have a *-u-boot.dtsi
for this change.
-Sumit
>
> diff --git a/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts b/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
> index 7a36c90ad4ec8b52f30b22b1621404857d6ef336..a9689f126cc7f94a01921fe2dc70efb83774610a 100644
> --- a/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
> +++ b/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
> @@ -881,8 +881,25 @@
>
> status = "okay";
> };
>
> +&usb_2 {
> + status = "okay";
> +};
> +
> +&usb_2_dwc3 {
> + dr_mode = "peripheral";
> + /delete-property/ usb-role-switch;
> +};
> +
> +&usb_2_hsphy {
> + vdda-pll-supply = <&vreg_l10c_0p88>;
> + vdda18-supply = <&vreg_l1c_1p8>;
> + vdda33-supply = <&vreg_l2b_3p072>;
> +
> + status = "okay";
> +};
> +
> &usb_dp_qmpphy_out {
> remote-endpoint = <&redriver_phy_con_ss>;
> };
>
>
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port
2025-06-17 9:49 ` Sumit Garg
@ 2025-06-18 18:05 ` Casey Connolly
0 siblings, 0 replies; 13+ messages in thread
From: Casey Connolly @ 2025-06-18 18:05 UTC (permalink / raw)
To: Sumit Garg
Cc: Heiko Schocher, Tom Rini, Rayagonda Kokatanur, Neil Armstrong,
u-boot, u-boot-qcom
On 6/17/25 11:49, Sumit Garg wrote:
> Hi Casey,
>
> On Mon, Jun 16, 2025 at 11:44:49AM +0200, Casey Connolly wrote:
>> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
>> ---
>> dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts | 17 +++++++++++++++++
>> 1 file changed, 17 insertions(+)
>
> I suppose this is an unrelated change to the patch-set and I don't think
> this patch as it is applied upstream since the manual patch isn't
> allowed for dts/upstream subtree. You can rather have a *-u-boot.dtsi
> for this change.
oops, didn't mean to include this one in the series...
thanks for pointing that out>
> -Sumit
>
>>
>> diff --git a/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts b/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
>> index 7a36c90ad4ec8b52f30b22b1621404857d6ef336..a9689f126cc7f94a01921fe2dc70efb83774610a 100644
>> --- a/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
>> +++ b/dts/upstream/src/arm64/qcom/qcs6490-rb3gen2.dts
>> @@ -881,8 +881,25 @@
>>
>> status = "okay";
>> };
>>
>> +&usb_2 {
>> + status = "okay";
>> +};
>> +
>> +&usb_2_dwc3 {
>> + dr_mode = "peripheral";
>> + /delete-property/ usb-role-switch;
>> +};
>> +
>> +&usb_2_hsphy {
>> + vdda-pll-supply = <&vreg_l10c_0p88>;
>> + vdda18-supply = <&vreg_l1c_1p8>;
>> + vdda33-supply = <&vreg_l2b_3p072>;
>> +
>> + status = "okay";
>> +};
>> +
>> &usb_dp_qmpphy_out {
>> remote-endpoint = <&redriver_phy_con_ss>;
>> };
>>
>>
>> --
>> 2.49.0
>>
--
Casey (she/they)
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-06-18 18:05 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-16 9:44 [PATCH v4 0/9] Qualcomm: implement support for GENI firmware loading Casey Connolly
2025-06-16 9:44 ` [PATCH v4 1/9] configs: run savedefconfig on qcom_ipq5424_mmc_defconfig Casey Connolly
2025-06-16 16:21 ` Tom Rini
2025-06-16 9:44 ` [PATCH v4 2/9] i2c: geni: fix error message wording in clk_disable Casey Connolly
2025-06-16 9:44 ` [PATCH v4 3/9] misc: introduce Qcom GENI wrapper Casey Connolly
2025-06-16 9:44 ` [PATCH v4 4/9] i2c: geni: load firmware if required Casey Connolly
2025-06-16 9:44 ` [PATCH v4 5/9] clk/qcom: sc7280: add uart7 clocks Casey Connolly
2025-06-16 9:44 ` [PATCH v4 6/9] serial: msm-geni: implement firmware loading Casey Connolly
2025-06-16 9:44 ` [PATCH v4 7/9] WIP: rb3gen2: describe micro-usb port Casey Connolly
2025-06-17 9:49 ` Sumit Garg
2025-06-18 18:05 ` Casey Connolly
2025-06-16 9:44 ` [PATCH v4 8/9] spi: geni: load firmware if required Casey Connolly
2025-06-16 9:44 ` [PATCH v4 9/9] configs: qcom_*: enable QCOM_GENI where needed Casey Connolly
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.