From 00ae055ba00802ef9bccd787553fe02f89baafd3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Dec 2015 01:12:57 +0100 Subject: [PATCH] mt7603: add basic mcu bringup code (currently broken) Signed-off-by: Felix Fietkau --- mt7603.h | 4 ++ mt7603_dma.c | 2 +- mt7603_init.c | 3 ++ mt7603_mcu.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++ mt7603_mcu.h | 102 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 mt7603_mcu.h diff --git a/mt7603.h b/mt7603.h index a07f846e..f2f384de 100644 --- a/mt7603.h +++ b/mt7603.h @@ -38,6 +38,8 @@ struct mt7603_mcu { struct mt76_queue q_rx; u32 msg_seq; + + bool running; }; struct mt7603_dev { @@ -67,6 +69,8 @@ int mt7603_init_hardware(struct mt7603_dev *dev); int mt7603_dma_init(struct mt7603_dev *dev); void mt7603_dma_cleanup(struct mt7603_dev *dev); int mt7603_mcu_init(struct mt7603_dev *dev); +int mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt7603_txq_id qid, + struct sk_buff *skb); void mt7603_set_irq_mask(struct mt7603_dev *dev, u32 clear, u32 set); diff --git a/mt7603_dma.c b/mt7603_dma.c index f210a390..77b2e0c8 100644 --- a/mt7603_dma.c +++ b/mt7603_dma.c @@ -58,7 +58,7 @@ mt7603_dma_rx_fill(struct mt7603_dev *dev, struct mt76_queue *q) int mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt7603_txq_id qid, - struct sk_buff *skb, int cmd, int seq) + struct sk_buff *skb) { struct mt76_queue *q = &dev->q_tx[qid]; dma_addr_t addr; diff --git a/mt7603_init.c b/mt7603_init.c index c338effd..5bcb194b 100644 --- a/mt7603_init.c +++ b/mt7603_init.c @@ -37,6 +37,9 @@ int mt7603_init_hardware(struct mt7603_dev *dev) if (ret) return ret; + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + mt7603_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL); + ret = mt7603_mcu_init(dev); if (ret) return ret; diff --git a/mt7603_mcu.c b/mt7603_mcu.c index 34972773..547198fa 100644 --- a/mt7603_mcu.c +++ b/mt7603_mcu.c @@ -13,6 +13,7 @@ #include #include "mt7603.h" +#include "mt7603_mcu.h" struct mt7603_fw_trailer { char fw_ver[10]; @@ -20,11 +21,137 @@ struct mt7603_fw_trailer { __le32 dl_len; } __packed; +static struct sk_buff * +mt7603_mcu_msg_alloc(struct mt7603_dev *dev, const void *data, int len) +{ + struct sk_buff *skb; + + skb = alloc_skb(len + sizeof(struct mt7603_mcu_txd), GFP_KERNEL); + skb_reserve(skb, sizeof(struct mt7603_mcu_txd)); + memcpy(skb_put(skb, len), data, len); + + return skb; +} + +static struct sk_buff * +mt7603_mcu_get_response(struct mt7603_dev *dev, unsigned long expires) +{ + unsigned long timeout; + + if (!time_is_after_jiffies(expires)) + return NULL; + + timeout = expires - jiffies; + wait_event_timeout(dev->mcu.wait, !skb_queue_empty(&dev->mcu.res_q), + timeout); + return skb_dequeue(&dev->mcu.res_q); +} + +static int +__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd, int query, int *wait_seq) +{ + int hdrlen = dev->mcu.running ? sizeof(struct mt7603_mcu_txd) : 12; + struct mt7603_mcu_txd *txd; + u8 seq; + + if (!skb) + return -EINVAL; + + seq = ++dev->mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mcu.msg_seq & 0xf; + + txd = (struct mt7603_mcu_txd *) skb_push(skb, hdrlen); + memset(txd, 0, hdrlen); + + txd->len = cpu_to_le16(skb->len - hdrlen); + 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); + txd->pkt_type = MCU_PKT_ID; + txd->seq = seq; + + if (cmd < 0) { + txd->cid = -cmd; + } else { + txd->cid = MCU_CMD_EXT_CID; + txd->ext_cid = cmd; + if (query != MCU_Q_NA) + txd->ext_cid_ack = 1; + + txd->set_query = query; + } + + if (wait_seq) + *wait_seq = seq; + + return mt7603_tx_queue_mcu(dev, MT_TXQ_MCU, skb); +} + +static int +mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd, int query) +{ + unsigned long expires = jiffies + HZ; + int ret, seq; + + mutex_lock(&dev->mcu.mutex); + + ret = __mt7603_mcu_msg_send(dev, skb, cmd, query, &seq); + if (ret) + goto out; + + while (1) { + bool check_seq = false; + + skb = mt7603_mcu_get_response(dev, expires); + if (!skb) { + printk("MCU message %d (seq %d) timed out\n", cmd, seq); + ret = -ETIMEDOUT; + break; + } + +#if 0 + rxfce = (u32 *) skb->cb; + + if (seq == MT76_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) +#endif + check_seq = true; + + dev_kfree_skb(skb); + if (check_seq) + break; + } + +out: + mutex_unlock(&dev->mcu.mutex); + + return ret; +} + +static int +mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) +{ + struct { + __le32 addr; + __le32 len; + __le32 mode; + } req = { + .addr = cpu_to_le32(addr), + .len = cpu_to_le32(len), + .mode = cpu_to_le32(BIT(31)), + }; + struct sk_buff *skb = mt7603_mcu_msg_alloc(dev, &req, sizeof(req)); + + return mt7603_mcu_msg_send(dev, skb, MCU_CMD_TARGET_ADDRESS_LEN_REQ, 0); +} + static int mt7603_load_firmware(struct mt7603_dev *dev) { const struct firmware *fw; const struct mt7603_fw_trailer *hdr; + int dl_len; u32 val; int ret; @@ -69,6 +196,9 @@ mt7603_load_firmware(struct mt7603_dev *dev) goto out; } + 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); out: release_firmware(fw); @@ -83,5 +213,6 @@ error: int mt7603_mcu_init(struct mt7603_dev *dev) { + mutex_init(&dev->mcu.mutex); return mt7603_load_firmware(dev); } diff --git a/mt7603_mcu.h b/mt7603_mcu.h new file mode 100644 index 00000000..b923f4f1 --- /dev/null +++ b/mt7603_mcu.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7603_MCU_H +#define __MT7603_MCU_H + +struct mt7603_mcu_txd { + __le16 pq_id; + __le16 len; + + u8 seq; + u8 set_query; + u8 pkt_type; + u8 cid; + + u8 ext_cid_ack; + u8 uc_d2b2_rev; + u8 ext_cid; + u8 uc_d2b0_rev; + + u8 au4_d3_to_d7_rev[5]; +} __packed __aligned(4); + +#define MCU_PKT_ID 0xa0 +#define MCU_PORT_QUEUE 0x8000 +#define MCU_PORT_QUEUE_FW 0xc000 + +#define MCU_FIRMWARE_ADDRESS 0x100000 + +enum { + MCU_Q_QUERY, + MCU_Q_SET, + MCU_Q_RESERVED, + MCU_Q_NA +}; + +enum { + MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, + MCU_CMD_FW_START_REQ = 0x02, + MCU_CMD_INIT_ACCESS_REG = 0x3, + MCU_CMD_PATCH_START_REQ = 0x05, + MCU_CMD_PATCH_FINISH_REQ = 0x07, + MCU_CMD_PATCH_SEM_CONTROL = 0x10, + MCU_CMD_HIF_LOOPBACK = 0x20, + MCU_CMD_CH_PRIVILEGE = 0x20, + MCU_CMD_ACCESS_REG = 0xC2, + MCU_CMD_EXT_CID = 0xED, + MCU_CMD_FW_SCATTER = 0xEE, + MCU_CMD_RESTART_DL_REQ = 0xEF, +}; + +enum { + MCU_EXT_CMD_RF_REG_ACCESS = 0x02, + MCU_EXT_CMD_RF_TEST = 0x04, + MCU_EXT_CMD_RADIO_ON_OFF_CTRL = 0x05, + MCU_EXT_CMD_WIFI_RX_DISABLE = 0x06, + MCU_EXT_CMD_PM_STATE_CTRL = 0x07, + MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_NIC_CAPABILITY = 0x09, + MCU_EXT_CMD_PWR_SAVING = 0x0A, + MCU_EXT_CMD_MULTIPLE_REG_ACCESS = 0x0E, + MCU_EXT_CMD_AP_PWR_SAVING_CAPABILITY = 0xF, + MCU_EXT_CMD_SEC_ADDREMOVE_KEY = 0x10, + MCU_EXT_CMD_SET_TX_POWER_CTRL=0x11, + MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, + MCU_EXT_CMD_PS_RETRIEVE_START = 0x14, + MCU_EXT_CMD_LED_CTRL=0x17, + MCU_EXT_CMD_PACKET_FILTER = 0x18, + MCU_EXT_CMD_PWR_MGT_BIT_WIFI = 0x1B, + MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_THERMAL_PROTECT = 0x23, + MCU_EXT_CMD_EDCA_SET = 0x27, + MCU_EXT_CMD_SLOT_TIME_SET = 0x28, + MCU_EXT_CMD_CONFIG_INTERNAL_SETTING = 0x29, + MCU_EXT_CMD_NOA_OFFLOAD_CTRL = 0x2B, + MCU_EXT_CMD_GET_THEMAL_SENSOR=0x2C, + MCU_EXT_CMD_WAKEUP_OPTION = 0x2E, + MCU_EXT_CMD_AC_QUEUE_CONTROL = 0x31, + MCU_EXT_CMD_BCN_UPDATE = 0x33 +}; + +enum { + MCU_EVENT_CMD_RESULT = 0x0, + MCU_EVENT_RF_REG_ACCESS = 0x2, + MCU_EVENT_MULTI_CR_ACCESS = 0x0E, + MCU_EVENT_FW_LOG_2_HOST = 0x13, + MCU_EVENT_BEACON_LOSS = 0x1A, + MCU_EVENT_THERMAL_PROTECT = 0x22, + MCU_EVENT_BCN_UPDATE = 0x31, +}; + +#endif