blob: 5ba99d68b7df0a48b1e1c5996d68b242c0dfe7ca [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass4ecaa6d2015-08-30 16:55:37 -06002/*
3 * Copyright (c) 2013 Google, Inc
Simon Glass4ecaa6d2015-08-30 16:55:37 -06004 */
5
Simon Glass4ecaa6d2015-08-30 16:55:37 -06006#include <clk.h>
7#include <dm.h>
Simon Glass4bb9ce42016-07-04 11:58:27 -06008#include <dt-structs.h>
Simon Glass4ecaa6d2015-08-30 16:55:37 -06009#include <dwmmc.h>
10#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass4bb9ce42016-07-04 11:58:27 -060012#include <mapmem.h>
Simon Glass947fd982016-01-21 19:43:34 -070013#include <pwrseq.h>
Simon Glass4ecaa6d2015-08-30 16:55:37 -060014#include <syscon.h>
Simon Glass947fd982016-01-21 19:43:34 -070015#include <asm/gpio.h>
Kever Yang9fbe17c2019-03-28 11:01:23 +080016#include <asm/arch-rockchip/clock.h>
17#include <asm/arch-rockchip/periph.h>
Simon Glassdbd79542020-05-10 11:40:11 -060018#include <linux/delay.h>
Simon Glass4ecaa6d2015-08-30 16:55:37 -060019#include <linux/err.h>
20
Simon Glassae696102016-05-14 14:03:08 -060021struct rockchip_mmc_plat {
Simon Glass4bb9ce42016-07-04 11:58:27 -060022#if CONFIG_IS_ENABLED(OF_PLATDATA)
23 struct dtd_rockchip_rk3288_dw_mshc dtplat;
24#endif
Simon Glassae696102016-05-14 14:03:08 -060025 struct mmc_config cfg;
26 struct mmc mmc;
27};
28
Simon Glass4ecaa6d2015-08-30 16:55:37 -060029struct rockchip_dwmmc_priv {
Stephen Warrena9622432016-06-17 09:44:00 -060030 struct clk clk;
Simon Glass4ecaa6d2015-08-30 16:55:37 -060031 struct dwmci_host host;
Simon Glass4188d942016-07-04 11:58:26 -060032 int fifo_depth;
33 bool fifo_mode;
34 u32 minmax[2];
Simon Glass4ecaa6d2015-08-30 16:55:37 -060035};
36
37static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
38{
39 struct udevice *dev = host->priv;
40 struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
41 int ret;
42
John Keeping9f9e9182023-01-17 17:07:47 +000043 /*
44 * The clock frequency chosen here affects CLKDIV in the dw_mmc core.
45 * That can be either 0 or 1, but it must be set to 1 for eMMC DDR52
46 * 8-bit mode. It will be set to 0 for all other modes.
47 */
48 if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8)
49 freq *= 2;
50
Stephen Warrena9622432016-06-17 09:44:00 -060051 ret = clk_set_rate(&priv->clk, freq);
Simon Glass4ecaa6d2015-08-30 16:55:37 -060052 if (ret < 0) {
Kever Yanga70d1ea2017-06-14 16:31:49 +080053 debug("%s: err=%d\n", __func__, ret);
Jonas Karlman57cfde52023-03-14 00:38:32 +000054 return 0;
Simon Glass4ecaa6d2015-08-30 16:55:37 -060055 }
56
57 return freq;
58}
59
Simon Glassaad29ae2020-12-03 16:55:21 -070060static int rockchip_dwmmc_of_to_plat(struct udevice *dev)
Simon Glass4ecaa6d2015-08-30 16:55:37 -060061{
62 struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
63 struct dwmci_host *host = &priv->host;
64
Simon Glass6d70ba02021-08-07 07:24:06 -060065 if (!CONFIG_IS_ENABLED(OF_REAL))
66 return 0;
67
Simon Glass4ecaa6d2015-08-30 16:55:37 -060068 host->name = dev->name;
Philipp Tomsichff788812017-09-11 22:04:15 +020069 host->ioaddr = dev_read_addr_ptr(dev);
Philipp Tomsich9b4c3802017-06-07 18:46:00 +020070 host->buswidth = dev_read_u32_default(dev, "bus-width", 4);
Simon Glass4ecaa6d2015-08-30 16:55:37 -060071 host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
72 host->priv = dev;
73
huang lin8799fc12015-11-18 09:37:25 +080074 /* use non-removeable as sdcard and emmc as judgement */
Philipp Tomsich9b4c3802017-06-07 18:46:00 +020075 if (dev_read_bool(dev, "non-removable"))
huang linb06352f2016-01-08 14:06:49 +080076 host->dev_index = 0;
77 else
huang lin8799fc12015-11-18 09:37:25 +080078 host->dev_index = 1;
Simon Glass4ecaa6d2015-08-30 16:55:37 -060079
Philipp Tomsich9b4c3802017-06-07 18:46:00 +020080 priv->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0);
81
Simon Glass4188d942016-07-04 11:58:26 -060082 if (priv->fifo_depth < 0)
Simon Glassce80ec92024-09-20 09:24:39 +020083 return log_msg_ret("rkp", -EINVAL);
Philipp Tomsich9b4c3802017-06-07 18:46:00 +020084 priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
Philipp Tomsich56b38d82017-04-25 09:52:07 +020085
Heiko Stuebner13f1f722019-11-19 12:04:01 +010086#ifdef CONFIG_SPL_BUILD
87 if (!priv->fifo_mode)
88 priv->fifo_mode = dev_read_bool(dev, "u-boot,spl-fifo-mode");
89#endif
90
Philipp Tomsich56b38d82017-04-25 09:52:07 +020091 /*
92 * 'clock-freq-min-max' is deprecated
93 * (see https://github.com/torvalds/linux/commit/b023030f10573de738bbe8df63d43acab64c9f7b)
94 */
Philipp Tomsich9b4c3802017-06-07 18:46:00 +020095 if (dev_read_u32_array(dev, "clock-freq-min-max", priv->minmax, 2)) {
96 int val = dev_read_u32_default(dev, "max-frequency", -EINVAL);
Philipp Tomsich56b38d82017-04-25 09:52:07 +020097
98 if (val < 0)
Simon Glassce80ec92024-09-20 09:24:39 +020099 return log_msg_ret("rkc", val);
Philipp Tomsich56b38d82017-04-25 09:52:07 +0200100
101 priv->minmax[0] = 400000; /* 400 kHz */
102 priv->minmax[1] = val;
103 } else {
104 debug("%s: 'clock-freq-min-max' property was deprecated.\n",
105 __func__);
106 }
Simon Glass6d70ba02021-08-07 07:24:06 -0600107
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600108 return 0;
109}
110
111static int rockchip_dwmmc_probe(struct udevice *dev)
112{
Simon Glassfa20e932020-12-03 16:55:20 -0700113 struct rockchip_mmc_plat *plat = dev_get_plat(dev);
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600114 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
115 struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
116 struct dwmci_host *host = &priv->host;
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600117 int ret;
118
Simon Glass4bb9ce42016-07-04 11:58:27 -0600119#if CONFIG_IS_ENABLED(OF_PLATDATA)
120 struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat;
121
122 host->name = dev->name;
123 host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
124 host->buswidth = dtplat->bus_width;
125 host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
126 host->priv = dev;
127 host->dev_index = 0;
128 priv->fifo_depth = dtplat->fifo_depth;
Johan Jonkerd3cdf652022-04-09 18:55:09 +0200129 priv->fifo_mode = dtplat->u_boot_spl_fifo_mode;
Kever Yang97087392017-06-14 16:31:46 +0800130 priv->minmax[0] = 400000; /* 400 kHz */
131 priv->minmax[1] = dtplat->max_frequency;
Simon Glass4bb9ce42016-07-04 11:58:27 -0600132
Johan Jonkerd8116bf2022-04-09 18:55:08 +0200133 ret = clk_get_by_phandle(dev, &dtplat->clocks[1], &priv->clk);
Simon Glass4bb9ce42016-07-04 11:58:27 -0600134#else
Johan Jonkerd8116bf2022-04-09 18:55:08 +0200135 ret = clk_get_by_index(dev, 1, &priv->clk);
Simon Glass4bb9ce42016-07-04 11:58:27 -0600136#endif
Simon Glass979f26d2024-09-20 09:24:40 +0200137 if (ret < 0 && ret != -ENOSYS)
138 return log_msg_ret("clk", ret);
Sam Protsenko751fdf12024-08-07 22:14:17 -0500139 host->fifo_depth = priv->fifo_depth;
Simon Glass4188d942016-07-04 11:58:26 -0600140 host->fifo_mode = priv->fifo_mode;
huang linb1b71cd2015-11-17 14:20:24 +0800141
Jonas Karlmanf2ceb752024-01-27 17:12:35 +0000142#if CONFIG_IS_ENABLED(MMC_PWRSEQ)
Simon Glass947fd982016-01-21 19:43:34 -0700143 /* Enable power if needed */
Jaehoon Chungc0674d42021-02-16 10:16:54 +0900144 ret = mmc_pwrseq_get_power(dev, &plat->cfg);
Simon Glass947fd982016-01-21 19:43:34 -0700145 if (!ret) {
Jaehoon Chungc0674d42021-02-16 10:16:54 +0900146 ret = pwrseq_set_power(plat->cfg.pwr_dev, true);
Simon Glass947fd982016-01-21 19:43:34 -0700147 if (ret)
148 return ret;
149 }
150#endif
Jaehoon Chungbf819d02016-09-23 19:13:16 +0900151 dwmci_setup_cfg(&plat->cfg, host, priv->minmax[1], priv->minmax[0]);
Simon Glassae696102016-05-14 14:03:08 -0600152 host->mmc = &plat->mmc;
Simon Glassae696102016-05-14 14:03:08 -0600153 host->mmc->priv = &priv->host;
Simon Glass77ca42b2016-05-01 13:52:34 -0600154 host->mmc->dev = dev;
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600155 upriv->mmc = host->mmc;
156
Jonas Karlman8b2dec82024-07-24 06:55:36 +0000157 /* Hosts capable of 8-bit can also do 4 bits */
158 if (host->buswidth == 8)
159 plat->cfg.host_caps |= MMC_MODE_4BIT;
160
Simon Glassfaeef3b2016-06-12 23:30:24 -0600161 return dwmci_probe(dev);
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600162}
163
Simon Glassae696102016-05-14 14:03:08 -0600164static int rockchip_dwmmc_bind(struct udevice *dev)
165{
Simon Glassfa20e932020-12-03 16:55:20 -0700166 struct rockchip_mmc_plat *plat = dev_get_plat(dev);
Simon Glassae696102016-05-14 14:03:08 -0600167
Masahiro Yamadacdb67f32016-09-06 22:17:32 +0900168 return dwmci_bind(dev, &plat->mmc, &plat->cfg);
Simon Glassae696102016-05-14 14:03:08 -0600169}
170
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600171static const struct udevice_id rockchip_dwmmc_ids[] = {
Heiko Stuebner52c55a22018-09-21 10:59:46 +0200172 { .compatible = "rockchip,rk2928-dw-mshc" },
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600173 { .compatible = "rockchip,rk3288-dw-mshc" },
174 { }
175};
176
Walter Lozano2901ac62020-06-25 01:10:04 -0300177U_BOOT_DRIVER(rockchip_rk3288_dw_mshc) = {
Simon Glass4bb9ce42016-07-04 11:58:27 -0600178 .name = "rockchip_rk3288_dw_mshc",
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600179 .id = UCLASS_MMC,
180 .of_match = rockchip_dwmmc_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700181 .of_to_plat = rockchip_dwmmc_of_to_plat,
Simon Glassfaeef3b2016-06-12 23:30:24 -0600182 .ops = &dm_dwmci_ops,
Simon Glassae696102016-05-14 14:03:08 -0600183 .bind = rockchip_dwmmc_bind,
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600184 .probe = rockchip_dwmmc_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700185 .priv_auto = sizeof(struct rockchip_dwmmc_priv),
Simon Glass71fa5b42020-12-03 16:55:18 -0700186 .plat_auto = sizeof(struct rockchip_mmc_plat),
Simon Glass4ecaa6d2015-08-30 16:55:37 -0600187};
Simon Glass947fd982016-01-21 19:43:34 -0700188
Johan Jonkerd3cdf652022-04-09 18:55:09 +0200189DM_DRIVER_ALIAS(rockchip_rk3288_dw_mshc, rockchip_rk2928_dw_mshc)
Simon Glassdf65db82020-12-28 20:34:57 -0700190DM_DRIVER_ALIAS(rockchip_rk3288_dw_mshc, rockchip_rk3328_dw_mshc)
191DM_DRIVER_ALIAS(rockchip_rk3288_dw_mshc, rockchip_rk3368_dw_mshc)