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

tmio_mmc.c (5300B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for the MMC / SD / SDIO cell found in:
      4 *
      5 * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
      6 *
      7 * Copyright (C) 2017 Renesas Electronics Corporation
      8 * Copyright (C) 2017 Horms Solutions, Simon Horman
      9 * Copyright (C) 2007 Ian Molton
     10 * Copyright (C) 2004 Ian Molton
     11 */
     12
     13#include <linux/delay.h>
     14#include <linux/device.h>
     15#include <linux/mfd/core.h>
     16#include <linux/mfd/tmio.h>
     17#include <linux/mmc/host.h>
     18#include <linux/module.h>
     19#include <linux/pagemap.h>
     20#include <linux/scatterlist.h>
     21
     22#include "tmio_mmc.h"
     23
     24/* Registers specific to this variant */
     25#define CTL_SDIO_REGS		0x100
     26#define CTL_CLK_AND_WAIT_CTL	0x138
     27#define CTL_RESET_SDIO		0x1e0
     28
     29static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
     30{
     31	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
     32		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
     33
     34	usleep_range(10000, 11000);
     35	sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
     36	usleep_range(10000, 11000);
     37}
     38
     39static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
     40{
     41	sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
     42	usleep_range(10000, 11000);
     43
     44	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
     45		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
     46
     47	usleep_range(10000, 11000);
     48}
     49
     50static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
     51			       unsigned int new_clock)
     52{
     53	unsigned int divisor;
     54	u32 clk = 0;
     55	int clk_sel;
     56
     57	if (new_clock == 0) {
     58		tmio_mmc_clk_stop(host);
     59		return;
     60	}
     61
     62	divisor = host->pdata->hclk / new_clock;
     63
     64	/* bit7 set: 1/512, ... bit0 set: 1/4, all bits clear: 1/2 */
     65	clk_sel = (divisor <= 1);
     66	clk = clk_sel ? 0 : (roundup_pow_of_two(divisor) >> 2);
     67
     68	host->pdata->set_clk_div(host->pdev, clk_sel);
     69
     70	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
     71			sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
     72	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
     73	usleep_range(10000, 11000);
     74
     75	tmio_mmc_clk_start(host);
     76}
     77
     78static void tmio_mmc_reset(struct tmio_mmc_host *host)
     79{
     80	sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
     81	usleep_range(10000, 11000);
     82	sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
     83	usleep_range(10000, 11000);
     84}
     85
     86#ifdef CONFIG_PM_SLEEP
     87static int tmio_mmc_suspend(struct device *dev)
     88{
     89	struct platform_device *pdev = to_platform_device(dev);
     90	const struct mfd_cell *cell = mfd_get_cell(pdev);
     91	int ret;
     92
     93	ret = pm_runtime_force_suspend(dev);
     94
     95	/* Tell MFD core it can disable us now.*/
     96	if (!ret && cell->disable)
     97		cell->disable(pdev);
     98
     99	return ret;
    100}
    101
    102static int tmio_mmc_resume(struct device *dev)
    103{
    104	struct platform_device *pdev = to_platform_device(dev);
    105	const struct mfd_cell *cell = mfd_get_cell(pdev);
    106	int ret = 0;
    107
    108	/* Tell the MFD core we are ready to be enabled */
    109	if (cell->resume)
    110		ret = cell->resume(pdev);
    111
    112	if (!ret)
    113		ret = pm_runtime_force_resume(dev);
    114
    115	return ret;
    116}
    117#endif
    118
    119static int tmio_mmc_probe(struct platform_device *pdev)
    120{
    121	const struct mfd_cell *cell = mfd_get_cell(pdev);
    122	struct tmio_mmc_data *pdata;
    123	struct tmio_mmc_host *host;
    124	struct resource *res;
    125	int ret = -EINVAL, irq;
    126
    127	if (pdev->num_resources != 2)
    128		goto out;
    129
    130	pdata = pdev->dev.platform_data;
    131	if (!pdata || !pdata->hclk)
    132		goto out;
    133
    134	irq = platform_get_irq(pdev, 0);
    135	if (irq < 0) {
    136		ret = irq;
    137		goto out;
    138	}
    139
    140	/* Tell the MFD core we are ready to be enabled */
    141	if (cell->enable) {
    142		ret = cell->enable(pdev);
    143		if (ret)
    144			goto out;
    145	}
    146
    147	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    148	if (!res) {
    149		ret = -EINVAL;
    150		goto cell_disable;
    151	}
    152
    153	host = tmio_mmc_host_alloc(pdev, pdata);
    154	if (IS_ERR(host)) {
    155		ret = PTR_ERR(host);
    156		goto cell_disable;
    157	}
    158
    159	/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
    160	host->bus_shift = resource_size(res) >> 10;
    161	host->set_clock = tmio_mmc_set_clock;
    162	host->reset = tmio_mmc_reset;
    163
    164	host->mmc->f_max = pdata->hclk;
    165	host->mmc->f_min = pdata->hclk / 512;
    166
    167	ret = tmio_mmc_host_probe(host);
    168	if (ret)
    169		goto host_free;
    170
    171	ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq,
    172			       IRQF_TRIGGER_FALLING,
    173			       dev_name(&pdev->dev), host);
    174	if (ret)
    175		goto host_remove;
    176
    177	pr_info("%s at 0x%p irq %d\n", mmc_hostname(host->mmc), host->ctl, irq);
    178
    179	return 0;
    180
    181host_remove:
    182	tmio_mmc_host_remove(host);
    183host_free:
    184	tmio_mmc_host_free(host);
    185cell_disable:
    186	if (cell->disable)
    187		cell->disable(pdev);
    188out:
    189	return ret;
    190}
    191
    192static int tmio_mmc_remove(struct platform_device *pdev)
    193{
    194	const struct mfd_cell *cell = mfd_get_cell(pdev);
    195	struct tmio_mmc_host *host = platform_get_drvdata(pdev);
    196
    197	tmio_mmc_host_remove(host);
    198	if (cell->disable)
    199		cell->disable(pdev);
    200
    201	return 0;
    202}
    203
    204/* ------------------- device registration ----------------------- */
    205
    206static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
    207	SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
    208	SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
    209			   tmio_mmc_host_runtime_resume, NULL)
    210};
    211
    212static struct platform_driver tmio_mmc_driver = {
    213	.driver = {
    214		.name = "tmio-mmc",
    215		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
    216		.pm = &tmio_mmc_dev_pm_ops,
    217	},
    218	.probe = tmio_mmc_probe,
    219	.remove = tmio_mmc_remove,
    220};
    221
    222module_platform_driver(tmio_mmc_driver);
    223
    224MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
    225MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
    226MODULE_LICENSE("GPL v2");
    227MODULE_ALIAS("platform:tmio-mmc");