sdhci-tegra.c 11.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (C) 2010 Google, Inc.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * 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 <linux/err.h>
16
#include <linux/module.h>
17 18 19 20
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
21
#include <linux/of.h>
22
#include <linux/of_device.h>
23 24
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
25
#include <linux/mmc/slot-gpio.h>
26
#include <linux/gpio/consumer.h>
27 28 29

#include "sdhci-pltfm.h"

30
/* Tegra SDHOST controller vendor register definitions */
L
Lucas Stach 已提交
31 32 33 34
#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL			0x100
#define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE		BIT(3)
#define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE	BIT(2)

35
#define SDHCI_TEGRA_VENDOR_MISC_CTRL		0x120
36 37
#define SDHCI_MISC_CTRL_ENABLE_SDR104		0x8
#define SDHCI_MISC_CTRL_ENABLE_SDR50		0x10
38
#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300	0x20
39
#define SDHCI_MISC_CTRL_ENABLE_DDR50		0x200
40

41 42
#define NVQUIRK_FORCE_SDHCI_SPEC_200	BIT(0)
#define NVQUIRK_ENABLE_BLOCK_GAP_DET	BIT(1)
43
#define NVQUIRK_ENABLE_SDHCI_SPEC_300	BIT(2)
44 45 46
#define NVQUIRK_DISABLE_SDR50		BIT(3)
#define NVQUIRK_DISABLE_SDR104		BIT(4)
#define NVQUIRK_DISABLE_DDR50		BIT(5)
47 48

struct sdhci_tegra_soc_data {
49
	const struct sdhci_pltfm_data *pdata;
50 51 52 53 54
	u32 nvquirks;
};

struct sdhci_tegra {
	const struct sdhci_tegra_soc_data *soc_data;
55
	struct gpio_desc *power_gpio;
56
	bool ddr_signaling;
57 58
};

59 60
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
{
61 62 63 64 65 66
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_tegra *tegra_host = pltfm_host->priv;
	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;

	if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
			(reg == SDHCI_HOST_VERSION))) {
67 68 69 70 71 72 73
		/* Erratum: Version register is invalid in HW. */
		return SDHCI_SPEC_200;
	}

	return readw(host->ioaddr + reg);
}

74 75 76 77
static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);

78 79 80 81 82 83 84 85 86 87 88 89
	switch (reg) {
	case SDHCI_TRANSFER_MODE:
		/*
		 * Postpone this write, we must do it together with a
		 * command write that is down below.
		 */
		pltfm_host->xfer_mode_shadow = val;
		return;
	case SDHCI_COMMAND:
		writel((val << 16) | pltfm_host->xfer_mode_shadow,
			host->ioaddr + SDHCI_TRANSFER_MODE);
		return;
90 91 92 93 94
	}

	writew(val, host->ioaddr + reg);
}

95 96
static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
{
97 98 99 100
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_tegra *tegra_host = pltfm_host->priv;
	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;

101 102 103 104 105 106 107 108 109
	/* Seems like we're getting spurious timeout and crc errors, so
	 * disable signalling of them. In case of real errors software
	 * timers should take care of eventually detecting them.
	 */
	if (unlikely(reg == SDHCI_SIGNAL_ENABLE))
		val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC);

	writel(val, host->ioaddr + reg);

110 111
	if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) &&
			(reg == SDHCI_INT_ENABLE))) {
112 113 114 115 116 117 118 119 120 121
		/* Erratum: Must enable block gap interrupt detection */
		u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
		if (val & SDHCI_INT_CARD_INT)
			gap_ctrl |= 0x8;
		else
			gap_ctrl &= ~0x8;
		writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
	}
}

122
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
123
{
124
	return mmc_gpio_get_ro(host->mmc);
125 126
}

127
static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
128 129 130 131
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_tegra *tegra_host = pltfm_host->priv;
	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
L
Lucas Stach 已提交
132
	u32 misc_ctrl, clk_ctrl;
133

134 135
	sdhci_reset(host, mask);

136 137 138
	if (!(mask & SDHCI_RESET_ALL))
		return;

139
	misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
140
	/* Erratum: Enable SDHCI spec v3.00 support */
