diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:17:52 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:17:52 +0000 |
commit | 3afb00d3f86d3d924f88b56fa8285d4e9db85852 (patch) | |
tree | 95a985d3019522cea546b7d8df621369bc44fc6c /drivers/mmc | |
parent | Adding debian version 6.9.12-1. (diff) | |
download | linux-3afb00d3f86d3d924f88b56fa8285d4e9db85852.tar.xz linux-3afb00d3f86d3d924f88b56fa8285d4e9db85852.zip |
Merging upstream version 6.10.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/block.c | 8 | ||||
-rw-r--r-- | drivers/mmc/core/debugfs.c | 7 | ||||
-rw-r--r-- | drivers/mmc/core/host.c | 1 | ||||
-rw-r--r-- | drivers/mmc/core/sd_ops.c | 83 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_bus.c | 9 | ||||
-rw-r--r-- | drivers/mmc/core/slot-gpio.c | 5 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 309 | ||||
-rw-r--r-- | drivers/mmc/host/cqhci-core.c | 11 | ||||
-rw-r--r-- | drivers/mmc/host/cqhci.h | 4 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc-hi3798cv200.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc-hi3798mv200.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/mtk-sd.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/renesas_sdhi_core.c | 3 | ||||
-rw-r--r-- | drivers/mmc/host/renesas_sdhi_internal_dmac.c | 9 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-mcf.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-of-dwcmshc.c | 305 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-omap.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci-gli.c | 46 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-s3c.c | 35 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-sprd.c | 3 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci_am654.c | 14 |
23 files changed, 574 insertions, 288 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 90c51b1214..367509b5b6 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -234,7 +234,7 @@ static ssize_t power_ro_lock_show(struct device *dev, else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) locked = 1; - ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); + ret = sysfs_emit(buf, "%d\n", locked); mmc_blk_put(md); @@ -296,9 +296,9 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, int ret; struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); - ret = snprintf(buf, PAGE_SIZE, "%d\n", - get_disk_ro(dev_to_disk(dev)) ^ - md->read_only); + ret = sysfs_emit(buf, "%d\n", + get_disk_ro(dev_to_disk(dev)) ^ + md->read_only); mmc_blk_put(md); return ret; } diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 1642ea72d2..f10a4dcf1f 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -351,11 +351,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) root = debugfs_create_dir(mmc_hostname(host), NULL); host->debugfs_root = root; - debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); + debugfs_create_file("ios", 0400, root, host, &mmc_ios_fops); debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops); debugfs_create_file("caps2", 0600, root, &host->caps2, &mmc_caps2_fops); - debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host, + debugfs_create_file_unsafe("clock", 0600, root, host, &mmc_clock_fops); debugfs_create_file_unsafe("err_state", 0600, root, host, @@ -388,7 +388,8 @@ void mmc_add_card_debugfs(struct mmc_card *card) root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root); card->debugfs_root = root; - debugfs_create_x32("state", S_IRUSR, root, &card->state); + debugfs_create_x32("state", 0400, root, &card->state); + debugfs_create_x32("quirks", 0400, root, &card->quirks); } void mmc_remove_card_debugfs(struct mmc_card *card) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 8f8781d6c2..48bda70145 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -13,7 +13,6 @@ #include <linux/err.h> #include <linux/idr.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pagemap.h> #include <linux/pm_wakeup.h> #include <linux/export.h> diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index a59cd592f0..8b9b34286e 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -19,6 +19,20 @@ #include "sd_ops.h" #include "mmc_ops.h" +/* + * Extensive testing has shown that some specific SD cards + * require an increased command timeout to be successfully + * initialized. + */ +#define SD_APP_OP_COND_PERIOD_US (10 * 1000) /* 10ms */ +#define SD_APP_OP_COND_TIMEOUT_MS 2000 /* 2s */ + +struct sd_app_op_cond_busy_data { + struct mmc_host *host; + u32 ocr; + struct mmc_command *cmd; +}; + int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) { int err; @@ -115,10 +129,45 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) return mmc_wait_for_app_cmd(card->host, card, &cmd); } +static int sd_app_op_cond_cb(void *cb_data, bool *busy) +{ + struct sd_app_op_cond_busy_data *data = cb_data; + struct mmc_host *host = data->host; + struct mmc_command *cmd = data->cmd; + u32 ocr = data->ocr; + int err; + + *busy = false; + + err = mmc_wait_for_app_cmd(host, NULL, cmd); + if (err) + return err; + + /* If we're just probing, do a single pass. */ + if (ocr == 0) + return 0; + + /* Wait until reset completes. */ + if (mmc_host_is_spi(host)) { + if (!(cmd->resp[0] & R1_SPI_IDLE)) + return 0; + } else if (cmd->resp[0] & MMC_CARD_BUSY) { + return 0; + } + + *busy = true; + return 0; +} + int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { struct mmc_command cmd = {}; - int i, err = 0; + struct sd_app_op_cond_busy_data cb_data = { + .host = host, + .ocr = ocr, + .cmd = &cmd + }; + int err; cmd.opcode = SD_APP_OP_COND; if (mmc_host_is_spi(host)) @@ -127,36 +176,16 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.arg = ocr; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; - for (i = 100; i; i--) { - err = mmc_wait_for_app_cmd(host, NULL, &cmd); - if (err) - break; - - /* if we're just probing, do a single pass */ - if (ocr == 0) - break; - - /* otherwise wait until reset completes */ - if (mmc_host_is_spi(host)) { - if (!(cmd.resp[0] & R1_SPI_IDLE)) - break; - } else { - if (cmd.resp[0] & MMC_CARD_BUSY) - break; - } - - err = -ETIMEDOUT; - - mmc_delay(10); - } - - if (!i) - pr_err("%s: card never left busy state\n", mmc_hostname(host)); + err = __mmc_poll_for_busy(host, SD_APP_OP_COND_PERIOD_US, + SD_APP_OP_COND_TIMEOUT_MS, &sd_app_op_cond_cb, + &cb_data); + if (err) + return err; if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; - return err; + return 0; } static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits, diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 71d885fbc2..c5fdfe2325 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -265,16 +265,19 @@ void sdio_unregister_bus(void) } /** - * sdio_register_driver - register a function driver + * __sdio_register_driver - register a function driver * @drv: SDIO function driver + * @owner: owning module/driver */ -int sdio_register_driver(struct sdio_driver *drv) +int __sdio_register_driver(struct sdio_driver *drv, struct module *owner) { drv->drv.name = drv->name; drv->drv.bus = &sdio_bus_type; + drv->drv.owner = owner; + return driver_register(&drv->drv); } -EXPORT_SYMBOL_GPL(sdio_register_driver); +EXPORT_SYMBOL_GPL(__sdio_register_driver); /** * sdio_unregister_driver - unregister a function driver diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 8791656e9e..12247219e1 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -19,7 +19,7 @@ struct mmc_gpio { struct gpio_desc *ro_gpio; struct gpio_desc *cd_gpio; - irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); + irq_handler_t cd_gpio_isr; char *ro_label; char *cd_label; u32 cd_debounce_delay_ms; @@ -162,8 +162,7 @@ EXPORT_SYMBOL(mmc_gpio_set_cd_wake); /* Register an alternate interrupt service routine for * the card-detect GPIO. */ -void mmc_gpio_set_cd_isr(struct mmc_host *host, - irqreturn_t (*isr)(int irq, void *dev_id)) +void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr) { struct mmc_gpio *ctx = host->slot.handler_priv; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index aebc587f77..bb0d4fb089 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -233,6 +233,7 @@ config MMC_SDHCI_OF_DWCMSHC depends on MMC_SDHCI_PLTFM depends on OF depends on COMMON_CLK + select MMC_CQHCI help This selects Synopsys DesignWare Cores Mobile Storage Controller support. diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index dba826db73..8199d96200 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -224,18 +224,6 @@ struct mci_slot_pdata { bool non_removable; }; -/** - * struct mci_platform_data - board-specific MMC/SDcard configuration - * @dma_slave: DMA slave interface to use in data transfers. - * @dma_filter: Filtering function to filter the DMA channel - * @slot: Per-slot configuration data. - */ -struct mci_platform_data { - void *dma_slave; - dma_filter_fn dma_filter; - struct mci_slot_pdata slot[ATMCI_MAX_NR_SLOTS]; -}; - struct atmel_mci_caps { bool has_dma_conf_reg; bool has_pdc; @@ -300,7 +288,8 @@ struct atmel_mci_dma { * rate and timeout calculations. * @mapbase: Physical address of the MMIO registers. * @mck: The peripheral bus clock hooked up to the MMC controller. - * @pdev: Platform device associated with the MMC controller. + * @dev: Device associated with the MMC controller. + * @pdata: Per-slot configuration data. * @slot: Slots sharing this MMC controller. * @caps: MCI capabilities depending on MCI version. * @prepare_data: function to setup MCI before data transfer which @@ -377,8 +366,9 @@ struct atmel_mci { unsigned long bus_hz; unsigned long mapbase; struct clk *mck; - struct platform_device *pdev; + struct device *dev; + struct mci_slot_pdata pdata[ATMCI_MAX_NR_SLOTS]; struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS]; struct atmel_mci_caps caps; @@ -530,6 +520,7 @@ static void atmci_show_status_reg(struct seq_file *s, static int atmci_regs_show(struct seq_file *s, void *v) { struct atmel_mci *host = s->private; + struct device *dev = host->dev; u32 *buf; int ret = 0; @@ -538,7 +529,7 @@ static int atmci_regs_show(struct seq_file *s, void *v) if (!buf) return -ENOMEM; - pm_runtime_get_sync(&host->pdev->dev); + pm_runtime_get_sync(dev); /* * Grab a more or less consistent snapshot. Note that we're @@ -549,8 +540,8 @@ static int atmci_regs_show(struct seq_file *s, void *v) memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); spin_unlock_bh(&host->lock); - pm_runtime_mark_last_busy(&host->pdev->dev); - pm_runtime_put_autosuspend(&host->pdev->dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); seq_printf(s, "MR:\t0x%08x%s%s ", buf[ATMCI_MR / 4], @@ -626,7 +617,6 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot) &host->completed_events); } -#if defined(CONFIG_OF) static const struct of_device_id atmci_dt_ids[] = { { .compatible = "atmel,hsmci" }, { /* sentinel */ } @@ -634,79 +624,64 @@ static const struct of_device_id atmci_dt_ids[] = { MODULE_DEVICE_TABLE(of, atmci_dt_ids); -static struct mci_platform_data* -atmci_of_init(struct platform_device *pdev) +static int atmci_of_init(struct atmel_mci *host) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = host->dev; + struct device_node *np = dev->of_node; struct device_node *cnp; - struct mci_platform_data *pdata; u32 slot_id; int err; - if (!np) { - dev_err(&pdev->dev, "device node not found\n"); - return ERR_PTR(-EINVAL); - } - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); + if (!np) + return dev_err_probe(dev, -EINVAL, "device node not found\n"); for_each_child_of_node(np, cnp) { if (of_property_read_u32(cnp, "reg", &slot_id)) { - dev_warn(&pdev->dev, "reg property is missing for %pOF\n", - cnp); + dev_warn(dev, "reg property is missing for %pOF\n", cnp); continue; } if (slot_id >= ATMCI_MAX_NR_SLOTS) { - dev_warn(&pdev->dev, "can't have more than %d slots\n", + dev_warn(dev, "can't have more than %d slots\n", ATMCI_MAX_NR_SLOTS); of_node_put(cnp); break; } if (of_property_read_u32(cnp, "bus-width", - &pdata->slot[slot_id].bus_width)) - pdata->slot[slot_id].bus_width = 1; + &host->pdata[slot_id].bus_width)) + host->pdata[slot_id].bus_width = 1; - pdata->slot[slot_id].detect_pin = - devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp), + host->pdata[slot_id].detect_pin = + devm_fwnode_gpiod_get(dev, of_fwnode_handle(cnp), "cd", GPIOD_IN, "cd-gpios"); - err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin); + err = PTR_ERR_OR_ZERO(host->pdata[slot_id].detect_pin); if (err) { if (err != -ENOENT) { of_node_put(cnp); - return ERR_PTR(err); + return err; } - pdata->slot[slot_id].detect_pin = NULL; + host->pdata[slot_id].detect_pin = NULL; } - pdata->slot[slot_id].non_removable = + host->pdata[slot_id].non_removable = of_property_read_bool(cnp, "non-removable"); - pdata->slot[slot_id].wp_pin = - devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp), + host->pdata[slot_id].wp_pin = + devm_fwnode_gpiod_get(dev, of_fwnode_handle(cnp), "wp", GPIOD_IN, "wp-gpios"); - err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin); + err = PTR_ERR_OR_ZERO(host->pdata[slot_id].wp_pin); if (err) { if (err != -ENOENT) { of_node_put(cnp); - return ERR_PTR(err); + return err; } - pdata->slot[slot_id].wp_pin = NULL; + host->pdata[slot_id].wp_pin = NULL; } } - return pdata; -} -#else /* CONFIG_OF */ -static inline struct mci_platform_data* -atmci_of_init(struct platform_device *dev) -{ - return ERR_PTR(-EINVAL); + return 0; } -#endif static inline unsigned int atmci_get_version(struct atmel_mci *host) { @@ -738,11 +713,10 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, static void atmci_timeout_timer(struct timer_list *t) { - struct atmel_mci *host; + struct atmel_mci *host = from_timer(host, t, timer); + struct device *dev = host->dev; - host = from_timer(host, t, timer); - - dev_dbg(&host->pdev->dev, "software timeout\n"); + dev_dbg(dev, "software timeout\n"); if (host->mrq->cmd->data) { host->mrq->cmd->data->error = -ETIMEDOUT; @@ -860,15 +834,14 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, static void atmci_send_command(struct atmel_mci *host, struct mmc_command *cmd, u32 cmd_flags) { + struct device *dev = host->dev; unsigned int timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : ATMCI_CMD_TIMEOUT_MS; WARN_ON(host->cmd); host->cmd = cmd; - dev_vdbg(&host->pdev->dev, - "start command: ARGR=0x%08x CMDR=0x%08x\n", - cmd->arg, cmd_flags); + dev_vdbg(dev, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); atmci_writel(host, ATMCI_ARGR, cmd->arg); atmci_writel(host, ATMCI_CMDR, cmd_flags); @@ -878,7 +851,9 @@ static void atmci_send_command(struct atmel_mci *host, static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { - dev_dbg(&host->pdev->dev, "send stop command\n"); + struct device *dev = host->dev; + + dev_dbg(dev, "send stop command\n"); atmci_send_command(host, data->stop, host->stop_cmdr); atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); } @@ -951,11 +926,10 @@ static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) static void atmci_pdc_cleanup(struct atmel_mci *host) { struct mmc_data *data = host->data; + struct device *dev = host->dev; if (data) - dma_unmap_sg(&host->pdev->dev, - data->sg, data->sg_len, - mmc_get_dma_dir(data)); + dma_unmap_sg(dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); } /* @@ -965,6 +939,7 @@ static void atmci_pdc_cleanup(struct atmel_mci *host) */ static void atmci_pdc_complete(struct atmel_mci *host) { + struct device *dev = host->dev; int transfer_size = host->data->blocks * host->data->blksz; int i; @@ -981,7 +956,7 @@ static void atmci_pdc_complete(struct atmel_mci *host) atmci_pdc_cleanup(host); - dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__); + dev_dbg(dev, "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); tasklet_schedule(&host->tasklet); } @@ -1003,8 +978,9 @@ static void atmci_dma_complete(void *arg) { struct atmel_mci *host = arg; struct mmc_data *data = host->data; + struct device *dev = host->dev; - dev_vdbg(&host->pdev->dev, "DMA complete\n"); + dev_vdbg(dev, "DMA complete\n"); if (host->caps.has_dma_conf_reg) /* Disable DMA hardware handshaking on MCI */ @@ -1017,8 +993,7 @@ static void atmci_dma_complete(void *arg) * to send the stop command or waiting for NBUSY in this case. */ if (data) { - dev_dbg(&host->pdev->dev, - "(%s) set pending xfer complete\n", __func__); + dev_dbg(dev, "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); tasklet_schedule(&host->tasklet); @@ -1092,6 +1067,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) static u32 atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) { + struct device *dev = host->dev; u32 iflags, tmp; int i; @@ -1117,8 +1093,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) /* Configure PDC */ host->data_size = data->blocks * data->blksz; - dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, - mmc_get_dma_dir(data)); + dma_map_sg(dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); if ((!host->caps.has_rwproof) && (host->data->flags & MMC_DATA_WRITE)) { @@ -1244,8 +1219,9 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) static void atmci_stop_transfer(struct atmel_mci *host) { - dev_dbg(&host->pdev->dev, - "(%s) set pending xfer complete\n", __func__); + struct device *dev = host->dev; + + dev_dbg(dev, "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } @@ -1261,14 +1237,14 @@ static void atmci_stop_transfer_pdc(struct atmel_mci *host) static void atmci_stop_transfer_dma(struct atmel_mci *host) { struct dma_chan *chan = host->data_chan; + struct device *dev = host->dev; if (chan) { dmaengine_terminate_all(chan); atmci_dma_cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ - dev_dbg(&host->pdev->dev, - "(%s) set pending xfer complete\n", __func__); + dev_dbg(dev, "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } @@ -1281,6 +1257,7 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host) static void atmci_start_request(struct atmel_mci *host, struct atmel_mci_slot *slot) { + struct device *dev = host->dev; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; @@ -1296,7 +1273,7 @@ static void atmci_start_request(struct atmel_mci *host, host->cmd_status = 0; host->data_status = 0; - dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); + dev_dbg(dev, "start request: cmd %u\n", mrq->cmd->opcode); if (host->need_reset || host->caps.need_reset_after_xfer) { iflags = atmci_readl(host, ATMCI_IMR); @@ -1375,6 +1352,8 @@ static void atmci_start_request(struct atmel_mci *host, static void atmci_queue_request(struct atmel_mci *host, struct atmel_mci_slot *slot, struct mmc_request *mrq) { + struct device *dev = host->dev; + dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", host->state); @@ -1384,7 +1363,7 @@ static void atmci_queue_request(struct atmel_mci *host, host->state = STATE_SENDING_CMD; atmci_start_request(host, slot); } else { - dev_dbg(&host->pdev->dev, "queue request\n"); + dev_dbg(dev, "queue request\n"); list_add_tail(&slot->queue_node, &host->queue); } spin_unlock_bh(&host->lock); @@ -1394,10 +1373,11 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct atmel_mci_slot *slot = mmc_priv(mmc); struct atmel_mci *host = slot->host; + struct device *dev = host->dev; struct mmc_data *data; WARN_ON(slot->mrq); - dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); + dev_dbg(dev, "MRQ: cmd %u\n", mrq->cmd->opcode); /* * We may "know" the card is gone even though there's still an @@ -1607,6 +1587,7 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) { struct atmel_mci_slot *slot = NULL; struct mmc_host *prev_mmc = host->cur_slot->mmc; + struct device *dev = host->dev; WARN_ON(host->cmd || host->data); @@ -1629,12 +1610,11 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) slot = list_entry(host->queue.next, struct atmel_mci_slot, queue_node); list_del(&slot->queue_node); - dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", - mmc_hostname(slot->mmc)); + dev_vdbg(dev, "list not empty: %s is next\n", mmc_hostname(slot->mmc)); host->state = STATE_SENDING_CMD; atmci_start_request(host, slot); } else { - dev_vdbg(&host->pdev->dev, "list empty\n"); + dev_vdbg(dev, "list empty\n"); host->state = STATE_IDLE; } @@ -1770,6 +1750,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t) struct atmel_mci *host = from_tasklet(host, t, tasklet); struct mmc_request *mrq = host->mrq; struct mmc_data *data = host->data; + struct device *dev = host->dev; enum atmel_mci_state state = host->state; enum atmel_mci_state prev_state; u32 status; @@ -1778,14 +1759,13 @@ static void atmci_tasklet_func(struct tasklet_struct *t) state = host->state; - dev_vdbg(&host->pdev->dev, - "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", + dev_vdbg(dev, "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", state, host->pending_events, host->completed_events, atmci_readl(host, ATMCI_IMR)); do { prev_state = state; - dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state); + dev_dbg(dev, "FSM: state=%d\n", state); switch (state) { case STATE_IDLE: @@ -1798,18 +1778,17 @@ static void atmci_tasklet_func(struct tasklet_struct *t) * END_REQUEST by default, WAITING_NOTBUSY if it's a * command needing it or DATA_XFER if there is data. */ - dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); + dev_dbg(dev, "FSM: cmd ready?\n"); if (!atmci_test_and_clear_pending(host, EVENT_CMD_RDY)) break; - dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); + dev_dbg(dev, "set completed cmd ready\n"); host->cmd = NULL; atmci_set_completed(host, EVENT_CMD_RDY); atmci_command_complete(host, mrq->cmd); if (mrq->data) { - dev_dbg(&host->pdev->dev, - "command with data transfer"); + dev_dbg(dev, "command with data transfer\n"); /* * If there is a command error don't start * data transfer. @@ -1824,8 +1803,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t) } else state = STATE_DATA_XFER; } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { - dev_dbg(&host->pdev->dev, - "command response need waiting notbusy"); + dev_dbg(dev, "command response need waiting notbusy\n"); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); state = STATE_WAITING_NOTBUSY; } else @@ -1836,7 +1814,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t) case STATE_DATA_XFER: if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) { - dev_dbg(&host->pdev->dev, "set completed data error\n"); + dev_dbg(dev, "set completed data error\n"); atmci_set_completed(host, EVENT_DATA_ERROR); state = STATE_END_REQUEST; break; @@ -1849,14 +1827,12 @@ static void atmci_tasklet_func(struct tasklet_struct *t) * to the next step which is WAITING_NOTBUSY in write * case and directly SENDING_STOP in read case. */ - dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n"); + dev_dbg(dev, "FSM: xfer complete?\n"); if (!atmci_test_and_clear_pending(host, EVENT_XFER_COMPLETE)) break; - dev_dbg(&host->pdev->dev, - "(%s) set completed xfer complete\n", - __func__); + dev_dbg(dev, "(%s) set completed xfer complete\n", __func__); atmci_set_completed(host, EVENT_XFER_COMPLETE); if (host->caps.need_notbusy_for_read_ops || @@ -1881,12 +1857,12 @@ static void atmci_tasklet_func(struct tasklet_struct *t) * included) or a write operation. In the latest case, * we need to send a stop command. */ - dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); + dev_dbg(dev, "FSM: not busy?\n"); if (!atmci_test_and_clear_pending(host, EVENT_NOTBUSY)) break; - dev_dbg(&host->pdev->dev, "set completed not busy\n"); + dev_dbg(dev, "set completed not busy\n"); atmci_set_completed(host, EVENT_NOTBUSY); if (host->data) { @@ -1916,12 +1892,12 @@ static void atmci_tasklet_func(struct tasklet_struct *t) * in order to go to the end request state instead of * sending stop again. */ - dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); + dev_dbg(dev, "FSM: cmd ready?\n"); if (!atmci_test_and_clear_pending(host, EVENT_CMD_RDY)) break; - dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); + dev_dbg(dev, "FSM: cmd ready\n"); host->cmd = NULL; data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -2120,6 +2096,7 @@ static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) static irqreturn_t atmci_interrupt(int irq, void *dev_id) { struct atmel_mci *host = dev_id; + struct device *dev = host->dev; u32 status, mask, pending; unsigned int pass_count = 0; @@ -2131,21 +2108,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) break; if (pending & ATMCI_DATA_ERROR_FLAGS) { - dev_dbg(&host->pdev->dev, "IRQ: data error\n"); + dev_dbg(dev, "IRQ: data error\n"); atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS | ATMCI_RXRDY | ATMCI_TXRDY | ATMCI_ENDRX | ATMCI_ENDTX | ATMCI_RXBUFF | ATMCI_TXBUFE); host->data_status = status; - dev_dbg(&host->pdev->dev, "set pending data error\n"); + dev_dbg(dev, "set pending data error\n"); smp_wmb(); atmci_set_pending(host, EVENT_DATA_ERROR); tasklet_schedule(&host->tasklet); } if (pending & ATMCI_TXBUFE) { - dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); + dev_dbg(dev, "IRQ: tx buffer empty\n"); atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); /* @@ -2161,7 +2138,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_pdc_complete(host); } } else if (pending & ATMCI_ENDTX) { - dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); + dev_dbg(dev, "IRQ: end of tx buffer\n"); atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); if (host->data_size) { @@ -2172,7 +2149,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) } if (pending & ATMCI_RXBUFF) { - dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); + dev_dbg(dev, "IRQ: rx buffer full\n"); atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); /* @@ -2188,7 +2165,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_pdc_complete(host); } } else if (pending & ATMCI_ENDRX) { - dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); + dev_dbg(dev, "IRQ: end of rx buffer\n"); atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); if (host->data_size) { @@ -2205,19 +2182,19 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) * The appropriate workaround is to use the BLKE signal. */ if (pending & ATMCI_BLKE) { - dev_dbg(&host->pdev->dev, "IRQ: blke\n"); + dev_dbg(dev, "IRQ: blke\n"); atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); smp_wmb(); - dev_dbg(&host->pdev->dev, "set pending notbusy\n"); + dev_dbg(dev, "set pending notbusy\n"); atmci_set_pending(host, EVENT_NOTBUSY); tasklet_schedule(&host->tasklet); } if (pending & ATMCI_NOTBUSY) { - dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); + dev_dbg(dev, "IRQ: not_busy\n"); atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); smp_wmb(); - dev_dbg(&host->pdev->dev, "set pending notbusy\n"); + dev_dbg(dev, "set pending notbusy\n"); atmci_set_pending(host, EVENT_NOTBUSY); tasklet_schedule(&host->tasklet); } @@ -2228,11 +2205,11 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_write_data_pio(host); if (pending & ATMCI_CMDRDY) { - dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); + dev_dbg(dev, "IRQ: cmd ready\n"); atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); host->cmd_status = status; smp_wmb(); - dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); + dev_dbg(dev, "set pending cmd rdy\n"); atmci_set_pending(host, EVENT_CMD_RDY); tasklet_schedule(&host->tasklet); } @@ -2264,11 +2241,12 @@ static int atmci_init_slot(struct atmel_mci *host, struct mci_slot_pdata *slot_data, unsigned int id, u32 sdc_reg, u32 sdio_irq) { + struct device *dev = host->dev; struct mmc_host *mmc; struct atmel_mci_slot *slot; int ret; - mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev); + mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), dev); if (!mmc) return -ENOMEM; @@ -2387,29 +2365,13 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, static int atmci_configure_dma(struct atmel_mci *host) { - host->dma.chan = dma_request_chan(&host->pdev->dev, "rxtx"); - - if (PTR_ERR(host->dma.chan) == -ENODEV) { - struct mci_platform_data *pdata = host->pdev->dev.platform_data; - dma_cap_mask_t mask; - - if (!pdata || !pdata->dma_filter) - return -ENODEV; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->dma.chan = dma_request_channel(mask, pdata->dma_filter, - pdata->dma_slave); - if (!host->dma.chan) - host->dma.chan = ERR_PTR(-ENODEV); - } + struct device *dev = host->dev; + host->dma.chan = dma_request_chan(dev, "rxtx"); if (IS_ERR(host->dma.chan)) return PTR_ERR(host->dma.chan); - dev_info(&host->pdev->dev, "using %s for DMA transfers\n", - dma_chan_name(host->dma.chan)); + dev_info(dev, "using %s for DMA transfers\n", dma_chan_name(host->dma.chan)); host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -2429,11 +2391,11 @@ static int atmci_configure_dma(struct atmel_mci *host) */ static void atmci_get_cap(struct atmel_mci *host) { + struct device *dev = host->dev; unsigned int version; version = atmci_get_version(host); - dev_info(&host->pdev->dev, - "version: 0x%x\n", version); + dev_info(dev, "version: 0x%x\n", version); host->caps.has_dma_conf_reg = false; host->caps.has_pdc = true; @@ -2474,15 +2436,14 @@ static void atmci_get_cap(struct atmel_mci *host) break; default: host->caps.has_pdc = false; - dev_warn(&host->pdev->dev, - "Unmanaged mci version, set minimum capabilities\n"); + dev_warn(dev, "Unmanaged mci version, set minimum capabilities\n"); break; } } static int atmci_probe(struct platform_device *pdev) { - struct mci_platform_data *pdata; + struct device *dev = &pdev->dev; struct atmel_mci *host; struct resource *regs; unsigned int nr_slots; @@ -2492,32 +2453,28 @@ static int atmci_probe(struct platform_device *pdev) regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) return -ENXIO; - pdata = pdev->dev.platform_data; - if (!pdata) { - pdata = atmci_of_init(pdev); - if (IS_ERR(pdata)) { - dev_err(&pdev->dev, "platform data not available\n"); - return PTR_ERR(pdata); - } - } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); if (!host) return -ENOMEM; - host->pdev = pdev; + host->dev = dev; spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); - host->mck = devm_clk_get(&pdev->dev, "mci_clk"); + ret = atmci_of_init(host); + if (ret) + return dev_err_probe(dev, ret, "Slot information not available\n"); + + host->mck = devm_clk_get(dev, "mci_clk"); if (IS_ERR(host->mck)) return PTR_ERR(host->mck); - host->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); + host->regs = devm_ioremap(dev, regs->start, resource_size(regs)); if (!host->regs) return -ENOMEM; @@ -2532,7 +2489,7 @@ static int atmci_probe(struct platform_device *pdev) tasklet_setup(&host->tasklet, atmci_tasklet_func); - ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); + ret = request_irq(irq, atmci_interrupt, 0, dev_name(dev), host); if (ret) { clk_disable_unprepare(host->mck); return ret; @@ -2548,12 +2505,12 @@ static int atmci_probe(struct platform_device *pdev) host->submit_data = &atmci_submit_data_dma; host->stop_transfer = &atmci_stop_transfer_dma; } else if (host->caps.has_pdc) { - dev_info(&pdev->dev, "using PDC\n"); + dev_info(dev, "using PDC\n"); host->prepare_data = &atmci_prepare_data_pdc; host->submit_data = &atmci_submit_data_pdc; host->stop_transfer = &atmci_stop_transfer_pdc; } else { - dev_info(&pdev->dev, "using PIO\n"); + dev_info(dev, "using PIO\n"); host->prepare_data = &atmci_prepare_data; host->submit_data = &atmci_submit_data; host->stop_transfer = &atmci_stop_transfer; @@ -2563,25 +2520,25 @@ static int atmci_probe(struct platform_device *pdev) timer_setup(&host->timer, atmci_timeout_timer, 0); - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_enable(&pdev->dev); + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); /* We need at least one slot to succeed */ nr_slots = 0; ret = -ENODEV; - if (pdata->slot[0].bus_width) { - ret = atmci_init_slot(host, &pdata->slot[0], + if (host->pdata[0].bus_width) { + ret = atmci_init_slot(host, &host->pdata[0], 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); if (!ret) { nr_slots++; host->buf_size = host->slot[0]->mmc->max_req_size; } } - if (pdata->slot[1].bus_width) { - ret = atmci_init_slot(host, &pdata->slot[1], + if (host->pdata[1].bus_width) { + ret = atmci_init_slot(host, &host->pdata[1], 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); if (!ret) { nr_slots++; @@ -2592,27 +2549,25 @@ static int atmci_probe(struct platform_device *pdev) } if (!nr_slots) { - dev_err(&pdev->dev, "init failed: no slot defined\n"); + dev_err_probe(dev, ret, "init failed: no slot defined\n"); goto err_init_slot; } if (!host->caps.has_rwproof) { - host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, + host->buffer = dma_alloc_coherent(dev, host->buf_size, &host->buf_phys_addr, GFP_KERNEL); if (!host->buffer) { - ret = -ENOMEM; - dev_err(&pdev->dev, "buffer allocation failed\n"); + ret = dev_err_probe(dev, -ENOMEM, "buffer allocation failed\n"); goto err_dma_alloc; } } - dev_info(&pdev->dev, - "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", - host->mapbase, irq, nr_slots); + dev_info(dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", + host->mapbase, irq, nr_slots); - pm_runtime_mark_last_busy(&host->pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; @@ -2624,8 +2579,8 @@ err_dma_alloc: err_init_slot: clk_disable_unprepare(host->mck); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); del_timer_sync(&host->timer); if (!IS_ERR(host->dma.chan)) @@ -2638,13 +2593,13 @@ err_dma_probe_defer: static void atmci_remove(struct platform_device *pdev) { struct atmel_mci *host = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; unsigned int i; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(dev); if (host->buffer) - dma_free_coherent(&pdev->dev, host->buf_size, - host->buffer, host->buf_phys_addr); + dma_free_coherent(dev, host->buf_size, host->buffer, host->buf_phys_addr); for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { if (host->slot[i]) @@ -2663,8 +2618,8 @@ static void atmci_remove(struct platform_device *pdev) clk_disable_unprepare(host->mck); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); } #ifdef CONFIG_PM @@ -2701,7 +2656,7 @@ static struct platform_driver atmci_driver = { .driver = { .name = "atmel_mci", .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .of_match_table = of_match_ptr(atmci_dt_ids), + .of_match_table = atmci_dt_ids, .pm = &atmci_dev_pm_ops, }, }; diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index 41e94cd141..c14d7251d0 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -474,8 +474,8 @@ static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq) return sg_count; } -static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, - bool dma64) +void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, + bool dma64) { __le32 *attr = (__le32 __force *)desc; @@ -495,6 +495,7 @@ static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, dataddr[0] = cpu_to_le32(addr); } } +EXPORT_SYMBOL(cqhci_set_tran_desc); static int cqhci_prep_tran_desc(struct mmc_request *mrq, struct cqhci_host *cq_host, int tag) @@ -522,7 +523,11 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq, if ((i+1) == sg_count) end = true; - cqhci_set_tran_desc(desc, addr, len, end, dma64); + if (cq_host->ops->set_tran_desc) + cq_host->ops->set_tran_desc(cq_host, &desc, addr, len, end, dma64); + else + cqhci_set_tran_desc(desc, addr, len, end, dma64); + desc += cq_host->trans_desc_len; } diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 1a12e40a02..fab9d74445 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -293,6 +293,9 @@ struct cqhci_host_ops { int (*program_key)(struct cqhci_host *cq_host, const union cqhci_crypto_cfg_entry *cfg, int slot); #endif + void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc, + dma_addr_t addr, int len, bool end, bool dma64); + }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) @@ -318,6 +321,7 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); int cqhci_deactivate(struct mmc_host *mmc); +void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64); static inline int cqhci_suspend(struct mmc_host *mmc) { return cqhci_deactivate(mmc); diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index 61923a5183..6099756e59 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -87,7 +87,6 @@ static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot, goto tuning_out; prev_err = err; - err = 0; } tuning_out: diff --git a/drivers/mmc/host/dw_mmc-hi3798mv200.c b/drivers/mmc/host/dw_mmc-hi3798mv200.c index 989ae8dda7..96af693e3e 100644 --- a/drivers/mmc/host/dw_mmc-hi3798mv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798mv200.c @@ -133,7 +133,6 @@ static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot, goto tuning_out; prev_err = err; - err = 0; } tuning_out: diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 1634b1f5d2..a94835b8ab 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -13,7 +13,6 @@ #include <linux/ioport.h> #include <linux/irq.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm.h> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index c675dec587..12f4faaaf4 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -589,6 +589,9 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve) sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); priv->needs_adjust_hs400 = false; renesas_sdhi_set_clock(host, host->clk_cache); + + /* Ensure default value for this driver. */ + renesas_sdhi_sdbuf_width(host, 16); } else if (priv->scc_ctl) { renesas_sdhi_scc_reset(host, priv); } diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 53d34c3edd..422fa63a2e 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -210,7 +210,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = { .manual_tap_correction = true, }; -static const struct renesas_sdhi_quirks sdhi_quirks_r9a09g011 = { +static const struct renesas_sdhi_quirks sdhi_quirks_rzg2l = { .fixed_addr_mode = true, .hs400_disabled = true, }; @@ -255,9 +255,9 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = { .quirks = &sdhi_quirks_r8a77990, }; -static const struct renesas_sdhi_of_data_with_quirks of_r9a09g011_compatible = { +static const struct renesas_sdhi_of_data_with_quirks of_rzg2l_compatible = { .of_data = &of_data_rcar_gen3, - .quirks = &sdhi_quirks_r9a09g011, + .quirks = &sdhi_quirks_rzg2l, }; static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = { @@ -283,7 +283,8 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, }, { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, - { .compatible = "renesas,sdhi-r9a09g011", .data = &of_r9a09g011_compatible, }, + { .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, }, + { .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, }, {}, diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c index c97363e2d8..3ad87322f6 100644 --- a/drivers/mmc/host/sdhci-esdhc-mcf.c +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -335,7 +335,7 @@ static void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host, data->blksz * data->blocks); } -static struct sdhci_ops sdhci_esdhc_ops = { +static const struct sdhci_ops sdhci_esdhc_ops = { .reset = esdhc_mcf_reset, .set_clock = esdhc_mcf_pltfm_set_clock, .get_max_clock = esdhc_mcf_pltfm_get_max_clock, diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index f2e4a93ed1..39edf04fed 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -21,6 +21,7 @@ #include <linux/sizes.h> #include "sdhci-pltfm.h" +#include "cqhci.h" #define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16) @@ -52,6 +53,9 @@ #define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */ #define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */ +/* DWC IP vendor area 2 pointer */ +#define DWCMSHC_P_VENDOR_AREA2 0xea + /* Sophgo CV18XX specific Registers */ #define CV18XX_SDHCI_MSHC_CTRL 0x00 #define CV18XX_EMMC_FUNC_EN BIT(0) @@ -66,6 +70,10 @@ #define CV18XX_SDHCI_PHY_CONFIG 0x4c #define CV18XX_PHY_TX_BPS BIT(0) +#define CV18XX_TUNE_MAX 128 +#define CV18XX_TUNE_STEP 1 +#define CV18XX_RETRY_TUNING_MAX 50 + /* Rockchip specific Registers */ #define DWCMSHC_EMMC_DLL_CTRL 0x800 #define DWCMSHC_EMMC_DLL_RXCLK 0x804 @@ -181,6 +189,10 @@ #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) +#define DWCMSHC_SDHCI_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ + SDHCI_TRNS_BLK_CNT_EN | \ + SDHCI_TRNS_DMA) + enum dwcmshc_rk_type { DWCMSHC_RK3568, DWCMSHC_RK3588, @@ -196,7 +208,9 @@ struct rk35xx_priv { struct dwcmshc_priv { struct clk *bus_clk; - int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */ + int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */ + void *priv; /* pointer to SoC private stuff */ u16 delay_line; u16 flags; @@ -455,6 +469,90 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, sdhci_writel(host, vendor, reg); } +static int dwcmshc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + int err = sdhci_execute_tuning(mmc, opcode); + struct sdhci_host *host = mmc_priv(mmc); + + if (err) + return err; + + /* + * Tuning can leave the IP in an active state (Buffer Read Enable bit + * set) which prevents the entry to low power states (i.e. S0i3). Data + * reset will clear it. + */ + sdhci_reset(host, SDHCI_RESET_DATA); + + return 0; +} + +static u32 dwcmshc_cqe_irq_handler(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + +static void dwcmshc_sdhci_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + u8 ctrl; + + sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); + + sdhci_cqe_enable(mmc); + + /* + * The "DesignWare Cores Mobile Storage Host Controller + * DWC_mshc / DWC_mshc_lite Databook" says: + * when Host Version 4 Enable" is 1 in Host Control 2 register, + * SDHCI_CTRL_ADMA32 bit means ADMA2 is selected. + * Selection of 32-bit/64-bit System Addressing: + * either 32-bit or 64-bit system addressing is selected by + * 64-bit Addressing bit in Host Control 2 register. + * + * On the other hand the "DesignWare Cores Mobile Storage Host + * Controller DWC_mshc / DWC_mshc_lite User Guide" says, that we have to + * set DMA_SEL to ADMA2 _only_ mode in the Host Control 2 register. + */ + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_DMA_MASK; + ctrl |= SDHCI_CTRL_ADMA32; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +} + +static void dwcmshc_set_tran_desc(struct cqhci_host *cq_host, u8 **desc, + dma_addr_t addr, int len, bool end, bool dma64) +{ + int tmplen, offset; + + if (likely(!len || BOUNDARY_OK(addr, len))) { + cqhci_set_tran_desc(*desc, addr, len, end, dma64); + return; + } + + offset = addr & (SZ_128M - 1); + tmplen = SZ_128M - offset; + cqhci_set_tran_desc(*desc, addr, tmplen, false, dma64); + + addr += tmplen; + len -= tmplen; + *desc += cq_host->trans_desc_len; + cqhci_set_tran_desc(*desc, addr, len, end, dma64); +} + +static void dwcmshc_cqhci_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -686,6 +784,113 @@ static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY); } +static void cv18xx_sdhci_set_tap(struct sdhci_host *host, int tap) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + u16 clk; + u32 val; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); + val &= ~CV18XX_LATANCY_1T; + sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); + + val = (FIELD_PREP(CV18XX_PHY_TX_DLY_MSK, 0) | + FIELD_PREP(CV18XX_PHY_TX_SRC_MSK, CV18XX_PHY_TX_SRC_INVERT_CLK_TX) | + FIELD_PREP(CV18XX_PHY_RX_DLY_MSK, tap)); + sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY); + + sdhci_writel(host, 0, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG); + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + usleep_range(1000, 2000); +} + +static int cv18xx_retry_tuning(struct mmc_host *mmc, u32 opcode, int *cmd_error) +{ + int ret, retry = 0; + + while (retry < CV18XX_RETRY_TUNING_MAX) { + ret = mmc_send_tuning(mmc, opcode, NULL); + if (ret) + return ret; + retry++; + } + + return 0; +} + +static void cv18xx_sdhci_post_tuning(struct sdhci_host *host) +{ + u32 val; + + val = sdhci_readl(host, SDHCI_INT_STATUS); + val |= SDHCI_INT_DATA_AVAIL; + sdhci_writel(host, val, SDHCI_INT_STATUS); + + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); +} + +static int cv18xx_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int min, max, avg, ret; + int win_length, target_min, target_max, target_win_length; + + min = max = 0; + target_win_length = 0; + + sdhci_reset_tuning(host); + + while (max < CV18XX_TUNE_MAX) { + /* find the mininum delay first which can pass tuning */ + while (min < CV18XX_TUNE_MAX) { + cv18xx_sdhci_set_tap(host, min); + if (!cv18xx_retry_tuning(host->mmc, opcode, NULL)) + break; + min += CV18XX_TUNE_STEP; + } + + /* find the maxinum delay which can not pass tuning */ + max = min + CV18XX_TUNE_STEP; + while (max < CV18XX_TUNE_MAX) { + cv18xx_sdhci_set_tap(host, max); + if (cv18xx_retry_tuning(host->mmc, opcode, NULL)) { + max -= CV18XX_TUNE_STEP; + break; + } + max += CV18XX_TUNE_STEP; + } + + win_length = max - min + 1; + /* get the largest pass window */ + if (win_length > target_win_length) { + target_win_length = win_length; + target_min = min; + target_max = max; + } + + /* continue to find the next pass window */ + min = max + CV18XX_TUNE_STEP; + } + + cv18xx_sdhci_post_tuning(host); + + /* use average delay to get the best timing */ + avg = (target_min + target_max) / 2; + cv18xx_sdhci_set_tap(host, avg); + ret = mmc_send_tuning(host->mmc, opcode, NULL); + + dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", + ret ? "failed" : "passed", avg, ret); + + return ret; +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, @@ -693,6 +898,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = { .get_max_clock = dwcmshc_get_max_clock, .reset = sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, + .irq = dwcmshc_cqe_irq_handler, }; static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { @@ -712,7 +918,7 @@ static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = { .reset = th1520_sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, .voltage_switch = dwcmshc_phy_1_8v_init, - .platform_execute_tuning = &th1520_execute_tuning, + .platform_execute_tuning = th1520_execute_tuning, }; static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { @@ -722,6 +928,7 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { .get_max_clock = dwcmshc_get_max_clock, .reset = cv18xx_sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, + .platform_execute_tuning = cv18xx_sdhci_execute_tuning, }; static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { @@ -759,6 +966,73 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, }; +static const struct cqhci_host_ops dwcmshc_cqhci_ops = { + .enable = dwcmshc_sdhci_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = dwcmshc_cqhci_dumpregs, + .set_tran_desc = dwcmshc_set_tran_desc, +}; + +static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev) +{ + struct cqhci_host *cq_host; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + bool dma64 = false; + u16 clk; + int err; + + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + dev_err(mmc_dev(host->mmc), "Unable to setup CQE: not enough memory\n"); + goto dsbl_cqe_caps; + } + + /* + * For dwcmshc host controller we have to enable internal clock + * before access to some registers from Vendor Specific Area 2. + */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + if (!(clk & SDHCI_CLOCK_INT_EN)) { + dev_err(mmc_dev(host->mmc), "Unable to setup CQE: internal clock enable error\n"); + goto free_cq_host; + } + + cq_host->mmio = host->ioaddr + priv->vendor_specific_area2; + cq_host->ops = &dwcmshc_cqhci_ops; + + /* Enable using of 128-bit task descriptors */ + dma64 = host->flags & SDHCI_USE_64_BIT_DMA; + if (dma64) { + dev_dbg(mmc_dev(host->mmc), "128-bit task descriptors\n"); + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + } + err = cqhci_init(cq_host, host->mmc, dma64); + if (err) { + dev_err(mmc_dev(host->mmc), "Unable to setup CQE: error %d\n", err); + goto int_clock_disable; + } + + dev_dbg(mmc_dev(host->mmc), "CQE init done\n"); + + return; + +int_clock_disable: + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + +free_cq_host: + devm_kfree(&pdev->dev, cq_host); + +dsbl_cqe_caps: + host->mmc->caps2 &= ~(MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD); +} + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) { int err; @@ -863,7 +1137,7 @@ static int dwcmshc_probe(struct platform_device *pdev) struct rk35xx_priv *rk_priv = NULL; const struct sdhci_pltfm_data *pltfm_data; int err; - u32 extra; + u32 extra, caps; pltfm_data = device_get_match_data(&pdev->dev); if (!pltfm_data) { @@ -914,6 +1188,7 @@ static int dwcmshc_probe(struct platform_device *pdev) host->mmc_host_ops.request = dwcmshc_request; host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; + host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning; if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) { rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); @@ -963,6 +1238,10 @@ static int dwcmshc_probe(struct platform_device *pdev) sdhci_enable_v4_mode(host); #endif + caps = sdhci_readl(host, SDHCI_CAPABILITIES); + if (caps & SDHCI_CAN_64BIT_V4) + sdhci_enable_v4_mode(host); + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; pm_runtime_get_noresume(dev); @@ -973,6 +1252,14 @@ static int dwcmshc_probe(struct platform_device *pdev) if (err) goto err_rpm; + /* Setup Command Queue Engine if enabled */ + if (device_property_read_bool(&pdev->dev, "supports-cqe")) { + priv->vendor_specific_area2 = + sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2); + + dwcmshc_cqhci_init(host, pdev); + } + if (rk_priv) dwcmshc_rk35xx_postinit(host, priv); @@ -1045,6 +1332,12 @@ static int dwcmshc_suspend(struct device *dev) pm_runtime_resume(dev); + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + } + ret = sdhci_suspend_host(host); if (ret) return ret; @@ -1089,6 +1382,12 @@ static int dwcmshc_resume(struct device *dev) if (ret) goto disable_rockchip_clks; + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_resume(host->mmc); + if (ret) + goto disable_rockchip_clks; + } + return 0; disable_rockchip_clks: diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 94076b0955..5841a9afeb 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -925,7 +925,7 @@ static void sdhci_omap_set_timeout(struct sdhci_host *host, __sdhci_set_timeout(host, cmd); } -static struct sdhci_ops sdhci_omap_ops = { +static const struct sdhci_ops sdhci_omap_ops = { .set_clock = sdhci_omap_set_clock, .set_power = sdhci_omap_set_power, .enable_dma = sdhci_omap_enable_dma, diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 9fe40f342d..23e6ba7014 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -63,7 +63,7 @@ static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) return device_wakeup_enable(&chip->pdev->dev); else if (!cap_cd_wake) - return device_wakeup_disable(&chip->pdev->dev); + device_wakeup_disable(&chip->pdev->dev); return 0; } diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 77911a57b1..0f81586a19 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -25,12 +25,6 @@ #define GLI_9750_WT_EN_ON 0x1 #define GLI_9750_WT_EN_OFF 0x0 -#define PCI_GLI_9750_PM_CTRL 0xFC -#define PCI_GLI_9750_PM_STATE GENMASK(1, 0) - -#define PCI_GLI_9750_CORRERR_MASK 0x214 -#define PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12) - #define SDHCI_GLI_9750_CFG2 0x848 #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) #define GLI_9750_CFG2_L1DLY_VALUE 0x1F @@ -152,12 +146,6 @@ #define PCI_GLI_9755_MISC 0x78 #define PCI_GLI_9755_MISC_SSC_OFF BIT(26) -#define PCI_GLI_9755_PM_CTRL 0xFC -#define PCI_GLI_9755_PM_STATE GENMASK(1, 0) - -#define PCI_GLI_9755_CORRERR_MASK 0x214 -#define PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12) - #define SDHCI_GLI_9767_GM_BURST_SIZE 0x510 #define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8) @@ -547,6 +535,7 @@ static void gl9750_hw_setting(struct sdhci_host *host) { struct sdhci_pci_slot *slot = sdhci_priv(host); struct pci_dev *pdev; + int aer; u32 value; pdev = slot->chip->pdev; @@ -561,16 +550,16 @@ static void gl9750_hw_setting(struct sdhci_host *host) sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); /* toggle PM state to allow GL9750 to enter ASPM L1.2 */ - pci_read_config_dword(pdev, PCI_GLI_9750_PM_CTRL, &value); - value |= PCI_GLI_9750_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value); - value &= ~PCI_GLI_9750_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value); + pci_set_power_state(pdev, PCI_D3hot); + pci_set_power_state(pdev, PCI_D0); /* mask the replay timer timeout of AER */ - pci_read_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, &value); - value |= PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT; - pci_write_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, value); + aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (aer) { + pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); + value |= PCI_ERR_COR_REP_TIMER; + pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); + } gl9750_wt_off(host); } @@ -745,6 +734,7 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) static void gl9755_hw_setting(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; + int aer; u32 value; gl9755_wt_on(pdev); @@ -775,16 +765,16 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value); /* toggle PM state to allow GL9755 to enter ASPM L1.2 */ - pci_read_config_dword(pdev, PCI_GLI_9755_PM_CTRL, &value); - value |= PCI_GLI_9755_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); - value &= ~PCI_GLI_9755_PM_STATE; - pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); + pci_set_power_state(pdev, PCI_D3hot); + pci_set_power_state(pdev, PCI_D0); /* mask the replay timer timeout of AER */ - pci_read_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, &value); - value |= PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT; - pci_write_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, value); + aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (aer) { + pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value); + value |= PCI_ERR_COR_REP_TIMER; + pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value); + } gl9755_wt_off(pdev); } diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 0e8a8ac14e..a71d56c703 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -17,10 +17,8 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -132,14 +130,16 @@ struct sdhci_s3c { * struct sdhci_s3c_drv_data - S3C SDHCI platform specific driver data * @sdhci_quirks: sdhci host specific quirks. * @no_divider: no or non-standard internal clock divider. + * @ops: sdhci_ops to use for this variant * * Specifies platform specific configuration of sdhci controller. * Note: A structure for driver specific platform data is used for future * expansion of its usage. */ struct sdhci_s3c_drv_data { - unsigned int sdhci_quirks; - bool no_divider; + unsigned int sdhci_quirks; + bool no_divider; + const struct sdhci_ops *ops; }; static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) @@ -414,7 +414,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } -static struct sdhci_ops sdhci_s3c_ops = { +static const struct sdhci_ops sdhci_s3c_ops_s3c6410 = { .get_max_clock = sdhci_s3c_get_max_clk, .set_clock = sdhci_s3c_set_clock, .get_min_clock = sdhci_s3c_get_min_clock, @@ -423,6 +423,15 @@ static struct sdhci_ops sdhci_s3c_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; +static const struct sdhci_ops sdhci_s3c_ops_exynos4 __maybe_unused = { + .get_max_clock = sdhci_cmu_get_max_clock, + .set_clock = sdhci_cmu_set_clock, + .get_min_clock = sdhci_cmu_get_min_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + #ifdef CONFIG_OF static int sdhci_s3c_parse_dt(struct device *dev, struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) @@ -446,7 +455,7 @@ static int sdhci_s3c_parse_dt(struct device *dev, return 0; } - if (of_get_named_gpio(node, "cd-gpios", 0)) + if (of_property_present(node, "cd-gpios")) return 0; /* assuming internal card detect that will be configured by pinctrl */ @@ -562,7 +571,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) pdata->cfg_gpio(pdev, pdata->max_width); host->hw_name = "samsung-hsmmc"; - host->ops = &sdhci_s3c_ops; + host->ops = &sdhci_s3c_ops_s3c6410; host->quirks = 0; host->quirks2 = 0; host->irq = irq; @@ -572,6 +581,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; if (drv_data) { host->quirks |= drv_data->sdhci_quirks; + host->ops = drv_data->ops; sc->no_divider = drv_data->no_divider; } @@ -619,16 +629,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; - /* - * If controller does not have internal clock divider, - * we can use overriding functions instead of default. - */ - if (sc->no_divider) { - sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; - sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; - sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; - } - /* It supports additional host capabilities if needed */ if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; @@ -760,6 +760,7 @@ MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); #ifdef CONFIG_OF static const struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { .no_divider = true, + .ops = &sdhci_s3c_ops_exynos4, }; static const struct of_device_id sdhci_s3c_dt_match[] = { diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index bed57a1c64..8776f42871 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -13,7 +13,6 @@ #include <linux/mmc/mmc.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -440,7 +439,7 @@ static void sdhci_sprd_set_power(struct sdhci_host *host, unsigned char mode, } } -static struct sdhci_ops sdhci_sprd_ops = { +static const struct sdhci_ops sdhci_sprd_ops = { .read_l = sdhci_sprd_readl, .write_l = sdhci_sprd_writel, .write_w = sdhci_sprd_writew, diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 562034af65..17ad32cfc0 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -141,8 +141,8 @@ static const struct timing_data td[] = { struct sdhci_am654_data { struct regmap *base; - int otap_del_sel[ARRAY_SIZE(td)]; - int itap_del_sel[ARRAY_SIZE(td)]; + u32 otap_del_sel[ARRAY_SIZE(td)]; + u32 itap_del_sel[ARRAY_SIZE(td)]; u32 itap_del_ena[ARRAY_SIZE(td)]; int clkbuf_sel; int trm_icp; @@ -279,7 +279,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_set_clock(host, clock); - /* Setup DLL Output TAP delay */ + /* Setup Output TAP delay */ otap_del_sel = sdhci_am654->otap_del_sel[timing]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; @@ -329,7 +329,7 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, u32 itap_del_sel; u32 mask, val; - /* Setup DLL Output TAP delay */ + /* Setup Output TAP delay */ otap_del_sel = sdhci_am654->otap_del_sel[timing]; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; @@ -543,7 +543,7 @@ static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, return 0; } -static struct sdhci_ops sdhci_am654_ops = { +static const struct sdhci_ops sdhci_am654_ops = { .platform_execute_tuning = sdhci_am654_platform_execute_tuning, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, @@ -573,7 +573,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = { .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT, }; -static struct sdhci_ops sdhci_j721e_8bit_ops = { +static const struct sdhci_ops sdhci_j721e_8bit_ops = { .platform_execute_tuning = sdhci_am654_platform_execute_tuning, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, @@ -597,7 +597,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { .flags = DLL_PRESENT | DLL_CALIB, }; -static struct sdhci_ops sdhci_j721e_4bit_ops = { +static const struct sdhci_ops sdhci_j721e_4bit_ops = { .platform_execute_tuning = sdhci_am654_platform_execute_tuning, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, |