blob: 99f21b2c546ae4d827c5d49247537056e5a39cb9 [file] [log] [blame]
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001/*
2 * (C) Copyright 2008
3 * Texas Instruments, <www.ti.com>
4 * Sukumar Ghorai <s-ghorai@ti.com>
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation's version 2 of
12 * the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
25#include <config.h>
26#include <common.h>
Simon Glass63334482019-11-14 12:57:39 -070027#include <cpu_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -060028#include <log.h>
Pantelis Antoniou2c850462014-03-11 19:34:20 +020029#include <malloc.h>
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +020030#include <memalign.h>
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -070031#include <mmc.h>
32#include <part.h>
33#include <i2c.h>
Felix Brack419eed22017-10-11 17:05:28 +020034#if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)
Nishanth Menon627612c2013-03-26 05:20:54 +000035#include <palmas.h>
Felix Brack419eed22017-10-11 17:05:28 +020036#endif
Simon Glass274e0b02020-05-10 11:39:56 -060037#include <asm/cache.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060038#include <asm/global_data.h>
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -070039#include <asm/io.h>
40#include <asm/arch/mmc_host_def.h>
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +010041#ifdef CONFIG_OMAP54XX
42#include <asm/arch/mux_dra7xx.h>
43#include <asm/arch/dra7xx_iodelay.h>
44#endif
Tom Rini84c0f692021-09-12 20:32:32 -040045#if !defined(CONFIG_ARCH_KEYSTONE)
Roger Quadros44157de2015-09-19 16:26:53 +053046#include <asm/gpio.h>
Dirk Behme74140232011-05-15 09:04:47 +000047#include <asm/arch/sys_proto.h>
Roger Quadros44157de2015-09-19 16:26:53 +053048#endif
Tom Rinidf5338c2017-02-09 13:41:28 -050049#ifdef CONFIG_MMC_OMAP36XX_PINS
50#include <asm/arch/mux.h>
51#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +053052#include <dm.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070053#include <dm/devres.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060054#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060055#include <linux/delay.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070056#include <linux/err.h>
Jean-Jacques Hiblot20157d42018-01-30 16:01:44 +010057#include <power/regulator.h>
Faiz Abbase4d30562019-01-30 18:08:42 +053058#include <thermal.h>
Mugunthan V Nd97631a2015-09-28 12:56:30 +053059
60DECLARE_GLOBAL_DATA_PTR;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -070061
Pantelis Antoniouc9e75912014-02-26 19:28:45 +020062/* simplify defines to OMAP_HSMMC_USE_GPIO */
63#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
Simon Glass035939e2021-07-10 21:14:30 -060064 (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO))
Pantelis Antoniouc9e75912014-02-26 19:28:45 +020065#define OMAP_HSMMC_USE_GPIO
66#else
67#undef OMAP_HSMMC_USE_GPIO
68#endif
69
Grazvydas Ignotasddde1882012-03-19 12:12:06 +000070/* common definitions for all OMAPs */
71#define SYSCTL_SRC (1 << 25)
72#define SYSCTL_SRD (1 << 26)
73
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +010074#ifdef CONFIG_IODELAY_RECALIBRATION
75struct omap_hsmmc_pinctrl_state {
76 struct pad_conf_entry *padconf;
77 int npads;
78 struct iodelay_cfg_entry *iodelay;
79 int niodelays;
80};
81#endif
82
Nikita Kiryanov13822862012-12-03 02:19:43 +000083struct omap_hsmmc_data {
84 struct hsmmc *base_addr;
Simon Glass5f4bd8c2017-07-04 13:31:19 -060085#if !CONFIG_IS_ENABLED(DM_MMC)
Pantelis Antoniou2c850462014-03-11 19:34:20 +020086 struct mmc_config cfg;
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +010087#endif
Kishon Vijay Abraham I2e18c9b2018-01-30 16:01:31 +010088 uint bus_width;
Jean-Jacques Hiblot7fe2f192018-01-30 16:01:30 +010089 uint clock;
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +010090 ushort last_cmd;
Pantelis Antoniouc9e75912014-02-26 19:28:45 +020091#ifdef OMAP_HSMMC_USE_GPIO
Simon Glass5f4bd8c2017-07-04 13:31:19 -060092#if CONFIG_IS_ENABLED(DM_MMC)
Mugunthan V Nd97631a2015-09-28 12:56:30 +053093 struct gpio_desc cd_gpio; /* Change Detect GPIO */
94 struct gpio_desc wp_gpio; /* Write Protect GPIO */
Mugunthan V Nd97631a2015-09-28 12:56:30 +053095#else
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +000096 int cd_gpio;
Nikita Kiryanov4be9dbc2012-12-03 02:19:47 +000097 int wp_gpio;
Pantelis Antoniouc9e75912014-02-26 19:28:45 +020098#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +053099#endif
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100100#if CONFIG_IS_ENABLED(DM_MMC)
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +0100101 enum bus_mode mode;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100102#endif
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200103 u8 controller_flags;
Jean-Jacques Hiblotcebf0592018-02-23 10:40:18 +0100104#ifdef CONFIG_MMC_OMAP_HS_ADMA
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200105 struct omap_hsmmc_adma_desc *adma_desc_table;
106 uint desc_slot;
107#endif
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +0100108 const char *hw_rev;
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100109 struct udevice *pbias_supply;
110 uint signal_voltage;
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100111#ifdef CONFIG_IODELAY_RECALIBRATION
112 struct omap_hsmmc_pinctrl_state *default_pinctrl_state;
113 struct omap_hsmmc_pinctrl_state *hs_pinctrl_state;
114 struct omap_hsmmc_pinctrl_state *hs200_1_8v_pinctrl_state;
115 struct omap_hsmmc_pinctrl_state *ddr_1_8v_pinctrl_state;
116 struct omap_hsmmc_pinctrl_state *sdr12_pinctrl_state;
117 struct omap_hsmmc_pinctrl_state *sdr25_pinctrl_state;
118 struct omap_hsmmc_pinctrl_state *ddr50_pinctrl_state;
119 struct omap_hsmmc_pinctrl_state *sdr50_pinctrl_state;
120 struct omap_hsmmc_pinctrl_state *sdr104_pinctrl_state;
121#endif
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200122};
123
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100124struct omap_mmc_of_data {
125 u8 controller_flags;
126};
127
Jean-Jacques Hiblotcebf0592018-02-23 10:40:18 +0100128#ifdef CONFIG_MMC_OMAP_HS_ADMA
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200129struct omap_hsmmc_adma_desc {
130 u8 attr;
131 u8 reserved;
132 u16 len;
133 u32 addr;
Nikita Kiryanov13822862012-12-03 02:19:43 +0000134};
135
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200136#define ADMA_MAX_LEN 63488
137
138/* Decriptor table defines */
139#define ADMA_DESC_ATTR_VALID BIT(0)
140#define ADMA_DESC_ATTR_END BIT(1)
141#define ADMA_DESC_ATTR_INT BIT(2)
142#define ADMA_DESC_ATTR_ACT1 BIT(4)
143#define ADMA_DESC_ATTR_ACT2 BIT(5)
144
145#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2
146#define ADMA_DESC_LINK_DESC (ADMA_DESC_ATTR_ACT1 | ADMA_DESC_ATTR_ACT2)
147#endif
148
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500149/* If we fail after 1 second wait, something is really bad */
150#define MAX_RETRY_MS 1000
Jean-Jacques Hiblot192e4302018-01-30 16:01:37 +0100151#define MMC_TIMEOUT_MS 20
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500152
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200153/* DMA transfers can take a long time if a lot a data is transferred.
154 * The timeout must take in account the amount of data. Let's assume
155 * that the time will never exceed 333 ms per MB (in other word we assume
156 * that the bandwidth is always above 3MB/s).
157 */
158#define DMA_TIMEOUT_PER_MB 333
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100159#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
160#define OMAP_HSMMC_NO_1_8_V BIT(1)
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200161#define OMAP_HSMMC_USE_ADMA BIT(2)
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100162#define OMAP_HSMMC_REQUIRE_IODELAY BIT(3)
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200163
Sricharanf72611f2011-11-15 09:49:53 -0500164static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
165static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
166 unsigned int siz);
Jean-Jacques Hiblot7fe2f192018-01-30 16:01:30 +0100167static void omap_hsmmc_start_clock(struct hsmmc *mmc_base);
168static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base);
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100169static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit);
Balaji T Kf843d332011-09-08 06:34:57 +0000170
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +0100171static inline struct omap_hsmmc_data *omap_hsmmc_get_data(struct mmc *mmc)
172{
Simon Glass5f4bd8c2017-07-04 13:31:19 -0600173#if CONFIG_IS_ENABLED(DM_MMC)
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +0100174 return dev_get_priv(mmc->dev);
175#else
176 return (struct omap_hsmmc_data *)mmc->priv;
177#endif
178}
Tom Rinibf3e2462020-06-04 16:03:55 -0400179
180#if defined(CONFIG_OMAP34XX) || defined(CONFIG_IODELAY_RECALIBRATION)
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +0100181static inline struct mmc_config *omap_hsmmc_get_cfg(struct mmc *mmc)
182{
Simon Glass5f4bd8c2017-07-04 13:31:19 -0600183#if CONFIG_IS_ENABLED(DM_MMC)
Simon Glassfa20e932020-12-03 16:55:20 -0700184 struct omap_hsmmc_plat *plat = dev_get_plat(mmc->dev);
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +0100185 return &plat->cfg;
186#else
187 return &((struct omap_hsmmc_data *)mmc->priv)->cfg;
188#endif
189}
Tom Rinibf3e2462020-06-04 16:03:55 -0400190#endif
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +0100191
Simon Glass5f4bd8c2017-07-04 13:31:19 -0600192#if defined(OMAP_HSMMC_USE_GPIO) && !CONFIG_IS_ENABLED(DM_MMC)
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +0000193static int omap_mmc_setup_gpio_in(int gpio, const char *label)
194{
Simon Glass1a96d7f2014-10-22 21:37:09 -0600195 int ret;
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +0000196
Simon Glassfa4689a2019-12-06 21:41:35 -0700197#if !CONFIG_IS_ENABLED(DM_GPIO)
Simon Glass1a96d7f2014-10-22 21:37:09 -0600198 if (!gpio_is_valid(gpio))
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +0000199 return -1;
Simon Glass1a96d7f2014-10-22 21:37:09 -0600200#endif
201 ret = gpio_request(gpio, label);
202 if (ret)
203 return ret;
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +0000204
Simon Glass1a96d7f2014-10-22 21:37:09 -0600205 ret = gpio_direction_input(gpio);
206 if (ret)
207 return ret;
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +0000208
209 return gpio;
210}
Nikita Kiryanov4eae05c2012-12-03 02:19:44 +0000211#endif
212
Jeroen Hofsteeaedeeaa2014-07-12 21:24:08 +0200213static unsigned char mmc_board_init(struct mmc *mmc)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700214{
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700215#if defined(CONFIG_OMAP34XX)
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +0100216 struct mmc_config *cfg = omap_hsmmc_get_cfg(mmc);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700217 t2_t *t2_base = (t2_t *)T2_BASE;
218 struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
Grazvydas Ignotasef2b7292012-03-19 03:50:53 +0000219 u32 pbias_lite;
Adam Fordef354962017-02-06 11:31:43 -0600220#ifdef CONFIG_MMC_OMAP36XX_PINS
221 u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
222#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700223
Grazvydas Ignotasef2b7292012-03-19 03:50:53 +0000224 pbias_lite = readl(&t2_base->pbias_lite);
225 pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
Albert ARIBAUD \(3ADEV\)6ad09812015-01-16 09:09:50 +0100226#ifdef CONFIG_TARGET_OMAP3_CAIRO
227 /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
228 pbias_lite &= ~PBIASLITEVMODE0;
229#endif
Adam Fordf2eb4322018-09-05 04:11:08 -0500230#ifdef CONFIG_TARGET_OMAP3_LOGIC
231 /* For Logic PD board, 1.8V bias to go enable gpio127 for mmc_cd */
232 pbias_lite &= ~PBIASLITEVMODE1;
233#endif
Adam Fordef354962017-02-06 11:31:43 -0600234#ifdef CONFIG_MMC_OMAP36XX_PINS
235 if (get_cpu_family() == CPU_OMAP36XX) {
236 /* Disable extended drain IO before changing PBIAS */
237 wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
238 writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
239 }
240#endif
Grazvydas Ignotasef2b7292012-03-19 03:50:53 +0000241 writel(pbias_lite, &t2_base->pbias_lite);
Paul Kocialkowski69559892014-11-08 20:55:47 +0100242
Grazvydas Ignotasef2b7292012-03-19 03:50:53 +0000243 writel(pbias_lite | PBIASLITEPWRDNZ1 |
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700244 PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
245 &t2_base->pbias_lite);
246
Adam Fordef354962017-02-06 11:31:43 -0600247#ifdef CONFIG_MMC_OMAP36XX_PINS
248 if (get_cpu_family() == CPU_OMAP36XX)
249 /* Enable extended drain IO after changing PBIAS */
250 writel(wkup_ctrl |
251 OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
252 OMAP34XX_CTRL_WKUP_CTRL);
253#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700254 writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
255 &t2_base->devconf0);
256
257 writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL,
258 &t2_base->devconf1);
259
Jonathan Solnita9b05562012-02-24 11:30:18 +0000260 /* Change from default of 52MHz to 26MHz if necessary */
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +0100261 if (!(cfg->host_caps & MMC_MODE_HS_52MHz))
Jonathan Solnita9b05562012-02-24 11:30:18 +0000262 writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
263 &t2_base->ctl_prog_io1);
264
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700265 writel(readl(&prcm_base->fclken1_core) |
266 EN_MMC1 | EN_MMC2 | EN_MMC3,
267 &prcm_base->fclken1_core);
268
269 writel(readl(&prcm_base->iclken1_core) |
270 EN_MMC1 | EN_MMC2 | EN_MMC3,
271 &prcm_base->iclken1_core);
272#endif
273
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100274#if (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) &&\
275 !CONFIG_IS_ENABLED(DM_REGULATOR)
Balaji T Kf843d332011-09-08 06:34:57 +0000276 /* PBIAS config needed for MMC1 only */
Jean-Jacques Hiblot26319b12017-03-22 16:00:32 +0100277 if (mmc_get_blk_desc(mmc)->devnum == 0)
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530278 vmmc_pbias_config(LDO_VOLT_3V3);
Balaji T Kd9cf8362012-03-12 02:25:49 +0000279#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700280
281 return 0;
282}
283
Sricharanf72611f2011-11-15 09:49:53 -0500284void mmc_init_stream(struct hsmmc *mmc_base)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700285{
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500286 ulong start;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700287
288 writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
289
290 writel(MMC_CMD0, &mmc_base->cmd);
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500291 start = get_timer(0);
292 while (!(readl(&mmc_base->stat) & CC_MASK)) {
293 if (get_timer(0) - start > MAX_RETRY_MS) {
294 printf("%s: timedout waiting for cc!\n", __func__);
295 return;
296 }
297 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700298 writel(CC_MASK, &mmc_base->stat)
299 ;
300 writel(MMC_CMD0, &mmc_base->cmd)
301 ;
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500302 start = get_timer(0);
303 while (!(readl(&mmc_base->stat) & CC_MASK)) {
304 if (get_timer(0) - start > MAX_RETRY_MS) {
305 printf("%s: timedout waiting for cc2!\n", __func__);
306 return;
307 }
308 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700309 writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
310}
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100311
312#if CONFIG_IS_ENABLED(DM_MMC)
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100313#ifdef CONFIG_IODELAY_RECALIBRATION
314static void omap_hsmmc_io_recalibrate(struct mmc *mmc)
315{
316 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
317 struct omap_hsmmc_pinctrl_state *pinctrl_state;
318
319 switch (priv->mode) {
320 case MMC_HS_200:
321 pinctrl_state = priv->hs200_1_8v_pinctrl_state;
322 break;
323 case UHS_SDR104:
324 pinctrl_state = priv->sdr104_pinctrl_state;
325 break;
326 case UHS_SDR50:
327 pinctrl_state = priv->sdr50_pinctrl_state;
328 break;
329 case UHS_DDR50:
330 pinctrl_state = priv->ddr50_pinctrl_state;
331 break;
332 case UHS_SDR25:
333 pinctrl_state = priv->sdr25_pinctrl_state;
334 break;
335 case UHS_SDR12:
336 pinctrl_state = priv->sdr12_pinctrl_state;
337 break;
338 case SD_HS:
339 case MMC_HS:
340 case MMC_HS_52:
341 pinctrl_state = priv->hs_pinctrl_state;
342 break;
343 case MMC_DDR_52:
344 pinctrl_state = priv->ddr_1_8v_pinctrl_state;
345 default:
346 pinctrl_state = priv->default_pinctrl_state;
347 break;
348 }
349
Jean-Jacques Hiblotdae1ad42018-01-30 16:01:42 +0100350 if (!pinctrl_state)
351 pinctrl_state = priv->default_pinctrl_state;
352
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100353 if (priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY) {
354 if (pinctrl_state->iodelay)
355 late_recalibrate_iodelay(pinctrl_state->padconf,
356 pinctrl_state->npads,
357 pinctrl_state->iodelay,
358 pinctrl_state->niodelays);
359 else
360 do_set_mux32((*ctrl)->control_padconf_core_base,
361 pinctrl_state->padconf,
362 pinctrl_state->npads);
363 }
364}
365#endif
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +0100366static void omap_hsmmc_set_timing(struct mmc *mmc)
367{
368 u32 val;
369 struct hsmmc *mmc_base;
370 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
371
372 mmc_base = priv->base_addr;
373
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100374 omap_hsmmc_stop_clock(mmc_base);
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +0100375 val = readl(&mmc_base->ac12);
376 val &= ~AC12_UHSMC_MASK;
377 priv->mode = mmc->selected_mode;
378
Kishon Vijay Abraham I0c1f3d02018-01-30 16:01:34 +0100379 if (mmc_is_mode_ddr(priv->mode))
380 writel(readl(&mmc_base->con) | DDR, &mmc_base->con);
381 else
382 writel(readl(&mmc_base->con) & ~DDR, &mmc_base->con);
383
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +0100384 switch (priv->mode) {
385 case MMC_HS_200:
386 case UHS_SDR104:
387 val |= AC12_UHSMC_SDR104;
388 break;
389 case UHS_SDR50:
390 val |= AC12_UHSMC_SDR50;
391 break;
392 case MMC_DDR_52:
393 case UHS_DDR50:
394 val |= AC12_UHSMC_DDR50;
395 break;
396 case SD_HS:
397 case MMC_HS_52:
398 case UHS_SDR25:
399 val |= AC12_UHSMC_SDR25;
400 break;
401 case MMC_LEGACY:
402 case MMC_HS:
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +0100403 case UHS_SDR12:
404 val |= AC12_UHSMC_SDR12;
405 break;
406 default:
407 val |= AC12_UHSMC_RES;
408 break;
409 }
410 writel(val, &mmc_base->ac12);
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +0100411
412#ifdef CONFIG_IODELAY_RECALIBRATION
413 omap_hsmmc_io_recalibrate(mmc);
414#endif
415 omap_hsmmc_start_clock(mmc_base);
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +0100416}
417
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100418static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage)
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100419{
420 struct hsmmc *mmc_base;
421 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100422 u32 hctl, ac12;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100423
424 mmc_base = priv->base_addr;
425
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100426 hctl = readl(&mmc_base->hctl) & ~SDVS_MASK;
427 ac12 = readl(&mmc_base->ac12) & ~AC12_V1V8_SIGEN;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100428
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100429 switch (signal_voltage) {
430 case MMC_SIGNAL_VOLTAGE_330:
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530431 hctl |= SDVS_3V3;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100432 break;
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100433 case MMC_SIGNAL_VOLTAGE_180:
434 hctl |= SDVS_1V8;
435 ac12 |= AC12_V1V8_SIGEN;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100436 break;
437 }
438
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100439 writel(hctl, &mmc_base->hctl);
440 writel(ac12, &mmc_base->ac12);
441}
442
Sam Protsenkodb174c62019-08-14 22:52:51 +0300443static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout_us)
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100444{
445 int ret = -ETIMEDOUT;
446 u32 con;
447 bool dat0_high;
448 bool target_dat0_high = !!state;
449 struct omap_hsmmc_data *priv = dev_get_priv(dev);
450 struct hsmmc *mmc_base = priv->base_addr;
451
452 con = readl(&mmc_base->con);
453 writel(con | CON_CLKEXTFREE | CON_PADEN, &mmc_base->con);
454
Sam Protsenkodb174c62019-08-14 22:52:51 +0300455 timeout_us = DIV_ROUND_UP(timeout_us, 10); /* check every 10 us. */
456 while (timeout_us--) {
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100457 dat0_high = !!(readl(&mmc_base->pstate) & PSTATE_DLEV_DAT0);
458 if (dat0_high == target_dat0_high) {
459 ret = 0;
460 break;
461 }
462 udelay(10);
463 }
464 writel(con, &mmc_base->con);
465
466 return ret;
467}
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100468
469#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
470#if CONFIG_IS_ENABLED(DM_REGULATOR)
471static int omap_hsmmc_set_io_regulator(struct mmc *mmc, int mV)
472{
473 int ret = 0;
474 int uV = mV * 1000;
475
476 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
477
478 if (!mmc->vqmmc_supply)
479 return 0;
480
481 /* Disable PBIAS */
Lokesh Vutlab2691972019-01-11 15:15:52 +0530482 ret = regulator_set_enable_if_allowed(priv->pbias_supply, false);
483 if (ret)
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100484 return ret;
485
486 /* Turn off IO voltage */
Lokesh Vutlab2691972019-01-11 15:15:52 +0530487 ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, false);
488 if (ret)
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100489 return ret;
490 /* Program a new IO voltage value */
491 ret = regulator_set_value(mmc->vqmmc_supply, uV);
492 if (ret)
493 return ret;
494 /* Turn on IO voltage */
Lokesh Vutlab2691972019-01-11 15:15:52 +0530495 ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, true);
496 if (ret)
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100497 return ret;
498
499 /* Program PBIAS voltage*/
500 ret = regulator_set_value(priv->pbias_supply, uV);
501 if (ret && ret != -ENOSYS)
502 return ret;
503 /* Enable PBIAS */
Lokesh Vutlab2691972019-01-11 15:15:52 +0530504 ret = regulator_set_enable_if_allowed(priv->pbias_supply, true);
505 if (ret)
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100506 return ret;
507
508 return 0;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100509}
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100510#endif
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100511
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100512static int omap_hsmmc_set_signal_voltage(struct mmc *mmc)
513{
514 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
515 struct hsmmc *mmc_base = priv->base_addr;
516 int mv = mmc_voltage_to_mv(mmc->signal_voltage);
517 u32 capa_mask;
518 __maybe_unused u8 palmas_ldo_volt;
519 u32 val;
520
521 if (mv < 0)
522 return -EINVAL;
523
524 if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530525 mv = 3300;
526 capa_mask = VS33_3V3SUP;
527 palmas_ldo_volt = LDO_VOLT_3V3;
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100528 } else if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
529 capa_mask = VS18_1V8SUP;
530 palmas_ldo_volt = LDO_VOLT_1V8;
531 } else {
532 return -EOPNOTSUPP;
533 }
534
535 val = readl(&mmc_base->capa);
536 if (!(val & capa_mask))
537 return -EOPNOTSUPP;
538
539 priv->signal_voltage = mmc->signal_voltage;
540
541 omap_hsmmc_conf_bus_power(mmc, mmc->signal_voltage);
542
543#if CONFIG_IS_ENABLED(DM_REGULATOR)
544 return omap_hsmmc_set_io_regulator(mmc, mv);
545#elif (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) && \
546 defined(CONFIG_PALMAS_POWER)
547 if (mmc_get_blk_desc(mmc)->devnum == 0)
548 vmmc_pbias_config(palmas_ldo_volt);
549 return 0;
550#else
551 return 0;
552#endif
553}
554#endif
555
556static uint32_t omap_hsmmc_set_capabilities(struct mmc *mmc)
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100557{
558 struct hsmmc *mmc_base;
559 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
560 u32 val;
561
562 mmc_base = priv->base_addr;
563 val = readl(&mmc_base->capa);
564
565 if (priv->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530566 val |= (VS33_3V3SUP | VS18_1V8SUP);
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100567 } else if (priv->controller_flags & OMAP_HSMMC_NO_1_8_V) {
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530568 val |= VS33_3V3SUP;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100569 val &= ~VS18_1V8SUP;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100570 } else {
571 val |= VS18_1V8SUP;
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530572 val &= ~VS33_3V3SUP;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100573 }
574
575 writel(val, &mmc_base->capa);
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100576
577 return val;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100578}
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100579
580#ifdef MMC_SUPPORTS_TUNING
581static void omap_hsmmc_disable_tuning(struct mmc *mmc)
582{
583 struct hsmmc *mmc_base;
584 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
585 u32 val;
586
587 mmc_base = priv->base_addr;
588 val = readl(&mmc_base->ac12);
589 val &= ~(AC12_SCLK_SEL);
590 writel(val, &mmc_base->ac12);
591
592 val = readl(&mmc_base->dll);
593 val &= ~(DLL_FORCE_VALUE | DLL_SWT);
594 writel(val, &mmc_base->dll);
595}
596
597static void omap_hsmmc_set_dll(struct mmc *mmc, int count)
598{
599 int i;
600 struct hsmmc *mmc_base;
601 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
602 u32 val;
603
604 mmc_base = priv->base_addr;
605 val = readl(&mmc_base->dll);
606 val |= DLL_FORCE_VALUE;
607 val &= ~(DLL_FORCE_SR_C_MASK << DLL_FORCE_SR_C_SHIFT);
608 val |= (count << DLL_FORCE_SR_C_SHIFT);
609 writel(val, &mmc_base->dll);
610
611 val |= DLL_CALIB;
612 writel(val, &mmc_base->dll);
613 for (i = 0; i < 1000; i++) {
614 if (readl(&mmc_base->dll) & DLL_CALIB)
615 break;
616 }
617 val &= ~DLL_CALIB;
618 writel(val, &mmc_base->dll);
619}
620
621static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
622{
623 struct omap_hsmmc_data *priv = dev_get_priv(dev);
624 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
625 struct mmc *mmc = upriv->mmc;
626 struct hsmmc *mmc_base;
627 u32 val;
628 u8 cur_match, prev_match = 0;
629 int ret;
630 u32 phase_delay = 0;
631 u32 start_window = 0, max_window = 0;
632 u32 length = 0, max_len = 0;
Faiz Abbase4d30562019-01-30 18:08:42 +0530633 bool single_point_failure = false;
634 struct udevice *thermal_dev;
635 int temperature;
636 int i;
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100637
638 mmc_base = priv->base_addr;
639 val = readl(&mmc_base->capa2);
640
641 /* clock tuning is not needed for upto 52MHz */
642 if (!((mmc->selected_mode == MMC_HS_200) ||
643 (mmc->selected_mode == UHS_SDR104) ||
644 ((mmc->selected_mode == UHS_SDR50) && (val & CAPA2_TSDR50))))
645 return 0;
646
Michal Suchanekac12a2f2022-10-12 21:57:59 +0200647 ret = uclass_first_device_err(UCLASS_THERMAL, &thermal_dev);
Faiz Abbase4d30562019-01-30 18:08:42 +0530648 if (ret) {
649 printf("Couldn't get thermal device for tuning\n");
650 return ret;
651 }
652 ret = thermal_get_temp(thermal_dev, &temperature);
653 if (ret) {
654 printf("Couldn't get temperature for tuning\n");
655 return ret;
656 }
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100657 val = readl(&mmc_base->dll);
658 val |= DLL_SWT;
659 writel(val, &mmc_base->dll);
Faiz Abbase4d30562019-01-30 18:08:42 +0530660
661 /*
662 * Stage 1: Search for a maximum pass window ignoring any
663 * any single point failures. If the tuning value ends up
664 * near it, move away from it in stage 2 below
665 */
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100666 while (phase_delay <= MAX_PHASE_DELAY) {
667 omap_hsmmc_set_dll(mmc, phase_delay);
668
Marek Vasutdad81fb2024-02-20 09:36:23 +0100669 cur_match = !mmc_send_tuning(mmc, opcode);
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100670
671 if (cur_match) {
672 if (prev_match) {
673 length++;
Faiz Abbase4d30562019-01-30 18:08:42 +0530674 } else if (single_point_failure) {
675 /* ignore single point failure */
676 length++;
677 single_point_failure = false;
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100678 } else {
679 start_window = phase_delay;
680 length = 1;
681 }
Faiz Abbase4d30562019-01-30 18:08:42 +0530682 } else {
683 single_point_failure = prev_match;
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100684 }
685
686 if (length > max_len) {
687 max_window = start_window;
688 max_len = length;
689 }
690
691 prev_match = cur_match;
692 phase_delay += 4;
693 }
694
695 if (!max_len) {
696 ret = -EIO;
697 goto tuning_error;
698 }
699
700 val = readl(&mmc_base->ac12);
701 if (!(val & AC12_SCLK_SEL)) {
702 ret = -EIO;
703 goto tuning_error;
704 }
Faiz Abbase4d30562019-01-30 18:08:42 +0530705 /*
706 * Assign tuning value as a ratio of maximum pass window based
707 * on temperature
708 */
709 if (temperature < -20000)
710 phase_delay = min(max_window + 4 * max_len - 24,
711 max_window +
712 DIV_ROUND_UP(13 * max_len, 16) * 4);
713 else if (temperature < 20000)
714 phase_delay = max_window + DIV_ROUND_UP(9 * max_len, 16) * 4;
715 else if (temperature < 40000)
716 phase_delay = max_window + DIV_ROUND_UP(8 * max_len, 16) * 4;
717 else if (temperature < 70000)
718 phase_delay = max_window + DIV_ROUND_UP(7 * max_len, 16) * 4;
719 else if (temperature < 90000)
720 phase_delay = max_window + DIV_ROUND_UP(5 * max_len, 16) * 4;
721 else if (temperature < 120000)
722 phase_delay = max_window + DIV_ROUND_UP(4 * max_len, 16) * 4;
723 else
724 phase_delay = max_window + DIV_ROUND_UP(3 * max_len, 16) * 4;
725
726 /*
727 * Stage 2: Search for a single point failure near the chosen tuning
728 * value in two steps. First in the +3 to +10 range and then in the
729 * +2 to -10 range. If found, move away from it in the appropriate
730 * direction by the appropriate amount depending on the temperature.
731 */
732 for (i = 3; i <= 10; i++) {
733 omap_hsmmc_set_dll(mmc, phase_delay + i);
Marek Vasutdad81fb2024-02-20 09:36:23 +0100734 if (mmc_send_tuning(mmc, opcode)) {
Faiz Abbase4d30562019-01-30 18:08:42 +0530735 if (temperature < 10000)
736 phase_delay += i + 6;
737 else if (temperature < 20000)
738 phase_delay += i - 12;
739 else if (temperature < 70000)
740 phase_delay += i - 8;
741 else if (temperature < 90000)
742 phase_delay += i - 6;
743 else
744 phase_delay += i - 6;
745
746 goto single_failure_found;
747 }
748 }
749
750 for (i = 2; i >= -10; i--) {
751 omap_hsmmc_set_dll(mmc, phase_delay + i);
Marek Vasutdad81fb2024-02-20 09:36:23 +0100752 if (mmc_send_tuning(mmc, opcode)) {
Faiz Abbase4d30562019-01-30 18:08:42 +0530753 if (temperature < 10000)
754 phase_delay += i + 12;
755 else if (temperature < 20000)
756 phase_delay += i + 8;
757 else if (temperature < 70000)
758 phase_delay += i + 8;
759 else if (temperature < 90000)
760 phase_delay += i + 10;
761 else
762 phase_delay += i + 12;
763
764 goto single_failure_found;
765 }
766 }
767
768single_failure_found:
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100769
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +0100770 omap_hsmmc_set_dll(mmc, phase_delay);
771
772 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
773 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
774
775 return 0;
776
777tuning_error:
778
779 omap_hsmmc_disable_tuning(mmc);
780 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
781 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
782
783 return ret;
784}
785#endif
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100786#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700787
Jean-Jacques Hiblota420d7d2018-01-30 16:01:36 +0100788static void mmc_enable_irq(struct mmc *mmc, struct mmc_cmd *cmd)
789{
790 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
791 struct hsmmc *mmc_base = priv->base_addr;
792 u32 irq_mask = INT_EN_MASK;
793
794 /*
795 * TODO: Errata i802 indicates only DCRC interrupts can occur during
796 * tuning procedure and DCRC should be disabled. But see occurences
797 * of DEB, CIE, CEB, CCRC interupts during tuning procedure. These
798 * interrupts occur along with BRR, so the data is actually in the
799 * buffer. It has to be debugged why these interrutps occur
800 */
801 if (cmd && mmc_is_tuning_cmd(cmd->cmdidx))
802 irq_mask &= ~(IE_DEB | IE_DCRC | IE_CIE | IE_CEB | IE_CCRC);
803
804 writel(irq_mask, &mmc_base->ie);
805}
806
Pantelis Antoniouc9e75912014-02-26 19:28:45 +0200807static int omap_hsmmc_init_setup(struct mmc *mmc)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700808{
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +0100809 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
Nikita Kiryanov13822862012-12-03 02:19:43 +0000810 struct hsmmc *mmc_base;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700811 unsigned int reg_val;
812 unsigned int dsor;
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500813 ulong start;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700814
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +0100815 mmc_base = priv->base_addr;
Balaji T Kf843d332011-09-08 06:34:57 +0000816 mmc_board_init(mmc);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700817
818 writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
819 &mmc_base->sysconfig);
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500820 start = get_timer(0);
821 while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
822 if (get_timer(0) - start > MAX_RETRY_MS) {
823 printf("%s: timedout waiting for cc2!\n", __func__);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900824 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500825 }
826 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700827 writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500828 start = get_timer(0);
829 while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
830 if (get_timer(0) - start > MAX_RETRY_MS) {
831 printf("%s: timedout waiting for softresetall!\n",
832 __func__);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900833 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500834 }
835 }
Jean-Jacques Hiblotcebf0592018-02-23 10:40:18 +0100836#ifdef CONFIG_MMC_OMAP_HS_ADMA
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200837 reg_val = readl(&mmc_base->hl_hwinfo);
838 if (reg_val & MADMA_EN)
839 priv->controller_flags |= OMAP_HSMMC_USE_ADMA;
840#endif
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100841
842#if CONFIG_IS_ENABLED(DM_MMC)
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100843 reg_val = omap_hsmmc_set_capabilities(mmc);
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530844 omap_hsmmc_conf_bus_power(mmc, (reg_val & VS33_3V3SUP) ?
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +0100845 MMC_SIGNAL_VOLTAGE_330 : MMC_SIGNAL_VOLTAGE_180);
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100846#else
Pali Rohárb2d1e562020-07-03 22:58:23 +0200847 writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V3, &mmc_base->hctl);
Faiz Abbasfc1ad622019-04-05 14:18:46 +0530848 writel(readl(&mmc_base->capa) | VS33_3V3SUP | VS18_1V8SUP,
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700849 &mmc_base->capa);
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +0100850#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700851
852 reg_val = readl(&mmc_base->con) & RESERVED_MASK;
853
854 writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
855 MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
856 HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
857
858 dsor = 240;
859 mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
Kishon Vijay Abraham I6e543812017-09-21 16:51:36 +0200860 (ICE_STOP | DTO_15THDTO));
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700861 mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
862 (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500863 start = get_timer(0);
864 while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
865 if (get_timer(0) - start > MAX_RETRY_MS) {
866 printf("%s: timedout waiting for ics!\n", __func__);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900867 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -0500868 }
869 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700870 writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
871
872 writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
873
Jean-Jacques Hiblota420d7d2018-01-30 16:01:36 +0100874 mmc_enable_irq(mmc, NULL);
Jean-Jacques Hiblot20157d42018-01-30 16:01:44 +0100875
876#if !CONFIG_IS_ENABLED(DM_MMC)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700877 mmc_init_stream(mmc_base);
Jean-Jacques Hiblot20157d42018-01-30 16:01:44 +0100878#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -0700879
880 return 0;
881}
882
Grazvydas Ignotasddde1882012-03-19 12:12:06 +0000883/*
884 * MMC controller internal finite state machine reset
885 *
886 * Used to reset command or data internal state machines, using respectively
887 * SRC or SRD bit of SYSCTL register
888 */
889static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
890{
891 ulong start;
892
893 mmc_reg_out(&mmc_base->sysctl, bit, bit);
894
Oleksandr Tyshchenko06640ca2013-08-06 13:44:16 +0300895 /*
896 * CMD(DAT) lines reset procedures are slightly different
897 * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
898 * According to OMAP3 TRM:
899 * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
900 * returns to 0x0.
901 * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
902 * procedure steps must be as follows:
903 * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
904 * MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
905 * 2. Poll the SRC(SRD) bit until it is set to 0x1.
906 * 3. Wait until the SRC (SRD) bit returns to 0x0
907 * (reset procedure is completed).
908 */
909#if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
Nikita Kiryanov5ffdd852015-07-30 23:56:20 +0300910 defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX)
Oleksandr Tyshchenko06640ca2013-08-06 13:44:16 +0300911 if (!(readl(&mmc_base->sysctl) & bit)) {
912 start = get_timer(0);
913 while (!(readl(&mmc_base->sysctl) & bit)) {
Jean-Jacques Hiblot192e4302018-01-30 16:01:37 +0100914 if (get_timer(0) - start > MMC_TIMEOUT_MS)
Oleksandr Tyshchenko06640ca2013-08-06 13:44:16 +0300915 return;
916 }
917 }
918#endif
Grazvydas Ignotasddde1882012-03-19 12:12:06 +0000919 start = get_timer(0);
920 while ((readl(&mmc_base->sysctl) & bit) != 0) {
921 if (get_timer(0) - start > MAX_RETRY_MS) {
922 printf("%s: timedout waiting for sysctl %x to clear\n",
923 __func__, bit);
924 return;
925 }
926 }
927}
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200928
Jean-Jacques Hiblotcebf0592018-02-23 10:40:18 +0100929#ifdef CONFIG_MMC_OMAP_HS_ADMA
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +0200930static void omap_hsmmc_adma_desc(struct mmc *mmc, char *buf, u16 len, bool end)
931{
932 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
933 struct omap_hsmmc_adma_desc *desc;
934 u8 attr;
935
936 desc = &priv->adma_desc_table[priv->desc_slot];
937
938 attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
939 if (!end)
940 priv->desc_slot++;
941 else
942 attr |= ADMA_DESC_ATTR_END;
943
944 desc->len = len;
945 desc->addr = (u32)buf;
946 desc->reserved = 0;
947 desc->attr = attr;
948}
949
950static void omap_hsmmc_prepare_adma_table(struct mmc *mmc,
951 struct mmc_data *data)
952{
953 uint total_len = data->blocksize * data->blocks;
954 uint desc_count = DIV_ROUND_UP(total_len, ADMA_MAX_LEN);
955 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
956 int i = desc_count;
957 char *buf;
958
959 priv->desc_slot = 0;
960 priv->adma_desc_table = (struct omap_hsmmc_adma_desc *)
961 memalign(ARCH_DMA_MINALIGN, desc_count *
962 sizeof(struct omap_hsmmc_adma_desc));
963
964 if (data->flags & MMC_DATA_READ)
965 buf = data->dest;
966 else
967 buf = (char *)data->src;
968
969 while (--i) {
970 omap_hsmmc_adma_desc(mmc, buf, ADMA_MAX_LEN, false);
971 buf += ADMA_MAX_LEN;
972 total_len -= ADMA_MAX_LEN;
973 }
974
975 omap_hsmmc_adma_desc(mmc, buf, total_len, true);
976
977 flush_dcache_range((long)priv->adma_desc_table,
978 (long)priv->adma_desc_table +
979 ROUND(desc_count *
980 sizeof(struct omap_hsmmc_adma_desc),
981 ARCH_DMA_MINALIGN));
982}
983
984static void omap_hsmmc_prepare_data(struct mmc *mmc, struct mmc_data *data)
985{
986 struct hsmmc *mmc_base;
987 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
988 u32 val;
989 char *buf;
990
991 mmc_base = priv->base_addr;
992 omap_hsmmc_prepare_adma_table(mmc, data);
993
994 if (data->flags & MMC_DATA_READ)
995 buf = data->dest;
996 else
997 buf = (char *)data->src;
998
999 val = readl(&mmc_base->hctl);
1000 val |= DMA_SELECT;
1001 writel(val, &mmc_base->hctl);
1002
1003 val = readl(&mmc_base->con);
1004 val |= DMA_MASTER;
1005 writel(val, &mmc_base->con);
1006
1007 writel((u32)priv->adma_desc_table, &mmc_base->admasal);
1008
1009 flush_dcache_range((u32)buf,
1010 (u32)buf +
1011 ROUND(data->blocksize * data->blocks,
1012 ARCH_DMA_MINALIGN));
1013}
1014
1015static void omap_hsmmc_dma_cleanup(struct mmc *mmc)
1016{
1017 struct hsmmc *mmc_base;
1018 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1019 u32 val;
1020
1021 mmc_base = priv->base_addr;
1022
1023 val = readl(&mmc_base->con);
1024 val &= ~DMA_MASTER;
1025 writel(val, &mmc_base->con);
1026
1027 val = readl(&mmc_base->hctl);
1028 val &= ~DMA_SELECT;
1029 writel(val, &mmc_base->hctl);
1030
1031 kfree(priv->adma_desc_table);
1032}
1033#else
1034#define omap_hsmmc_adma_desc
1035#define omap_hsmmc_prepare_adma_table
1036#define omap_hsmmc_prepare_data
1037#define omap_hsmmc_dma_cleanup
1038#endif
1039
Simon Glass5f4bd8c2017-07-04 13:31:19 -06001040#if !CONFIG_IS_ENABLED(DM_MMC)
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001041static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001042 struct mmc_data *data)
1043{
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001044 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001045#else
1046static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
1047 struct mmc_data *data)
1048{
1049 struct omap_hsmmc_data *priv = dev_get_priv(dev);
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +02001050 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
1051 struct mmc *mmc = upriv->mmc;
1052#endif
Nikita Kiryanov13822862012-12-03 02:19:43 +00001053 struct hsmmc *mmc_base;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001054 unsigned int flags, mmc_stat;
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001055 ulong start;
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +01001056 priv->last_cmd = cmd->cmdidx;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001057
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001058 mmc_base = priv->base_addr;
Kishon Vijay Abraham I316e7ae2017-09-21 16:51:35 +02001059
1060 if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
1061 return 0;
1062
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001063 start = get_timer(0);
Tom Rini32ec3252012-01-30 11:22:25 +00001064 while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001065 if (get_timer(0) - start > MAX_RETRY_MS) {
Tom Rini32ec3252012-01-30 11:22:25 +00001066 printf("%s: timedout waiting on cmd inhibit to clear\n",
1067 __func__);
Jean-Jacques Hiblota1e7a4d2019-07-02 10:53:48 +02001068 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
1069 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
Jaehoon Chung7825d202016-07-19 16:33:36 +09001070 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001071 }
1072 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001073 writel(0xFFFFFFFF, &mmc_base->stat);
Jean-Jacques Hiblota1e7a4d2019-07-02 10:53:48 +02001074 if (readl(&mmc_base->stat)) {
1075 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
1076 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001077 }
Jean-Jacques Hiblota1e7a4d2019-07-02 10:53:48 +02001078
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001079 /*
1080 * CMDREG
1081 * CMDIDX[13:8] : Command index
1082 * DATAPRNT[5] : Data Present Select
1083 * ENCMDIDX[4] : Command Index Check Enable
1084 * ENCMDCRC[3] : Command CRC Check Enable
1085 * RSPTYP[1:0]
1086 * 00 = No Response
1087 * 01 = Length 136
1088 * 10 = Length 48
1089 * 11 = Length 48 Check busy after response
1090 */
1091 /* Delay added before checking the status of frq change
1092 * retry not supported by mmc.c(core file)
1093 */
1094 if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
1095 udelay(50000); /* wait 50 ms */
1096
1097 if (!(cmd->resp_type & MMC_RSP_PRESENT))
1098 flags = 0;
1099 else if (cmd->resp_type & MMC_RSP_136)
1100 flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
1101 else if (cmd->resp_type & MMC_RSP_BUSY)
1102 flags = RSP_TYPE_LGHT48B;
1103 else
1104 flags = RSP_TYPE_LGHT48;
1105
1106 /* enable default flags */
1107 flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
Kishon Vijay Abraham I6e543812017-09-21 16:51:36 +02001108 MSBS_SGLEBLK);
1109 flags &= ~(ACEN_ENABLE | BCE_ENABLE | DE_ENABLE);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001110
1111 if (cmd->resp_type & MMC_RSP_CRC)
1112 flags |= CCCE_CHECK;
1113 if (cmd->resp_type & MMC_RSP_OPCODE)
1114 flags |= CICE_CHECK;
1115
1116 if (data) {
1117 if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
1118 (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
Kishon Vijay Abraham I316e7ae2017-09-21 16:51:35 +02001119 flags |= (MSBS_MULTIBLK | BCE_ENABLE | ACEN_ENABLE);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001120 data->blocksize = 512;
1121 writel(data->blocksize | (data->blocks << 16),
1122 &mmc_base->blk);
1123 } else
1124 writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
1125
1126 if (data->flags & MMC_DATA_READ)
1127 flags |= (DP_DATA | DDIR_READ);
1128 else
1129 flags |= (DP_DATA | DDIR_WRITE);
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +02001130
Jean-Jacques Hiblotcebf0592018-02-23 10:40:18 +01001131#ifdef CONFIG_MMC_OMAP_HS_ADMA
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +02001132 if ((priv->controller_flags & OMAP_HSMMC_USE_ADMA) &&
1133 !mmc_is_tuning_cmd(cmd->cmdidx)) {
1134 omap_hsmmc_prepare_data(mmc, data);
1135 flags |= DE_ENABLE;
1136 }
1137#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001138 }
1139
Jean-Jacques Hiblota420d7d2018-01-30 16:01:36 +01001140 mmc_enable_irq(mmc, cmd);
1141
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001142 writel(cmd->cmdarg, &mmc_base->arg);
Lubomir Popov19df4122013-08-14 18:59:18 +03001143 udelay(20); /* To fix "No status update" error on eMMC */
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001144 writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
1145
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001146 start = get_timer(0);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001147 do {
1148 mmc_stat = readl(&mmc_base->stat);
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +02001149 if (get_timer(start) > MAX_RETRY_MS) {
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001150 printf("%s : timeout: No status update\n", __func__);
Jaehoon Chung7825d202016-07-19 16:33:36 +09001151 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001152 }
1153 } while (!mmc_stat);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001154
Grazvydas Ignotasddde1882012-03-19 12:12:06 +00001155 if ((mmc_stat & IE_CTO) != 0) {
1156 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
Jaehoon Chung7825d202016-07-19 16:33:36 +09001157 return -ETIMEDOUT;
Grazvydas Ignotasddde1882012-03-19 12:12:06 +00001158 } else if ((mmc_stat & ERRI_MASK) != 0)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001159 return -1;
1160
1161 if (mmc_stat & CC_MASK) {
1162 writel(CC_MASK, &mmc_base->stat);
1163 if (cmd->resp_type & MMC_RSP_PRESENT) {
1164 if (cmd->resp_type & MMC_RSP_136) {
1165 /* response type 2 */
1166 cmd->response[3] = readl(&mmc_base->rsp10);
1167 cmd->response[2] = readl(&mmc_base->rsp32);
1168 cmd->response[1] = readl(&mmc_base->rsp54);
1169 cmd->response[0] = readl(&mmc_base->rsp76);
1170 } else
1171 /* response types 1, 1b, 3, 4, 5, 6 */
1172 cmd->response[0] = readl(&mmc_base->rsp10);
1173 }
1174 }
1175
Jean-Jacques Hiblotcebf0592018-02-23 10:40:18 +01001176#ifdef CONFIG_MMC_OMAP_HS_ADMA
Kishon Vijay Abraham I826be2a2017-09-21 16:51:34 +02001177 if ((priv->controller_flags & OMAP_HSMMC_USE_ADMA) && data &&
1178 !mmc_is_tuning_cmd(cmd->cmdidx)) {
1179 u32 sz_mb, timeout;
1180
1181 if (mmc_stat & IE_ADMAE) {
1182 omap_hsmmc_dma_cleanup(mmc);
1183 return -EIO;
1184 }
1185
1186 sz_mb = DIV_ROUND_UP(data->blocksize * data->blocks, 1 << 20);
1187 timeout = sz_mb * DMA_TIMEOUT_PER_MB;
1188 if (timeout < MAX_RETRY_MS)
1189 timeout = MAX_RETRY_MS;
1190
1191 start = get_timer(0);
1192 do {
1193 mmc_stat = readl(&mmc_base->stat);
1194 if (mmc_stat & TC_MASK) {
1195 writel(readl(&mmc_base->stat) | TC_MASK,
1196 &mmc_base->stat);
1197 break;
1198 }
1199 if (get_timer(start) > timeout) {
1200 printf("%s : DMA timeout: No status update\n",
1201 __func__);
1202 return -ETIMEDOUT;
1203 }
1204 } while (1);
1205
1206 omap_hsmmc_dma_cleanup(mmc);
1207 return 0;
1208 }
1209#endif
1210
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001211 if (data && (data->flags & MMC_DATA_READ)) {
1212 mmc_read_data(mmc_base, data->dest,
1213 data->blocksize * data->blocks);
1214 } else if (data && (data->flags & MMC_DATA_WRITE)) {
1215 mmc_write_data(mmc_base, data->src,
1216 data->blocksize * data->blocks);
1217 }
1218 return 0;
1219}
1220
Sricharanf72611f2011-11-15 09:49:53 -05001221static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001222{
1223 unsigned int *output_buf = (unsigned int *)buf;
1224 unsigned int mmc_stat;
1225 unsigned int count;
1226
1227 /*
1228 * Start Polled Read
1229 */
1230 count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
1231 count /= 4;
1232
1233 while (size) {
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001234 ulong start = get_timer(0);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001235 do {
1236 mmc_stat = readl(&mmc_base->stat);
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001237 if (get_timer(0) - start > MAX_RETRY_MS) {
1238 printf("%s: timedout waiting for status!\n",
1239 __func__);
Jaehoon Chung7825d202016-07-19 16:33:36 +09001240 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001241 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001242 } while (mmc_stat == 0);
1243
Grazvydas Ignotasddde1882012-03-19 12:12:06 +00001244 if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
1245 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
1246
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001247 if ((mmc_stat & ERRI_MASK) != 0)
1248 return 1;
1249
1250 if (mmc_stat & BRR_MASK) {
1251 unsigned int k;
1252
1253 writel(readl(&mmc_base->stat) | BRR_MASK,
1254 &mmc_base->stat);
1255 for (k = 0; k < count; k++) {
1256 *output_buf = readl(&mmc_base->data);
1257 output_buf++;
1258 }
1259 size -= (count*4);
1260 }
1261
1262 if (mmc_stat & BWR_MASK)
1263 writel(readl(&mmc_base->stat) | BWR_MASK,
1264 &mmc_base->stat);
1265
1266 if (mmc_stat & TC_MASK) {
1267 writel(readl(&mmc_base->stat) | TC_MASK,
1268 &mmc_base->stat);
1269 break;
1270 }
1271 }
1272 return 0;
1273}
1274
Jean-Jacques Hiblot98821552018-02-23 10:40:17 +01001275#if CONFIG_IS_ENABLED(MMC_WRITE)
Sricharanf72611f2011-11-15 09:49:53 -05001276static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
Jean-Jacques Hiblot98821552018-02-23 10:40:17 +01001277 unsigned int size)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001278{
1279 unsigned int *input_buf = (unsigned int *)buf;
1280 unsigned int mmc_stat;
1281 unsigned int count;
1282
1283 /*
Lubomir Popov19df4122013-08-14 18:59:18 +03001284 * Start Polled Write
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001285 */
1286 count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
1287 count /= 4;
1288
1289 while (size) {
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001290 ulong start = get_timer(0);
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001291 do {
1292 mmc_stat = readl(&mmc_base->stat);
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001293 if (get_timer(0) - start > MAX_RETRY_MS) {
1294 printf("%s: timedout waiting for status!\n",
1295 __func__);
Jaehoon Chung7825d202016-07-19 16:33:36 +09001296 return -ETIMEDOUT;
Nishanth Menond3bfaac2010-11-19 11:18:12 -05001297 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001298 } while (mmc_stat == 0);
1299
Grazvydas Ignotasddde1882012-03-19 12:12:06 +00001300 if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
1301 mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
1302
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001303 if ((mmc_stat & ERRI_MASK) != 0)
1304 return 1;
1305
1306 if (mmc_stat & BWR_MASK) {
1307 unsigned int k;
1308
1309 writel(readl(&mmc_base->stat) | BWR_MASK,
1310 &mmc_base->stat);
1311 for (k = 0; k < count; k++) {
1312 writel(*input_buf, &mmc_base->data);
1313 input_buf++;
1314 }
1315 size -= (count*4);
1316 }
1317
1318 if (mmc_stat & BRR_MASK)
1319 writel(readl(&mmc_base->stat) | BRR_MASK,
1320 &mmc_base->stat);
1321
1322 if (mmc_stat & TC_MASK) {
1323 writel(readl(&mmc_base->stat) | TC_MASK,
1324 &mmc_base->stat);
1325 break;
1326 }
1327 }
1328 return 0;
1329}
Jean-Jacques Hiblot98821552018-02-23 10:40:17 +01001330#else
1331static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
1332 unsigned int size)
1333{
1334 return -ENOTSUPP;
1335}
1336#endif
Jean-Jacques Hiblot7fe2f192018-01-30 16:01:30 +01001337static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base)
1338{
1339 writel(readl(&mmc_base->sysctl) & ~CEN_ENABLE, &mmc_base->sysctl);
1340}
1341
1342static void omap_hsmmc_start_clock(struct hsmmc *mmc_base)
1343{
1344 writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
1345}
1346
1347static void omap_hsmmc_set_clock(struct mmc *mmc)
1348{
1349 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1350 struct hsmmc *mmc_base;
1351 unsigned int dsor = 0;
1352 ulong start;
1353
1354 mmc_base = priv->base_addr;
1355 omap_hsmmc_stop_clock(mmc_base);
1356
1357 /* TODO: Is setting DTO required here? */
1358 mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK),
1359 (ICE_STOP | DTO_15THDTO));
1360
1361 if (mmc->clock != 0) {
1362 dsor = DIV_ROUND_UP(MMC_CLOCK_REFERENCE * 1000000, mmc->clock);
1363 if (dsor > CLKD_MAX)
1364 dsor = CLKD_MAX;
1365 } else {
1366 dsor = CLKD_MAX;
1367 }
1368
1369 mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
1370 (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
1371
1372 start = get_timer(0);
1373 while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
1374 if (get_timer(0) - start > MAX_RETRY_MS) {
1375 printf("%s: timedout waiting for ics!\n", __func__);
1376 return;
1377 }
1378 }
1379
Jean-Jacques Hiblot6ce31e42018-01-30 16:01:43 +01001380 priv->clock = MMC_CLOCK_REFERENCE * 1000000 / dsor;
1381 mmc->clock = priv->clock;
Jean-Jacques Hiblot7fe2f192018-01-30 16:01:30 +01001382 omap_hsmmc_start_clock(mmc_base);
1383}
1384
Kishon Vijay Abraham I2e18c9b2018-01-30 16:01:31 +01001385static void omap_hsmmc_set_bus_width(struct mmc *mmc)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001386{
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001387 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
Nikita Kiryanov13822862012-12-03 02:19:43 +00001388 struct hsmmc *mmc_base;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001389
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001390 mmc_base = priv->base_addr;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001391 /* configue bus width */
1392 switch (mmc->bus_width) {
1393 case 8:
1394 writel(readl(&mmc_base->con) | DTW_8_BITMODE,
1395 &mmc_base->con);
1396 break;
1397
1398 case 4:
1399 writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
1400 &mmc_base->con);
1401 writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
1402 &mmc_base->hctl);
1403 break;
1404
1405 case 1:
1406 default:
1407 writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
1408 &mmc_base->con);
1409 writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
1410 &mmc_base->hctl);
1411 break;
1412 }
1413
Kishon Vijay Abraham I2e18c9b2018-01-30 16:01:31 +01001414 priv->bus_width = mmc->bus_width;
1415}
1416
1417#if !CONFIG_IS_ENABLED(DM_MMC)
1418static int omap_hsmmc_set_ios(struct mmc *mmc)
1419{
1420 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1421#else
1422static int omap_hsmmc_set_ios(struct udevice *dev)
1423{
1424 struct omap_hsmmc_data *priv = dev_get_priv(dev);
1425 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
1426 struct mmc *mmc = upriv->mmc;
1427#endif
Kishon Vijay Abraham Ie1f25c02018-01-30 16:01:45 +01001428 struct hsmmc *mmc_base = priv->base_addr;
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +01001429 int ret = 0;
Kishon Vijay Abraham I2e18c9b2018-01-30 16:01:31 +01001430
1431 if (priv->bus_width != mmc->bus_width)
1432 omap_hsmmc_set_bus_width(mmc);
1433
Jean-Jacques Hiblot7fe2f192018-01-30 16:01:30 +01001434 if (priv->clock != mmc->clock)
1435 omap_hsmmc_set_clock(mmc);
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +09001436
Kishon Vijay Abraham Ie1f25c02018-01-30 16:01:45 +01001437 if (mmc->clk_disable)
1438 omap_hsmmc_stop_clock(mmc_base);
1439 else
1440 omap_hsmmc_start_clock(mmc_base);
1441
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +01001442#if CONFIG_IS_ENABLED(DM_MMC)
1443 if (priv->mode != mmc->selected_mode)
1444 omap_hsmmc_set_timing(mmc);
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +01001445
1446#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1447 if (priv->signal_voltage != mmc->signal_voltage)
1448 ret = omap_hsmmc_set_signal_voltage(mmc);
Jean-Jacques Hiblotcf38d4e2018-01-30 16:01:33 +01001449#endif
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +01001450#endif
1451 return ret;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001452}
1453
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001454#ifdef OMAP_HSMMC_USE_GPIO
Simon Glass5f4bd8c2017-07-04 13:31:19 -06001455#if CONFIG_IS_ENABLED(DM_MMC)
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001456static int omap_hsmmc_getcd(struct udevice *dev)
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001457{
Adam Ford6122af42018-08-21 07:16:56 -05001458 int value = -1;
1459#if CONFIG_IS_ENABLED(DM_GPIO)
Adam Fordac740ff2018-09-08 08:16:23 -05001460 struct omap_hsmmc_data *priv = dev_get_priv(dev);
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301461 value = dm_gpio_get_value(&priv->cd_gpio);
Adam Ford6122af42018-08-21 07:16:56 -05001462#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301463 /* if no CD return as 1 */
1464 if (value < 0)
1465 return 1;
1466
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301467 return value;
1468}
1469
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001470static int omap_hsmmc_getwp(struct udevice *dev)
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301471{
Adam Ford6122af42018-08-21 07:16:56 -05001472 int value = 0;
1473#if CONFIG_IS_ENABLED(DM_GPIO)
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001474 struct omap_hsmmc_data *priv = dev_get_priv(dev);
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301475 value = dm_gpio_get_value(&priv->wp_gpio);
Adam Ford6122af42018-08-21 07:16:56 -05001476#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301477 /* if no WP return as 0 */
1478 if (value < 0)
1479 return 0;
1480 return value;
1481}
1482#else
1483static int omap_hsmmc_getcd(struct mmc *mmc)
1484{
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001485 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001486 int cd_gpio;
1487
1488 /* if no CD return as 1 */
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001489 cd_gpio = priv->cd_gpio;
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001490 if (cd_gpio < 0)
1491 return 1;
1492
Igor Grinberg2f4e0952014-11-03 11:32:23 +02001493 /* NOTE: assumes card detect signal is active-low */
1494 return !gpio_get_value(cd_gpio);
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001495}
1496
1497static int omap_hsmmc_getwp(struct mmc *mmc)
1498{
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001499 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001500 int wp_gpio;
1501
1502 /* if no WP return as 0 */
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001503 wp_gpio = priv->wp_gpio;
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001504 if (wp_gpio < 0)
1505 return 0;
1506
Igor Grinberg2f4e0952014-11-03 11:32:23 +02001507 /* NOTE: assumes write protect signal is active-high */
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001508 return gpio_get_value(wp_gpio);
1509}
1510#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301511#endif
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001512
Simon Glass5f4bd8c2017-07-04 13:31:19 -06001513#if CONFIG_IS_ENABLED(DM_MMC)
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001514static const struct dm_mmc_ops omap_hsmmc_ops = {
1515 .send_cmd = omap_hsmmc_send_cmd,
1516 .set_ios = omap_hsmmc_set_ios,
1517#ifdef OMAP_HSMMC_USE_GPIO
1518 .get_cd = omap_hsmmc_getcd,
1519 .get_wp = omap_hsmmc_getwp,
1520#endif
Jean-Jacques Hiblotf0f821b2018-01-30 16:01:35 +01001521#ifdef MMC_SUPPORTS_TUNING
1522 .execute_tuning = omap_hsmmc_execute_tuning,
1523#endif
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +01001524 .wait_dat0 = omap_hsmmc_wait_dat0,
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001525};
1526#else
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001527static const struct mmc_ops omap_hsmmc_ops = {
1528 .send_cmd = omap_hsmmc_send_cmd,
1529 .set_ios = omap_hsmmc_set_ios,
1530 .init = omap_hsmmc_init_setup,
1531#ifdef OMAP_HSMMC_USE_GPIO
1532 .getcd = omap_hsmmc_getcd,
1533 .getwp = omap_hsmmc_getwp,
1534#endif
1535};
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02001536#endif
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001537
Simon Glass5f4bd8c2017-07-04 13:31:19 -06001538#if !CONFIG_IS_ENABLED(DM_MMC)
Nikita Kiryanov4be9dbc2012-12-03 02:19:47 +00001539int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
1540 int wp_gpio)
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001541{
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001542 struct mmc *mmc;
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001543 struct omap_hsmmc_data *priv;
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001544 struct mmc_config *cfg;
1545 uint host_caps_val;
1546
Alex Kiernan4b9cb772018-02-09 15:24:38 +00001547 priv = calloc(1, sizeof(*priv));
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001548 if (priv == NULL)
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001549 return -1;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001550
Rob Herring5fd3edd2015-03-23 17:56:59 -05001551 host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001552
1553 switch (dev_index) {
1554 case 0:
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001555 priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001556 break;
Tom Rinifd6e2942011-10-12 06:20:50 +00001557#ifdef OMAP_HSMMC2_BASE
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001558 case 1:
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001559 priv->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
Lubomir Popov19df4122013-08-14 18:59:18 +03001560#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
Nishanth Menon813fe9d2016-11-29 15:22:00 +05301561 defined(CONFIG_DRA7XX) || defined(CONFIG_AM33XX) || \
Tom Rini84c0f692021-09-12 20:32:32 -04001562 defined(CONFIG_AM43XX) || defined(CONFIG_ARCH_KEYSTONE)) && \
Roger Quadros44157de2015-09-19 16:26:53 +05301563 defined(CONFIG_HSMMC2_8BIT)
Lubomir Popov19df4122013-08-14 18:59:18 +03001564 /* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
1565 host_caps_val |= MMC_MODE_8BIT;
1566#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001567 break;
Tom Rinifd6e2942011-10-12 06:20:50 +00001568#endif
1569#ifdef OMAP_HSMMC3_BASE
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001570 case 2:
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001571 priv->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
Nishanth Menon813fe9d2016-11-29 15:22:00 +05301572#if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT)
Lubomir Popov19df4122013-08-14 18:59:18 +03001573 /* Enable 8-bit interface for eMMC on DRA7XX */
1574 host_caps_val |= MMC_MODE_8BIT;
1575#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001576 break;
Tom Rinifd6e2942011-10-12 06:20:50 +00001577#endif
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001578 default:
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001579 priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001580 return 1;
1581 }
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001582#ifdef OMAP_HSMMC_USE_GPIO
1583 /* on error gpio values are set to -1, which is what we want */
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001584 priv->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
1585 priv->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
Pantelis Antoniouc9e75912014-02-26 19:28:45 +02001586#endif
Peter Korsgaard47c6b2a2013-03-21 04:00:04 +00001587
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001588 cfg = &priv->cfg;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001589
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001590 cfg->name = "OMAP SD/MMC";
1591 cfg->ops = &omap_hsmmc_ops;
1592
1593 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
1594 cfg->host_caps = host_caps_val & ~host_caps_mask;
1595
1596 cfg->f_min = 400000;
Jonathan Solnita9b05562012-02-24 11:30:18 +00001597
1598 if (f_max != 0)
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001599 cfg->f_max = f_max;
Jonathan Solnita9b05562012-02-24 11:30:18 +00001600 else {
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001601 if (cfg->host_caps & MMC_MODE_HS) {
1602 if (cfg->host_caps & MMC_MODE_HS_52MHz)
1603 cfg->f_max = 52000000;
Jonathan Solnita9b05562012-02-24 11:30:18 +00001604 else
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001605 cfg->f_max = 26000000;
Jonathan Solnita9b05562012-02-24 11:30:18 +00001606 } else
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001607 cfg->f_max = 20000000;
Jonathan Solnita9b05562012-02-24 11:30:18 +00001608 }
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001609
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001610 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
John Rigbyf2f43662011-04-18 05:50:08 +00001611
John Rigby91fcc4b2011-04-19 05:48:14 +00001612#if defined(CONFIG_OMAP34XX)
1613 /*
1614 * Silicon revs 2.1 and older do not support multiblock transfers.
1615 */
1616 if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001617 cfg->b_max = 1;
John Rigby91fcc4b2011-04-19 05:48:14 +00001618#endif
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001619
Jean-Jacques Hiblotd58ef8e2017-03-22 16:00:31 +01001620 mmc = mmc_create(cfg, priv);
Pantelis Antoniou2c850462014-03-11 19:34:20 +02001621 if (mmc == NULL)
1622 return -1;
Sukumar Ghoraic53f5e52010-09-18 20:32:33 -07001623
1624 return 0;
1625}
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301626#else
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001627
1628#ifdef CONFIG_IODELAY_RECALIBRATION
1629static struct pad_conf_entry *
1630omap_hsmmc_get_pad_conf_entry(const fdt32_t *pinctrl, int count)
1631{
1632 int index = 0;
1633 struct pad_conf_entry *padconf;
1634
1635 padconf = (struct pad_conf_entry *)malloc(sizeof(*padconf) * count);
1636 if (!padconf) {
1637 debug("failed to allocate memory\n");
1638 return 0;
1639 }
1640
1641 while (index < count) {
1642 padconf[index].offset = fdt32_to_cpu(pinctrl[2 * index]);
1643 padconf[index].val = fdt32_to_cpu(pinctrl[2 * index + 1]);
1644 index++;
1645 }
1646
1647 return padconf;
1648}
1649
1650static struct iodelay_cfg_entry *
1651omap_hsmmc_get_iodelay_cfg_entry(const fdt32_t *pinctrl, int count)
1652{
1653 int index = 0;
1654 struct iodelay_cfg_entry *iodelay;
1655
1656 iodelay = (struct iodelay_cfg_entry *)malloc(sizeof(*iodelay) * count);
1657 if (!iodelay) {
1658 debug("failed to allocate memory\n");
1659 return 0;
1660 }
1661
1662 while (index < count) {
1663 iodelay[index].offset = fdt32_to_cpu(pinctrl[3 * index]);
1664 iodelay[index].a_delay = fdt32_to_cpu(pinctrl[3 * index + 1]);
1665 iodelay[index].g_delay = fdt32_to_cpu(pinctrl[3 * index + 2]);
1666 index++;
1667 }
1668
1669 return iodelay;
1670}
1671
1672static const fdt32_t *omap_hsmmc_get_pinctrl_entry(u32 phandle,
1673 const char *name, int *len)
1674{
1675 const void *fdt = gd->fdt_blob;
1676 int offset;
1677 const fdt32_t *pinctrl;
1678
1679 offset = fdt_node_offset_by_phandle(fdt, phandle);
1680 if (offset < 0) {
1681 debug("failed to get pinctrl node %s.\n",
1682 fdt_strerror(offset));
1683 return 0;
1684 }
1685
1686 pinctrl = fdt_getprop(fdt, offset, name, len);
1687 if (!pinctrl) {
1688 debug("failed to get property %s\n", name);
1689 return 0;
1690 }
1691
1692 return pinctrl;
1693}
1694
1695static uint32_t omap_hsmmc_get_pad_conf_phandle(struct mmc *mmc,
1696 char *prop_name)
1697{
1698 const void *fdt = gd->fdt_blob;
1699 const __be32 *phandle;
1700 int node = dev_of_offset(mmc->dev);
1701
1702 phandle = fdt_getprop(fdt, node, prop_name, NULL);
1703 if (!phandle) {
1704 debug("failed to get property %s\n", prop_name);
1705 return 0;
1706 }
1707
1708 return fdt32_to_cpu(*phandle);
1709}
1710
1711static uint32_t omap_hsmmc_get_iodelay_phandle(struct mmc *mmc,
1712 char *prop_name)
1713{
1714 const void *fdt = gd->fdt_blob;
1715 const __be32 *phandle;
1716 int len;
1717 int count;
1718 int node = dev_of_offset(mmc->dev);
1719
1720 phandle = fdt_getprop(fdt, node, prop_name, &len);
1721 if (!phandle) {
1722 debug("failed to get property %s\n", prop_name);
1723 return 0;
1724 }
1725
1726 /* No manual mode iodelay values if count < 2 */
1727 count = len / sizeof(*phandle);
1728 if (count < 2)
1729 return 0;
1730
1731 return fdt32_to_cpu(*(phandle + 1));
1732}
1733
1734static struct pad_conf_entry *
1735omap_hsmmc_get_pad_conf(struct mmc *mmc, char *prop_name, int *npads)
1736{
1737 int len;
1738 int count;
1739 struct pad_conf_entry *padconf;
1740 u32 phandle;
1741 const fdt32_t *pinctrl;
1742
1743 phandle = omap_hsmmc_get_pad_conf_phandle(mmc, prop_name);
1744 if (!phandle)
1745 return ERR_PTR(-EINVAL);
1746
1747 pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-single,pins",
1748 &len);
1749 if (!pinctrl)
1750 return ERR_PTR(-EINVAL);
1751
1752 count = (len / sizeof(*pinctrl)) / 2;
1753 padconf = omap_hsmmc_get_pad_conf_entry(pinctrl, count);
1754 if (!padconf)
1755 return ERR_PTR(-EINVAL);
1756
1757 *npads = count;
1758
1759 return padconf;
1760}
1761
1762static struct iodelay_cfg_entry *
1763omap_hsmmc_get_iodelay(struct mmc *mmc, char *prop_name, int *niodelay)
1764{
1765 int len;
1766 int count;
1767 struct iodelay_cfg_entry *iodelay;
1768 u32 phandle;
1769 const fdt32_t *pinctrl;
1770
1771 phandle = omap_hsmmc_get_iodelay_phandle(mmc, prop_name);
1772 /* Not all modes have manual mode iodelay values. So its not fatal */
1773 if (!phandle)
1774 return 0;
1775
1776 pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-pin-array",
1777 &len);
1778 if (!pinctrl)
1779 return ERR_PTR(-EINVAL);
1780
1781 count = (len / sizeof(*pinctrl)) / 3;
1782 iodelay = omap_hsmmc_get_iodelay_cfg_entry(pinctrl, count);
1783 if (!iodelay)
1784 return ERR_PTR(-EINVAL);
1785
1786 *niodelay = count;
1787
1788 return iodelay;
1789}
1790
1791static struct omap_hsmmc_pinctrl_state *
1792omap_hsmmc_get_pinctrl_by_mode(struct mmc *mmc, char *mode)
1793{
1794 int index;
1795 int npads = 0;
1796 int niodelays = 0;
1797 const void *fdt = gd->fdt_blob;
1798 int node = dev_of_offset(mmc->dev);
1799 char prop_name[11];
1800 struct omap_hsmmc_pinctrl_state *pinctrl_state;
1801
1802 pinctrl_state = (struct omap_hsmmc_pinctrl_state *)
1803 malloc(sizeof(*pinctrl_state));
1804 if (!pinctrl_state) {
1805 debug("failed to allocate memory\n");
1806 return 0;
1807 }
1808
1809 index = fdt_stringlist_search(fdt, node, "pinctrl-names", mode);
1810 if (index < 0) {
1811 debug("fail to find %s mode %s\n", mode, fdt_strerror(index));
1812 goto err_pinctrl_state;
1813 }
1814
1815 sprintf(prop_name, "pinctrl-%d", index);
1816
1817 pinctrl_state->padconf = omap_hsmmc_get_pad_conf(mmc, prop_name,
1818 &npads);
1819 if (IS_ERR(pinctrl_state->padconf))
1820 goto err_pinctrl_state;
1821 pinctrl_state->npads = npads;
1822
1823 pinctrl_state->iodelay = omap_hsmmc_get_iodelay(mmc, prop_name,
1824 &niodelays);
1825 if (IS_ERR(pinctrl_state->iodelay))
1826 goto err_padconf;
1827 pinctrl_state->niodelays = niodelays;
1828
1829 return pinctrl_state;
1830
1831err_padconf:
1832 kfree(pinctrl_state->padconf);
1833
1834err_pinctrl_state:
1835 kfree(pinctrl_state);
1836 return 0;
1837}
1838
Jean-Jacques Hiblotdae1ad42018-01-30 16:01:42 +01001839#define OMAP_HSMMC_SETUP_PINCTRL(capmask, mode, optional) \
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001840 do { \
1841 struct omap_hsmmc_pinctrl_state *s = NULL; \
1842 char str[20]; \
1843 if (!(cfg->host_caps & capmask)) \
1844 break; \
1845 \
1846 if (priv->hw_rev) { \
1847 sprintf(str, "%s-%s", #mode, priv->hw_rev); \
1848 s = omap_hsmmc_get_pinctrl_by_mode(mmc, str); \
1849 } \
1850 \
1851 if (!s) \
1852 s = omap_hsmmc_get_pinctrl_by_mode(mmc, #mode); \
1853 \
Jean-Jacques Hiblotdae1ad42018-01-30 16:01:42 +01001854 if (!s && !optional) { \
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001855 debug("%s: no pinctrl for %s\n", \
1856 mmc->dev->name, #mode); \
1857 cfg->host_caps &= ~(capmask); \
1858 } else { \
1859 priv->mode##_pinctrl_state = s; \
1860 } \
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001861 } while (0)
1862
1863static int omap_hsmmc_get_pinctrl_state(struct mmc *mmc)
1864{
1865 struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1866 struct mmc_config *cfg = omap_hsmmc_get_cfg(mmc);
1867 struct omap_hsmmc_pinctrl_state *default_pinctrl;
1868
1869 if (!(priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY))
1870 return 0;
1871
1872 default_pinctrl = omap_hsmmc_get_pinctrl_by_mode(mmc, "default");
1873 if (!default_pinctrl) {
1874 printf("no pinctrl state for default mode\n");
1875 return -EINVAL;
1876 }
1877
1878 priv->default_pinctrl_state = default_pinctrl;
1879
Jean-Jacques Hiblotdae1ad42018-01-30 16:01:42 +01001880 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR104), sdr104, false);
1881 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR50), sdr50, false);
1882 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_DDR50), ddr50, false);
1883 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR25), sdr25, false);
1884 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR12), sdr12, false);
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001885
Jean-Jacques Hiblotdae1ad42018-01-30 16:01:42 +01001886 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_HS_200), hs200_1_8v, false);
1887 OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_DDR_52), ddr_1_8v, false);
1888 OMAP_HSMMC_SETUP_PINCTRL(MMC_MODE_HS, hs, true);
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001889
1890 return 0;
1891}
1892#endif
1893
Simon Glass3580f6d2021-08-07 07:24:03 -06001894#if CONFIG_IS_ENABLED(OF_REAL)
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001895#ifdef CONFIG_OMAP54XX
1896__weak const struct mmc_platform_fixups *platform_fixups_mmc(uint32_t addr)
1897{
1898 return NULL;
1899}
1900#endif
1901
Simon Glassaad29ae2020-12-03 16:55:21 -07001902static int omap_hsmmc_of_to_plat(struct udevice *dev)
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301903{
Simon Glassfa20e932020-12-03 16:55:20 -07001904 struct omap_hsmmc_plat *plat = dev_get_plat(dev);
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001905 struct omap_mmc_of_data *of_data = (void *)dev_get_driver_data(dev);
1906
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +01001907 struct mmc_config *cfg = &plat->cfg;
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001908#ifdef CONFIG_OMAP54XX
1909 const struct mmc_platform_fixups *fixups;
1910#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301911 const void *fdt = gd->fdt_blob;
Simon Glassdd79d6e2017-01-17 16:52:55 -07001912 int node = dev_of_offset(dev);
Kishon Vijay Abraham I569c3d52018-01-30 16:01:38 +01001913 int ret;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301914
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +09001915 plat->base_addr = map_physmem(dev_read_addr(dev),
Simon Glassba1dea42017-05-17 17:18:05 -06001916 sizeof(struct hsmmc *),
Jean-Jacques Hiblot3d45bb42017-09-21 16:51:32 +02001917 MAP_NOCACHE);
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301918
Kishon Vijay Abraham I569c3d52018-01-30 16:01:38 +01001919 ret = mmc_of_parse(dev, cfg);
1920 if (ret < 0)
1921 return ret;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301922
Jean-Jacques Hiblot8e2bdbd2018-02-23 10:40:19 +01001923 if (!cfg->f_max)
1924 cfg->f_max = 52000000;
Kishon Vijay Abraham I569c3d52018-01-30 16:01:38 +01001925 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301926 cfg->f_min = 400000;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301927 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
1928 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
Kishon Vijay Abraham I73897ed2018-01-30 16:01:32 +01001929 if (fdtdec_get_bool(fdt, node, "ti,dual-volt"))
1930 plat->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
1931 if (fdtdec_get_bool(fdt, node, "no-1-8-v"))
1932 plat->controller_flags |= OMAP_HSMMC_NO_1_8_V;
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001933 if (of_data)
1934 plat->controller_flags |= of_data->controller_flags;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301935
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001936#ifdef CONFIG_OMAP54XX
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +09001937 fixups = platform_fixups_mmc(dev_read_addr(dev));
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001938 if (fixups) {
1939 plat->hw_rev = fixups->hw_rev;
1940 cfg->host_caps &= ~fixups->unsupported_caps;
1941 cfg->f_max = fixups->max_freq;
1942 }
1943#endif
1944
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301945 return 0;
1946}
Lokesh Vutla9a696fb2017-04-26 13:37:05 +05301947#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301948
Jean-Jacques Hiblota3c556c2017-03-22 16:00:34 +01001949#ifdef CONFIG_BLK
1950
1951static int omap_hsmmc_bind(struct udevice *dev)
1952{
Simon Glassfa20e932020-12-03 16:55:20 -07001953 struct omap_hsmmc_plat *plat = dev_get_plat(dev);
Jean-Jacques Hiblot4cb36a22018-02-23 10:40:16 +01001954 plat->mmc = calloc(1, sizeof(struct mmc));
1955 return mmc_bind(dev, plat->mmc, &plat->cfg);
Jean-Jacques Hiblota3c556c2017-03-22 16:00:34 +01001956}
1957#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301958static int omap_hsmmc_probe(struct udevice *dev)
1959{
Simon Glassfa20e932020-12-03 16:55:20 -07001960 struct omap_hsmmc_plat *plat = dev_get_plat(dev);
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301961 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
1962 struct omap_hsmmc_data *priv = dev_get_priv(dev);
Jean-Jacques Hiblotae51a662017-03-22 16:00:33 +01001963 struct mmc_config *cfg = &plat->cfg;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301964 struct mmc *mmc;
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001965#ifdef CONFIG_IODELAY_RECALIBRATION
1966 int ret;
1967#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301968
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301969 cfg->name = "OMAP SD/MMC";
Lokesh Vutla9a696fb2017-04-26 13:37:05 +05301970 priv->base_addr = plat->base_addr;
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001971 priv->controller_flags = plat->controller_flags;
Kishon Vijay Abraham I8c2efe92018-01-30 16:01:41 +01001972 priv->hw_rev = plat->hw_rev;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301973
Jean-Jacques Hiblota3c556c2017-03-22 16:00:34 +01001974#ifdef CONFIG_BLK
Jean-Jacques Hiblot4cb36a22018-02-23 10:40:16 +01001975 mmc = plat->mmc;
Jean-Jacques Hiblota3c556c2017-03-22 16:00:34 +01001976#else
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301977 mmc = mmc_create(cfg, priv);
1978 if (mmc == NULL)
1979 return -1;
Jean-Jacques Hiblota3c556c2017-03-22 16:00:34 +01001980#endif
Jean-Jacques Hiblot7a41bb42018-01-30 16:01:46 +01001981#if CONFIG_IS_ENABLED(DM_REGULATOR)
1982 device_get_supply_regulator(dev, "pbias-supply",
1983 &priv->pbias_supply);
1984#endif
Adam Ford6122af42018-08-21 07:16:56 -05001985#if defined(OMAP_HSMMC_USE_GPIO)
1986#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_GPIO)
Mugunthan V Na9a0aa72016-04-04 17:28:01 +05301987 gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
1988 gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
1989#endif
Adam Ford6122af42018-08-21 07:16:56 -05001990#endif
Mugunthan V Na9a0aa72016-04-04 17:28:01 +05301991
Simon Glass77ca42b2016-05-01 13:52:34 -06001992 mmc->dev = dev;
Mugunthan V Nd97631a2015-09-28 12:56:30 +05301993 upriv->mmc = mmc;
1994
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01001995#ifdef CONFIG_IODELAY_RECALIBRATION
1996 ret = omap_hsmmc_get_pinctrl_state(mmc);
1997 /*
1998 * disable high speed modes for the platforms that require IO delay
1999 * and for which we don't have this information
2000 */
2001 if ((ret < 0) &&
2002 (priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY)) {
2003 priv->controller_flags &= ~OMAP_HSMMC_REQUIRE_IODELAY;
2004 cfg->host_caps &= ~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_DDR_52) |
2005 UHS_CAPS);
2006 }
2007#endif
2008
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02002009 return omap_hsmmc_init_setup(mmc);
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302010}
2011
Simon Glass3580f6d2021-08-07 07:24:03 -06002012#if CONFIG_IS_ENABLED(OF_REAL)
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01002013
2014static const struct omap_mmc_of_data dra7_mmc_of_data = {
2015 .controller_flags = OMAP_HSMMC_REQUIRE_IODELAY,
2016};
2017
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302018static const struct udevice_id omap_hsmmc_ids[] = {
Jean-Jacques Hiblot3d45bb42017-09-21 16:51:32 +02002019 { .compatible = "ti,omap3-hsmmc" },
2020 { .compatible = "ti,omap4-hsmmc" },
2021 { .compatible = "ti,am33xx-hsmmc" },
Lukasz Majewski46e86692022-02-18 13:28:41 +01002022 { .compatible = "ti,am335-sdhci" },
Kishon Vijay Abraham Ie7da6ac2018-01-30 16:01:40 +01002023 { .compatible = "ti,dra7-hsmmc", .data = (ulong)&dra7_mmc_of_data },
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302024 { }
2025};
Lokesh Vutla9a696fb2017-04-26 13:37:05 +05302026#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302027
2028U_BOOT_DRIVER(omap_hsmmc) = {
2029 .name = "omap_hsmmc",
2030 .id = UCLASS_MMC,
Simon Glass3580f6d2021-08-07 07:24:03 -06002031#if CONFIG_IS_ENABLED(OF_REAL)
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302032 .of_match = omap_hsmmc_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -07002033 .of_to_plat = omap_hsmmc_of_to_plat,
Simon Glass71fa5b42020-12-03 16:55:18 -07002034 .plat_auto = sizeof(struct omap_hsmmc_plat),
Lokesh Vutla9a696fb2017-04-26 13:37:05 +05302035#endif
Jean-Jacques Hiblota3c556c2017-03-22 16:00:34 +01002036#ifdef CONFIG_BLK
2037 .bind = omap_hsmmc_bind,
2038#endif
Jean-Jacques Hiblot8fc9d3a2017-04-14 19:50:02 +02002039 .ops = &omap_hsmmc_ops,
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302040 .probe = omap_hsmmc_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -07002041 .priv_auto = sizeof(struct omap_hsmmc_data),
Bin Meng793260a2018-10-24 06:36:32 -07002042#if !CONFIG_IS_ENABLED(OF_CONTROL)
Lokesh Vutlac38e6452017-04-26 13:37:06 +05302043 .flags = DM_FLAG_PRE_RELOC,
Bin Meng793260a2018-10-24 06:36:32 -07002044#endif
Mugunthan V Nd97631a2015-09-28 12:56:30 +05302045};
2046#endif