cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdhci-of-dwcmshc.c (14393B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for Synopsys DesignWare Cores Mobile Storage Host Controller
      4 *
      5 * Copyright (C) 2018 Synaptics Incorporated
      6 *
      7 * Author: Jisheng Zhang <jszhang@kernel.org>
      8 */
      9
     10#include <linux/acpi.h>
     11#include <linux/clk.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/iopoll.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18#include <linux/sizes.h>
     19
     20#include "sdhci-pltfm.h"
     21
     22#define SDHCI_DWCMSHC_ARG2_STUFF	GENMASK(31, 16)
     23
     24/* DWCMSHC specific Mode Select value */
     25#define DWCMSHC_CTRL_HS400		0x7
     26
     27/* DWC IP vendor area 1 pointer */
     28#define DWCMSHC_P_VENDOR_AREA1		0xe8
     29#define DWCMSHC_AREA1_MASK		GENMASK(11, 0)
     30/* Offset inside the  vendor area 1 */
     31#define DWCMSHC_HOST_CTRL3		0x8
     32#define DWCMSHC_EMMC_CONTROL		0x2c
     33#define DWCMSHC_ENHANCED_STROBE		BIT(8)
     34#define DWCMSHC_EMMC_ATCTRL		0x40
     35
     36/* Rockchip specific Registers */
     37#define DWCMSHC_EMMC_DLL_CTRL		0x800
     38#define DWCMSHC_EMMC_DLL_RXCLK		0x804
     39#define DWCMSHC_EMMC_DLL_TXCLK		0x808
     40#define DWCMSHC_EMMC_DLL_STRBIN		0x80c
     41#define DLL_STRBIN_TAPNUM_FROM_SW	BIT(24)
     42#define DWCMSHC_EMMC_DLL_STATUS0	0x840
     43#define DWCMSHC_EMMC_DLL_START		BIT(0)
     44#define DWCMSHC_EMMC_DLL_LOCKED		BIT(8)
     45#define DWCMSHC_EMMC_DLL_TIMEOUT	BIT(9)
     46#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL	29
     47#define DWCMSHC_EMMC_DLL_START_POINT	16
     48#define DWCMSHC_EMMC_DLL_INC		8
     49#define DWCMSHC_EMMC_DLL_DLYENA		BIT(27)
     50#define DLL_TXCLK_TAPNUM_DEFAULT	0x8
     51#define DLL_STRBIN_TAPNUM_DEFAULT	0x8
     52#define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
     53#define DLL_RXCLK_NO_INVERTER		1
     54#define DLL_RXCLK_INVERTER		0
     55#define DLL_LOCK_WO_TMOUT(x) \
     56	((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
     57	(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
     58#define RK3568_MAX_CLKS 3
     59
     60#define BOUNDARY_OK(addr, len) \
     61	((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
     62
     63struct rk3568_priv {
     64	/* Rockchip specified optional clocks */
     65	struct clk_bulk_data rockchip_clks[RK3568_MAX_CLKS];
     66	u8 txclk_tapnum;
     67};
     68
     69struct dwcmshc_priv {
     70	struct clk	*bus_clk;
     71	int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
     72	void *priv; /* pointer to SoC private stuff */
     73};
     74
     75/*
     76 * If DMA addr spans 128MB boundary, we split the DMA transfer into two
     77 * so that each DMA transfer doesn't exceed the boundary.
     78 */
     79static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
     80				    dma_addr_t addr, int len, unsigned int cmd)
     81{
     82	int tmplen, offset;
     83
     84	if (likely(!len || BOUNDARY_OK(addr, len))) {
     85		sdhci_adma_write_desc(host, desc, addr, len, cmd);
     86		return;
     87	}
     88
     89	offset = addr & (SZ_128M - 1);
     90	tmplen = SZ_128M - offset;
     91	sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
     92
     93	addr += tmplen;
     94	len -= tmplen;
     95	sdhci_adma_write_desc(host, desc, addr, len, cmd);
     96}
     97
     98static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host)
     99{
    100	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    101
    102	if (pltfm_host->clk)
    103		return sdhci_pltfm_clk_get_max_clock(host);
    104	else
    105		return pltfm_host->clock;
    106}
    107
    108static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc,
    109				     struct mmc_request *mrq)
    110{
    111	struct sdhci_host *host = mmc_priv(mmc);
    112
    113	/*
    114	 * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit
    115	 * block count register which doesn't support stuff bits of
    116	 * CMD23 argument on dwcmsch host controller.
    117	 */
    118	if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF))
    119		host->flags &= ~SDHCI_AUTO_CMD23;
    120	else
    121		host->flags |= SDHCI_AUTO_CMD23;
    122}
    123
    124static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
    125{
    126	dwcmshc_check_auto_cmd23(mmc, mrq);
    127
    128	sdhci_request(mmc, mrq);
    129}
    130
    131static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
    132				      unsigned int timing)
    133{
    134	u16 ctrl_2;
    135
    136	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
    137	/* Select Bus Speed Mode for host */
    138	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
    139	if ((timing == MMC_TIMING_MMC_HS200) ||
    140	    (timing == MMC_TIMING_UHS_SDR104))
    141		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
    142	else if (timing == MMC_TIMING_UHS_SDR12)
    143		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
    144	else if ((timing == MMC_TIMING_UHS_SDR25) ||
    145		 (timing == MMC_TIMING_MMC_HS))
    146		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
    147	else if (timing == MMC_TIMING_UHS_SDR50)
    148		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
    149	else if ((timing == MMC_TIMING_UHS_DDR50) ||
    150		 (timing == MMC_TIMING_MMC_DDR52))
    151		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
    152	else if (timing == MMC_TIMING_MMC_HS400)
    153		ctrl_2 |= DWCMSHC_CTRL_HS400;
    154	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
    155}
    156
    157static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
    158					  struct mmc_ios *ios)
    159{
    160	u32 vendor;
    161	struct sdhci_host *host = mmc_priv(mmc);
    162	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    163	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
    164	int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL;
    165
    166	vendor = sdhci_readl(host, reg);
    167	if (ios->enhanced_strobe)
    168		vendor |= DWCMSHC_ENHANCED_STROBE;
    169	else
    170		vendor &= ~DWCMSHC_ENHANCED_STROBE;
    171
    172	sdhci_writel(host, vendor, reg);
    173}
    174
    175static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
    176{
    177	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    178	struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
    179	struct rk3568_priv *priv = dwc_priv->priv;
    180	u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
    181	u32 extra, reg;
    182	int err;
    183
    184	host->mmc->actual_clock = 0;
    185
    186	/*
    187	 * DO NOT TOUCH THIS SETTING. RX clk inverter unit is enabled
    188	 * by default, but it shouldn't be enabled. We should anyway
    189	 * disable it before issuing any cmds.
    190	 */
    191	extra = DWCMSHC_EMMC_DLL_DLYENA |
    192		DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
    193	sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
    194
    195	if (clock == 0)
    196		return;
    197
    198	/* Rockchip platform only support 375KHz for identify mode */
    199	if (clock <= 400000)
    200		clock = 375000;
    201
    202	err = clk_set_rate(pltfm_host->clk, clock);
    203	if (err)
    204		dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock);
    205
    206	sdhci_set_clock(host, clock);
    207
    208	/* Disable cmd conflict check */
    209	reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3;
    210	extra = sdhci_readl(host, reg);
    211	extra &= ~BIT(0);
    212	sdhci_writel(host, extra, reg);
    213
    214	if (clock <= 400000) {
    215		/* Disable DLL to reset sample clock */
    216		sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
    217		return;
    218	}
    219
    220	/* Reset DLL */
    221	sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL);
    222	udelay(1);
    223	sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
    224
    225	/* Init DLL settings */
    226	extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
    227		0x2 << DWCMSHC_EMMC_DLL_INC |
    228		DWCMSHC_EMMC_DLL_START;
    229	sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
    230	err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0,
    231				 extra, DLL_LOCK_WO_TMOUT(extra), 1,
    232				 500 * USEC_PER_MSEC);
    233	if (err) {
    234		dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
    235		return;
    236	}
    237
    238	extra = 0x1 << 16 | /* tune clock stop en */
    239		0x2 << 17 | /* pre-change delay */
    240		0x3 << 19;  /* post-change delay */
    241	sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
    242
    243	if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
    244	    host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
    245		txclk_tapnum = priv->txclk_tapnum;
    246
    247	extra = DWCMSHC_EMMC_DLL_DLYENA |
    248		DLL_TXCLK_TAPNUM_FROM_SW |
    249		txclk_tapnum;
    250	sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
    251
    252	extra = DWCMSHC_EMMC_DLL_DLYENA |
    253		DLL_STRBIN_TAPNUM_DEFAULT |
    254		DLL_STRBIN_TAPNUM_FROM_SW;
    255	sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
    256}
    257
    258static const struct sdhci_ops sdhci_dwcmshc_ops = {
    259	.set_clock		= sdhci_set_clock,
    260	.set_bus_width		= sdhci_set_bus_width,
    261	.set_uhs_signaling	= dwcmshc_set_uhs_signaling,
    262	.get_max_clock		= dwcmshc_get_max_clock,
    263	.reset			= sdhci_reset,
    264	.adma_write_desc	= dwcmshc_adma_write_desc,
    265};
    266
    267static const struct sdhci_ops sdhci_dwcmshc_rk3568_ops = {
    268	.set_clock		= dwcmshc_rk3568_set_clock,
    269	.set_bus_width		= sdhci_set_bus_width,
    270	.set_uhs_signaling	= dwcmshc_set_uhs_signaling,
    271	.get_max_clock		= sdhci_pltfm_clk_get_max_clock,
    272	.reset			= sdhci_reset,
    273	.adma_write_desc	= dwcmshc_adma_write_desc,
    274};
    275
    276static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
    277	.ops = &sdhci_dwcmshc_ops,
    278	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
    279	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
    280};
    281
    282static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = {
    283	.ops = &sdhci_dwcmshc_rk3568_ops,
    284	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
    285		  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
    286	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
    287		   SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
    288};
    289
    290static int dwcmshc_rk3568_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
    291{
    292	int err;
    293	struct rk3568_priv *priv = dwc_priv->priv;
    294
    295	priv->rockchip_clks[0].id = "axi";
    296	priv->rockchip_clks[1].id = "block";
    297	priv->rockchip_clks[2].id = "timer";
    298	err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK3568_MAX_CLKS,
    299					 priv->rockchip_clks);
    300	if (err) {
    301		dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
    302		return err;
    303	}
    304
    305	err = clk_bulk_prepare_enable(RK3568_MAX_CLKS, priv->rockchip_clks);
    306	if (err) {
    307		dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
    308		return err;
    309	}
    310
    311	if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
    312				&priv->txclk_tapnum))
    313		priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
    314
    315	/* Disable cmd conflict check */
    316	sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3);
    317	/* Reset previous settings */
    318	sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
    319	sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
    320
    321	return 0;
    322}
    323
    324static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
    325	{
    326		.compatible = "rockchip,rk3568-dwcmshc",
    327		.data = &sdhci_dwcmshc_rk3568_pdata,
    328	},
    329	{
    330		.compatible = "snps,dwcmshc-sdhci",
    331		.data = &sdhci_dwcmshc_pdata,
    332	},
    333	{},
    334};
    335MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
    336
    337#ifdef CONFIG_ACPI
    338static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
    339	{ .id = "MLNXBF30" },
    340	{}
    341};
    342#endif
    343
    344static int dwcmshc_probe(struct platform_device *pdev)
    345{
    346	struct device *dev = &pdev->dev;
    347	struct sdhci_pltfm_host *pltfm_host;
    348	struct sdhci_host *host;
    349	struct dwcmshc_priv *priv;
    350	struct rk3568_priv *rk_priv = NULL;
    351	const struct sdhci_pltfm_data *pltfm_data;
    352	int err;
    353	u32 extra;
    354
    355	pltfm_data = of_device_get_match_data(&pdev->dev);
    356	if (!pltfm_data) {
    357		dev_err(&pdev->dev, "Error: No device match data found\n");
    358		return -ENODEV;
    359	}
    360
    361	host = sdhci_pltfm_init(pdev, pltfm_data,
    362				sizeof(struct dwcmshc_priv));
    363	if (IS_ERR(host))
    364		return PTR_ERR(host);
    365
    366	/*
    367	 * extra adma table cnt for cross 128M boundary handling.
    368	 */
    369	extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M);
    370	if (extra > SDHCI_MAX_SEGS)
    371		extra = SDHCI_MAX_SEGS;
    372	host->adma_table_cnt += extra;
    373
    374	pltfm_host = sdhci_priv(host);
    375	priv = sdhci_pltfm_priv(pltfm_host);
    376
    377	if (dev->of_node) {
    378		pltfm_host->clk = devm_clk_get(dev, "core");
    379		if (IS_ERR(pltfm_host->clk)) {
    380			err = PTR_ERR(pltfm_host->clk);
    381			dev_err(dev, "failed to get core clk: %d\n", err);
    382			goto free_pltfm;
    383		}
    384		err = clk_prepare_enable(pltfm_host->clk);
    385		if (err)
    386			goto free_pltfm;
    387
    388		priv->bus_clk = devm_clk_get(dev, "bus");
    389		if (!IS_ERR(priv->bus_clk))
    390			clk_prepare_enable(priv->bus_clk);
    391	}
    392
    393	err = mmc_of_parse(host->mmc);
    394	if (err)
    395		goto err_clk;
    396
    397	sdhci_get_of_property(pdev);
    398
    399	priv->vendor_specific_area1 =
    400		sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
    401
    402	host->mmc_host_ops.request = dwcmshc_request;
    403	host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
    404
    405	if (pltfm_data == &sdhci_dwcmshc_rk3568_pdata) {
    406		rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk3568_priv), GFP_KERNEL);
    407		if (!rk_priv) {
    408			err = -ENOMEM;
    409			goto err_clk;
    410		}
    411
    412		priv->priv = rk_priv;
    413
    414		err = dwcmshc_rk3568_init(host, priv);
    415		if (err)
    416			goto err_clk;
    417	}
    418
    419	host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
    420
    421	err = sdhci_add_host(host);
    422	if (err)
    423		goto err_clk;
    424
    425	return 0;
    426
    427err_clk:
    428	clk_disable_unprepare(pltfm_host->clk);
    429	clk_disable_unprepare(priv->bus_clk);
    430	if (rk_priv)
    431		clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
    432					   rk_priv->rockchip_clks);
    433free_pltfm:
    434	sdhci_pltfm_free(pdev);
    435	return err;
    436}
    437
    438static int dwcmshc_remove(struct platform_device *pdev)
    439{
    440	struct sdhci_host *host = platform_get_drvdata(pdev);
    441	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    442	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
    443	struct rk3568_priv *rk_priv = priv->priv;
    444
    445	sdhci_remove_host(host, 0);
    446
    447	clk_disable_unprepare(pltfm_host->clk);
    448	clk_disable_unprepare(priv->bus_clk);
    449	if (rk_priv)
    450		clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
    451					   rk_priv->rockchip_clks);
    452	sdhci_pltfm_free(pdev);
    453
    454	return 0;
    455}
    456
    457#ifdef CONFIG_PM_SLEEP
    458static int dwcmshc_suspend(struct device *dev)
    459{
    460	struct sdhci_host *host = dev_get_drvdata(dev);
    461	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    462	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
    463	struct rk3568_priv *rk_priv = priv->priv;
    464	int ret;
    465
    466	ret = sdhci_suspend_host(host);
    467	if (ret)
    468		return ret;
    469
    470	clk_disable_unprepare(pltfm_host->clk);
    471	if (!IS_ERR(priv->bus_clk))
    472		clk_disable_unprepare(priv->bus_clk);
    473
    474	if (rk_priv)
    475		clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
    476					   rk_priv->rockchip_clks);
    477
    478	return ret;
    479}
    480
    481static int dwcmshc_resume(struct device *dev)
    482{
    483	struct sdhci_host *host = dev_get_drvdata(dev);
    484	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
    485	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
    486	struct rk3568_priv *rk_priv = priv->priv;
    487	int ret;
    488
    489	ret = clk_prepare_enable(pltfm_host->clk);
    490	if (ret)
    491		return ret;
    492
    493	if (!IS_ERR(priv->bus_clk)) {
    494		ret = clk_prepare_enable(priv->bus_clk);
    495		if (ret)
    496			return ret;
    497	}
    498
    499	if (rk_priv) {
    500		ret = clk_bulk_prepare_enable(RK3568_MAX_CLKS,
    501					      rk_priv->rockchip_clks);
    502		if (ret)
    503			return ret;
    504	}
    505
    506	return sdhci_resume_host(host);
    507}
    508#endif
    509
    510static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume);
    511
    512static struct platform_driver sdhci_dwcmshc_driver = {
    513	.driver	= {
    514		.name	= "sdhci-dwcmshc",
    515		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
    516		.of_match_table = sdhci_dwcmshc_dt_ids,
    517		.acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids),
    518		.pm = &dwcmshc_pmops,
    519	},
    520	.probe	= dwcmshc_probe,
    521	.remove	= dwcmshc_remove,
    522};
    523module_platform_driver(sdhci_dwcmshc_driver);
    524
    525MODULE_DESCRIPTION("SDHCI platform driver for Synopsys DWC MSHC");
    526MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
    527MODULE_LICENSE("GPL v2");