mac80211: read alternative brcm fw names from DT

This patch is required for the Raspberry Pi Zero 2 W.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
This commit is contained in:
Stijn Tintel 2022-05-18 21:40:51 +03:00
parent 416d4483e8
commit a5526efde0

View File

@ -0,0 +1,205 @@
From 4e32024cbb14230af3048e249e84f8c2b25ce45a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 28 Oct 2021 15:03:16 +0100
Subject: [PATCH] brcmfmac: Read alternative firmware names from DT
Add the ability to load the names of alternative firmwares from the
Device Tree node. This permits separate firmwares for 43436s and 43438
and allows downstream firmwares to coexist with upstream.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
.../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 ++++++++++++++
.../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 +++
.../broadcom/brcm80211/brcmfmac/sdio.c | 47 +++++++++++++++++--
3 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index 2f7bc3a70c65..c2d6b8a22858 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -10,6 +10,7 @@
#include "debug.h"
#include "core.h"
#include "common.h"
+#include "firmware.h"
#include "of.h"
static int brcmf_of_get_country_codes(struct device *dev,
@@ -118,3 +119,38 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
sdio->oob_irq_nr = irq;
sdio->oob_irq_flags = irqf;
}
+
+struct brcmf_firmware_mapping *
+brcmf_of_fwnames(struct device *dev, u32 *fwname_count)
+{
+ struct device_node *np = dev->of_node;
+ struct brcmf_firmware_mapping *fwnames;
+ struct device_node *map_np, *fw_np;
+ int of_count;
+ int count = 0;
+
+ map_np = of_get_child_by_name(np, "firmwares");
+ of_count = of_get_child_count(map_np);
+ if (!of_count)
+ return NULL;
+
+ fwnames = devm_kcalloc(dev, of_count,
+ sizeof(struct brcmf_firmware_mapping),
+ GFP_KERNEL);
+
+ for_each_child_of_node(map_np, fw_np)
+ {
+ struct brcmf_firmware_mapping *cur = &fwnames[count];
+
+ if (of_property_read_u32(fw_np, "chipid", &cur->chipid) ||
+ of_property_read_u32(fw_np, "revmask", &cur->revmask))
+ continue;
+ cur->fw_base = of_get_property(fw_np, "fw_base", NULL);
+ if (cur->fw_base)
+ count++;
+ }
+
+ *fwname_count = count;
+
+ return count ? fwnames : NULL;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
index 10bf52253337..5b39a39812d0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
@@ -5,9 +5,16 @@
#ifdef CONFIG_OF
void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings);
+struct brcmf_firmware_mapping *
+brcmf_of_fwnames(struct device *dev, u32 *map_count);
#else
static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings)
{
}
+static struct brcmf_firmware_mapping *
+brcmf_of_fwnames(struct device *dev, u32 *map_count)
+{
+ return NULL;
+}
#endif /* CONFIG_OF */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 89de65d32ed5..88c08fee58f6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -35,6 +35,7 @@
#include "core.h"
#include "common.h"
#include "bcdc.h"
+#include "of.h"
#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
@@ -634,7 +635,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt");
/* per-board firmware binaries */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin");
-static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
+static const struct brcmf_firmware_mapping sdio_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4),
@@ -660,6 +661,9 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752)
};
+static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames;
+static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames);
+
#define TXCTL_CREDITS 2
static void pkt_align(struct sk_buff *p, int len, int align)
@@ -4151,7 +4155,7 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name,
}
fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
brcmf_sdio_fwnames,
- ARRAY_SIZE(brcmf_sdio_fwnames),
+ brcmf_sdio_fwnames_count,
fwnames, ARRAY_SIZE(fwnames));
if (!fwreq)
return -ENOMEM;
@@ -4207,6 +4211,9 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
#define BRCMF_SDIO_FW_CODE 0
#define BRCMF_SDIO_FW_NVRAM 1
+static struct brcmf_fw_request *
+brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus);
+
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
struct brcmf_fw_request *fwreq)
{
@@ -4222,6 +4229,22 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
+ if (err && brcmf_sdio_fwnames != sdio_fwnames) {
+ /* Try again with the standard firmware names */
+ brcmf_sdio_fwnames = sdio_fwnames;
+ brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames);
+ kfree(fwreq);
+ fwreq = brcmf_sdio_prepare_fw_request(bus);
+ if (!fwreq) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ err = brcmf_fw_get_firmwares(dev, fwreq,
+ brcmf_sdio_firmware_callback);
+ if (!err)
+ return;
+ }
+
if (err)
goto fail;
@@ -4430,7 +4453,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
brcmf_sdio_fwnames,
- ARRAY_SIZE(brcmf_sdio_fwnames),
+ brcmf_sdio_fwnames_count,
fwnames, ARRAY_SIZE(fwnames));
if (!fwreq)
return NULL;
@@ -4448,6 +4471,9 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
struct brcmf_sdio *bus;
struct workqueue_struct *wq;
struct brcmf_fw_request *fwreq;
+ struct brcmf_firmware_mapping *of_fwnames, *fwnames = NULL;
+ const int fwname_size = sizeof(struct brcmf_firmware_mapping);
+ u32 of_fw_count;
brcmf_dbg(TRACE, "Enter\n");
@@ -4530,6 +4556,21 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
brcmf_dbg(INFO, "completed!!\n");
+ of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count);
+ if (of_fwnames)
+ fwnames = devm_kcalloc(sdiodev->dev,
+ of_fw_count + brcmf_sdio_fwnames_count,
+ fwname_size, GFP_KERNEL);
+
+ if (fwnames) {
+ /* The array is scanned in order, so overrides come first */
+ memcpy(fwnames, of_fwnames, of_fw_count * fwname_size);
+ memcpy(fwnames + of_fw_count, sdio_fwnames,
+ brcmf_sdio_fwnames_count * fwname_size);
+ brcmf_sdio_fwnames = fwnames;
+ brcmf_sdio_fwnames_count += of_fw_count;
+ }
+
fwreq = brcmf_sdio_prepare_fw_request(bus);
if (!fwreq) {
ret = -ENOMEM;
--
2.30.2