From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/mmc/host/dw_mmc.c | 315 +++++++++++++++++++++++++++++++-------------------- 1 files changed, 190 insertions(+), 125 deletions(-) diff --git a/kernel/drivers/mmc/host/dw_mmc.c b/kernel/drivers/mmc/host/dw_mmc.c index 51dee0a..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) */ @@ -246,8 +241,9 @@ * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is * expected. */ -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT - if (host->slot->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) +#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC + 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,6 +1501,15 @@ switch (ios->power_mode) { case MMC_POWER_UP: + 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, ios->vdd); @@ -1524,6 +1526,9 @@ mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_ON: + if (!IS_ERR_OR_NULL(slot->host->pinctrl)) + pinctrl_select_state(slot->host->pinctrl, slot->host->normal_state); + if (!slot->host->vqmmc_enabled) { if (!IS_ERR(mmc->supply.vqmmc)) { ret = regulator_enable(mmc->supply.vqmmc); @@ -1538,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 */ @@ -1548,17 +1555,17 @@ break; case MMC_POWER_OFF: + if (!IS_ERR_OR_NULL(slot->host->pinctrl)) + pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state); + /* Turn clock off before power goes down */ dw_mci_setup_bus(slot, false); 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); @@ -1612,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"); @@ -1843,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, @@ -1865,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)) { @@ -1885,6 +1893,7 @@ } spin_unlock(&host->lock); + mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); } @@ -1926,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; @@ -1958,6 +1970,7 @@ */ dw_mci_reset(host); } else { +finish: data->bytes_xfered = data->blocks * data->blksz; data->error = 0; } @@ -2005,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, @@ -2123,7 +2138,7 @@ } prev_state = state = STATE_SENDING_DATA; - /* fall through */ + fallthrough; case STATE_SENDING_DATA: /* @@ -2141,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; } @@ -2152,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; } @@ -2184,7 +2205,7 @@ } prev_state = state = STATE_DATA_BUSY; - /* fall through */ + fallthrough; case STATE_DATA_BUSY: if (!dw_mci_clear_pending_data_complete(host)) { @@ -2195,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; } @@ -2211,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 @@ -2237,7 +2271,7 @@ */ prev_state = state = STATE_SENDING_STOP; - /* fall through */ + fallthrough; case STATE_SENDING_STOP: if (!dw_mci_clear_pending_cmd_complete(host)) @@ -2743,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); @@ -2762,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 */ @@ -2836,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; } } @@ -2851,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; @@ -2875,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) @@ -2937,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; @@ -2960,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) @@ -3272,6 +3296,22 @@ return ERR_PTR(ret); } + host->pinctrl = devm_pinctrl_get(host->dev); + if (!IS_ERR(host->pinctrl)) { + host->normal_state = pinctrl_lookup_state(host->pinctrl, "normal"); + if (IS_ERR(host->normal_state)) + dev_warn(dev, "No normal pinctrl state\n"); + + host->idle_state = pinctrl_lookup_state(host->pinctrl, "idle"); + if (IS_ERR(host->idle_state)) + dev_warn(dev, "No idle pinctrl state\n"); + + if (!IS_ERR(host->normal_state) && !IS_ERR(host->idle_state)) + pinctrl_select_state(host->pinctrl, host->idle_state); + else + host->pinctrl = NULL; + } + return pdata; } @@ -3311,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"); @@ -3329,8 +3366,10 @@ return ret; } } -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT - if (device_property_read_bool(host->dev, "supports-emmc")) { + +#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC + 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))), @@ -3507,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); @@ -3604,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