#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,
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;
+}
#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 */
#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)
}
static struct brcmf_fw_request *
-brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
+brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus,
+ const struct brcmf_firmware_mapping *fwmap,
+ int fwmap_count)
{
struct brcmf_fw_request *fwreq;
struct brcmf_fw_name fwnames[] = {
};
fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
- brcmf_sdio_fwnames,
- ARRAY_SIZE(brcmf_sdio_fwnames),
+ fwmap, fwmap_count,
fwnames, ARRAY_SIZE(fwnames));
if (!fwreq)
return NULL;
return fwreq;
}
+static void brcmf_sdio_of_firmware_callback(struct device *dev, int err,
+ struct brcmf_fw_request *fwreq)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiod->bus;
+
+ brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
+
+ if (err) {
+ /* Try again with the standard firmware names */
+ kfree(fwreq);
+ fwreq = brcmf_sdio_prepare_fw_request(bus,
+ brcmf_sdio_fwnames,
+ ARRAY_SIZE(brcmf_sdio_fwnames));
+ if (!fwreq) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ err = brcmf_fw_get_firmwares(sdiod->dev, fwreq,
+ brcmf_sdio_firmware_callback);
+ if (!err)
+ return;
+ }
+
+fail:
+ brcmf_sdio_firmware_callback(dev, err, fwreq);
+}
+
struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret;
struct brcmf_sdio *bus;
struct workqueue_struct *wq;
struct brcmf_fw_request *fwreq;
+ struct brcmf_firmware_mapping *of_fwnames;
+ u32 of_fwcount;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(INFO, "completed!!\n");
- fwreq = brcmf_sdio_prepare_fw_request(bus);
+ of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fwcount);
+
+ if (of_fwnames)
+ fwreq = brcmf_sdio_prepare_fw_request(bus, of_fwnames,
+ of_fwcount);
+ else
+ fwreq = brcmf_sdio_prepare_fw_request(bus, brcmf_sdio_fwnames,
+ ARRAY_SIZE(brcmf_sdio_fwnames));
+
if (!fwreq) {
ret = -ENOMEM;
goto fail;
}
ret = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
+ of_fwnames ?
+ brcmf_sdio_of_firmware_callback :
brcmf_sdio_firmware_callback);
if (ret != 0) {
brcmf_err("async firmware request failed: %d\n", ret);