sdio_mcu.c (4424B)
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 "../sdio.h" 14#include "mt7615.h" 15#include "mac.h" 16#include "mcu.h" 17#include "regs.h" 18 19static 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 sdio->sched.pse_page_size = MT_PSE_PAGE_SZ; 31 txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT, 32 MT_PP_TXDWCNT_TX1_ADD_DW_CNT); 33 sdio->sched.deficit = txdwcnt << 2; 34 35 return 0; 36} 37 38static int 39mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, 40 int cmd, int *seq) 41{ 42 struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); 43 int ret; 44 45 mt7615_mcu_fill_msg(dev, skb, cmd, seq); 46 ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0); 47 if (ret) 48 return ret; 49 50 mt76_queue_kick(dev, mdev->q_mcu[MT_MCUQ_WM]); 51 52 return ret; 53} 54 55static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) 56{ 57 struct sdio_func *func = dev->mt76.sdio.func; 58 struct mt76_phy *mphy = &dev->mt76.phy; 59 struct mt76_connac_pm *pm = &dev->pm; 60 u32 status; 61 int ret; 62 63 sdio_claim_host(func); 64 65 sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); 66 67 ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 68 status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); 69 if (ret < 0) { 70 dev_err(dev->mt76.dev, "Cannot get ownership from device"); 71 } else { 72 clear_bit(MT76_STATE_PM, &mphy->state); 73 74 pm->stats.last_wake_event = jiffies; 75 pm->stats.doze_time += pm->stats.last_wake_event - 76 pm->stats.last_doze_event; 77 } 78 sdio_release_host(func); 79 80 return ret; 81} 82 83static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) 84{ 85 struct mt76_phy *mphy = &dev->mt76.phy; 86 int ret = 0; 87 88 mutex_lock(&dev->pm.mutex); 89 90 if (test_bit(MT76_STATE_PM, &mphy->state)) 91 ret = __mt7663s_mcu_drv_pmctrl(dev); 92 93 mutex_unlock(&dev->pm.mutex); 94 95 return ret; 96} 97 98static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) 99{ 100 struct sdio_func *func = dev->mt76.sdio.func; 101 struct mt76_phy *mphy = &dev->mt76.phy; 102 struct mt76_connac_pm *pm = &dev->pm; 103 int ret = 0; 104 u32 status; 105 106 mutex_lock(&pm->mutex); 107 108 if (mt76_connac_skip_fw_pmctrl(mphy, pm)) 109 goto out; 110 111 sdio_claim_host(func); 112 113 sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); 114 115 ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status, 116 !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); 117 if (ret < 0) { 118 dev_err(dev->mt76.dev, "Cannot set ownership to device"); 119 clear_bit(MT76_STATE_PM, &mphy->state); 120 } else { 121 pm->stats.last_doze_event = jiffies; 122 pm->stats.awake_time += pm->stats.last_doze_event - 123 pm->stats.last_wake_event; 124 } 125 126 sdio_release_host(func); 127out: 128 mutex_unlock(&pm->mutex); 129 130 return ret; 131} 132 133int mt7663s_mcu_init(struct mt7615_dev *dev) 134{ 135 static const struct mt76_mcu_ops mt7663s_mcu_ops = { 136 .headroom = sizeof(struct mt7615_mcu_txd), 137 .tailroom = MT_USB_TAIL_SIZE, 138 .mcu_skb_send_msg = mt7663s_mcu_send_message, 139 .mcu_parse_response = mt7615_mcu_parse_response, 140 .mcu_restart = mt7615_mcu_restart, 141 .mcu_rr = mt76_connac_mcu_reg_rr, 142 .mcu_wr = mt76_connac_mcu_reg_wr, 143 }; 144 struct mt7615_mcu_ops *mcu_ops; 145 int ret; 146 147 ret = __mt7663s_mcu_drv_pmctrl(dev); 148 if (ret) 149 return ret; 150 151 dev->mt76.mcu_ops = &mt7663s_mcu_ops, 152 153 ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); 154 if (ret) { 155 mt7615_mcu_restart(&dev->mt76); 156 if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, 157 MT_TOP_MISC2_FW_N9_RDY, 0, 500)) 158 return -EIO; 159 } 160 161 ret = __mt7663_load_firmware(dev); 162 if (ret) 163 return ret; 164 165 mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops), 166 GFP_KERNEL); 167 if (!mcu_ops) 168 return -ENOMEM; 169 170 mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl; 171 mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl; 172 dev->mcu_ops = mcu_ops; 173 174 ret = mt7663s_mcu_init_sched(dev); 175 if (ret) 176 return ret; 177 178 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); 179 180 return 0; 181}