1 // SPDX-License-Identifier: ISC 2 /* Copyright (C) 2021 MediaTek Inc. */ 3 4 #include <linux/kernel.h> 5 #include <linux/mmc/sdio_func.h> 6 #include <linux/module.h> 7 #include <linux/iopoll.h> 8 9 #include "mt7921.h" 10 #include "../sdio.h" 11 #include "mac.h" 12 #include "mcu.h" 13 #include "regs.h" 14 15 static int 16 mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 17 int cmd, int *seq) 18 { 19 struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 20 enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD; 21 enum mt76_mcuq_id txq = MT_MCUQ_WM; 22 int ret, pad; 23 24 /* We just return in case firmware assertion to avoid blocking the 25 * common workqueue to run, for example, the coredump work might be 26 * blocked by mt7921_mac_work that is excuting register access via sdio 27 * bus. 28 */ 29 if (dev->fw_assert) 30 return -EBUSY; 31 32 ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq); 33 if (ret) 34 return ret; 35 36 if (cmd == MCU_CMD(FW_SCATTER)) 37 type = MT7921_SDIO_FWDL; 38 39 mt7921_skb_add_sdio_hdr(skb, type); 40 pad = round_up(skb->len, 4) - skb->len; 41 __skb_put_zero(skb, pad); 42 43 ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); 44 if (ret) 45 return ret; 46 47 mt76_queue_kick(dev, mdev->q_mcu[txq]); 48 49 return ret; 50 } 51 52 int mt7921s_mcu_init(struct mt7921_dev *dev) 53 { 54 static const struct mt76_mcu_ops mt7921s_mcu_ops = { 55 .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd), 56 .tailroom = MT_SDIO_TAIL_SIZE, 57 .mcu_skb_send_msg = mt7921s_mcu_send_message, 58 .mcu_parse_response = mt7921_mcu_parse_response, 59 .mcu_rr = mt76_connac_mcu_reg_rr, 60 .mcu_wr = mt76_connac_mcu_reg_wr, 61 }; 62 int ret; 63 64 mt7921s_mcu_drv_pmctrl(dev); 65 66 dev->mt76.mcu_ops = &mt7921s_mcu_ops; 67 68 ret = mt7921_run_firmware(dev); 69 if (ret) 70 return ret; 71 72 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 73 74 return 0; 75 } 76 77 int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev) 78 { 79 struct sdio_func *func = dev->mt76.sdio.func; 80 struct mt76_phy *mphy = &dev->mt76.phy; 81 struct mt76_connac_pm *pm = &dev->pm; 82 int err = 0; 83 u32 status; 84 85 sdio_claim_host(func); 86 87 sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); 88 89 err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 90 status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); 91 sdio_release_host(func); 92 93 if (err < 0) { 94 dev_err(dev->mt76.dev, "driver own failed\n"); 95 err = -EIO; 96 goto out; 97 } 98 99 clear_bit(MT76_STATE_PM, &mphy->state); 100 101 pm->stats.last_wake_event = jiffies; 102 pm->stats.doze_time += pm->stats.last_wake_event - 103 pm->stats.last_doze_event; 104 out: 105 return err; 106 } 107 108 int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev) 109 { 110 struct sdio_func *func = dev->mt76.sdio.func; 111 struct mt76_phy *mphy = &dev->mt76.phy; 112 struct mt76_connac_pm *pm = &dev->pm; 113 int err = 0; 114 u32 status; 115 116 sdio_claim_host(func); 117 118 sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); 119 120 err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 121 !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); 122 sdio_release_host(func); 123 124 if (err < 0) { 125 dev_err(dev->mt76.dev, "firmware own failed\n"); 126 clear_bit(MT76_STATE_PM, &mphy->state); 127 err = -EIO; 128 } 129 130 pm->stats.last_doze_event = jiffies; 131 pm->stats.awake_time += pm->stats.last_doze_event - 132 pm->stats.last_wake_event; 133 134 return err; 135 } 136