mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			192 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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(-)
 | |
| 
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
 | |
| @@ -11,6 +11,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,
 | |
| @@ -175,3 +176,38 @@ void brcmf_of_probe(struct device *dev,
 | |
|  	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;
 | |
| +}
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
 | |
| @@ -5,9 +5,20 @@
 | |
|  #ifdef CONFIG_OF
 | |
|  void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
 | |
|  		    struct brcmf_mp_device *settings);
 | |
| +#ifdef CPTCFG_BRCMFMAC_SDIO
 | |
| +struct brcmf_firmware_mapping *
 | |
| +brcmf_of_fwnames(struct device *dev, u32 *map_count);
 | |
| +#endif
 | |
|  #else
 | |
|  static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
 | |
|  			   struct brcmf_mp_device *settings)
 | |
|  {
 | |
|  }
 | |
| +#ifdef CPTCFG_BRCMFMAC_SDIO
 | |
| +static struct brcmf_firmware_mapping *
 | |
| +brcmf_of_fwnames(struct device *dev, u32 *map_count)
 | |
| +{
 | |
| +	return NULL;
 | |
| +}
 | |
| +#endif
 | |
|  #endif /* CONFIG_OF */
 | |
| --- 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)
 | |
| @@ -632,7 +633,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "b
 | |
|  /* 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_mappi
 | |
|  	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)
 | |
| @@ -4201,6 +4205,9 @@ static const struct brcmf_bus_ops brcmf_
 | |
|  #define BRCMF_SDIO_FW_NVRAM	1
 | |
|  #define BRCMF_SDIO_FW_CLM	2
 | |
|  
 | |
| +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)
 | |
|  {
 | |
| @@ -4216,6 +4223,22 @@ static void brcmf_sdio_firmware_callback
 | |
|  
 | |
|  	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;
 | |
|  
 | |
| @@ -4426,7 +4449,7 @@ brcmf_sdio_prepare_fw_request(struct brc
 | |
|  
 | |
|  	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;
 | |
| @@ -4446,6 +4469,9 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
 | |
|  	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");
 | |
|  
 | |
| @@ -4528,6 +4554,21 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
 | |
|  
 | |
|  	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;
 |