mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 05:16:57 +00:00
MediaTek has asked to switch from the ISC license to BSD-3-Clause-Clear, in order to improve clarity and the legal integrity of the code. The BSD-3-Clause license includes the "no endorsement" clause, which is important for protecting the reputation of the original authors and contributors by preventing unauthorized use of their names for endorsement purposes. This clause is absent in the BSD-2-Clause license, which is more permissive but lacks this specific protection. This change also cleans up the license of some Kconfig/Makefile files, which were accidentally marked as GPL. The GPL 2.0 remains in use on mt76x0, as well as two source files in mt7615 for which the license situation still needs to be clarified. Signed-off-by: Felix Fietkau <[email protected]>
200 lines
4.6 KiB
C
200 lines
4.6 KiB
C
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
/* Copyright (C) 2021 MediaTek Inc. */
|
|
|
|
#include <linux/iopoll.h>
|
|
#include <linux/mmc/sdio_func.h>
|
|
#include "mt7921.h"
|
|
#include "../mt76_connac2_mac.h"
|
|
#include "../sdio.h"
|
|
#include <linux/mmc/host.h>
|
|
#include <linux/kallsyms.h>
|
|
|
|
static void mt7921s_enable_irq(struct mt76_dev *dev)
|
|
{
|
|
struct mt76_sdio *sdio = &dev->sdio;
|
|
|
|
sdio_claim_host(sdio->func);
|
|
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
|
|
sdio_release_host(sdio->func);
|
|
}
|
|
|
|
static void mt7921s_disable_irq(struct mt76_dev *dev)
|
|
{
|
|
struct mt76_sdio *sdio = &dev->sdio;
|
|
|
|
sdio_claim_host(sdio->func);
|
|
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
|
|
sdio_release_host(sdio->func);
|
|
}
|
|
|
|
static u32 mt7921s_read_whcr(struct mt76_dev *dev)
|
|
{
|
|
return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
|
|
}
|
|
|
|
int mt7921s_wfsys_reset(struct mt792x_dev *dev)
|
|
{
|
|
struct mt76_sdio *sdio = &dev->mt76.sdio;
|
|
u32 val, status;
|
|
|
|
if (atomic_read(&dev->mt76.bus_hung))
|
|
return 0;
|
|
|
|
mt7921s_mcu_drv_pmctrl(dev);
|
|
|
|
sdio_claim_host(sdio->func);
|
|
|
|
val = sdio_readl(sdio->func, MCR_WHCR, NULL);
|
|
val &= ~WF_WHOLE_PATH_RSTB;
|
|
sdio_writel(sdio->func, val, MCR_WHCR, NULL);
|
|
|
|
msleep(50);
|
|
|
|
val = sdio_readl(sdio->func, MCR_WHCR, NULL);
|
|
val &= ~WF_SDIO_WF_PATH_RSTB;
|
|
sdio_writel(sdio->func, val, MCR_WHCR, NULL);
|
|
|
|
usleep_range(1000, 2000);
|
|
|
|
val = sdio_readl(sdio->func, MCR_WHCR, NULL);
|
|
val |= WF_WHOLE_PATH_RSTB;
|
|
sdio_writel(sdio->func, val, MCR_WHCR, NULL);
|
|
|
|
readx_poll_timeout(mt7921s_read_whcr, &dev->mt76, status,
|
|
status & WF_RST_DONE, 50000, 2000000);
|
|
|
|
sdio_release_host(sdio->func);
|
|
|
|
clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
|
|
|
|
/* activate mt7921s again */
|
|
mt7921s_mcu_drv_pmctrl(dev);
|
|
mt76_clear(dev, MT_CONN_STATUS, MT_WIFI_PATCH_DL_STATE);
|
|
mt7921s_mcu_fw_pmctrl(dev);
|
|
mt7921s_mcu_drv_pmctrl(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mt7921s_init_reset(struct mt792x_dev *dev)
|
|
{
|
|
set_bit(MT76_MCU_RESET, &dev->mphy.state);
|
|
|
|
wake_up(&dev->mt76.mcu.wait);
|
|
skb_queue_purge(&dev->mt76.mcu.res_q);
|
|
wait_event_timeout(dev->mt76.sdio.wait,
|
|
mt76s_txqs_empty(&dev->mt76), 5 * HZ);
|
|
mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
|
|
|
|
mt7921s_disable_irq(&dev->mt76);
|
|
mt7921s_wfsys_reset(dev);
|
|
|
|
mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
|
|
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
|
|
mt7921s_enable_irq(&dev->mt76);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct mt76_sdio *msdio;
|
|
static void mt7921s_card_reset(struct work_struct *work)
|
|
{
|
|
struct mmc_host *sdio_host = msdio->func->card->host;
|
|
|
|
sdio_claim_host(msdio->func);
|
|
sdio_release_irq(msdio->func);
|
|
sdio_release_host(msdio->func);
|
|
|
|
mmc_remove_host(sdio_host);
|
|
msleep(50);
|
|
mmc_add_host(sdio_host);
|
|
}
|
|
|
|
static DECLARE_WORK(sdio_reset_work, mt7921s_card_reset);
|
|
static int mt7921s_check_bus(struct mt76_dev *dev)
|
|
{
|
|
struct mt76_sdio *sdio = &dev->sdio;
|
|
int err;
|
|
|
|
sdio_claim_host(sdio->func);
|
|
sdio_readl(dev->sdio.func, MCR_WHCR, &err);
|
|
sdio_release_host(sdio->func);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int mt7921s_host_reset(struct mt792x_dev *dev)
|
|
{
|
|
struct mt76_dev *mdev = &dev->mt76;
|
|
int err = -1;
|
|
|
|
if (!atomic_read(&mdev->bus_hung))
|
|
err = mt7921s_check_bus(&dev->mt76);
|
|
|
|
if (err) {
|
|
atomic_set(&mdev->bus_hung, true);
|
|
msdio = &dev->mt76.sdio;
|
|
dev_err(mdev->dev, "SDIO bus problem detected(%d), resetting card!!\n", err);
|
|
schedule_work(&sdio_reset_work);
|
|
return err;
|
|
}
|
|
|
|
atomic_set(&mdev->bus_hung, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mt7921s_mac_reset(struct mt792x_dev *dev)
|
|
{
|
|
int err;
|
|
|
|
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
|
|
|
|
mt7921s_host_reset(dev);
|
|
if (atomic_read(&dev->mt76.bus_hung))
|
|
return 0;
|
|
|
|
mt76_txq_schedule_all(&dev->mphy);
|
|
mt76_worker_disable(&dev->mt76.tx_worker);
|
|
set_bit(MT76_MCU_RESET, &dev->mphy.state);
|
|
wake_up(&dev->mt76.mcu.wait);
|
|
skb_queue_purge(&dev->mt76.mcu.res_q);
|
|
wait_event_timeout(dev->mt76.sdio.wait,
|
|
mt76s_txqs_empty(&dev->mt76), 5 * HZ);
|
|
mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
|
|
mt76_worker_disable(&dev->mt76.sdio.status_worker);
|
|
mt76_worker_disable(&dev->mt76.sdio.net_worker);
|
|
mt76_worker_disable(&dev->mt76.sdio.stat_worker);
|
|
|
|
mt7921s_disable_irq(&dev->mt76);
|
|
mt7921s_wfsys_reset(dev);
|
|
|
|
mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
|
|
mt76_worker_enable(&dev->mt76.sdio.status_worker);
|
|
mt76_worker_enable(&dev->mt76.sdio.net_worker);
|
|
mt76_worker_enable(&dev->mt76.sdio.stat_worker);
|
|
|
|
dev->fw_assert = false;
|
|
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
|
|
mt7921s_enable_irq(&dev->mt76);
|
|
|
|
err = mt7921_run_firmware(dev);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = mt7921_mcu_set_eeprom(dev);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = mt7921_mac_init(dev);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = __mt7921_start(&dev->phy);
|
|
out:
|
|
|
|
mt76_worker_enable(&dev->mt76.tx_worker);
|
|
|
|
return err;
|
|
}
|