Introduce support for the Qualcomm IPQ50xx SoC. This series adds support for the following components: - minimal boot support: GCC/pinctrl/watchdog/CPUFreq/SDI (upstreamed) - USB2 (upstreamed) - Thermal/Tsens - PCIe gen2 1&2-lane PHY and controller - PWM and PWM LED - QPIC SPI NAND controller - CMN PLL Block (provider of fixed rate clocks to GCC/ethernet/more.) - Ethernet: IPQ5018 Internal GE PHY (1 gbps) - Remoteproc MPD driver for IPQ5018 (2.4G) & QCN6122 (5/6G) Wifi Co-developed-by: Ziyang Huang <hzyitc@outlook.com> Signed-off-by: Ziyang Huang <hzyitc@outlook.com> Signed-off-by: George Moussalem <george.moussalem@outlook.com> Link: https://github.com/openwrt/openwrt/pull/17182 Signed-off-by: Robert Marko <robimarko@gmail.com>
164 lines
4.7 KiB
Diff
164 lines
4.7 KiB
Diff
From: George Moussalem <george.moussalem@outlook.com>
|
|
Date: Mon, 09 Dec 2024 09:59:38 +0400
|
|
Subject: [PATCH] remoteproc: qcom_q6v5_mpd: add support for passing v1 bootargs
|
|
|
|
On multi-PD platforms such as IPQ5018, boot args are passed to the root PD
|
|
run on the Q6 processor which in turn boots the user PDs for internal
|
|
(IPQ5018) and external wifi radios (such as QCN6122). These boot args
|
|
let the user PD process know details like what PCIE index, user PD ID, and
|
|
reset GPIO is used. These are otherwise hardcoded in the firmware.
|
|
|
|
Below is the structure expected of the version 1 boot args including the
|
|
default values hardcoded in the firmware for IPQ5018:
|
|
|
|
+------------+------+--------------+--------------+
|
|
| Argument | type | def val UPD2 | def val UPD3 |
|
|
+------------+------+--------------+--------------+
|
|
| PCIE Index | u32 | 0x02 (PCIE1) | 0x01 (PCIE0) |
|
|
| Length | u32 | 0x04 | 0x04 |
|
|
| User PD ID | u32 | 0x02 | 0x03 |
|
|
| Reset GPIO | u32 | 0x12 | 0x0f |
|
|
| Reserved 1 | u32 | 0x00 | 0x00 |
|
|
| Reserved 2 | u32 | 0x00 | 0x00 |
|
|
+------------+------+--------------+--------------+
|
|
|
|
On IPQ5018/QCN6122 boards, the default mapping is as follows:
|
|
|
|
+-> UPD1 ----> IPQ5018 Internal 2.4G Radio
|
|
/
|
|
/
|
|
Root PD +---> UPD2 ----> QCN6122 6G Radio on PCIE1 (if available)
|
|
\
|
|
\
|
|
+-> UPD3 ----> QCN6102 5G Radio on PCIE0
|
|
|
|
To support (future) boards with other mappings or control what UPD ID is
|
|
used, let's add support for passing boot args for more flexibility.
|
|
|
|
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
|
|
---
|
|
--- a/drivers/remoteproc/qcom_q6v5_mpd.c
|
|
+++ b/drivers/remoteproc/qcom_q6v5_mpd.c
|
|
@@ -42,7 +42,11 @@
|
|
#define UPD_BOOT_INFO_SMEM_SIZE 4096
|
|
#define UPD_BOOT_INFO_HEADER_TYPE 0x2
|
|
#define UPD_BOOT_INFO_SMEM_ID 507
|
|
-#define VERSION2 2
|
|
+
|
|
+enum q6_bootargs_version {
|
|
+ VERSION1 = 1,
|
|
+ VERSION2,
|
|
+};
|
|
|
|
/**
|
|
* struct userpd_boot_info_header - header of user pd bootinfo
|
|
@@ -94,6 +98,7 @@ struct userpd {
|
|
struct wcss_data {
|
|
u32 pasid;
|
|
bool share_upd_info_to_q6;
|
|
+ u8 bootargs_version;
|
|
};
|
|
|
|
/**
|
|
@@ -298,10 +303,13 @@ static void *q6_wcss_da_to_va(struct rpr
|
|
static int share_upd_bootinfo_to_q6(struct rproc *rproc)
|
|
{
|
|
int i, ret;
|
|
+ u32 rd_val;
|
|
size_t size;
|
|
u16 cnt = 0, version;
|
|
void *ptr;
|
|
+ u8 *bootargs_arr;
|
|
struct q6_wcss *wcss = rproc->priv;
|
|
+ struct device_node *np = wcss->dev->of_node;
|
|
struct userpd *upd;
|
|
struct userpd_boot_info upd_bootinfo = {0};
|
|
const struct firmware *fw;
|
|
@@ -323,10 +331,47 @@ static int share_upd_bootinfo_to_q6(stru
|
|
}
|
|
|
|
/*Version*/
|
|
- version = VERSION2;
|
|
+ version = (wcss->desc->bootargs_version) ? wcss->desc->bootargs_version : VERSION2;
|
|
memcpy_toio(ptr, &version, sizeof(version));
|
|
ptr += sizeof(version);
|
|
|
|
+ cnt = ret = of_property_count_u32_elems(np, "boot-args");
|
|
+ if (ret < 0) {
|
|
+ if (ret == -ENODATA) {
|
|
+ dev_err(wcss->dev, "failed to read boot args ret:%d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ cnt = 0;
|
|
+ }
|
|
+
|
|
+ /* No of elements */
|
|
+ memcpy_toio(ptr, &cnt, sizeof(u16));
|
|
+ ptr += sizeof(u16);
|
|
+
|
|
+ bootargs_arr = kzalloc(cnt, GFP_KERNEL);
|
|
+ if (!bootargs_arr) {
|
|
+ dev_err(wcss->dev, "failed to allocate memory\n");
|
|
+ return PTR_ERR(bootargs_arr);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < cnt; i++) {
|
|
+ ret = of_property_read_u32_index(np, "boot-args", i, &rd_val);
|
|
+ if (ret) {
|
|
+ dev_err(wcss->dev, "failed to read boot args\n");
|
|
+ kfree(bootargs_arr);
|
|
+ return ret;
|
|
+ }
|
|
+ bootargs_arr[i] = (u8)rd_val;
|
|
+ }
|
|
+
|
|
+ /* Copy bootargs */
|
|
+ memcpy_toio(ptr, bootargs_arr, cnt);
|
|
+ ptr += (cnt);
|
|
+
|
|
+ of_node_put(np);
|
|
+ kfree(bootargs_arr);
|
|
+ cnt = 0;
|
|
+
|
|
for (i = 0; i < ARRAY_SIZE(wcss->upd); i++)
|
|
if (wcss->upd[i])
|
|
cnt++;
|
|
@@ -382,12 +427,14 @@ static int q6_wcss_load(struct rproc *rp
|
|
|
|
/* Share user pd boot info to Q6 remote processor */
|
|
if (desc->share_upd_info_to_q6) {
|
|
- ret = share_upd_bootinfo_to_q6(rproc);
|
|
- if (ret) {
|
|
- dev_err(wcss->dev,
|
|
- "user pd boot info sharing with q6 failed %d\n",
|
|
- ret);
|
|
- return ret;
|
|
+ if (of_property_present(wcss->dev->of_node, "boot-args")) {
|
|
+ ret = share_upd_bootinfo_to_q6(rproc);
|
|
+ if (ret) {
|
|
+ dev_err(wcss->dev,
|
|
+ "user pd boot info sharing with q6 failed %d\n",
|
|
+ ret);
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -803,13 +850,15 @@ static int q6_wcss_remove(struct platfor
|
|
|
|
static const struct wcss_data q6_ipq5018_res_init = {
|
|
.pasid = MPD_WCNSS_PAS_ID,
|
|
- // .share_upd_info_to_q6 = true, /* Version 1 */
|
|
+ .share_upd_info_to_q6 = true,
|
|
+ .bootargs_version = VERSION1,
|
|
// .mdt_load_sec = qcom_mdt_load_pd_seg,
|
|
};
|
|
|
|
static const struct wcss_data q6_ipq5332_res_init = {
|
|
.pasid = MPD_WCNSS_PAS_ID,
|
|
.share_upd_info_to_q6 = true,
|
|
+ .bootargs_version = VERSION2,
|
|
};
|
|
|
|
static const struct wcss_data q6_ipq9574_res_init = {
|