1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2020 MediaTek Inc. 3 * 4 * Author: Felix Fietkau <nbd@nbd.name> 5 * Lorenzo Bianconi <lorenzo@kernel.org> 6 * Sean Wang <sean.wang@mediatek.com> 7 */ 8 #include <linux/kernel.h> 9 #include <linux/mmc/sdio_func.h> 10 #include <linux/module.h> 11 #include <linux/iopoll.h> 12 13 #include "mt7615.h" 14 #include "mac.h" 15 #include "mcu.h" 16 #include "regs.h" 17 #include "sdio.h" 18 19 static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) 20 { 21 struct mt76_sdio *sdio = &dev->mt76.sdio; 22 u32 txdwcnt; 23 24 sdio->sched.pse_data_quota = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, 25 MT_HIF0_MIN_QUOTA); 26 sdio->sched.pse_mcu_quota = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, 27 MT_HIF1_MIN_QUOTA); 28 sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, 29 MT_HIF0_MIN_QUOTA); 30 txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT, 31 MT_PP_TXDWCNT_TX1_ADD_DW_CNT); 32 sdio->sched.deficit = txdwcnt << 2; 33 34 return 0; 35 } 36 37 static int 38 mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 39 int cmd, int *seq) 40 { 41 struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 42 int ret; 43 44 mt7615_mcu_fill_msg(dev, skb, cmd, seq); 45 ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0); 46 if (ret) 47 return ret; 48 49 mt76_queue_kick(dev, mdev->q_mcu[MT_MCUQ_WM]); 50 51 return ret; 52 } 53 54 static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) 55 { 56 struct sdio_func *func = dev->mt76.sdio.func; 57 struct mt76_phy *mphy = &dev->mt76.phy; 58 u32 status; 59 int ret; 60 61 sdio_claim_host(func); 62 63 sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); 64 65 ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, 66 status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); 67 if (ret < 0) { 68 dev_err(dev->mt76.dev, "Cannot get ownership from device"); 69 set_bit(MT76_STATE_PM, &mphy->state); 70 sdio_release_host(func); 71 72 return ret; 73 } 74 75 sdio_release_host(func); 76 dev->pm.last_activity = jiffies; 77 78 return 0; 79 } 80 81 static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) 82 { 83 struct mt76_phy *mphy = &dev->mt76.phy; 84 85 if (test_and_clear_bit(MT76_STATE_PM, &mphy->state)) 86 return __mt7663s_mcu_drv_pmctrl(dev); 87 88 return 0; 89 } 90 91 static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) 92 { 93 struct sdio_func *func = dev->mt76.sdio.func; 94 struct mt76_phy *mphy = &dev->mt76.phy; 95 u32 status; 96 int ret; 97 98 if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) 99 return 0; 100 101 sdio_claim_host(func); 102 103 sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); 104 105 ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, 106 !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); 107 if (ret < 0) { 108 dev_err(dev->mt76.dev, "Cannot set ownership to device"); 109 clear_bit(MT76_STATE_PM, &mphy->state); 110 } 111 112 sdio_release_host(func); 113 114 return ret; 115 } 116 117 int mt7663s_mcu_init(struct mt7615_dev *dev) 118 { 119 static const struct mt76_mcu_ops mt7663s_mcu_ops = { 120 .headroom = sizeof(struct mt7615_mcu_txd), 121 .tailroom = MT_USB_TAIL_SIZE, 122 .mcu_skb_send_msg = mt7663s_mcu_send_message, 123 .mcu_parse_response = mt7615_mcu_parse_response, 124 .mcu_restart = mt7615_mcu_restart, 125 .mcu_rr = mt7615_mcu_reg_rr, 126 .mcu_wr = mt7615_mcu_reg_wr, 127 }; 128 struct mt7615_mcu_ops *mcu_ops; 129 int ret; 130 131 ret = __mt7663s_mcu_drv_pmctrl(dev); 132 if (ret) 133 return ret; 134 135 dev->mt76.mcu_ops = &mt7663s_mcu_ops, 136 137 ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 138 if (ret) { 139 mt7615_mcu_restart(&dev->mt76); 140 if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, 141 MT_TOP_MISC2_FW_N9_RDY, 0, 500)) 142 return -EIO; 143 } 144 145 ret = __mt7663_load_firmware(dev); 146 if (ret) 147 return ret; 148 149 mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops), 150 GFP_KERNEL); 151 if (!mcu_ops) 152 return -ENOMEM; 153 154 mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl; 155 mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl; 156 dev->mcu_ops = mcu_ops; 157 158 ret = mt7663s_mcu_init_sched(dev); 159 if (ret) 160 return ret; 161 162 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 163 164 return 0; 165 } 166