static int mt7601u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { struct usb_device *usb_dev = interface_to_usbdev(usb_intf); struct mt7601u_dev *dev; u32 asic_rev, mac_rev; int ret; dev = mt7601u_alloc_device(&usb_intf->dev); if (!dev) return -ENOMEM; usb_dev = usb_get_dev(usb_dev); usb_reset_device(usb_dev); usb_set_intfdata(usb_intf, dev); ret = mt7601u_assign_pipes(usb_intf, dev); if (ret) goto err; ret = mt7601u_wait_asic_ready(dev); if (ret) goto err; asic_rev = mt7601u_rr(dev, MT_ASIC_VERSION); mac_rev = mt7601u_rr(dev, MT_MAC_CSR0); dev_info(dev->dev, "ASIC revision: %08x MAC revision: %08x\n", asic_rev, mac_rev); /* Note: vendor driver skips this check for MT7601U */ if (!(mt7601u_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) dev_warn(dev->dev, "Warning: eFUSE not present\n"); ret = mt7601u_init_hardware(dev); if (ret) goto err; ret = mt7601u_register_device(dev); if (ret) goto err_hw; set_bit(MT7601U_STATE_INITIALIZED, &dev->state); return 0; err_hw: mt7601u_cleanup(dev); err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); destroy_workqueue(dev->stat_wq); ieee80211_free_hw(dev->hw); return ret; }
static void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset) { u32 val; mutex_lock(&dev->hw_atomic_mutex); val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL); if (reset) { val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | MT_WLAN_FUN_CTRL_WLAN_RESET_RF); mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); udelay(20); val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | MT_WLAN_FUN_CTRL_WLAN_RESET_RF); } } mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); udelay(20); mt7601u_set_wlan_state(dev, val, enable); mutex_unlock(&dev->hw_atomic_mutex); }
u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) { u32 reg = mt7601u_rr(dev, offset); val |= reg & ~mask; if (reg != val) mt7601u_wr(dev, offset, val); return val; }
int mt7601u_wait_asic_ready(struct mt7601u_dev *dev) { int i = 100; u32 val; do { val = mt7601u_rr(dev, MT_MAC_CSR0); if (val && ~val) return 0; } while (i--); return -EIO; }
static int __mt7601u_dma_fw(struct mt7601u_dev *dev, const struct mt7601u_dma_buf *dma_buf, const void *data, u32 len, u32 dst_addr) { DECLARE_COMPLETION_ONSTACK(cmpl); struct mt7601u_dma_buf buf = *dma_buf; /* we need to fake length */ __le32 reg; u32 val; int ret; reg = cpu_to_le32(MT76_SET(MT_TXD_INFO_TYPE, DMA_PACKET) | MT76_SET(MT_TXD_INFO_D_PORT, CPU_TX_PORT) | MT76_SET(MT_TXD_INFO_LEN, len)); memcpy(buf.buf, ®, sizeof(reg)); memcpy(buf.buf + sizeof(reg), data, len); memset(buf.buf + sizeof(reg) + len, 0, 8); ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE, MT_FCE_DMA_ADDR, dst_addr); if (ret) return ret; len = roundup(len, 4); ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE, MT_FCE_DMA_LEN, len << 16); if (ret) return ret; buf.len = MT_DMA_HDR_LEN + len + 4; ret = mt7601u_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, &buf, GFP_KERNEL, mt7601u_complete_urb, &cmpl); if (ret) return ret; if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) { dev_err(dev->dev, "Error: firmware upload timed out\n"); usb_kill_urb(buf.urb); return -ETIMEDOUT; } if (mt7601u_urb_has_error(buf.urb)) { dev_err(dev->dev, "Error: firmware upload urb failed:%d\n", buf.urb->status); return buf.urb->status; } val = mt7601u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); val++; mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); return 0; }
static void mt7601u_reset_counters(struct mt7601u_dev *dev) { mt7601u_rr(dev, MT_RX_STA_CNT0); mt7601u_rr(dev, MT_RX_STA_CNT1); mt7601u_rr(dev, MT_RX_STA_CNT2); mt7601u_rr(dev, MT_TX_STA_CNT0); mt7601u_rr(dev, MT_TX_STA_CNT1); mt7601u_rr(dev, MT_TX_STA_CNT2); }
int mt7601u_wait_asic_ready(struct mt7601u_dev *dev) { int i = 100; u32 val; do { if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) return -EIO; val = mt7601u_rr(dev, MT_MAC_CSR0); if (val && ~val) return 0; udelay(10); } while (i--); return -EIO; }
bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, int timeout) { u32 cur; timeout /= 10; do { if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) return false; cur = mt7601u_rr(dev, offset) & mask; if (cur == val) return true; msleep(10); } while (timeout-- > 0); dev_err(dev->dev, "Error: Time out with reg %08x\n", offset); return false; }
static void mt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable) { int i; /* Note: we don't turn off WLAN_CLK because that makes the device * not respond properly on the probe path. * In case anyone (PSM?) wants to use this function we can * bring the clock stuff back and fixup the probe path. */ if (enable) val |= (MT_WLAN_FUN_CTRL_WLAN_EN | MT_WLAN_FUN_CTRL_WLAN_CLK_EN); else val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); udelay(20); if (enable) { set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); } else { clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); return; } for (i = 200; i; i--) { val = mt7601u_rr(dev, MT_CMB_CTRL); if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD) break; udelay(20); } /* Note: vendor driver tries to disable/enable wlan here and retry * but the code which does it is so buggy it must have never * triggered, so don't bother. */ if (!i) dev_err(dev->dev, "Error: PLL and XTAL check failed!\n"); }
u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) { val |= mt7601u_rr(dev, offset) & ~mask; mt7601u_wr(dev, offset, val); return val; }
static inline int firmware_running(struct mt7601u_dev *dev) { return mt7601u_rr(dev, MT_MCU_COM_REG0) == 1; }