141
	if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
142
		misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
143 144 145 146 147 148 149 150
	/* Don't advertise UHS modes which aren't supported yet */
	if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR50)
		misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
	if (soc_data->nvquirks & NVQUIRK_DISABLE_DDR50)
		misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
	if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104)
		misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
	sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
151

L
Lucas Stach 已提交
152 153 154 155
	clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
	clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
	sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);

156
	tegra_host->ddr_signaling = false;
157 158
}

159
static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
160 161 162 163
{
	u32 ctrl;

	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
164 165
	if ((host->mmc->caps & MMC_CAP_8_BIT_DATA) &&
	    (bus_width == MMC_BUS_WIDTH_8)) {
166 167 168 169 170 171 172 173 174 175 176 177
		ctrl &= ~SDHCI_CTRL_4BITBUS;
		ctrl |= SDHCI_CTRL_8BITBUS;
	} else {
		ctrl &= ~SDHCI_CTRL_8BITBUS;
		if (bus_width == MMC_BUS_WIDTH_4)
			ctrl |= SDHCI_CTRL_4BITBUS;
		else
			ctrl &= ~SDHCI_CTRL_4BITBUS;
	}
	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_tegra *tegra_host = pltfm_host->priv;
	unsigned long host_clk;

	if (!clock)
		return;

	host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
	clk_set_rate(pltfm_host->clk, host_clk);
	host->max_clk = clk_get_rate(pltfm_host->clk);

	return sdhci_set_clock(host, clock);
}

static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
					  unsigned timing)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_tegra *tegra_host = pltfm_host->priv;

	if (timing == MMC_TIMING_UHS_DDR50)
		tegra_host->ddr_signaling = true;

	return sdhci_set_uhs_signaling(host, timing);
}

static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);

	/*
	 * DDR modes require the host to run at double the card frequency, so
	 * the maximum rate we can support is half of the module input clock.
	 */
	return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2;
}

217
static const struct sdhci_ops tegra_sdhci_ops = {
218 219 220
	.get_ro     = tegra_sdhci_get_ro,
	.read_w     = tegra_sdhci_readw,
	.write_l    = tegra_sdhci_writel,
221
	.set_clock  = tegra_sdhci_set_clock,
222
	.set_bus_width = tegra_sdhci_set_bus_width,
223
	.reset      = tegra_sdhci_reset,
224 225
	.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
	.get_max_clock = tegra_sdhci_get_max_clock,
226 227
};

228
static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
229 230 231
	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
		  SDHCI_QUIRK_NO_HISPD_BIT |
232 233
		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
234 235 236
	.ops  = &tegra_sdhci_ops,
};

T
Thierry Reding 已提交
237
static const struct sdhci_tegra_soc_data soc_data_tegra20 = {
238 239 240 241 242
	.pdata = &sdhci_tegra20_pdata,
	.nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
		    NVQUIRK_ENABLE_BLOCK_GAP_DET,
};

243
static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
244
	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
245
		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
246 247
		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
		  SDHCI_QUIRK_NO_HISPD_BIT |
248 249
		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
250
	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
251 252
	.ops  = &tegra_sdhci_ops,
};
253

T
Thierry Reding 已提交
254
static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
255
	.pdata = &sdhci_tegra30_pdata,
256 257 258
	.nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
		    NVQUIRK_DISABLE_SDR50 |
		    NVQUIRK_DISABLE_SDR104,
259 260
};

261 262 263 264 265
static const struct sdhci_ops tegra114_sdhci_ops = {
	.get_ro     = tegra_sdhci_get_ro,
	.read_w     = tegra_sdhci_readw,
	.write_w    = tegra_sdhci_writew,
	.write_l    = tegra_sdhci_writel,
266
	.set_clock  = tegra_sdhci_set_clock,
267 268
	.set_bus_width = tegra_sdhci_set_bus_width,
	.reset      = tegra_sdhci_reset,
269 270
	.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
	.get_max_clock = tegra_sdhci_get_max_clock,
271 272
};

273
static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
274 275 276 277
	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
		  SDHCI_QUIRK_NO_HISPD_BIT |
278 279
		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
