From c8b144f2fcd99b46707afefdde727ee3fcac6d2a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Dec 2015 16:33:39 +0100 Subject: [PATCH] mt7603: implement firmware loading / start Signed-off-by: Felix Fietkau --- mt7603_mcu.c | 85 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/mt7603_mcu.c b/mt7603_mcu.c index 87dd6421..167bc2d0 100644 --- a/mt7603_mcu.c +++ b/mt7603_mcu.c @@ -65,7 +65,7 @@ __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd, int memset(txd, 0, hdrlen); txd->len = cpu_to_le16(skb->len); - if (cmd == MCU_CMD_FW_SCATTER) + if (cmd == -MCU_CMD_FW_SCATTER) txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW); else txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE); @@ -145,6 +145,45 @@ mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, MCU_Q_NA); } +static int +mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len) +{ + struct sk_buff *skb; + int ret = 0; + + while (len > 0) { + int cur_len = min_t(int, 4096 - 12, len); + + skb = mt7603_mcu_msg_alloc(dev, data, cur_len); + if (!skb) + return -ENOMEM; + + ret = __mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER, MCU_Q_NA, NULL); + if (ret) + break; + + data += cur_len; + len -= cur_len; + } + + return ret; +} + +static int +mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr) +{ + struct { + __le32 override; + __le32 addr; + } req = { + .override = cpu_to_le32(addr ? 1 : 0), + .addr = cpu_to_le32(addr), + }; + struct sk_buff *skb = mt7603_mcu_msg_alloc(dev, &req, sizeof(req)); + + return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_START_REQ, MCU_Q_NA); +} + static int mt7603_load_firmware(struct mt7603_dev *dev) { @@ -154,12 +193,15 @@ mt7603_load_firmware(struct mt7603_dev *dev) u32 val; int ret; - ret = request_firmware(&fw, MT7603_FIRMWARE_E1, dev->mt76.dev); + ret = request_firmware(&fw, MT7603_FIRMWARE_E2, dev->mt76.dev); if (ret) return ret; - if (!fw || !fw->data || fw->size < sizeof(*hdr)) - goto error; + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } hdr = (const struct mt7603_fw_trailer *) (fw->data + fw->size - sizeof(*hdr)); @@ -195,17 +237,40 @@ mt7603_load_firmware(struct mt7603_dev *dev) dl_len = le32_to_cpu(hdr->dl_len) + 4; ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len); - printk("init_download(%d): %d\n", dl_len, ret); + if (ret) { + dev_err(dev->mt76.dev, "Download request failed\n"); + goto out; + } + + ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len); + if (ret) { + dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); + goto out; + } + + ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start firmware\n"); + goto out; + } + + if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) { + dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n"); + ret = -EIO; + goto out; + } + + mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS); + + mt76_set(dev, MT_SCH_4, BIT(8)); + mt76_clear(dev, MT_SCH_4, BIT(8)); + + printk("firmware init done\n"); out: release_firmware(fw); return ret; - -error: - printk("Invalid firmware\n"); - release_firmware(fw); - return -ENOENT; } int mt7603_mcu_init(struct mt7603_dev *dev)