From e3dec20ce3b9c4637b3591fc0896706e5df4ba76 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 6 Dec 2015 19:54:32 +0100 Subject: [PATCH] add basic stub driver for mt7603 Signed-off-by: Felix Fietkau --- Makefile | 5 +- mt7603.h | 35 ++++++++++ mt7603_init.c | 30 +++++++++ mt7603_main.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++ mt7603_mcu.c | 87 +++++++++++++++++++++++++ mt7603_pci.c | 83 ++++++++++++++++++++++++ mt7603_regs.h | 46 ++++++++++++++ 7 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 mt7603.h create mode 100644 mt7603_init.c create mode 100644 mt7603_main.c create mode 100644 mt7603_mcu.c create mode 100644 mt7603_pci.c create mode 100644 mt7603_regs.h diff --git a/Makefile b/Makefile index 6477af8c..b01de11a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ EXTRA_CFLAGS += -Werror -obj-m := mt76.o mt76x2e.o +obj-m := mt76.o mt76x2e.o mt7603e.o mt76-y := \ mmio.o util.o trace.o @@ -12,3 +12,6 @@ mt76x2e-y := \ mt76x2_trace.o mt76x2e-$(CONFIG_OF) += mt76x2_of.o + +mt7603e-y := \ + mt7603_pci.o mt7603_main.o mt7603_init.o mt7603_mcu.o diff --git a/mt7603.h b/mt7603.h new file mode 100644 index 00000000..25dfba4e --- /dev/null +++ b/mt7603.h @@ -0,0 +1,35 @@ +/* + * 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_H +#define __MT7603_H + +#include +#include "mt76.h" +#include "mt7603_regs.h" + +#define MT7603_FIRMWARE_E1 "mt7603_e1.bin" +#define MT7603_FIRMWARE_E2 "mt7603_e2.bin" + +struct mt7603_dev { + struct mt76_dev mt76; + struct device *dev; + + u32 rev; +}; + +extern const struct ieee80211_ops mt7603_ops; +struct mt7603_dev *mt7603_alloc_device(struct device *pdev); +int mt7603_mcu_init(struct mt7603_dev *dev); + +#endif diff --git a/mt7603_init.c b/mt7603_init.c new file mode 100644 index 00000000..751e9adb --- /dev/null +++ b/mt7603_init.c @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "mt7603.h" + +struct mt7603_dev *mt7603_alloc_device(struct device *pdev) +{ + struct ieee80211_hw *hw; + struct mt7603_dev *dev; + + hw = ieee80211_alloc_hw(sizeof(*dev), &mt7603_ops); + if (!hw) + return NULL; + + dev = hw->priv; + dev->dev = pdev; + dev->mt76.hw = hw; + + return dev; +} diff --git a/mt7603_main.c b/mt7603_main.c new file mode 100644 index 00000000..32f1e413 --- /dev/null +++ b/mt7603_main.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "mt7603.h" + +static int +mt7603_start(struct ieee80211_hw *hw) +{ + return -EINVAL; +} + +static void +mt7603_stop(struct ieee80211_hw *hw) +{ +} + +static int +mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + return -EINVAL; +} + +static void +mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ +} + +static int +mt7603_config(struct ieee80211_hw *hw, u32 changed) +{ + return -EINVAL; +} + +static void +mt7603_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ +} + +static void +mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ +} + +static int +mt7603_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return -EINVAL; +} + +static int +mt7603_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return -EINVAL; +} + +static void +mt7603_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +{ +} + +static int +mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + return -EINVAL; +} + +static int +mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + return -EINVAL; +} + +static void +mt7603_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac) +{ +} + +static void +mt7603_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ +} + +static void +mt7603_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ +} + +static int +mt7603_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) +{ + return -EINVAL; +} + +static int +mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta,u16 tid, u16 *ssn, u8 buf_size, + bool amsdu) +{ + return -EINVAL; +} + +static void +mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ +} + +static void mt7603_set_coverage_class(struct ieee80211_hw *hw, + s16 coverage_class) +{ +} + +static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ +} + +static void mt7603_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +{ +} + +static void +mt7603_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tids, int nframes, + enum ieee80211_frame_release_type reason, + bool more_data) +{ +} + +const struct ieee80211_ops mt7603_ops = { + .tx = mt7603_tx, + .start = mt7603_start, + .stop = mt7603_stop, + .add_interface = mt7603_add_interface, + .remove_interface = mt7603_remove_interface, + .config = mt7603_config, + .configure_filter = mt7603_configure_filter, + .bss_info_changed = mt7603_bss_info_changed, + .sta_add = mt7603_sta_add, + .sta_remove = mt7603_sta_remove, + .sta_notify = mt7603_sta_notify, + .set_key = mt7603_set_key, + .conf_tx = mt7603_conf_tx, + .sw_scan_start = mt7603_sw_scan, + .sw_scan_complete = mt7603_sw_scan_complete, + .flush = mt7603_flush, + .ampdu_action = mt7603_ampdu_action, + .get_txpower = mt7603_get_txpower, + .wake_tx_queue = mt7603_wake_tx_queue, + .sta_rate_tbl_update = mt7603_sta_rate_tbl_update, + .release_buffered_frames = mt7603_release_buffered_frames, + .set_coverage_class = mt7603_set_coverage_class, +}; diff --git a/mt7603_mcu.c b/mt7603_mcu.c new file mode 100644 index 00000000..a935b893 --- /dev/null +++ b/mt7603_mcu.c @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#include +#include "mt7603.h" + +struct mt7603_fw_trailer { + char fw_ver[10]; + char build_date[15]; + __le32 dl_len; +} __packed; + +static int +mt7603_load_firmware(struct mt7603_dev *dev) +{ + const struct firmware *fw; + const struct mt7603_fw_trailer *hdr; + u32 val; + int ret; + + ret = request_firmware(&fw, MT7603_FIRMWARE_E1, dev->dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + goto error; + + hdr = (const struct mt7603_fw_trailer *) (fw->data + fw->size - sizeof(*hdr)); + + dev_info(dev->dev, "Firmware Version: %.10s\n", hdr->fw_ver); + dev_info(dev->dev, "Build Time: %.15s\n", hdr->build_date); + + val = mt76_rr(dev, MT_MCU_PCIE_REMAP_1); + mt76_wr(dev, MT_MCU_PCIE_REMAP_1, + MT76_SET(MT_MCU_PCIE_REMAP_1_OFFSET, 0x1400)); + mt76_wr(dev, MT_PCIE_REMAP_BASE_1 + 0x12498, 0x5); + mt76_wr(dev, MT_PCIE_REMAP_BASE_1 + 0x12498, 0x5); + udelay(1); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_1, + MT76_SET(MT_MCU_PCIE_REMAP_1_BASE, 0x2940)); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_2, + MT76_SET(MT_MCU_PCIE_REMAP_2_BASE, 0x1001)); + + /* switch to bypass mode */ + mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID, + MT_SCH_4_BYPASS | MT76_SET(MT_SCH_4_FORCE_QID, 5)); + + val = mt76_rr(dev, MT_TOP_MISC2); + if (val & BIT(1)) { + dev_info(dev->dev, "Firmware already running!\n"); + goto out; + } + + if (!mt76_poll(dev, MT_TOP_MISC2, BIT(0), BIT(0), 500)) { + dev_err(dev->dev, "Timeout waiting for ROM code to become ready\n"); + ret = -EIO; + goto out; + } + + +out: + release_firmware(fw); + + return ret; + +error: + printk("Invalid firmware\n"); + release_firmware(fw); + return -ENOENT; +} + +int mt7603_mcu_init(struct mt7603_dev *dev) +{ + return mt7603_load_firmware(dev); +} diff --git a/mt7603_pci.c b/mt7603_pci.c new file mode 100644 index 00000000..e6ff43be --- /dev/null +++ b/mt7603_pci.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 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. + */ + +#include +#include +#include + +#include "mt7603.h" + +static const struct pci_device_id mt76pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7603) }, + { }, +}; + +static int +mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mt7603_dev *dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + dev = mt7603_alloc_device(&pdev->dev); + if (!dev) + return -ENOMEM; + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + + pci_set_drvdata(pdev, dev); + + dev->rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_printk(KERN_INFO, dev->dev, "ASIC revision: %08x\n", dev->rev); + + ret = mt7603_mcu_init(dev); + if (ret) + return ret; + + return -EINVAL; +} + +static void +mt76pci_remove(struct pci_dev *pdev) +{ + struct mt7603_dev *dev = pci_get_drvdata(pdev); + + ieee80211_free_hw(mt76_hw(dev)); +} + +MODULE_DEVICE_TABLE(pci, mt76pci_device_table); +MODULE_FIRMWARE(MT7603_FIRMWARE_E1); +MODULE_FIRMWARE(MT7603_FIRMWARE_E2); +MODULE_LICENSE("GPL"); + +static struct pci_driver mt76pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt76pci_device_table, + .probe = mt76pci_probe, + .remove = mt76pci_remove, +}; + +module_pci_driver(mt76pci_driver); diff --git a/mt7603_regs.h b/mt7603_regs.h new file mode 100644 index 00000000..7c71b5e0 --- /dev/null +++ b/mt7603_regs.h @@ -0,0 +1,46 @@ +/* + * 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_REGS_H +#define __MT7603_REGS_H + +#define MT_TOP_MISC2 0x1134 + +#define MT_MCU_BASE 0x2000 +#define MT_MCU(ofs) (MT_MCU_BASE + (ofs)) + +#define MT_MCU_PCIE_REMAP_1 MT_MCU(0x500) +#define MT_MCU_PCIE_REMAP_1_OFFSET GENMASK(17, 0) +#define MT_MCU_PCIE_REMAP_1_BASE GENMASK(31, 18) + +#define MT_MCU_PCIE_REMAP_2 MT_MCU(0x504) +#define MT_MCU_PCIE_REMAP_2_OFFSET GENMASK(18, 0) +#define MT_MCU_PCIE_REMAP_2_BASE GENMASK(31, 19) + +#define MT_HIF_BASE 0x4000 +#define MT_HIF(ofs) (MT_HIF_BASE + (ofs)) + +#define MT_ASIC_VERSION MT_HIF(0x000) + +#define MT_SCH_1 MT_HIF(0x588) +#define MT_SCH_2 MT_HIF(0x58c) +#define MT_SCH_3 MT_HIF(0x590) + +#define MT_SCH_4 MT_HIF(0x594) +#define MT_SCH_4_FORCE_QID GENMASK(4, 0) +#define MT_SCH_4_BYPASS BIT(5) + +#define MT_PCIE_REMAP_BASE_1 0x40000 +#define MT_PCIE_REMAP_BASE_2 0x80000 + +#endif