zynq_sdhci.c 7.2 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
M
Michal Simek 已提交
3
 * (C) Copyright 2013 - 2015 Xilinx, Inc.
4 5 6 7
 *
 * Xilinx Zynq SD Host Controller Interface
 */

8
#include <clk.h>
9
#include <common.h>
M
Michal Simek 已提交
10
#include <dm.h>
11
#include <fdtdec.h>
12
#include "mmc_private.h"
13
#include <linux/libfdt.h>
14 15
#include <malloc.h>
#include <sdhci.h>
16
#include <zynqmp_tap_delay.h>
17

18 19
DECLARE_GLOBAL_DATA_PTR;

20 21 22
struct arasan_sdhci_plat {
	struct mmc_config cfg;
	struct mmc mmc;
23
	unsigned int f_max;
24 25
};

26 27 28 29 30 31 32 33
struct arasan_sdhci_priv {
	struct sdhci_host *host;
	u8 deviceid;
	u8 bank;
	u8 no_1p8;
};

#if defined(CONFIG_ARCH_ZYNQMP)
34 35
#define MMC_HS200_BUS_SPEED	5

36
static const u8 mode2timing[] = {
37 38 39 40 41 42 43 44 45 46 47 48
	[MMC_LEGACY] = UHS_SDR12_BUS_SPEED,
	[SD_LEGACY] = UHS_SDR12_BUS_SPEED,
	[MMC_HS] = HIGH_SPEED_BUS_SPEED,
	[SD_HS] = HIGH_SPEED_BUS_SPEED,
	[MMC_HS_52] = HIGH_SPEED_BUS_SPEED,
	[MMC_DDR_52] = HIGH_SPEED_BUS_SPEED,
	[UHS_SDR12] = UHS_SDR12_BUS_SPEED,
	[UHS_SDR25] = UHS_SDR25_BUS_SPEED,
	[UHS_SDR50] = UHS_SDR50_BUS_SPEED,
	[UHS_DDR50] = UHS_DDR50_BUS_SPEED,
	[UHS_SDR104] = UHS_SDR104_BUS_SPEED,
	[MMC_HS_200] = MMC_HS200_BUS_SPEED,
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
};

#define SDHCI_TUNING_LOOP_COUNT	40

static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
{
	u16 clk;
	unsigned long timeout;

	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
	clk &= ~(SDHCI_CLOCK_CARD_EN);
	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

	/* Issue DLL Reset */
	zynqmp_dll_reset(deviceid);

	/* Wait max 20 ms */
	timeout = 100;
	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
				& SDHCI_CLOCK_INT_STABLE)) {
		if (timeout == 0) {
			dev_err(mmc_dev(host->mmc),
				": Internal clock never stabilised.\n");
			return;
		}
		timeout--;
		udelay(1000);
	}

	clk |= SDHCI_CLOCK_CARD_EN;
	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}

static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
{
	struct mmc_cmd cmd;
	struct mmc_data data;
	u32 ctrl;
	struct sdhci_host *host;
	struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev);
89
	char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT;
90 91 92 93 94 95 96
	u8 deviceid;

	debug("%s\n", __func__);

	host = priv->host;
	deviceid = priv->deviceid;

97
	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
98
	ctrl |= SDHCI_CTRL_EXEC_TUNING;
99
	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

	mdelay(1);

	arasan_zynqmp_dll_reset(host, deviceid);

	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);

	do {
		cmd.cmdidx = opcode;
		cmd.resp_type = MMC_RSP_R1;
		cmd.cmdarg = 0;

		data.blocksize = 64;
		data.blocks = 1;
		data.flags = MMC_DATA_READ;

		if (tuning_loop_counter-- == 0)
			break;

		if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 &&
		    mmc->bus_width == 8)
			data.blocksize = 128;

		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
						    data.blocksize),
			     SDHCI_BLOCK_SIZE);
		sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT);
		sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);

		mmc_send_cmd(mmc, &cmd, NULL);
131
		ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
132 133 134 135 136 137 138 139

		if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
			udelay(1);

	} while (ctrl & SDHCI_CTRL_EXEC_TUNING);

	if (tuning_loop_counter < 0) {
		ctrl &= ~SDHCI_CTRL_TUNED_CLK;
140
		sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2);
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	}

	if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
		printf("%s:Tuning failed\n", __func__);
		return -1;
	}

	udelay(1);
	arasan_zynqmp_dll_reset(host, deviceid);

	/* Enable only interrupts served by the SD controller */
	sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
		     SDHCI_INT_ENABLE);
	/* Mask all sdhci interrupt sources */
	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);

	return 0;
}

static void arasan_sdhci_set_tapdelay(struct sdhci_host *host)
{
	struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
	struct mmc *mmc = (struct mmc *)host->mmc;
	u8 uhsmode;

	uhsmode = mode2timing[mmc->selected_mode];

	if (uhsmode >= UHS_SDR25_BUS_SPEED)
		arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
					   priv->bank);
}

