mac80211: read alternative brcm fw names from DT
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / brcm / 865-brcmfmac-Read-alternative-firmware-names-from-DT.patch
1 From 4e32024cbb14230af3048e249e84f8c2b25ce45a Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.com>
3 Date: Thu, 28 Oct 2021 15:03:16 +0100
4 Subject: [PATCH] brcmfmac: Read alternative firmware names from DT
5
6 Add the ability to load the names of alternative firmwares from the
7 Device Tree node. This permits separate firmwares for 43436s and 43438
8 and allows downstream firmwares to coexist with upstream.
9
10 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
11 ---
12 .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 ++++++++++++++
13 .../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 +++
14 .../broadcom/brcm80211/brcmfmac/sdio.c | 47 +++++++++++++++++--
15 3 files changed, 87 insertions(+), 3 deletions(-)
16
17 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
18 index 2f7bc3a70c65..c2d6b8a22858 100644
19 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
20 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
21 @@ -10,6 +10,7 @@
22 #include "debug.h"
23 #include "core.h"
24 #include "common.h"
25 +#include "firmware.h"
26 #include "of.h"
27
28 static int brcmf_of_get_country_codes(struct device *dev,
29 @@ -118,3 +119,38 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
30 sdio->oob_irq_nr = irq;
31 sdio->oob_irq_flags = irqf;
32 }
33 +
34 +struct brcmf_firmware_mapping *
35 +brcmf_of_fwnames(struct device *dev, u32 *fwname_count)
36 +{
37 + struct device_node *np = dev->of_node;
38 + struct brcmf_firmware_mapping *fwnames;
39 + struct device_node *map_np, *fw_np;
40 + int of_count;
41 + int count = 0;
42 +
43 + map_np = of_get_child_by_name(np, "firmwares");
44 + of_count = of_get_child_count(map_np);
45 + if (!of_count)
46 + return NULL;
47 +
48 + fwnames = devm_kcalloc(dev, of_count,
49 + sizeof(struct brcmf_firmware_mapping),
50 + GFP_KERNEL);
51 +
52 + for_each_child_of_node(map_np, fw_np)
53 + {
54 + struct brcmf_firmware_mapping *cur = &fwnames[count];
55 +
56 + if (of_property_read_u32(fw_np, "chipid", &cur->chipid) ||
57 + of_property_read_u32(fw_np, "revmask", &cur->revmask))
58 + continue;
59 + cur->fw_base = of_get_property(fw_np, "fw_base", NULL);
60 + if (cur->fw_base)
61 + count++;
62 + }
63 +
64 + *fwname_count = count;
65 +
66 + return count ? fwnames : NULL;
67 +}
68 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
69 index 10bf52253337..5b39a39812d0 100644
70 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
71 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
72 @@ -5,9 +5,16 @@
73 #ifdef CONFIG_OF
74 void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
75 struct brcmf_mp_device *settings);
76 +struct brcmf_firmware_mapping *
77 +brcmf_of_fwnames(struct device *dev, u32 *map_count);
78 #else
79 static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
80 struct brcmf_mp_device *settings)
81 {
82 }
83 +static struct brcmf_firmware_mapping *
84 +brcmf_of_fwnames(struct device *dev, u32 *map_count)
85 +{
86 + return NULL;
87 +}
88 #endif /* CONFIG_OF */
89 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
90 index 89de65d32ed5..88c08fee58f6 100644
91 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
92 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
93 @@ -35,6 +35,7 @@
94 #include "core.h"
95 #include "common.h"
96 #include "bcdc.h"
97 +#include "of.h"
98
99 #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
100 #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
101 @@ -634,7 +635,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt");
102 /* per-board firmware binaries */
103 MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin");
104
105 -static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
106 +static const struct brcmf_firmware_mapping sdio_fwnames[] = {
107 BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
108 BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
109 BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4),
110 @@ -660,6 +661,9 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
111 BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752)
112 };
113
114 +static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames;
115 +static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames);
116 +
117 #define TXCTL_CREDITS 2
118
119 static void pkt_align(struct sk_buff *p, int len, int align)
120 @@ -4151,7 +4155,7 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name,
121 }
122 fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
123 brcmf_sdio_fwnames,
124 - ARRAY_SIZE(brcmf_sdio_fwnames),
125 + brcmf_sdio_fwnames_count,
126 fwnames, ARRAY_SIZE(fwnames));
127 if (!fwreq)
128 return -ENOMEM;
129 @@ -4207,6 +4211,9 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
130 #define BRCMF_SDIO_FW_CODE 0
131 #define BRCMF_SDIO_FW_NVRAM 1
132
133 +static struct brcmf_fw_request *
134 +brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus);
135 +
136 static void brcmf_sdio_firmware_callback(struct device *dev, int err,
137 struct brcmf_fw_request *fwreq)
138 {
139 @@ -4222,6 +4229,22 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
140
141 brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
142
143 + if (err && brcmf_sdio_fwnames != sdio_fwnames) {
144 + /* Try again with the standard firmware names */
145 + brcmf_sdio_fwnames = sdio_fwnames;
146 + brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames);
147 + kfree(fwreq);
148 + fwreq = brcmf_sdio_prepare_fw_request(bus);
149 + if (!fwreq) {
150 + err = -ENOMEM;
151 + goto fail;
152 + }
153 + err = brcmf_fw_get_firmwares(dev, fwreq,
154 + brcmf_sdio_firmware_callback);
155 + if (!err)
156 + return;
157 + }
158 +
159 if (err)
160 goto fail;
161
162 @@ -4430,7 +4453,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
163
164 fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
165 brcmf_sdio_fwnames,
166 - ARRAY_SIZE(brcmf_sdio_fwnames),
167 + brcmf_sdio_fwnames_count,
168 fwnames, ARRAY_SIZE(fwnames));
169 if (!fwreq)
170 return NULL;
171 @@ -4448,6 +4471,9 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
172 struct brcmf_sdio *bus;
173 struct workqueue_struct *wq;
174 struct brcmf_fw_request *fwreq;
175 + struct brcmf_firmware_mapping *of_fwnames, *fwnames = NULL;
176 + const int fwname_size = sizeof(struct brcmf_firmware_mapping);
177 + u32 of_fw_count;
178
179 brcmf_dbg(TRACE, "Enter\n");
180
181 @@ -4530,6 +4556,21 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
182
183 brcmf_dbg(INFO, "completed!!\n");
184
185 + of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count);
186 + if (of_fwnames)
187 + fwnames = devm_kcalloc(sdiodev->dev,
188 + of_fw_count + brcmf_sdio_fwnames_count,
189 + fwname_size, GFP_KERNEL);
190 +
191 + if (fwnames) {
192 + /* The array is scanned in order, so overrides come first */
193 + memcpy(fwnames, of_fwnames, of_fw_count * fwname_size);
194 + memcpy(fwnames + of_fw_count, sdio_fwnames,
195 + brcmf_sdio_fwnames_count * fwname_size);
196 + brcmf_sdio_fwnames = fwnames;
197 + brcmf_sdio_fwnames_count += of_fw_count;
198 + }
199 +
200 fwreq = brcmf_sdio_prepare_fw_request(bus);
201 if (!fwreq) {
202 ret = -ENOMEM;
203 --
204 2.30.2
205