Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mcu.c
48525 views
// SPDX-License-Identifier: ISC1/* Copyright (C) 2021 MediaTek Inc. */23#include <linux/kernel.h>4#include <linux/mmc/sdio_func.h>5#include <linux/module.h>6#include <linux/iopoll.h>78#include "mt7921.h"9#include "../sdio.h"10#include "../mt76_connac2_mac.h"11#include "mcu.h"12#include "regs.h"1314static int15mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,16int cmd, int *seq)17{18struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);19enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD;20enum mt76_mcuq_id txq = MT_MCUQ_WM;21int ret, pad;2223/* We just return in case firmware assertion to avoid blocking the24* common workqueue to run, for example, the coredump work might be25* blocked by mt792x_mac_work that is excuting register access via sdio26* bus.27*/28if (dev->fw_assert)29return -EBUSY;3031ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq);32if (ret)33return ret;3435mdev->mcu.timeout = 3 * HZ;3637if (cmd == MCU_CMD(FW_SCATTER))38type = MT7921_SDIO_FWDL;3940mt792x_skb_add_usb_sdio_hdr(dev, skb, type);41pad = round_up(skb->len, 4) - skb->len;42__skb_put_zero(skb, pad);4344ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);45if (ret)46return ret;4748mt76_queue_kick(dev, mdev->q_mcu[txq]);4950return ret;51}5253static u32 mt7921s_read_rm3r(struct mt792x_dev *dev)54{55struct mt76_sdio *sdio = &dev->mt76.sdio;5657return sdio_readl(sdio->func, MCR_D2HRM3R, NULL);58}5960static u32 mt7921s_clear_rm3r_drv_own(struct mt792x_dev *dev)61{62struct mt76_sdio *sdio = &dev->mt76.sdio;63u32 val;6465val = sdio_readl(sdio->func, MCR_D2HRM3R, NULL);66if (val)67sdio_writel(sdio->func, H2D_SW_INT_CLEAR_MAILBOX_ACK,68MCR_WSICR, NULL);6970return val;71}7273int mt7921s_mcu_init(struct mt792x_dev *dev)74{75static const struct mt76_mcu_ops mt7921s_mcu_ops = {76.headroom = MT_SDIO_HDR_SIZE +77sizeof(struct mt76_connac2_mcu_txd),78.tailroom = MT_SDIO_TAIL_SIZE,79.mcu_skb_send_msg = mt7921s_mcu_send_message,80.mcu_parse_response = mt7921_mcu_parse_response,81.mcu_rr = mt76_connac_mcu_reg_rr,82.mcu_wr = mt76_connac_mcu_reg_wr,83};84int ret;8586mt7921s_mcu_drv_pmctrl(dev);8788dev->mt76.mcu_ops = &mt7921s_mcu_ops;8990ret = mt7921_run_firmware(dev);91if (ret)92return ret;9394set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);9596return 0;97}9899int mt7921s_mcu_drv_pmctrl(struct mt792x_dev *dev)100{101struct sdio_func *func = dev->mt76.sdio.func;102struct mt76_phy *mphy = &dev->mt76.phy;103struct mt76_connac_pm *pm = &dev->pm;104u32 status;105int err;106107sdio_claim_host(func);108109sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);110111err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,112status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);113114if (!err && test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))115err = readx_poll_timeout(mt7921s_read_rm3r, dev, status,116status & D2HRM3R_IS_DRIVER_OWN,1172000, 1000000);118119sdio_release_host(func);120121if (err < 0) {122dev_err(dev->mt76.dev, "driver own failed\n");123return -EIO;124}125126clear_bit(MT76_STATE_PM, &mphy->state);127128pm->stats.last_wake_event = jiffies;129pm->stats.doze_time += pm->stats.last_wake_event -130pm->stats.last_doze_event;131132return 0;133}134135int mt7921s_mcu_fw_pmctrl(struct mt792x_dev *dev)136{137struct sdio_func *func = dev->mt76.sdio.func;138struct mt76_phy *mphy = &dev->mt76.phy;139struct mt76_connac_pm *pm = &dev->pm;140u32 status;141int err;142143sdio_claim_host(func);144145if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) {146err = readx_poll_timeout(mt7921s_clear_rm3r_drv_own,147dev, status,148!(status & D2HRM3R_IS_DRIVER_OWN),1492000, 1000000);150if (err < 0) {151dev_err(dev->mt76.dev, "mailbox ACK not cleared\n");152goto out;153}154}155156sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);157158err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,159!(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);160out:161sdio_release_host(func);162163if (err < 0) {164dev_err(dev->mt76.dev, "firmware own failed\n");165clear_bit(MT76_STATE_PM, &mphy->state);166return -EIO;167}168169pm->stats.last_doze_event = jiffies;170pm->stats.awake_time += pm->stats.last_doze_event -171pm->stats.last_wake_event;172173return 0;174}175176177