xref: /rk3399_rockchip-uboot/drivers/mmc/rockchip_dw_mmc.c (revision e1efec4e0aadb90e5b10b7d3ed4c34da372aad92)
1a8cb4fb5SSimon Glass /*
2a8cb4fb5SSimon Glass  * Copyright (c) 2013 Google, Inc
3a8cb4fb5SSimon Glass  *
4a8cb4fb5SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
5a8cb4fb5SSimon Glass  */
6a8cb4fb5SSimon Glass 
7a8cb4fb5SSimon Glass #include <common.h>
8a8cb4fb5SSimon Glass #include <clk.h>
9a8cb4fb5SSimon Glass #include <dm.h>
10a8cb4fb5SSimon Glass #include <dwmmc.h>
11a8cb4fb5SSimon Glass #include <errno.h>
12*e1efec4eSSimon Glass #include <pwrseq.h>
13a8cb4fb5SSimon Glass #include <syscon.h>
14*e1efec4eSSimon Glass #include <asm/gpio.h>
15a8cb4fb5SSimon Glass #include <asm/arch/clock.h>
16a8cb4fb5SSimon Glass #include <asm/arch/periph.h>
17a8cb4fb5SSimon Glass #include <linux/err.h>
18a8cb4fb5SSimon Glass 
19a8cb4fb5SSimon Glass DECLARE_GLOBAL_DATA_PTR;
20a8cb4fb5SSimon Glass 
21a8cb4fb5SSimon Glass struct rockchip_dwmmc_priv {
22a8cb4fb5SSimon Glass 	struct udevice *clk;
23a8cb4fb5SSimon Glass 	struct rk3288_grf *grf;
24a8cb4fb5SSimon Glass 	struct dwmci_host host;
25a8cb4fb5SSimon Glass };
26a8cb4fb5SSimon Glass 
27a8cb4fb5SSimon Glass static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
28a8cb4fb5SSimon Glass {
29a8cb4fb5SSimon Glass 	struct udevice *dev = host->priv;
30a8cb4fb5SSimon Glass 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
31a8cb4fb5SSimon Glass 	int ret;
32a8cb4fb5SSimon Glass 
33a8cb4fb5SSimon Glass 	ret = clk_set_periph_rate(priv->clk, PERIPH_ID_SDMMC0 + host->dev_index,
34a8cb4fb5SSimon Glass 				  freq);
35a8cb4fb5SSimon Glass 	if (ret < 0) {
36a8cb4fb5SSimon Glass 		debug("%s: err=%d\n", __func__, ret);
37a8cb4fb5SSimon Glass 		return ret;
38a8cb4fb5SSimon Glass 	}
39a8cb4fb5SSimon Glass 
40a8cb4fb5SSimon Glass 	return freq;
41a8cb4fb5SSimon Glass }
42a8cb4fb5SSimon Glass 
43a8cb4fb5SSimon Glass static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
44a8cb4fb5SSimon Glass {
45a8cb4fb5SSimon Glass 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
46a8cb4fb5SSimon Glass 	struct dwmci_host *host = &priv->host;
47a8cb4fb5SSimon Glass 
48a8cb4fb5SSimon Glass 	host->name = dev->name;
49a8cb4fb5SSimon Glass 	host->ioaddr = (void *)dev_get_addr(dev);
50a8cb4fb5SSimon Glass 	host->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
51a8cb4fb5SSimon Glass 					"bus-width", 4);
52a8cb4fb5SSimon Glass 	host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
53a8cb4fb5SSimon Glass 	host->priv = dev;
54a8cb4fb5SSimon Glass 
55ace2198bShuang lin 	/* use non-removeable as sdcard and emmc as judgement */
56ace2198bShuang lin 	if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "non-removable"))
576579385bShuang lin 		host->dev_index = 0;
586579385bShuang lin 	else
59ace2198bShuang lin 		host->dev_index = 1;
60a8cb4fb5SSimon Glass 
61a8cb4fb5SSimon Glass 	return 0;
62a8cb4fb5SSimon Glass }
63a8cb4fb5SSimon Glass 
64a8cb4fb5SSimon Glass static int rockchip_dwmmc_probe(struct udevice *dev)
65a8cb4fb5SSimon Glass {
66a8cb4fb5SSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
67a8cb4fb5SSimon Glass 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
68a8cb4fb5SSimon Glass 	struct dwmci_host *host = &priv->host;
69*e1efec4eSSimon Glass 	struct udevice *pwr_dev __maybe_unused;
70a8cb4fb5SSimon Glass 	u32 minmax[2];
71a8cb4fb5SSimon Glass 	int ret;
7228637248Shuang lin 	int fifo_depth;
73a8cb4fb5SSimon Glass 
74a8cb4fb5SSimon Glass 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
75a8cb4fb5SSimon Glass 	if (IS_ERR(priv->grf))
76a8cb4fb5SSimon Glass 		return PTR_ERR(priv->grf);
77a8cb4fb5SSimon Glass 	ret = uclass_get_device(UCLASS_CLK, CLK_GENERAL, &priv->clk);
78a8cb4fb5SSimon Glass 	if (ret)
79a8cb4fb5SSimon Glass 		return ret;
80a8cb4fb5SSimon Glass 
8128637248Shuang lin 	if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
8228637248Shuang lin 				 "clock-freq-min-max", minmax, 2))
8328637248Shuang lin 		return -EINVAL;
8428637248Shuang lin 
8528637248Shuang lin 	fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
8628637248Shuang lin 				    "fifo-depth", 0);
8728637248Shuang lin 	if (fifo_depth < 0)
8828637248Shuang lin 		return -EINVAL;
8928637248Shuang lin 
9028637248Shuang lin 	host->fifoth_val = MSIZE(0x2) |
9128637248Shuang lin 		RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2);
9228637248Shuang lin 
9328637248Shuang lin 	if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode"))
9428637248Shuang lin 		host->fifo_mode = true;
9528637248Shuang lin 
96*e1efec4eSSimon Glass #ifdef CONFIG_PWRSEQ
97*e1efec4eSSimon Glass 	/* Enable power if needed */
98*e1efec4eSSimon Glass 	ret = uclass_get_device_by_phandle(UCLASS_PWRSEQ, dev, "mmc-pwrseq",
99*e1efec4eSSimon Glass 					   &pwr_dev);
100*e1efec4eSSimon Glass 	if (!ret) {
101*e1efec4eSSimon Glass 		ret = pwrseq_set_power(pwr_dev, true);
102*e1efec4eSSimon Glass 		if (ret)
103*e1efec4eSSimon Glass 			return ret;
104*e1efec4eSSimon Glass 	}
105*e1efec4eSSimon Glass #endif
106a8cb4fb5SSimon Glass 	ret = add_dwmci(host, minmax[1], minmax[0]);
107a8cb4fb5SSimon Glass 	if (ret)
108a8cb4fb5SSimon Glass 		return ret;
109a8cb4fb5SSimon Glass 
110a8cb4fb5SSimon Glass 	upriv->mmc = host->mmc;
111a8cb4fb5SSimon Glass 
112a8cb4fb5SSimon Glass 	return 0;
113a8cb4fb5SSimon Glass }
114a8cb4fb5SSimon Glass 
115a8cb4fb5SSimon Glass static const struct udevice_id rockchip_dwmmc_ids[] = {
116a8cb4fb5SSimon Glass 	{ .compatible = "rockchip,rk3288-dw-mshc" },
117a8cb4fb5SSimon Glass 	{ }
118a8cb4fb5SSimon Glass };
119a8cb4fb5SSimon Glass 
120a8cb4fb5SSimon Glass U_BOOT_DRIVER(rockchip_dwmmc_drv) = {
121a8cb4fb5SSimon Glass 	.name		= "rockchip_dwmmc",
122a8cb4fb5SSimon Glass 	.id		= UCLASS_MMC,
123a8cb4fb5SSimon Glass 	.of_match	= rockchip_dwmmc_ids,
124a8cb4fb5SSimon Glass 	.ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata,
125a8cb4fb5SSimon Glass 	.probe		= rockchip_dwmmc_probe,
126a8cb4fb5SSimon Glass 	.priv_auto_alloc_size = sizeof(struct rockchip_dwmmc_priv),
127a8cb4fb5SSimon Glass };
128*e1efec4eSSimon Glass 
129*e1efec4eSSimon Glass #ifdef CONFIG_PWRSEQ
130*e1efec4eSSimon Glass static int rockchip_dwmmc_pwrseq_set_power(struct udevice *dev, bool enable)
131*e1efec4eSSimon Glass {
132*e1efec4eSSimon Glass 	struct gpio_desc reset;
133*e1efec4eSSimon Glass 	int ret;
134*e1efec4eSSimon Glass 
135*e1efec4eSSimon Glass 	ret = gpio_request_by_name(dev, "reset-gpios", 0, &reset, GPIOD_IS_OUT);
136*e1efec4eSSimon Glass 	if (ret)
137*e1efec4eSSimon Glass 		return ret;
138*e1efec4eSSimon Glass 	dm_gpio_set_value(&reset, 1);
139*e1efec4eSSimon Glass 	udelay(1);
140*e1efec4eSSimon Glass 	dm_gpio_set_value(&reset, 0);
141*e1efec4eSSimon Glass 	udelay(200);
142*e1efec4eSSimon Glass 
143*e1efec4eSSimon Glass 	return 0;
144*e1efec4eSSimon Glass }
145*e1efec4eSSimon Glass 
146*e1efec4eSSimon Glass static const struct pwrseq_ops rockchip_dwmmc_pwrseq_ops = {
147*e1efec4eSSimon Glass 	.set_power	= rockchip_dwmmc_pwrseq_set_power,
148*e1efec4eSSimon Glass };
149*e1efec4eSSimon Glass 
150*e1efec4eSSimon Glass static const struct udevice_id rockchip_dwmmc_pwrseq_ids[] = {
151*e1efec4eSSimon Glass 	{ .compatible = "mmc-pwrseq-emmc" },
152*e1efec4eSSimon Glass 	{ }
153*e1efec4eSSimon Glass };
154*e1efec4eSSimon Glass 
155*e1efec4eSSimon Glass U_BOOT_DRIVER(rockchip_dwmmc_pwrseq_drv) = {
156*e1efec4eSSimon Glass 	.name		= "mmc_pwrseq_emmc",
157*e1efec4eSSimon Glass 	.id		= UCLASS_PWRSEQ,
158*e1efec4eSSimon Glass 	.of_match	= rockchip_dwmmc_pwrseq_ids,
159*e1efec4eSSimon Glass 	.ops		= &rockchip_dwmmc_pwrseq_ops,
160*e1efec4eSSimon Glass };
161*e1efec4eSSimon Glass #endif
162