diff options
Diffstat (limited to 'drivers/mci/dw_mmc.c')
-rw-r--r-- | drivers/mci/dw_mmc.c | 128 |
1 files changed, 68 insertions, 60 deletions
diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c index f035317ef2..c49e839c94 100644 --- a/drivers/mci/dw_mmc.c +++ b/drivers/mci/dw_mmc.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2013 Altera Corporation <www.altera.com> +// SPDX-FileCopyrightText: 2012 SAMSUNG Electronics + /* - * Copyright (C) 2013 Altera Corporation <www.altera.com> - * - * (C) Copyright 2012 SAMSUNG Electronics * Jaehoon Chung <jh80.chung@samsung.com> * Rajeshawari Shinde <rajeshwari.s@samsung.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <common.h> @@ -27,23 +17,26 @@ #include <io.h> #include <platform_data/dw_mmc.h> #include <linux/bitops.h> +#include <linux/reset.h> #include <linux/clk.h> #include <linux/err.h> -#include <asm-generic/errno.h> +#include <errno.h> #include "dw_mmc.h" struct dwmci_host { struct mci_host mci; + struct device *dev; struct clk *clk_biu, *clk_ciu; void *ioaddr; unsigned int fifo_size_bytes; struct dwmci_idmac *idmac; - unsigned long clkrate; + u32 clkrate; int ciu_div; u32 fifoth_val; u32 pwren_value; + dma_addr_t idmac_dma; }; struct dwmci_idmac { @@ -120,12 +113,12 @@ static int dwmci_prepare_data_pio(struct dwmci_host *host, } static int dwmci_prepare_data_dma(struct dwmci_host *host, - struct mci_data *data) + struct mci_data *data, dma_addr_t dma) { unsigned long ctrl; unsigned int i = 0, flags, cnt, blk_cnt; - unsigned long data_start, start_addr; struct dwmci_idmac *desc = host->idmac; + dma_addr_t desc_dma = host->idmac_dma; blk_cnt = data->blocks; @@ -134,13 +127,7 @@ static int dwmci_prepare_data_dma(struct dwmci_host *host, dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); - data_start = (uint32_t)desc; - dwmci_writel(host, DWMCI_DBADDR, (uint32_t)desc); - - if (data->flags & MMC_DATA_READ) - start_addr = (uint32_t)data->dest; - else - start_addr = (uint32_t)data->src; + dwmci_writel(host, DWMCI_DBADDR, desc_dma); do { flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH; @@ -153,10 +140,12 @@ static int dwmci_prepare_data_dma(struct dwmci_host *host, cnt = data->blocksize * 8; } + desc_dma += sizeof(*desc); + desc->flags = flags; desc->cnt = cnt; - desc->addr = start_addr + (i * PAGE_SIZE); - desc->next_addr = (uint32_t)(desc + 1); + desc->addr = dma + (i * PAGE_SIZE); + desc->next_addr = desc_dma; dev_dbg(host->mci.hw_dev, "desc@ 0x%p 0x%08x 0x%08x 0x%08x 0x%08x\n", desc, flags, cnt, desc->addr, desc->next_addr); @@ -183,12 +172,12 @@ static int dwmci_prepare_data_dma(struct dwmci_host *host, } static int dwmci_prepare_data(struct dwmci_host *host, - struct mci_data *data) + struct mci_data *data, dma_addr_t dma) { if (dwmci_use_pio(host)) return dwmci_prepare_data_pio(host, data); else - return dwmci_prepare_data_dma(host, data); + return dwmci_prepare_data_dma(host, data, dma); } static int dwmci_set_transfer_mode(struct dwmci_host *host, @@ -283,6 +272,7 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) uint64_t start; int ret; unsigned int num_bytes = 0; + dma_addr_t dma = 0; start = get_time_ns(); while (1) { @@ -298,16 +288,20 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); if (data) { + num_bytes = data->blocks * data->blocksize; if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_device((unsigned long)data->src, - num_bytes, DMA_TO_DEVICE); + dma = dma_map_single(host->dev, (void *)data->src, num_bytes, + DMA_TO_DEVICE); else - dma_sync_single_for_device((unsigned long)data->dest, - num_bytes, DMA_FROM_DEVICE); + dma = dma_map_single(host->dev, data->dest, num_bytes, + DMA_FROM_DEVICE); + + if (dma_mapping_error(host->dev, dma)) + return -EFAULT; - ret = dwmci_prepare_data(host, data); + ret = dwmci_prepare_data(host, data, dma); if (ret) return ret; } @@ -411,11 +405,11 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) dwmci_writel(host, DWMCI_CTRL, ctrl); if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_cpu((unsigned long)data->src, - num_bytes, DMA_TO_DEVICE); + dma_unmap_single(host->dev, dma, num_bytes, + DMA_TO_DEVICE); else - dma_sync_single_for_cpu((unsigned long)data->dest, - num_bytes, DMA_FROM_DEVICE); + dma_unmap_single(host->dev, dma, num_bytes, + DMA_FROM_DEVICE); } } @@ -502,7 +496,7 @@ static int dwmci_card_present(struct mci_host *mci) return 1; } -static int dwmci_init(struct mci_host *mci, struct device_d *dev) +static int dwmci_init(struct mci_host *mci, struct device *dev) { struct dwmci_host *host = to_dwmci_host(mci); uint32_t fifo_size; @@ -534,8 +528,8 @@ static int dwmci_init(struct mci_host *mci, struct device_d *dev) /* * If fifo-depth property is set, use this value */ - if (!of_property_read_u32(host->mci.hw_dev->device_node, - "fifo-depth", &fifo_size)) { + if (!of_property_read_u32(host->mci.hw_dev->of_node, + "fifo-depth", &fifo_size)) { host->fifo_size_bytes = fifo_size; dev_dbg(host->mci.hw_dev, "Using fifo-depth=%u\n", host->fifo_size_bytes); @@ -553,21 +547,18 @@ static int dwmci_init(struct mci_host *mci, struct device_d *dev) return 0; } -static int dw_mmc_detect(struct device_d *dev) -{ - struct dwmci_host *host = dev->priv; - - return mci_detect_card(&host->mci); -} - -static int dw_mmc_probe(struct device_d *dev) +static int dw_mmc_probe(struct device *dev) { + struct reset_control *rst; struct resource *iores; struct dwmci_host *host; struct dw_mmc_platform_data *pdata = dev->platform_data; host = xzalloc(sizeof(*host)); + dma_set_mask(dev, DMA_BIT_MASK(32)); + host->dev = dev; + host->clk_biu = clk_get(dev, "biu"); if (IS_ERR(host->clk_biu)) return PTR_ERR(host->clk_biu); @@ -579,13 +570,24 @@ static int dw_mmc_probe(struct device_d *dev) clk_enable(host->clk_biu); clk_enable(host->clk_ciu); + rst = reset_control_get_optional(dev, "reset"); + if (IS_ERR(rst)) { + dev_warn(dev, "error claiming reset: %pe\n", rst); + } else if (rst) { + reset_control_assert(rst); + udelay(10); + reset_control_deassert(rst); + } + iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) return PTR_ERR(iores); host->ioaddr = IOMEM(iores->start); host->idmac = dma_alloc_coherent(sizeof(*host->idmac) * DW_MMC_NUM_IDMACS, - DMA_ADDRESS_BROKEN); + &host->idmac_dma); + if (!host->idmac) + return -ENOMEM; host->mci.send_cmd = dwmci_cmd; host->mci.set_ios = dwmci_set_ios; @@ -601,23 +603,26 @@ static int dw_mmc_probe(struct device_d *dev) host->ciu_div = pdata->ciu_div; host->mci.host_caps &= ~MMC_CAP_BIT_DATA_MASK; host->mci.host_caps |= pdata->bus_width_caps; - } else if (dev->device_node) { - of_property_read_u32(dev->device_node, "dw-mshc-ciu-div", - &host->ciu_div); + } else if (dev->of_node) { + of_property_read_u32(dev->of_node, "dw-mshc-ciu-div", + &host->ciu_div); } /* divider is 0 based in pdata and 1 based in our private struct */ host->ciu_div++; - if (of_device_is_compatible(dev->device_node, - "rockchip,rk2928-dw-mshc")) + if (of_device_is_compatible(dev->of_node, + "rockchip,rk2928-dw-mshc")) host->pwren_value = 0; else host->pwren_value = 1; - dev->detect = dw_mmc_detect; + if (of_device_is_compatible(dev->of_node, "starfive,jh7100-dw-mshc")) + of_property_read_u32(dev->of_node, "clock-frequency", + &host->clkrate); + if (!host->clkrate) + host->clkrate = clk_get_rate(host->clk_ciu); - host->clkrate = clk_get_rate(host->clk_ciu); host->mci.f_min = host->clkrate / 510 / host->ciu_div; if (host->mci.f_min < 200000) host->mci.f_min = 200000; @@ -625,8 +630,6 @@ static int dw_mmc_probe(struct device_d *dev) mci_of_parse(&host->mci); - dev->priv = host; - return mci_register(&host->mci); } @@ -638,11 +641,16 @@ static __maybe_unused struct of_device_id dw_mmc_compatible[] = { }, { .compatible = "rockchip,rk3288-dw-mshc", }, { + .compatible = "snps,dw-mshc", + }, { + .compatible = "starfive,jh7100-dw-mshc", + }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, dw_mmc_compatible); -static struct driver_d dw_mmc_driver = { +static struct driver dw_mmc_driver = { .name = "dw_mmc", .probe = dw_mmc_probe, .of_compatible = DRV_OF_COMPAT(dw_mmc_compatible), |