280
	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
281
	.ops  = &tegra114_sdhci_ops,
282 283
};

T
Thierry Reding 已提交
284
static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
285
	.pdata = &sdhci_tegra114_pdata,
286 287
	.nvquirks = NVQUIRK_DISABLE_SDR50 |
		    NVQUIRK_DISABLE_DDR50 |
288
		    NVQUIRK_DISABLE_SDR104,
289 290
};

T
Thierry Reding 已提交
291 292 293 294 295
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
		  SDHCI_QUIRK_NO_HISPD_BIT |
296 297 298
		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
T
Thierry Reding 已提交
299 300 301 302 303 304 305 306 307 308
	.ops  = &tegra114_sdhci_ops,
};

static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
	.pdata = &sdhci_tegra210_pdata,
	.nvquirks = NVQUIRK_DISABLE_SDR50 |
		    NVQUIRK_DISABLE_DDR50 |
		    NVQUIRK_DISABLE_SDR104,
};

B
Bill Pemberton 已提交
309
static const struct of_device_id sdhci_tegra_dt_match[] = {
T
Thierry Reding 已提交
310
	{ .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
311
	{ .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 },
312
	{ .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
313 314
	{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
	{ .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
315 316
	{}
};
317
MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
318

B
Bill Pemberton 已提交
319
static int sdhci_tegra_probe(struct platform_device *pdev)
320
{
321 322 323
	const struct of_device_id *match;
	const struct sdhci_tegra_soc_data *soc_data;
	struct sdhci_host *host;
324
	struct sdhci_pltfm_host *pltfm_host;
325
	struct sdhci_tegra *tegra_host;
326 327 328
	struct clk *clk;
	int rc;

329
	match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
330 331 332
	if (!match)
		return -EINVAL;
	soc_data = match->data;
333

334
	host = sdhci_pltfm_init(pdev, soc_data->pdata, 0);
335 336 337 338
	if (IS_ERR(host))
		return PTR_ERR(host);
	pltfm_host = sdhci_priv(host);

339 340 341 342
	tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL);
	if (!tegra_host) {
		dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
		rc = -ENOMEM;
343
		goto err_alloc_tegra_host;
344
	}
345
	tegra_host->ddr_signaling = false;
346 347
	tegra_host->soc_data = soc_data;
	pltfm_host->priv = tegra_host;
348

349
	rc = mmc_of_parse(host->mmc);
350 351
	if (rc)
		goto err_parse_dt;
352

353 354 355 356 357
	tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
							 GPIOD_OUT_HIGH);
	if (IS_ERR(tegra_host->power_gpio)) {
		rc = PTR_ERR(tegra_host->power_gpio);
		goto err_power_req;
358 359
	}

360
	clk = devm_clk_get(mmc_dev(host->mmc), NULL);
361 362 363
	if (IS_ERR(clk)) {
		dev_err(mmc_dev(host->mmc), "clk err\n");
		rc = PTR_ERR(clk);
364
		goto err_clk_get;
365
	}
366
	clk_prepare_enable(clk);
367 368
	pltfm_host->clk = clk;

369 370 371 372
	rc = sdhci_add_host(host);
	if (rc)
		goto err_add_host;

373 374
	return 0;

375
err_add_host:
376
	clk_disable_unprepare(pltfm_host->clk);
377 378
err_clk_get:
err_power_req:
379
err_parse_dt:
380
err_alloc_tegra_host:
381
	sdhci_pltfm_free(pdev);
382 383 384
	return rc;
}

385 386 387
static struct platform_driver sdhci_tegra_driver = {
	.driver		= {
		.name	= "sdhci-tegra",
388
		.of_match_table = sdhci_tegra_dt_match,
389
		.pm	= SDHCI_PLTFM_PMOPS,
390 391
	},
	.probe		= sdhci_tegra_probe,
392
	.remove		= sdhci_pltfm_unregister,
393 394
};

395
module_platform_driver(sdhci_tegra_driver);
396 397

MODULE_DESCRIPTION("SDHCI driver for Tegra");
398
MODULE_AUTHOR("Google, Inc.");
399
MODULE_LICENSE("GPL v2");