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 if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) 62 goto out; 63 64 sdio_claim_host(func); 65 66 sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); 67 68 ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, 69 status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); 70 if (ret < 0) { 71 dev_err(dev->mt76.dev, "Cannot get ownership from device"); 72 set_bit(MT76_STATE_PM, &mphy->state); 73 sdio_release_host(func); 74 75 return ret; 76 } 77 78 sdio_release_host(func); 79 80 out: 81 dev->pm.last_activity = jiffies; 82 83 return 0; 84 } 85 86 static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) 87 { 88 struct sdio_func *func = dev->mt76.sdio.func; 89 struct mt76_phy *mphy = &dev->mt76.phy; 90 u32 status; 91 int ret; 92 93 if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) 94 return 0; 95 96 sdio_claim_host(func); 97 98 sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); 99 100 ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, 101 !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); 102 if (ret < 0) { 103 dev_err(dev->mt76.dev, "Cannot set ownership to device"); 104 clear_bit(MT76_STATE_PM, &mphy->state); 105 } 106 107 sdio_release_host(func); 108 109 return ret; 110 } 111 112 int mt7663s_mcu_init(struct mt7615_dev *dev) 113 { 114 static const struct mt76_mcu_ops mt7663s_mcu_ops = { 115 .headroom = sizeof(struct mt7615_mcu_txd), 116 .tailroom = MT_USB_TAIL_SIZE, 117 .mcu_skb_send_msg = mt7663s_mcu_send_message, 118 .mcu_parse_response = mt7615_mcu_parse_response, 119 .mcu_restart = mt7615_mcu_restart, 120 .mcu_rr = mt7615_mcu_reg_rr, 121 .mcu_wr = mt7615_mcu_reg_wr, 122 }; 123 struct mt7615_mcu_ops *mcu_ops; 124 int ret; 125 126 ret = mt7663s_mcu_drv_pmctrl(dev); 127 if (ret) 128 return ret; 129 130 dev->mt76.mcu_ops = &mt7663s_mcu_ops, 131 132 ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 133 if (ret) { 134 mt7615_mcu_restart(&dev->mt76); 135 if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, 136 MT_TOP_MISC2_FW_N9_RDY, 0, 500)) 137 return -EIO; 138 } 139 140 ret = __mt7663_load_firmware(dev); 141 if (ret) 142 return ret; 143 144 mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops), 145 GFP_KERNEL); 146 if (!mcu_ops) 147 return -ENOMEM; 148 149 mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl; 150 mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl; 151 dev->mcu_ops = mcu_ops; 152 153 ret = mt7663s_mcu_init_sched(dev); 154 if (ret) 155 return ret; 156 157 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 158 159 return 0; 160 } 161