static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
{
	struct mmc *mmc = (struct mmc *)host->mmc;
	u32 reg;

178 179 180
	if (!IS_SD(mmc))
		return;

181
	if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
182 183 184
		reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
		reg |= SDHCI_CTRL_VDD_180;
		sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
185 186 187
	}

	if (mmc->selected_mode > SD_HS &&
188 189
	    mmc->selected_mode <= UHS_DDR50)
		sdhci_set_uhs_timing(host);
190 191 192 193 194 195 196 197 198 199 200
}
#endif

#if defined(CONFIG_DM_MMC) && defined(CONFIG_ARCH_ZYNQMP)
const struct sdhci_ops arasan_ops = {
	.platform_execute_tuning	= &arasan_sdhci_execute_tuning,
	.set_delay = &arasan_sdhci_set_tapdelay,
	.set_control_reg = &arasan_sdhci_set_control_reg,
};
#endif

M
Michal Simek 已提交
201
static int arasan_sdhci_probe(struct udevice *dev)
202
{
203
	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);
M
Michal Simek 已提交
204
	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
205 206
	struct arasan_sdhci_priv *priv = dev_get_priv(dev);
	struct sdhci_host *host;
207 208
	struct clk clk;
	unsigned long clock;
209
	int ret;
210

211 212
	host = priv->host;

213 214 215 216 217 218 219 220 221 222 223
	ret = clk_get_by_index(dev, 0, &clk);
	if (ret < 0) {
		dev_err(dev, "failed to get clock\n");
		return ret;
	}

	clock = clk_get_rate(&clk);
	if (IS_ERR_VALUE(clock)) {
		dev_err(dev, "failed to get rate\n");
		return clock;
	}
224

225 226 227 228 229 230 231 232
	debug("%s: CLK %ld\n", __func__, clock);

	ret = clk_enable(&clk);
	if (ret && ret != -ENOSYS) {
		dev_err(dev, "failed to enable clock\n");
		return ret;
	}

233
	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
234
		       SDHCI_QUIRK_BROKEN_R1B;
235 236

#ifdef CONFIG_ZYNQ_HISPD_BROKEN
237
	host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE;
238 239
#endif

240 241 242
	if (priv->no_1p8)
		host->quirks |= SDHCI_QUIRK_NO_1_8_V;

243
	host->max_clk = clock;
244

245 246 247 248
	host->mmc = &plat->mmc;
	host->mmc->dev = dev;
	host->mmc->priv = host;

249
	ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max,
250
			      CONFIG_ZYNQ_SDHCI_MIN_FREQ);
251 252 253
	if (ret)
		return ret;
	upriv->mmc = host->mmc;
M
Michal Simek 已提交
254

255
	return sdhci_probe(dev);
256
}
M
Michal Simek 已提交
257 258 259

static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
{
260
	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);
261 262 263 264 265
	struct arasan_sdhci_priv *priv = dev_get_priv(dev);

	priv->host = calloc(1, sizeof(struct sdhci_host));
	if (!priv->host)
		return -1;
M
Michal Simek 已提交
266

267 268 269 270 271
	priv->host->name = dev->name;

#if defined(CONFIG_DM_MMC) && defined(CONFIG_ARCH_ZYNQMP)
	priv->host->ops = &arasan_ops;
#endif
M
Michal Simek 已提交
272

273 274 275
	priv->host->ioaddr = (void *)dev_read_addr(dev);
	if (IS_ERR(priv->host->ioaddr))
		return PTR_ERR(priv->host->ioaddr);
276

277 278 279 280 281 282
	priv->deviceid = dev_read_u32_default(dev, "xlnx,device_id", -1);
	priv->bank = dev_read_u32_default(dev, "xlnx,mio_bank", -1);
	priv->no_1p8 = dev_read_bool(dev, "no-1-8-v");

	plat->f_max = dev_read_u32_default(dev, "max-frequency",
					   CONFIG_ZYNQ_SDHCI_MAX_FREQ);
M
Michal Simek 已提交
283 284 285
	return 0;
}

286 287 288 289
static int arasan_sdhci_bind(struct udevice *dev)
{
	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);

290
	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
291 292
}

M
Michal Simek 已提交
293 294 295 296 297 298 299 300 301 302
static const struct udevice_id arasan_sdhci_ids[] = {
	{ .compatible = "arasan,sdhci-8.9a" },
	{ }
};

U_BOOT_DRIVER(arasan_sdhci_drv) = {
	.name		= "arasan_sdhci",
	.id		= UCLASS_MMC,
	.of_match	= arasan_sdhci_ids,
	.ofdata_to_platdata = arasan_sdhci_ofdata_to_platdata,
303 304
	.ops		= &sdhci_ops,
	.bind		= arasan_sdhci_bind,
M
Michal Simek 已提交
305
	.probe		= arasan_sdhci_probe,
306
	.priv_auto_alloc_size = sizeof(struct arasan_sdhci_priv),
307
	.platdata_auto_alloc_size = sizeof(struct arasan_sdhci_plat),
M
Michal Simek 已提交
308
};