From 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 22 Oct 2024 10:36:11 +0000
Subject: [PATCH] 修改4g拨号为QMI,需要在系统里后台执行quectel-CM
---
kernel/drivers/mmc/host/dw_mmc.c | 290 +++++++++++++++++++++++++++++++++-------------------------
1 files changed, 165 insertions(+), 125 deletions(-)
diff --git a/kernel/drivers/mmc/host/dw_mmc.c b/kernel/drivers/mmc/host/dw_mmc.c
index 954e932..5997010 100644
--- a/kernel/drivers/mmc/host/dw_mmc.c
+++ b/kernel/drivers/mmc/host/dw_mmc.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Synopsys DesignWare Multimedia Card Interface driver
* (Based on NXP driver for lpc 31xx)
*
* Copyright (C) 2009 NXP Semiconductors
* Copyright (C) 2009, 2010 Imagination Technologies Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/blkdev.h>
@@ -40,6 +36,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
+#include <linux/soc/rockchip/rk_sdmmc.h>
#include <linux/soc/rockchip/rockchip_decompress.h>
#include "dw_mmc.h"
@@ -109,6 +106,26 @@
/* Each descriptor can transfer up to 4KB of data in chained mode */
#define DW_MCI_DESC_DATA_LENGTH 0x1000
+#if IS_ENABLED(CONFIG_CPU_RV1106)
+static spinlock_t *g_sdmmc_ispvicap_lock;
+
+void rv1106_sdmmc_get_lock(void)
+{
+ if (g_sdmmc_ispvicap_lock)
+ spin_lock(g_sdmmc_ispvicap_lock);
+}
+EXPORT_SYMBOL(rv1106_sdmmc_get_lock);
+
+void rv1106_sdmmc_put_lock(void)
+{
+ if (g_sdmmc_ispvicap_lock)
+ spin_unlock(g_sdmmc_ispvicap_lock);
+}
+EXPORT_SYMBOL(rv1106_sdmmc_put_lock);
+#endif
+
+#define RV1106_RAMDON_DATA_SIZE 508
+
#if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v)
{
@@ -175,40 +192,18 @@
struct mmc_host *mmc = slot->mmc;
struct dw_mci *host = slot->host;
struct dentry *root;
- struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &dw_mci_regs_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot,
- &dw_mci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
+ debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
+ debugfs_create_u32("state", S_IRUSR, root, &host->state);
+ debugfs_create_xul("pending_events", S_IRUSR, root,
+ &host->pending_events);
+ debugfs_create_xul("completed_events", S_IRUSR, root,
+ &host->completed_events);
}
#endif /* defined(CONFIG_DEBUG_FS) */
@@ -247,7 +242,8 @@
* expected.
*/
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
- if (host->slot->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)
+ if (host->slot->mmc->caps2 & MMC_CAP2_NO_SD &&
+ host->slot->mmc->caps2 & MMC_CAP2_NO_SDIO)
delay = 0;
#endif
if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) &&
@@ -488,14 +484,20 @@
/* Disable and reset the IDMAC interface */
temp = mci_readl(host, CTRL);
- temp &= ~SDMMC_CTRL_USE_IDMAC;
+ if (!host->is_rv1106_sd)
+ temp &= ~SDMMC_CTRL_USE_IDMAC;
+
temp |= SDMMC_CTRL_DMA_RESET;
mci_writel(host, CTRL, temp);
/* Stop the IDMAC running */
temp = mci_readl(host, BMOD);
- temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
- temp |= SDMMC_IDMAC_SWRESET;
+ if (host->is_rv1106_sd) {
+ temp |= SDMMC_IDMAC_SWRESET;
+ } else {
+ temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
+ temp |= SDMMC_IDMAC_SWRESET;
+ }
mci_writel(host, BMOD, temp);
}
@@ -525,8 +527,7 @@
tasklet_schedule(&host->tasklet);
}
- if (host->need_xfer_timer &&
- host->dir_status == DW_MCI_RECV_STATUS)
+ if (host->need_xfer_timer)
del_timer(&host->xfer_timer);
}
@@ -736,6 +737,13 @@
}
}
+ if (host->is_rv1106_sd && (data->flags & MMC_DATA_WRITE)) {
+ desc->des0 = desc_last->des0;
+ desc->des2 = desc_last->des2;
+ desc->des1 = RV1106_RAMDON_DATA_SIZE; /* Random dirty data for last one desc */
+ desc_last = desc;
+ }
+
/* Set first descriptor */
desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD);
@@ -871,12 +879,14 @@
if (!host->dms)
return -ENOMEM;
- host->dms->ch = dma_request_slave_channel(host->dev, "rx-tx");
- if (!host->dms->ch) {
+ host->dms->ch = dma_request_chan(host->dev, "rx-tx");
+ if (IS_ERR(host->dms->ch)) {
+ int ret = PTR_ERR(host->dms->ch);
+
dev_err(host->dev, "Failed to get external DMA channel.\n");
kfree(host->dms);
host->dms = NULL;
- return -ENXIO;
+ return ret;
}
return 0;
@@ -918,7 +928,7 @@
* non-word-aligned buffers or lengths. Also, we don't bother
* with all the DMA setup overhead for short transfers.
*/
- if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
+ if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD && !host->is_rv1106_sd)
return -EINVAL;
if (data->blksz & 3)
@@ -976,39 +986,12 @@
data->host_cookie = COOKIE_UNMAPPED;
}
-static int dw_mci_set_sdio_status(struct mmc_host *mmc, int val)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci *host = slot->host;
-
- if (!(mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO))
- return 0;
-
- spin_lock_bh(&host->lock);
-
- if (val)
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- else
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
- spin_unlock_bh(&host->lock);
-
- mmc_detect_change(slot->mmc, 20);
-
- return 0;
-}
-
static int dw_mci_get_cd(struct mmc_host *mmc)
{
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
int gpio_cd = mmc_gpio_get_cd(mmc);
-
-#ifdef CONFIG_SDIO_KEEPALIVE
- if (mmc->logic_remove_card)
- return test_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-#endif
/* Use platform get_cd function, else try onboard card detect */
if (((mmc->caps & MMC_CAP_NEEDS_POLL)
@@ -1358,10 +1341,16 @@
host->data_status = 0;
host->dir_status = 0;
+ if (host->is_rv1106_sd)
+ mci_writel(host, CTYPE, (slot->ctype << slot->id));
+
data = cmd->data;
if (data) {
mci_writel(host, TMOUT, 0xFFFFFFFF);
- mci_writel(host, BYTCNT, data->blksz*data->blocks);
+ if (host->is_rv1106_sd && (data->flags & MMC_DATA_WRITE))
+ mci_writel(host, BYTCNT, 0);
+ else
+ mci_writel(host, BYTCNT, data->blksz*data->blocks);
mci_writel(host, BLKSIZ, data->blksz);
}
@@ -1439,6 +1428,7 @@
}
}
+static bool dw_mci_reset(struct dw_mci *host);
static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
@@ -1460,6 +1450,9 @@
spin_lock_bh(&host->lock);
+ if (host->is_rv1106_sd)
+ dw_mci_reset(host);
+
dw_mci_queue_request(host, slot, mrq);
spin_unlock_bh(&host->lock);
@@ -1469,7 +1462,7 @@
{
struct dw_mci_slot *slot = mmc_priv(mmc);
const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
- u32 regs;
+ u32 regs, power_off_delay;
int ret;
switch (ios->bus_width) {
@@ -1508,8 +1501,14 @@
switch (ios->power_mode) {
case MMC_POWER_UP:
- if (!IS_ERR_OR_NULL(slot->host->pinctrl))
- pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state);
+ if (dw_mci_get_cd(mmc) && !IS_ERR_OR_NULL(slot->host->pinctrl)) {
+ if (!pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state)) {
+ if (device_property_read_u32(slot->host->dev, "power-off-delay-ms",
+ &power_off_delay))
+ power_off_delay = 200;
+ msleep(power_off_delay);
+ }
+ }
if (!IS_ERR(mmc->supply.vmmc)) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
@@ -1544,9 +1543,11 @@
slot->host->vqmmc_enabled = true;
}
+#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
/* Reset our state machine after powering on */
dw_mci_ctrl_reset(slot->host,
SDMMC_CTRL_ALL_RESET_FLAGS);
+#endif
}
/* Adjust clock / bus width after power is up */
@@ -1563,11 +1564,8 @@
if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
- if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) {
- ios->signal_voltage = MMC_SIGNAL_VOLTAGE_330;
- mmc_regulator_set_vqmmc(mmc, ios);
+ if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled)
regulator_disable(mmc->supply.vqmmc);
- }
slot->host->vqmmc_enabled = false;
regs = mci_readl(slot->host, PWREN);
@@ -1621,8 +1619,7 @@
if (!IS_ERR(mmc->supply.vqmmc)) {
ret = mmc_regulator_set_vqmmc(mmc, ios);
-
- if (ret) {
+ if (ret < 0) {
dev_dbg(&mmc->class_dev,
"Regulator set error %d - %s V\n",
ret, uhs & v18 ? "1.8" : "3.3");
@@ -1852,7 +1849,6 @@
.pre_req = dw_mci_pre_req,
.post_req = dw_mci_post_req,
.set_ios = dw_mci_set_ios,
- .set_sdio_status = dw_mci_set_sdio_status,
.get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd,
.hw_reset = dw_mci_hw_reset,
@@ -1874,6 +1870,9 @@
WARN_ON(host->cmd || host->data);
+ if (host->need_xfer_timer)
+ del_timer(&host->xfer_timer);
+
host->slot->mrq = NULL;
host->mrq = NULL;
if (!list_empty(&host->queue)) {
@@ -1894,6 +1893,7 @@
}
spin_unlock(&host->lock);
+
mmc_request_done(prev_mmc, mrq);
spin_lock(&host->lock);
}
@@ -1935,6 +1935,9 @@
{
u32 status = host->data_status;
+ if (host->is_rv1106_sd && (data->flags & MMC_DATA_WRITE) && (status & SDMMC_INT_DATA_OVER))
+ goto finish;
+
if (status & DW_MCI_DATA_ERROR_FLAGS) {
if (status & SDMMC_INT_DRTO) {
data->error = -ETIMEDOUT;
@@ -1967,6 +1970,7 @@
*/
dw_mci_reset(host);
} else {
+finish:
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
}
@@ -2014,8 +2018,10 @@
host->bus_hz);
/* add a bit spare time */
- xfer_ms += 100;
-
+ if (host->dir_status == DW_MCI_RECV_STATUS)
+ xfer_ms += 100;
+ else
+ xfer_ms += 2500;
spin_lock_irqsave(&host->irq_lock, irqflags);
if (!test_bit(EVENT_XFER_COMPLETE, &host->pending_events))
mod_timer(&host->xfer_timer,
@@ -2132,7 +2138,7 @@
}
prev_state = state = STATE_SENDING_DATA;
- /* fall through */
+ fallthrough;
case STATE_SENDING_DATA:
/*
@@ -2150,6 +2156,13 @@
send_stop_abort(host, data);
dw_mci_stop_dma(host);
state = STATE_DATA_ERROR;
+ if (host->dir_status == DW_MCI_SEND_STATUS) {
+ data->bytes_xfered = 0;
+ data->error = -ETIMEDOUT;
+ host->data = NULL;
+ dw_mci_request_end(host, mrq);
+ goto unlock;
+ }
break;
}
@@ -2161,8 +2174,7 @@
*/
if (host->dir_status == DW_MCI_RECV_STATUS)
dw_mci_set_drto(host);
- if (host->need_xfer_timer &&
- host->dir_status == DW_MCI_RECV_STATUS)
+ if (host->need_xfer_timer)
dw_mci_set_xfer_timeout(host);
break;
}
@@ -2193,7 +2205,7 @@
}
prev_state = state = STATE_DATA_BUSY;
- /* fall through */
+ fallthrough;
case STATE_DATA_BUSY:
if (!dw_mci_clear_pending_data_complete(host)) {
@@ -2204,6 +2216,8 @@
*/
if (host->dir_status == DW_MCI_RECV_STATUS)
dw_mci_set_drto(host);
+ if (host->need_xfer_timer && host->dir_status == DW_MCI_SEND_STATUS)
+ dw_mci_set_xfer_timeout(host);
break;
}
@@ -2220,8 +2234,19 @@
}
/* stop command for open-ended transfer*/
- if (data->stop)
+ if (data->stop) {
+ if (host->is_rv1106_sd && (data->flags & MMC_DATA_WRITE)) {
+ int fifo_count;
+
+ if (readl_poll_timeout_atomic(host->regs + SDMMC_STATUS, fifo_count,
+ ((fifo_count >> 17) & 0x7FF) <= RV1106_RAMDON_DATA_SIZE / 4,
+ 0, 5000 * USEC_PER_MSEC))
+ data->error = -ETIMEDOUT;
+ udelay(1);
+ dw_mci_reset(host);
+ }
send_stop_abort(host, data);
+ }
} else {
/*
* If we don't have a command complete now we'll
@@ -2246,7 +2271,7 @@
*/
prev_state = state = STATE_SENDING_STOP;
- /* fall through */
+ fallthrough;
case STATE_SENDING_STOP:
if (!dw_mci_clear_pending_cmd_complete(host))
@@ -2752,8 +2777,7 @@
del_timer(&host->cto_timer);
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
host->cmd_status = pending;
- if ((host->need_xfer_timer) &&
- host->dir_status == DW_MCI_RECV_STATUS)
+ if (host->need_xfer_timer)
del_timer(&host->xfer_timer);
smp_wmb(); /* drain writebuffer */
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
@@ -2771,11 +2795,14 @@
}
if (pending & SDMMC_INT_DATA_OVER) {
+rv1106_sd:
spin_lock_irqsave(&host->irq_lock, irqflags);
del_timer(&host->dto_timer);
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
+ if (host->is_rv1106_sd)
+ pending |= SDMMC_INT_DATA_OVER;
if (!host->data_status)
host->data_status = pending;
smp_wmb(); /* drain writebuffer */
@@ -2845,6 +2872,9 @@
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))
host->dma_ops->complete((void *)host);
+
+ if (host->is_rv1106_sd && (pending & SDMMC_IDMAC_INT_TI))
+ goto rv1106_sd;
}
}
@@ -2860,12 +2890,6 @@
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
-
- /*
- * Support MMC_CAP_ERASE by default.
- * It needs to use trim/discard/erase commands.
- */
- mmc->caps |= MMC_CAP_ERASE;
if (host->pdata->pm_caps)
mmc->pm_caps = host->pdata->pm_caps;
@@ -2884,15 +2908,7 @@
ctrl_id);
return -EINVAL;
}
- /*
- * Some sd cards violate the spec. They claim to support
- * CMD23 but actually not. We don't have a good method to
- * work around them except for adding MMC_QUIRK_BLK_NO_CMD23
- * one by one. But it's not a acceptable way for our custmors.
- * So removing CMD23 support for all sd cards to solve it.
- */
- if (!(mmc->restrict_caps & RESTRICT_CARD_TYPE_SD))
- mmc->caps |= drv_data->caps[ctrl_id];
+ mmc->caps |= drv_data->caps[ctrl_id];
}
if (host->pdata->caps2)
@@ -2946,6 +2962,10 @@
/* Useful defaults if platform data is unset. */
if (host->use_dma == TRANS_MODE_IDMAC) {
+ /* Reserve last desc for dirty data */
+ if (host->is_rv1106_sd)
+ host->ring_size--;
+
mmc->max_segs = host->ring_size;
mmc->max_blk_size = 65535;
mmc->max_seg_size = 0x1000;
@@ -2969,11 +2989,6 @@
}
dw_mci_get_cd(mmc);
-
-#ifdef CONFIG_SDIO_KEEPALIVE
- if (mmc->logic_remove_card)
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-#endif
ret = mmc_add_host(mmc);
if (ret)
@@ -3336,12 +3351,9 @@
if (!host->pdata) {
host->pdata = dw_mci_parse_dt(host);
- if (PTR_ERR(host->pdata) == -EPROBE_DEFER) {
- return -EPROBE_DEFER;
- } else if (IS_ERR(host->pdata)) {
- dev_err(host->dev, "platform data not available\n");
- return -EINVAL;
- }
+ if (IS_ERR(host->pdata))
+ return dev_err_probe(host->dev, PTR_ERR(host->pdata),
+ "platform data not available\n");
}
host->biu_clk = devm_clk_get(host->dev, "biu");
@@ -3354,8 +3366,10 @@
return ret;
}
}
+
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
- if (device_property_read_bool(host->dev, "supports-emmc")) {
+ if (device_property_read_bool(host->dev, "no-sd") &&
+ device_property_read_bool(host->dev, "no-sdio")) {
if (readl_poll_timeout(host->regs + SDMMC_STATUS,
fifo_size,
!(fifo_size & (BIT(10) | GENMASK(7, 4))),
@@ -3532,6 +3546,24 @@
goto err_dmaunmap;
}
+ if (host->is_rv1106_sd) {
+#if IS_ENABLED(CONFIG_CPU_RV1106)
+ g_sdmmc_ispvicap_lock = &host->lock;
+#endif
+ /* Select IDMAC interface */
+ fifo_size = mci_readl(host, CTRL);
+ fifo_size |= SDMMC_CTRL_USE_IDMAC;
+ mci_writel(host, CTRL, fifo_size);
+
+ fifo_size = mci_readl(host, INTMASK);
+ fifo_size &= ~SDMMC_INT_HTO;
+ mci_writel(host, INTMASK, fifo_size);
+
+ host->slot->mmc->caps &= ~(MMC_CAP_UHS_DDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR12);
+ }
+
/* Now that slots are all setup, we can enable card detect */
dw_mci_enable_cd(host);
@@ -3629,20 +3661,28 @@
* Restore the initial value at FIFOTH register
* And Invalidate the prev_blksz with zero
*/
- mci_writel(host, FIFOTH, host->fifoth_val);
- host->prev_blksz = 0;
+ mci_writel(host, FIFOTH, host->fifoth_val);
+ host->prev_blksz = 0;
/* Put in max timeout */
mci_writel(host, TMOUT, 0xFFFFFFFF);
mci_writel(host, RINTSTS, 0xFFFFFFFF);
- mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
- SDMMC_INT_TXDR | SDMMC_INT_RXDR |
- DW_MCI_ERROR_FLAGS);
+ mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | DW_MCI_ERROR_FLAGS);
mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
+ if (host->is_rv1106_sd) {
+ /* Select IDMAC interface */
+ ret = mci_readl(host, CTRL);
+ ret |= SDMMC_CTRL_USE_IDMAC;
+ mci_writel(host, CTRL, ret);
- if (host->slot->mmc->pm_flags & MMC_PM_KEEP_POWER)
+ ret = mci_readl(host, INTMASK);
+ ret &= ~SDMMC_INT_HTO;
+ mci_writel(host, INTMASK, ret);
+ }
+
+ if (host->slot && host->slot->mmc->pm_flags & MMC_PM_KEEP_POWER)
dw_mci_set_ios(host->slot->mmc, &host->slot->mmc->ios);
/* Force setup bus to guarantee available clock output */
--
Gitblit v1.6.2