1de941241SSukumar Ghorai /*
2de941241SSukumar Ghorai * (C) Copyright 2008
3de941241SSukumar Ghorai * Texas Instruments, <www.ti.com>
4de941241SSukumar Ghorai * Sukumar Ghorai <s-ghorai@ti.com>
5de941241SSukumar Ghorai *
6de941241SSukumar Ghorai * See file CREDITS for list of people who contributed to this
7de941241SSukumar Ghorai * project.
8de941241SSukumar Ghorai *
9de941241SSukumar Ghorai * This program is free software; you can redistribute it and/or
10de941241SSukumar Ghorai * modify it under the terms of the GNU General Public License as
11de941241SSukumar Ghorai * published by the Free Software Foundation's version 2 of
12de941241SSukumar Ghorai * the License.
13de941241SSukumar Ghorai *
14de941241SSukumar Ghorai * This program is distributed in the hope that it will be useful,
15de941241SSukumar Ghorai * but WITHOUT ANY WARRANTY; without even the implied warranty of
16de941241SSukumar Ghorai * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17de941241SSukumar Ghorai * GNU General Public License for more details.
18de941241SSukumar Ghorai *
19de941241SSukumar Ghorai * You should have received a copy of the GNU General Public License
20de941241SSukumar Ghorai * along with this program; if not, write to the Free Software
21de941241SSukumar Ghorai * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22de941241SSukumar Ghorai * MA 02111-1307 USA
23de941241SSukumar Ghorai */
24de941241SSukumar Ghorai
25de941241SSukumar Ghorai #include <config.h>
26de941241SSukumar Ghorai #include <common.h>
2793bfd616SPantelis Antoniou #include <malloc.h>
28f0d53e88SKishon Vijay Abraham I #include <memalign.h>
29de941241SSukumar Ghorai #include <mmc.h>
30de941241SSukumar Ghorai #include <part.h>
31de941241SSukumar Ghorai #include <i2c.h>
32339d5789SFelix Brack #if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)
33cb199102SNishanth Menon #include <palmas.h>
34339d5789SFelix Brack #endif
35de941241SSukumar Ghorai #include <asm/io.h>
36de941241SSukumar Ghorai #include <asm/arch/mmc_host_def.h>
3733c1d77fSKishon Vijay Abraham I #ifdef CONFIG_OMAP54XX
3833c1d77fSKishon Vijay Abraham I #include <asm/arch/mux_dra7xx.h>
3933c1d77fSKishon Vijay Abraham I #include <asm/arch/dra7xx_iodelay.h>
4033c1d77fSKishon Vijay Abraham I #endif
413b68939fSRoger Quadros #if !defined(CONFIG_SOC_KEYSTONE)
423b68939fSRoger Quadros #include <asm/gpio.h>
4396e0e7b3SDirk Behme #include <asm/arch/sys_proto.h>
443b68939fSRoger Quadros #endif
452a48b3a2STom Rini #ifdef CONFIG_MMC_OMAP36XX_PINS
462a48b3a2STom Rini #include <asm/arch/mux.h>
472a48b3a2STom Rini #endif
48a9d6a7e2SMugunthan V N #include <dm.h>
4942182c9bSJean-Jacques Hiblot #include <power/regulator.h>
50351a4aa0SFaiz Abbas #include <thermal.h>
51a9d6a7e2SMugunthan V N
52a9d6a7e2SMugunthan V N DECLARE_GLOBAL_DATA_PTR;
53de941241SSukumar Ghorai
54ab769f22SPantelis Antoniou /* simplify defines to OMAP_HSMMC_USE_GPIO */
55ab769f22SPantelis Antoniou #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
56ab769f22SPantelis Antoniou (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
57ab769f22SPantelis Antoniou #define OMAP_HSMMC_USE_GPIO
58ab769f22SPantelis Antoniou #else
59ab769f22SPantelis Antoniou #undef OMAP_HSMMC_USE_GPIO
60ab769f22SPantelis Antoniou #endif
61ab769f22SPantelis Antoniou
6225c719e2SGrazvydas Ignotas /* common definitions for all OMAPs */
6325c719e2SGrazvydas Ignotas #define SYSCTL_SRC (1 << 25)
6425c719e2SGrazvydas Ignotas #define SYSCTL_SRD (1 << 26)
6525c719e2SGrazvydas Ignotas
6633c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
6733c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state {
6833c1d77fSKishon Vijay Abraham I struct pad_conf_entry *padconf;
6933c1d77fSKishon Vijay Abraham I int npads;
7033c1d77fSKishon Vijay Abraham I struct iodelay_cfg_entry *iodelay;
7133c1d77fSKishon Vijay Abraham I int niodelays;
7233c1d77fSKishon Vijay Abraham I };
7333c1d77fSKishon Vijay Abraham I #endif
7433c1d77fSKishon Vijay Abraham I
75cc22b0c0SNikita Kiryanov struct omap_hsmmc_data {
76cc22b0c0SNikita Kiryanov struct hsmmc *base_addr;
77c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
7893bfd616SPantelis Antoniou struct mmc_config cfg;
793d673ffcSJean-Jacques Hiblot #endif
8048a2f114SKishon Vijay Abraham I uint bus_width;
815baf543eSJean-Jacques Hiblot uint clock;
8204f9f8beSJean-Jacques Hiblot ushort last_cmd;
83ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
84c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
85a9d6a7e2SMugunthan V N struct gpio_desc cd_gpio; /* Change Detect GPIO */
86a9d6a7e2SMugunthan V N struct gpio_desc wp_gpio; /* Write Protect GPIO */
87a9d6a7e2SMugunthan V N #else
88e874d5b0SNikita Kiryanov int cd_gpio;
89e3913f56SNikita Kiryanov int wp_gpio;
90ab769f22SPantelis Antoniou #endif
91a9d6a7e2SMugunthan V N #endif
92b5944817SKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC)
938fc238bfSJean-Jacques Hiblot enum bus_mode mode;
94b5944817SKishon Vijay Abraham I #endif
95f0d53e88SKishon Vijay Abraham I u8 controller_flags;
9627a4b3bcSJean-Jacques Hiblot #ifdef CONFIG_MMC_OMAP_HS_ADMA
97f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_adma_desc *adma_desc_table;
98f0d53e88SKishon Vijay Abraham I uint desc_slot;
99f0d53e88SKishon Vijay Abraham I #endif
1002d28eedaSKishon Vijay Abraham I const char *hw_rev;
10104f9f8beSJean-Jacques Hiblot struct udevice *pbias_supply;
10204f9f8beSJean-Jacques Hiblot uint signal_voltage;
10333c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
10433c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *default_pinctrl_state;
10533c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *hs_pinctrl_state;
10633c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *hs200_1_8v_pinctrl_state;
10733c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *ddr_1_8v_pinctrl_state;
10833c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *sdr12_pinctrl_state;
10933c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *sdr25_pinctrl_state;
11033c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *ddr50_pinctrl_state;
11133c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *sdr50_pinctrl_state;
11233c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *sdr104_pinctrl_state;
11333c1d77fSKishon Vijay Abraham I #endif
11433c1d77fSKishon Vijay Abraham I };
11533c1d77fSKishon Vijay Abraham I
11633c1d77fSKishon Vijay Abraham I struct omap_mmc_of_data {
11733c1d77fSKishon Vijay Abraham I u8 controller_flags;
118cc22b0c0SNikita Kiryanov };
119cc22b0c0SNikita Kiryanov
12027a4b3bcSJean-Jacques Hiblot #ifdef CONFIG_MMC_OMAP_HS_ADMA
121f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_adma_desc {
122f0d53e88SKishon Vijay Abraham I u8 attr;
123f0d53e88SKishon Vijay Abraham I u8 reserved;
124f0d53e88SKishon Vijay Abraham I u16 len;
125f0d53e88SKishon Vijay Abraham I u32 addr;
126f0d53e88SKishon Vijay Abraham I };
127f0d53e88SKishon Vijay Abraham I
128f0d53e88SKishon Vijay Abraham I #define ADMA_MAX_LEN 63488
129f0d53e88SKishon Vijay Abraham I
130f0d53e88SKishon Vijay Abraham I /* Decriptor table defines */
131f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_ATTR_VALID BIT(0)
132f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_ATTR_END BIT(1)
133f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_ATTR_INT BIT(2)
134f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_ATTR_ACT1 BIT(4)
135f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_ATTR_ACT2 BIT(5)
136f0d53e88SKishon Vijay Abraham I
137f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2
138f0d53e88SKishon Vijay Abraham I #define ADMA_DESC_LINK_DESC (ADMA_DESC_ATTR_ACT1 | ADMA_DESC_ATTR_ACT2)
139f0d53e88SKishon Vijay Abraham I #endif
140f0d53e88SKishon Vijay Abraham I
141eb9a28f6SNishanth Menon /* If we fail after 1 second wait, something is really bad */
142eb9a28f6SNishanth Menon #define MAX_RETRY_MS 1000
143a4efd737SJean-Jacques Hiblot #define MMC_TIMEOUT_MS 20
144eb9a28f6SNishanth Menon
145f0d53e88SKishon Vijay Abraham I /* DMA transfers can take a long time if a lot a data is transferred.
146f0d53e88SKishon Vijay Abraham I * The timeout must take in account the amount of data. Let's assume
147f0d53e88SKishon Vijay Abraham I * that the time will never exceed 333 ms per MB (in other word we assume
148f0d53e88SKishon Vijay Abraham I * that the bandwidth is always above 3MB/s).
149f0d53e88SKishon Vijay Abraham I */
150f0d53e88SKishon Vijay Abraham I #define DMA_TIMEOUT_PER_MB 333
151b5944817SKishon Vijay Abraham I #define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
152b5944817SKishon Vijay Abraham I #define OMAP_HSMMC_NO_1_8_V BIT(1)
153f0d53e88SKishon Vijay Abraham I #define OMAP_HSMMC_USE_ADMA BIT(2)
15433c1d77fSKishon Vijay Abraham I #define OMAP_HSMMC_REQUIRE_IODELAY BIT(3)
155f0d53e88SKishon Vijay Abraham I
156933efe64SSricharan static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
157933efe64SSricharan static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
158933efe64SSricharan unsigned int siz);
1595baf543eSJean-Jacques Hiblot static void omap_hsmmc_start_clock(struct hsmmc *mmc_base);
1605baf543eSJean-Jacques Hiblot static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base);
16114761caeSJean-Jacques Hiblot static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit);
16214fa2dd0SBalaji T K
omap_hsmmc_get_data(struct mmc * mmc)163ae000e23SJean-Jacques Hiblot static inline struct omap_hsmmc_data *omap_hsmmc_get_data(struct mmc *mmc)
164ae000e23SJean-Jacques Hiblot {
165c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
166ae000e23SJean-Jacques Hiblot return dev_get_priv(mmc->dev);
167ae000e23SJean-Jacques Hiblot #else
168ae000e23SJean-Jacques Hiblot return (struct omap_hsmmc_data *)mmc->priv;
169ae000e23SJean-Jacques Hiblot #endif
170ae000e23SJean-Jacques Hiblot }
omap_hsmmc_get_cfg(struct mmc * mmc)1713d673ffcSJean-Jacques Hiblot static inline struct mmc_config *omap_hsmmc_get_cfg(struct mmc *mmc)
1723d673ffcSJean-Jacques Hiblot {
173c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
1743d673ffcSJean-Jacques Hiblot struct omap_hsmmc_plat *plat = dev_get_platdata(mmc->dev);
1753d673ffcSJean-Jacques Hiblot return &plat->cfg;
1763d673ffcSJean-Jacques Hiblot #else
1773d673ffcSJean-Jacques Hiblot return &((struct omap_hsmmc_data *)mmc->priv)->cfg;
1783d673ffcSJean-Jacques Hiblot #endif
1793d673ffcSJean-Jacques Hiblot }
180ae000e23SJean-Jacques Hiblot
181c4d660d4SSimon Glass #if defined(OMAP_HSMMC_USE_GPIO) && !CONFIG_IS_ENABLED(DM_MMC)
omap_mmc_setup_gpio_in(int gpio,const char * label)182e874d5b0SNikita Kiryanov static int omap_mmc_setup_gpio_in(int gpio, const char *label)
183e874d5b0SNikita Kiryanov {
1845915a2adSSimon Glass int ret;
1855915a2adSSimon Glass
1865915a2adSSimon Glass #ifndef CONFIG_DM_GPIO
187e874d5b0SNikita Kiryanov if (!gpio_is_valid(gpio))
188e874d5b0SNikita Kiryanov return -1;
1895915a2adSSimon Glass #endif
1905915a2adSSimon Glass ret = gpio_request(gpio, label);
1915915a2adSSimon Glass if (ret)
1925915a2adSSimon Glass return ret;
193e874d5b0SNikita Kiryanov
1945915a2adSSimon Glass ret = gpio_direction_input(gpio);
1955915a2adSSimon Glass if (ret)
1965915a2adSSimon Glass return ret;
197e874d5b0SNikita Kiryanov
198e874d5b0SNikita Kiryanov return gpio;
199e874d5b0SNikita Kiryanov }
200e874d5b0SNikita Kiryanov #endif
201e874d5b0SNikita Kiryanov
mmc_board_init(struct mmc * mmc)202750121c3SJeroen Hofstee static unsigned char mmc_board_init(struct mmc *mmc)
203de941241SSukumar Ghorai {
204de941241SSukumar Ghorai #if defined(CONFIG_OMAP34XX)
2053d673ffcSJean-Jacques Hiblot struct mmc_config *cfg = omap_hsmmc_get_cfg(mmc);
206de941241SSukumar Ghorai t2_t *t2_base = (t2_t *)T2_BASE;
207de941241SSukumar Ghorai struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
208b1e725f2SGrazvydas Ignotas u32 pbias_lite;
2096aca17c9SAdam Ford #ifdef CONFIG_MMC_OMAP36XX_PINS
2106aca17c9SAdam Ford u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
2116aca17c9SAdam Ford #endif
212de941241SSukumar Ghorai
213b1e725f2SGrazvydas Ignotas pbias_lite = readl(&t2_base->pbias_lite);
214b1e725f2SGrazvydas Ignotas pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
2155bfdd1fcSAlbert ARIBAUD \(3ADEV\) #ifdef CONFIG_TARGET_OMAP3_CAIRO
2165bfdd1fcSAlbert ARIBAUD \(3ADEV\) /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
2175bfdd1fcSAlbert ARIBAUD \(3ADEV\) pbias_lite &= ~PBIASLITEVMODE0;
2185bfdd1fcSAlbert ARIBAUD \(3ADEV\) #endif
21903190a78SAdam Ford #ifdef CONFIG_TARGET_OMAP3_LOGIC
22003190a78SAdam Ford /* For Logic PD board, 1.8V bias to go enable gpio127 for mmc_cd */
22103190a78SAdam Ford pbias_lite &= ~PBIASLITEVMODE1;
22203190a78SAdam Ford #endif
2236aca17c9SAdam Ford #ifdef CONFIG_MMC_OMAP36XX_PINS
2246aca17c9SAdam Ford if (get_cpu_family() == CPU_OMAP36XX) {
2256aca17c9SAdam Ford /* Disable extended drain IO before changing PBIAS */
2266aca17c9SAdam Ford wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
2276aca17c9SAdam Ford writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
2286aca17c9SAdam Ford }
2296aca17c9SAdam Ford #endif
230b1e725f2SGrazvydas Ignotas writel(pbias_lite, &t2_base->pbias_lite);
231aac5450eSPaul Kocialkowski
232b1e725f2SGrazvydas Ignotas writel(pbias_lite | PBIASLITEPWRDNZ1 |
233de941241SSukumar Ghorai PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
234de941241SSukumar Ghorai &t2_base->pbias_lite);
235de941241SSukumar Ghorai
2366aca17c9SAdam Ford #ifdef CONFIG_MMC_OMAP36XX_PINS
2376aca17c9SAdam Ford if (get_cpu_family() == CPU_OMAP36XX)
2386aca17c9SAdam Ford /* Enable extended drain IO after changing PBIAS */
2396aca17c9SAdam Ford writel(wkup_ctrl |
2406aca17c9SAdam Ford OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
2416aca17c9SAdam Ford OMAP34XX_CTRL_WKUP_CTRL);
2426aca17c9SAdam Ford #endif
243de941241SSukumar Ghorai writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
244de941241SSukumar Ghorai &t2_base->devconf0);
245de941241SSukumar Ghorai
246de941241SSukumar Ghorai writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL,
247de941241SSukumar Ghorai &t2_base->devconf1);
248de941241SSukumar Ghorai
249bbbc1ae9SJonathan Solnit /* Change from default of 52MHz to 26MHz if necessary */
2503d673ffcSJean-Jacques Hiblot if (!(cfg->host_caps & MMC_MODE_HS_52MHz))
251bbbc1ae9SJonathan Solnit writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
252bbbc1ae9SJonathan Solnit &t2_base->ctl_prog_io1);
253bbbc1ae9SJonathan Solnit
254de941241SSukumar Ghorai writel(readl(&prcm_base->fclken1_core) |
255de941241SSukumar Ghorai EN_MMC1 | EN_MMC2 | EN_MMC3,
256de941241SSukumar Ghorai &prcm_base->fclken1_core);
257de941241SSukumar Ghorai
258de941241SSukumar Ghorai writel(readl(&prcm_base->iclken1_core) |
259de941241SSukumar Ghorai EN_MMC1 | EN_MMC2 | EN_MMC3,
260de941241SSukumar Ghorai &prcm_base->iclken1_core);
261de941241SSukumar Ghorai #endif
262de941241SSukumar Ghorai
26304f9f8beSJean-Jacques Hiblot #if (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) &&\
26404f9f8beSJean-Jacques Hiblot !CONFIG_IS_ENABLED(DM_REGULATOR)
26514fa2dd0SBalaji T K /* PBIAS config needed for MMC1 only */
266dc09127aSJean-Jacques Hiblot if (mmc_get_blk_desc(mmc)->devnum == 0)
267b4b06006SLokesh Vutla vmmc_pbias_config(LDO_VOLT_3V0);
268dd23e59dSBalaji T K #endif
269de941241SSukumar Ghorai
270de941241SSukumar Ghorai return 0;
271de941241SSukumar Ghorai }
272de941241SSukumar Ghorai
mmc_init_stream(struct hsmmc * mmc_base)273933efe64SSricharan void mmc_init_stream(struct hsmmc *mmc_base)
274de941241SSukumar Ghorai {
275eb9a28f6SNishanth Menon ulong start;
276de941241SSukumar Ghorai
277de941241SSukumar Ghorai writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
278de941241SSukumar Ghorai
279de941241SSukumar Ghorai writel(MMC_CMD0, &mmc_base->cmd);
280eb9a28f6SNishanth Menon start = get_timer(0);
281eb9a28f6SNishanth Menon while (!(readl(&mmc_base->stat) & CC_MASK)) {
282eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
283eb9a28f6SNishanth Menon printf("%s: timedout waiting for cc!\n", __func__);
284eb9a28f6SNishanth Menon return;
285eb9a28f6SNishanth Menon }
286eb9a28f6SNishanth Menon }
287de941241SSukumar Ghorai writel(CC_MASK, &mmc_base->stat)
288de941241SSukumar Ghorai ;
289de941241SSukumar Ghorai writel(MMC_CMD0, &mmc_base->cmd)
290de941241SSukumar Ghorai ;
291eb9a28f6SNishanth Menon start = get_timer(0);
292eb9a28f6SNishanth Menon while (!(readl(&mmc_base->stat) & CC_MASK)) {
293eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
294eb9a28f6SNishanth Menon printf("%s: timedout waiting for cc2!\n", __func__);
295eb9a28f6SNishanth Menon return;
296eb9a28f6SNishanth Menon }
297eb9a28f6SNishanth Menon }
298de941241SSukumar Ghorai writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
299de941241SSukumar Ghorai }
300de941241SSukumar Ghorai
301b5944817SKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC)
30233c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
omap_hsmmc_io_recalibrate(struct mmc * mmc)30333c1d77fSKishon Vijay Abraham I static void omap_hsmmc_io_recalibrate(struct mmc *mmc)
30433c1d77fSKishon Vijay Abraham I {
30533c1d77fSKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
30633c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *pinctrl_state;
30733c1d77fSKishon Vijay Abraham I
30833c1d77fSKishon Vijay Abraham I switch (priv->mode) {
30933c1d77fSKishon Vijay Abraham I case MMC_HS_200:
31033c1d77fSKishon Vijay Abraham I pinctrl_state = priv->hs200_1_8v_pinctrl_state;
31133c1d77fSKishon Vijay Abraham I break;
31233c1d77fSKishon Vijay Abraham I case UHS_SDR104:
31333c1d77fSKishon Vijay Abraham I pinctrl_state = priv->sdr104_pinctrl_state;
31433c1d77fSKishon Vijay Abraham I break;
31533c1d77fSKishon Vijay Abraham I case UHS_SDR50:
31633c1d77fSKishon Vijay Abraham I pinctrl_state = priv->sdr50_pinctrl_state;
31733c1d77fSKishon Vijay Abraham I break;
31833c1d77fSKishon Vijay Abraham I case UHS_DDR50:
31933c1d77fSKishon Vijay Abraham I pinctrl_state = priv->ddr50_pinctrl_state;
32033c1d77fSKishon Vijay Abraham I break;
32133c1d77fSKishon Vijay Abraham I case UHS_SDR25:
32233c1d77fSKishon Vijay Abraham I pinctrl_state = priv->sdr25_pinctrl_state;
32333c1d77fSKishon Vijay Abraham I break;
32433c1d77fSKishon Vijay Abraham I case UHS_SDR12:
32533c1d77fSKishon Vijay Abraham I pinctrl_state = priv->sdr12_pinctrl_state;
32633c1d77fSKishon Vijay Abraham I break;
32733c1d77fSKishon Vijay Abraham I case SD_HS:
32833c1d77fSKishon Vijay Abraham I case MMC_HS:
32933c1d77fSKishon Vijay Abraham I case MMC_HS_52:
33033c1d77fSKishon Vijay Abraham I pinctrl_state = priv->hs_pinctrl_state;
33133c1d77fSKishon Vijay Abraham I break;
33233c1d77fSKishon Vijay Abraham I case MMC_DDR_52:
33333c1d77fSKishon Vijay Abraham I pinctrl_state = priv->ddr_1_8v_pinctrl_state;
33433c1d77fSKishon Vijay Abraham I default:
33533c1d77fSKishon Vijay Abraham I pinctrl_state = priv->default_pinctrl_state;
33633c1d77fSKishon Vijay Abraham I break;
33733c1d77fSKishon Vijay Abraham I }
33833c1d77fSKishon Vijay Abraham I
339bcc6bd84SJean-Jacques Hiblot if (!pinctrl_state)
340bcc6bd84SJean-Jacques Hiblot pinctrl_state = priv->default_pinctrl_state;
341bcc6bd84SJean-Jacques Hiblot
34233c1d77fSKishon Vijay Abraham I if (priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY) {
34333c1d77fSKishon Vijay Abraham I if (pinctrl_state->iodelay)
34433c1d77fSKishon Vijay Abraham I late_recalibrate_iodelay(pinctrl_state->padconf,
34533c1d77fSKishon Vijay Abraham I pinctrl_state->npads,
34633c1d77fSKishon Vijay Abraham I pinctrl_state->iodelay,
34733c1d77fSKishon Vijay Abraham I pinctrl_state->niodelays);
34833c1d77fSKishon Vijay Abraham I else
34933c1d77fSKishon Vijay Abraham I do_set_mux32((*ctrl)->control_padconf_core_base,
35033c1d77fSKishon Vijay Abraham I pinctrl_state->padconf,
35133c1d77fSKishon Vijay Abraham I pinctrl_state->npads);
35233c1d77fSKishon Vijay Abraham I }
35333c1d77fSKishon Vijay Abraham I }
35433c1d77fSKishon Vijay Abraham I #endif
omap_hsmmc_set_timing(struct mmc * mmc)3558fc238bfSJean-Jacques Hiblot static void omap_hsmmc_set_timing(struct mmc *mmc)
3568fc238bfSJean-Jacques Hiblot {
3578fc238bfSJean-Jacques Hiblot u32 val;
3588fc238bfSJean-Jacques Hiblot struct hsmmc *mmc_base;
3598fc238bfSJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
3608fc238bfSJean-Jacques Hiblot
3618fc238bfSJean-Jacques Hiblot mmc_base = priv->base_addr;
3628fc238bfSJean-Jacques Hiblot
36333c1d77fSKishon Vijay Abraham I omap_hsmmc_stop_clock(mmc_base);
3648fc238bfSJean-Jacques Hiblot val = readl(&mmc_base->ac12);
3658fc238bfSJean-Jacques Hiblot val &= ~AC12_UHSMC_MASK;
3668fc238bfSJean-Jacques Hiblot priv->mode = mmc->selected_mode;
3678fc238bfSJean-Jacques Hiblot
3689b3fc218SKishon Vijay Abraham I if (mmc_is_mode_ddr(priv->mode))
3699b3fc218SKishon Vijay Abraham I writel(readl(&mmc_base->con) | DDR, &mmc_base->con);
3709b3fc218SKishon Vijay Abraham I else
3719b3fc218SKishon Vijay Abraham I writel(readl(&mmc_base->con) & ~DDR, &mmc_base->con);
3729b3fc218SKishon Vijay Abraham I
3738fc238bfSJean-Jacques Hiblot switch (priv->mode) {
3748fc238bfSJean-Jacques Hiblot case MMC_HS_200:
3758fc238bfSJean-Jacques Hiblot case UHS_SDR104:
3768fc238bfSJean-Jacques Hiblot val |= AC12_UHSMC_SDR104;
3778fc238bfSJean-Jacques Hiblot break;
3788fc238bfSJean-Jacques Hiblot case UHS_SDR50:
3798fc238bfSJean-Jacques Hiblot val |= AC12_UHSMC_SDR50;
3808fc238bfSJean-Jacques Hiblot break;
3818fc238bfSJean-Jacques Hiblot case MMC_DDR_52:
3828fc238bfSJean-Jacques Hiblot case UHS_DDR50:
3838fc238bfSJean-Jacques Hiblot val |= AC12_UHSMC_DDR50;
3848fc238bfSJean-Jacques Hiblot break;
3858fc238bfSJean-Jacques Hiblot case SD_HS:
3868fc238bfSJean-Jacques Hiblot case MMC_HS_52:
3878fc238bfSJean-Jacques Hiblot case UHS_SDR25:
3888fc238bfSJean-Jacques Hiblot val |= AC12_UHSMC_SDR25;
3898fc238bfSJean-Jacques Hiblot break;
3908fc238bfSJean-Jacques Hiblot case MMC_LEGACY:
3918fc238bfSJean-Jacques Hiblot case MMC_HS:
3928fc238bfSJean-Jacques Hiblot case SD_LEGACY:
3938fc238bfSJean-Jacques Hiblot case UHS_SDR12:
3948fc238bfSJean-Jacques Hiblot val |= AC12_UHSMC_SDR12;
3958fc238bfSJean-Jacques Hiblot break;
3968fc238bfSJean-Jacques Hiblot default:
3978fc238bfSJean-Jacques Hiblot val |= AC12_UHSMC_RES;
3988fc238bfSJean-Jacques Hiblot break;
3998fc238bfSJean-Jacques Hiblot }
4008fc238bfSJean-Jacques Hiblot writel(val, &mmc_base->ac12);
40133c1d77fSKishon Vijay Abraham I
40233c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
40333c1d77fSKishon Vijay Abraham I omap_hsmmc_io_recalibrate(mmc);
40433c1d77fSKishon Vijay Abraham I #endif
40533c1d77fSKishon Vijay Abraham I omap_hsmmc_start_clock(mmc_base);
4068fc238bfSJean-Jacques Hiblot }
4078fc238bfSJean-Jacques Hiblot
omap_hsmmc_conf_bus_power(struct mmc * mmc,uint signal_voltage)40804f9f8beSJean-Jacques Hiblot static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage)
409b5944817SKishon Vijay Abraham I {
410b5944817SKishon Vijay Abraham I struct hsmmc *mmc_base;
411b5944817SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
41204f9f8beSJean-Jacques Hiblot u32 hctl, ac12;
413b5944817SKishon Vijay Abraham I
414b5944817SKishon Vijay Abraham I mmc_base = priv->base_addr;
415b5944817SKishon Vijay Abraham I
41604f9f8beSJean-Jacques Hiblot hctl = readl(&mmc_base->hctl) & ~SDVS_MASK;
41704f9f8beSJean-Jacques Hiblot ac12 = readl(&mmc_base->ac12) & ~AC12_V1V8_SIGEN;
418b5944817SKishon Vijay Abraham I
41904f9f8beSJean-Jacques Hiblot switch (signal_voltage) {
42004f9f8beSJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330:
42104f9f8beSJean-Jacques Hiblot hctl |= SDVS_3V0;
422b5944817SKishon Vijay Abraham I break;
42304f9f8beSJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180:
42404f9f8beSJean-Jacques Hiblot hctl |= SDVS_1V8;
42504f9f8beSJean-Jacques Hiblot ac12 |= AC12_V1V8_SIGEN;
426b5944817SKishon Vijay Abraham I break;
427b5944817SKishon Vijay Abraham I }
428b5944817SKishon Vijay Abraham I
42904f9f8beSJean-Jacques Hiblot writel(hctl, &mmc_base->hctl);
43004f9f8beSJean-Jacques Hiblot writel(ac12, &mmc_base->ac12);
431b5944817SKishon Vijay Abraham I }
432b5944817SKishon Vijay Abraham I
43304f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
omap_hsmmc_wait_dat0(struct udevice * dev,int state,int timeout)43404f9f8beSJean-Jacques Hiblot static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout)
43504f9f8beSJean-Jacques Hiblot {
43604f9f8beSJean-Jacques Hiblot int ret = -ETIMEDOUT;
43704f9f8beSJean-Jacques Hiblot u32 con;
43804f9f8beSJean-Jacques Hiblot bool dat0_high;
43904f9f8beSJean-Jacques Hiblot bool target_dat0_high = !!state;
44004f9f8beSJean-Jacques Hiblot struct omap_hsmmc_data *priv = dev_get_priv(dev);
44104f9f8beSJean-Jacques Hiblot struct hsmmc *mmc_base = priv->base_addr;
44204f9f8beSJean-Jacques Hiblot
44304f9f8beSJean-Jacques Hiblot con = readl(&mmc_base->con);
44404f9f8beSJean-Jacques Hiblot writel(con | CON_CLKEXTFREE | CON_PADEN, &mmc_base->con);
44504f9f8beSJean-Jacques Hiblot
44604f9f8beSJean-Jacques Hiblot timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */
44704f9f8beSJean-Jacques Hiblot while (timeout--) {
44804f9f8beSJean-Jacques Hiblot dat0_high = !!(readl(&mmc_base->pstate) & PSTATE_DLEV_DAT0);
44904f9f8beSJean-Jacques Hiblot if (dat0_high == target_dat0_high) {
45004f9f8beSJean-Jacques Hiblot ret = 0;
45104f9f8beSJean-Jacques Hiblot break;
45204f9f8beSJean-Jacques Hiblot }
45304f9f8beSJean-Jacques Hiblot udelay(10);
45404f9f8beSJean-Jacques Hiblot }
45504f9f8beSJean-Jacques Hiblot writel(con, &mmc_base->con);
45604f9f8beSJean-Jacques Hiblot
45704f9f8beSJean-Jacques Hiblot return ret;
45804f9f8beSJean-Jacques Hiblot }
45904f9f8beSJean-Jacques Hiblot #endif
46004f9f8beSJean-Jacques Hiblot
46104f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
46204f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
omap_hsmmc_set_io_regulator(struct mmc * mmc,int mV)46304f9f8beSJean-Jacques Hiblot static int omap_hsmmc_set_io_regulator(struct mmc *mmc, int mV)
46404f9f8beSJean-Jacques Hiblot {
46504f9f8beSJean-Jacques Hiblot int ret = 0;
46604f9f8beSJean-Jacques Hiblot int uV = mV * 1000;
46704f9f8beSJean-Jacques Hiblot
46804f9f8beSJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
46904f9f8beSJean-Jacques Hiblot
47004f9f8beSJean-Jacques Hiblot if (!mmc->vqmmc_supply)
47104f9f8beSJean-Jacques Hiblot return 0;
47204f9f8beSJean-Jacques Hiblot
47304f9f8beSJean-Jacques Hiblot /* Disable PBIAS */
474*d3de3855SLokesh Vutla ret = regulator_set_enable_if_allowed(priv->pbias_supply, false);
475*d3de3855SLokesh Vutla if (ret)
47604f9f8beSJean-Jacques Hiblot return ret;
47704f9f8beSJean-Jacques Hiblot
47804f9f8beSJean-Jacques Hiblot /* Turn off IO voltage */
479*d3de3855SLokesh Vutla ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, false);
480*d3de3855SLokesh Vutla if (ret)
48104f9f8beSJean-Jacques Hiblot return ret;
48204f9f8beSJean-Jacques Hiblot /* Program a new IO voltage value */
48304f9f8beSJean-Jacques Hiblot ret = regulator_set_value(mmc->vqmmc_supply, uV);
48404f9f8beSJean-Jacques Hiblot if (ret)
48504f9f8beSJean-Jacques Hiblot return ret;
48604f9f8beSJean-Jacques Hiblot /* Turn on IO voltage */
487*d3de3855SLokesh Vutla ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, true);
488*d3de3855SLokesh Vutla if (ret)
48904f9f8beSJean-Jacques Hiblot return ret;
49004f9f8beSJean-Jacques Hiblot
49104f9f8beSJean-Jacques Hiblot /* Program PBIAS voltage*/
49204f9f8beSJean-Jacques Hiblot ret = regulator_set_value(priv->pbias_supply, uV);
49304f9f8beSJean-Jacques Hiblot if (ret && ret != -ENOSYS)
49404f9f8beSJean-Jacques Hiblot return ret;
49504f9f8beSJean-Jacques Hiblot /* Enable PBIAS */
496*d3de3855SLokesh Vutla ret = regulator_set_enable_if_allowed(priv->pbias_supply, true);
497*d3de3855SLokesh Vutla if (ret)
49804f9f8beSJean-Jacques Hiblot return ret;
49904f9f8beSJean-Jacques Hiblot
50004f9f8beSJean-Jacques Hiblot return 0;
50104f9f8beSJean-Jacques Hiblot }
50204f9f8beSJean-Jacques Hiblot #endif
50304f9f8beSJean-Jacques Hiblot
omap_hsmmc_set_signal_voltage(struct mmc * mmc)50404f9f8beSJean-Jacques Hiblot static int omap_hsmmc_set_signal_voltage(struct mmc *mmc)
50504f9f8beSJean-Jacques Hiblot {
50604f9f8beSJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
50704f9f8beSJean-Jacques Hiblot struct hsmmc *mmc_base = priv->base_addr;
50804f9f8beSJean-Jacques Hiblot int mv = mmc_voltage_to_mv(mmc->signal_voltage);
50904f9f8beSJean-Jacques Hiblot u32 capa_mask;
51004f9f8beSJean-Jacques Hiblot __maybe_unused u8 palmas_ldo_volt;
51104f9f8beSJean-Jacques Hiblot u32 val;
51204f9f8beSJean-Jacques Hiblot
51304f9f8beSJean-Jacques Hiblot if (mv < 0)
51404f9f8beSJean-Jacques Hiblot return -EINVAL;
51504f9f8beSJean-Jacques Hiblot
51604f9f8beSJean-Jacques Hiblot if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
51704f9f8beSJean-Jacques Hiblot /* Use 3.0V rather than 3.3V */
51804f9f8beSJean-Jacques Hiblot mv = 3000;
51904f9f8beSJean-Jacques Hiblot capa_mask = VS30_3V0SUP;
52004f9f8beSJean-Jacques Hiblot palmas_ldo_volt = LDO_VOLT_3V0;
52104f9f8beSJean-Jacques Hiblot } else if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
52204f9f8beSJean-Jacques Hiblot capa_mask = VS18_1V8SUP;
52304f9f8beSJean-Jacques Hiblot palmas_ldo_volt = LDO_VOLT_1V8;
52404f9f8beSJean-Jacques Hiblot } else {
52504f9f8beSJean-Jacques Hiblot return -EOPNOTSUPP;
52604f9f8beSJean-Jacques Hiblot }
52704f9f8beSJean-Jacques Hiblot
52804f9f8beSJean-Jacques Hiblot val = readl(&mmc_base->capa);
52904f9f8beSJean-Jacques Hiblot if (!(val & capa_mask))
53004f9f8beSJean-Jacques Hiblot return -EOPNOTSUPP;
53104f9f8beSJean-Jacques Hiblot
53204f9f8beSJean-Jacques Hiblot priv->signal_voltage = mmc->signal_voltage;
53304f9f8beSJean-Jacques Hiblot
53404f9f8beSJean-Jacques Hiblot omap_hsmmc_conf_bus_power(mmc, mmc->signal_voltage);
53504f9f8beSJean-Jacques Hiblot
53604f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
53704f9f8beSJean-Jacques Hiblot return omap_hsmmc_set_io_regulator(mmc, mv);
53804f9f8beSJean-Jacques Hiblot #elif (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) && \
53904f9f8beSJean-Jacques Hiblot defined(CONFIG_PALMAS_POWER)
54004f9f8beSJean-Jacques Hiblot if (mmc_get_blk_desc(mmc)->devnum == 0)
54104f9f8beSJean-Jacques Hiblot vmmc_pbias_config(palmas_ldo_volt);
54204f9f8beSJean-Jacques Hiblot return 0;
54304f9f8beSJean-Jacques Hiblot #else
54404f9f8beSJean-Jacques Hiblot return 0;
54504f9f8beSJean-Jacques Hiblot #endif
54604f9f8beSJean-Jacques Hiblot }
54704f9f8beSJean-Jacques Hiblot #endif
54804f9f8beSJean-Jacques Hiblot
omap_hsmmc_set_capabilities(struct mmc * mmc)54904f9f8beSJean-Jacques Hiblot static uint32_t omap_hsmmc_set_capabilities(struct mmc *mmc)
550b5944817SKishon Vijay Abraham I {
551b5944817SKishon Vijay Abraham I struct hsmmc *mmc_base;
552b5944817SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
553b5944817SKishon Vijay Abraham I u32 val;
554b5944817SKishon Vijay Abraham I
555b5944817SKishon Vijay Abraham I mmc_base = priv->base_addr;
556b5944817SKishon Vijay Abraham I val = readl(&mmc_base->capa);
557b5944817SKishon Vijay Abraham I
558b5944817SKishon Vijay Abraham I if (priv->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
559b5944817SKishon Vijay Abraham I val |= (VS30_3V0SUP | VS18_1V8SUP);
560b5944817SKishon Vijay Abraham I } else if (priv->controller_flags & OMAP_HSMMC_NO_1_8_V) {
561b5944817SKishon Vijay Abraham I val |= VS30_3V0SUP;
562b5944817SKishon Vijay Abraham I val &= ~VS18_1V8SUP;
563b5944817SKishon Vijay Abraham I } else {
564b5944817SKishon Vijay Abraham I val |= VS18_1V8SUP;
565b5944817SKishon Vijay Abraham I val &= ~VS30_3V0SUP;
566b5944817SKishon Vijay Abraham I }
567b5944817SKishon Vijay Abraham I
568b5944817SKishon Vijay Abraham I writel(val, &mmc_base->capa);
56904f9f8beSJean-Jacques Hiblot
57004f9f8beSJean-Jacques Hiblot return val;
571b5944817SKishon Vijay Abraham I }
57214761caeSJean-Jacques Hiblot
57314761caeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
omap_hsmmc_disable_tuning(struct mmc * mmc)57414761caeSJean-Jacques Hiblot static void omap_hsmmc_disable_tuning(struct mmc *mmc)
57514761caeSJean-Jacques Hiblot {
57614761caeSJean-Jacques Hiblot struct hsmmc *mmc_base;
57714761caeSJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
57814761caeSJean-Jacques Hiblot u32 val;
57914761caeSJean-Jacques Hiblot
58014761caeSJean-Jacques Hiblot mmc_base = priv->base_addr;
58114761caeSJean-Jacques Hiblot val = readl(&mmc_base->ac12);
58214761caeSJean-Jacques Hiblot val &= ~(AC12_SCLK_SEL);
58314761caeSJean-Jacques Hiblot writel(val, &mmc_base->ac12);
58414761caeSJean-Jacques Hiblot
58514761caeSJean-Jacques Hiblot val = readl(&mmc_base->dll);
58614761caeSJean-Jacques Hiblot val &= ~(DLL_FORCE_VALUE | DLL_SWT);
58714761caeSJean-Jacques Hiblot writel(val, &mmc_base->dll);
58814761caeSJean-Jacques Hiblot }
58914761caeSJean-Jacques Hiblot
omap_hsmmc_set_dll(struct mmc * mmc,int count)59014761caeSJean-Jacques Hiblot static void omap_hsmmc_set_dll(struct mmc *mmc, int count)
59114761caeSJean-Jacques Hiblot {
59214761caeSJean-Jacques Hiblot int i;
59314761caeSJean-Jacques Hiblot struct hsmmc *mmc_base;
59414761caeSJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
59514761caeSJean-Jacques Hiblot u32 val;
59614761caeSJean-Jacques Hiblot
59714761caeSJean-Jacques Hiblot mmc_base = priv->base_addr;
59814761caeSJean-Jacques Hiblot val = readl(&mmc_base->dll);
59914761caeSJean-Jacques Hiblot val |= DLL_FORCE_VALUE;
60014761caeSJean-Jacques Hiblot val &= ~(DLL_FORCE_SR_C_MASK << DLL_FORCE_SR_C_SHIFT);
60114761caeSJean-Jacques Hiblot val |= (count << DLL_FORCE_SR_C_SHIFT);
60214761caeSJean-Jacques Hiblot writel(val, &mmc_base->dll);
60314761caeSJean-Jacques Hiblot
60414761caeSJean-Jacques Hiblot val |= DLL_CALIB;
60514761caeSJean-Jacques Hiblot writel(val, &mmc_base->dll);
60614761caeSJean-Jacques Hiblot for (i = 0; i < 1000; i++) {
60714761caeSJean-Jacques Hiblot if (readl(&mmc_base->dll) & DLL_CALIB)
60814761caeSJean-Jacques Hiblot break;
60914761caeSJean-Jacques Hiblot }
61014761caeSJean-Jacques Hiblot val &= ~DLL_CALIB;
61114761caeSJean-Jacques Hiblot writel(val, &mmc_base->dll);
61214761caeSJean-Jacques Hiblot }
61314761caeSJean-Jacques Hiblot
omap_hsmmc_execute_tuning(struct udevice * dev,uint opcode)61414761caeSJean-Jacques Hiblot static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
61514761caeSJean-Jacques Hiblot {
61614761caeSJean-Jacques Hiblot struct omap_hsmmc_data *priv = dev_get_priv(dev);
61714761caeSJean-Jacques Hiblot struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
61814761caeSJean-Jacques Hiblot struct mmc *mmc = upriv->mmc;
61914761caeSJean-Jacques Hiblot struct hsmmc *mmc_base;
62014761caeSJean-Jacques Hiblot u32 val;
62114761caeSJean-Jacques Hiblot u8 cur_match, prev_match = 0;
62214761caeSJean-Jacques Hiblot int ret;
62314761caeSJean-Jacques Hiblot u32 phase_delay = 0;
62414761caeSJean-Jacques Hiblot u32 start_window = 0, max_window = 0;
62514761caeSJean-Jacques Hiblot u32 length = 0, max_len = 0;
626351a4aa0SFaiz Abbas bool single_point_failure = false;
627351a4aa0SFaiz Abbas struct udevice *thermal_dev;
628351a4aa0SFaiz Abbas int temperature;
629351a4aa0SFaiz Abbas int i;
63014761caeSJean-Jacques Hiblot
63114761caeSJean-Jacques Hiblot mmc_base = priv->base_addr;
63214761caeSJean-Jacques Hiblot val = readl(&mmc_base->capa2);
63314761caeSJean-Jacques Hiblot
63414761caeSJean-Jacques Hiblot /* clock tuning is not needed for upto 52MHz */
63514761caeSJean-Jacques Hiblot if (!((mmc->selected_mode == MMC_HS_200) ||
63614761caeSJean-Jacques Hiblot (mmc->selected_mode == UHS_SDR104) ||
63714761caeSJean-Jacques Hiblot ((mmc->selected_mode == UHS_SDR50) && (val & CAPA2_TSDR50))))
63814761caeSJean-Jacques Hiblot return 0;
63914761caeSJean-Jacques Hiblot
640351a4aa0SFaiz Abbas ret = uclass_first_device(UCLASS_THERMAL, &thermal_dev);
641351a4aa0SFaiz Abbas if (ret) {
642351a4aa0SFaiz Abbas printf("Couldn't get thermal device for tuning\n");
643351a4aa0SFaiz Abbas return ret;
644351a4aa0SFaiz Abbas }
645351a4aa0SFaiz Abbas ret = thermal_get_temp(thermal_dev, &temperature);
646351a4aa0SFaiz Abbas if (ret) {
647351a4aa0SFaiz Abbas printf("Couldn't get temperature for tuning\n");
648351a4aa0SFaiz Abbas return ret;
649351a4aa0SFaiz Abbas }
65014761caeSJean-Jacques Hiblot val = readl(&mmc_base->dll);
65114761caeSJean-Jacques Hiblot val |= DLL_SWT;
65214761caeSJean-Jacques Hiblot writel(val, &mmc_base->dll);
653351a4aa0SFaiz Abbas
654351a4aa0SFaiz Abbas /*
655351a4aa0SFaiz Abbas * Stage 1: Search for a maximum pass window ignoring any
656351a4aa0SFaiz Abbas * any single point failures. If the tuning value ends up
657351a4aa0SFaiz Abbas * near it, move away from it in stage 2 below
658351a4aa0SFaiz Abbas */
65914761caeSJean-Jacques Hiblot while (phase_delay <= MAX_PHASE_DELAY) {
66014761caeSJean-Jacques Hiblot omap_hsmmc_set_dll(mmc, phase_delay);
66114761caeSJean-Jacques Hiblot
66214761caeSJean-Jacques Hiblot cur_match = !mmc_send_tuning(mmc, opcode, NULL);
66314761caeSJean-Jacques Hiblot
66414761caeSJean-Jacques Hiblot if (cur_match) {
66514761caeSJean-Jacques Hiblot if (prev_match) {
66614761caeSJean-Jacques Hiblot length++;
667351a4aa0SFaiz Abbas } else if (single_point_failure) {
668351a4aa0SFaiz Abbas /* ignore single point failure */
669351a4aa0SFaiz Abbas length++;
670351a4aa0SFaiz Abbas single_point_failure = false;
67114761caeSJean-Jacques Hiblot } else {
67214761caeSJean-Jacques Hiblot start_window = phase_delay;
67314761caeSJean-Jacques Hiblot length = 1;
67414761caeSJean-Jacques Hiblot }
675351a4aa0SFaiz Abbas } else {
676351a4aa0SFaiz Abbas single_point_failure = prev_match;
67714761caeSJean-Jacques Hiblot }
67814761caeSJean-Jacques Hiblot
67914761caeSJean-Jacques Hiblot if (length > max_len) {
68014761caeSJean-Jacques Hiblot max_window = start_window;
68114761caeSJean-Jacques Hiblot max_len = length;
68214761caeSJean-Jacques Hiblot }
68314761caeSJean-Jacques Hiblot
68414761caeSJean-Jacques Hiblot prev_match = cur_match;
68514761caeSJean-Jacques Hiblot phase_delay += 4;
68614761caeSJean-Jacques Hiblot }
68714761caeSJean-Jacques Hiblot
68814761caeSJean-Jacques Hiblot if (!max_len) {
68914761caeSJean-Jacques Hiblot ret = -EIO;
69014761caeSJean-Jacques Hiblot goto tuning_error;
69114761caeSJean-Jacques Hiblot }
69214761caeSJean-Jacques Hiblot
69314761caeSJean-Jacques Hiblot val = readl(&mmc_base->ac12);
69414761caeSJean-Jacques Hiblot if (!(val & AC12_SCLK_SEL)) {
69514761caeSJean-Jacques Hiblot ret = -EIO;
69614761caeSJean-Jacques Hiblot goto tuning_error;
69714761caeSJean-Jacques Hiblot }
698351a4aa0SFaiz Abbas /*
699351a4aa0SFaiz Abbas * Assign tuning value as a ratio of maximum pass window based
700351a4aa0SFaiz Abbas * on temperature
701351a4aa0SFaiz Abbas */
702351a4aa0SFaiz Abbas if (temperature < -20000)
703351a4aa0SFaiz Abbas phase_delay = min(max_window + 4 * max_len - 24,
704351a4aa0SFaiz Abbas max_window +
705351a4aa0SFaiz Abbas DIV_ROUND_UP(13 * max_len, 16) * 4);
706351a4aa0SFaiz Abbas else if (temperature < 20000)
707351a4aa0SFaiz Abbas phase_delay = max_window + DIV_ROUND_UP(9 * max_len, 16) * 4;
708351a4aa0SFaiz Abbas else if (temperature < 40000)
709351a4aa0SFaiz Abbas phase_delay = max_window + DIV_ROUND_UP(8 * max_len, 16) * 4;
710351a4aa0SFaiz Abbas else if (temperature < 70000)
711351a4aa0SFaiz Abbas phase_delay = max_window + DIV_ROUND_UP(7 * max_len, 16) * 4;
712351a4aa0SFaiz Abbas else if (temperature < 90000)
713351a4aa0SFaiz Abbas phase_delay = max_window + DIV_ROUND_UP(5 * max_len, 16) * 4;
714351a4aa0SFaiz Abbas else if (temperature < 120000)
715351a4aa0SFaiz Abbas phase_delay = max_window + DIV_ROUND_UP(4 * max_len, 16) * 4;
716351a4aa0SFaiz Abbas else
717351a4aa0SFaiz Abbas phase_delay = max_window + DIV_ROUND_UP(3 * max_len, 16) * 4;
71814761caeSJean-Jacques Hiblot
719351a4aa0SFaiz Abbas /*
720351a4aa0SFaiz Abbas * Stage 2: Search for a single point failure near the chosen tuning
721351a4aa0SFaiz Abbas * value in two steps. First in the +3 to +10 range and then in the
722351a4aa0SFaiz Abbas * +2 to -10 range. If found, move away from it in the appropriate
723351a4aa0SFaiz Abbas * direction by the appropriate amount depending on the temperature.
724351a4aa0SFaiz Abbas */
725351a4aa0SFaiz Abbas for (i = 3; i <= 10; i++) {
726351a4aa0SFaiz Abbas omap_hsmmc_set_dll(mmc, phase_delay + i);
727351a4aa0SFaiz Abbas if (mmc_send_tuning(mmc, opcode, NULL)) {
728351a4aa0SFaiz Abbas if (temperature < 10000)
729351a4aa0SFaiz Abbas phase_delay += i + 6;
730351a4aa0SFaiz Abbas else if (temperature < 20000)
731351a4aa0SFaiz Abbas phase_delay += i - 12;
732351a4aa0SFaiz Abbas else if (temperature < 70000)
733351a4aa0SFaiz Abbas phase_delay += i - 8;
734351a4aa0SFaiz Abbas else if (temperature < 90000)
735351a4aa0SFaiz Abbas phase_delay += i - 6;
736351a4aa0SFaiz Abbas else
737351a4aa0SFaiz Abbas phase_delay += i - 6;
738351a4aa0SFaiz Abbas
739351a4aa0SFaiz Abbas goto single_failure_found;
740351a4aa0SFaiz Abbas }
741351a4aa0SFaiz Abbas }
742351a4aa0SFaiz Abbas
743351a4aa0SFaiz Abbas for (i = 2; i >= -10; i--) {
744351a4aa0SFaiz Abbas omap_hsmmc_set_dll(mmc, phase_delay + i);
745351a4aa0SFaiz Abbas if (mmc_send_tuning(mmc, opcode, NULL)) {
746351a4aa0SFaiz Abbas if (temperature < 10000)
747351a4aa0SFaiz Abbas phase_delay += i + 12;
748351a4aa0SFaiz Abbas else if (temperature < 20000)
749351a4aa0SFaiz Abbas phase_delay += i + 8;
750351a4aa0SFaiz Abbas else if (temperature < 70000)
751351a4aa0SFaiz Abbas phase_delay += i + 8;
752351a4aa0SFaiz Abbas else if (temperature < 90000)
753351a4aa0SFaiz Abbas phase_delay += i + 10;
754351a4aa0SFaiz Abbas else
755351a4aa0SFaiz Abbas phase_delay += i + 12;
756351a4aa0SFaiz Abbas
757351a4aa0SFaiz Abbas goto single_failure_found;
758351a4aa0SFaiz Abbas }
759351a4aa0SFaiz Abbas }
760351a4aa0SFaiz Abbas
761351a4aa0SFaiz Abbas single_failure_found:
762351a4aa0SFaiz Abbas
76314761caeSJean-Jacques Hiblot omap_hsmmc_set_dll(mmc, phase_delay);
76414761caeSJean-Jacques Hiblot
76514761caeSJean-Jacques Hiblot mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
76614761caeSJean-Jacques Hiblot mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
76714761caeSJean-Jacques Hiblot
76814761caeSJean-Jacques Hiblot return 0;
76914761caeSJean-Jacques Hiblot
77014761caeSJean-Jacques Hiblot tuning_error:
77114761caeSJean-Jacques Hiblot
77214761caeSJean-Jacques Hiblot omap_hsmmc_disable_tuning(mmc);
77314761caeSJean-Jacques Hiblot mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
77414761caeSJean-Jacques Hiblot mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
77514761caeSJean-Jacques Hiblot
77614761caeSJean-Jacques Hiblot return ret;
77714761caeSJean-Jacques Hiblot }
77814761caeSJean-Jacques Hiblot #endif
77942182c9bSJean-Jacques Hiblot
omap_hsmmc_send_init_stream(struct udevice * dev)78042182c9bSJean-Jacques Hiblot static void omap_hsmmc_send_init_stream(struct udevice *dev)
78142182c9bSJean-Jacques Hiblot {
78242182c9bSJean-Jacques Hiblot struct omap_hsmmc_data *priv = dev_get_priv(dev);
78342182c9bSJean-Jacques Hiblot struct hsmmc *mmc_base = priv->base_addr;
78442182c9bSJean-Jacques Hiblot
78542182c9bSJean-Jacques Hiblot mmc_init_stream(mmc_base);
78642182c9bSJean-Jacques Hiblot }
787b5944817SKishon Vijay Abraham I #endif
788b5944817SKishon Vijay Abraham I
mmc_enable_irq(struct mmc * mmc,struct mmc_cmd * cmd)7892faa1a30SJean-Jacques Hiblot static void mmc_enable_irq(struct mmc *mmc, struct mmc_cmd *cmd)
7902faa1a30SJean-Jacques Hiblot {
7912faa1a30SJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
7922faa1a30SJean-Jacques Hiblot struct hsmmc *mmc_base = priv->base_addr;
7932faa1a30SJean-Jacques Hiblot u32 irq_mask = INT_EN_MASK;
7942faa1a30SJean-Jacques Hiblot
7952faa1a30SJean-Jacques Hiblot /*
7962faa1a30SJean-Jacques Hiblot * TODO: Errata i802 indicates only DCRC interrupts can occur during
7972faa1a30SJean-Jacques Hiblot * tuning procedure and DCRC should be disabled. But see occurences
7982faa1a30SJean-Jacques Hiblot * of DEB, CIE, CEB, CCRC interupts during tuning procedure. These
7992faa1a30SJean-Jacques Hiblot * interrupts occur along with BRR, so the data is actually in the
8002faa1a30SJean-Jacques Hiblot * buffer. It has to be debugged why these interrutps occur
8012faa1a30SJean-Jacques Hiblot */
8022faa1a30SJean-Jacques Hiblot if (cmd && mmc_is_tuning_cmd(cmd->cmdidx))
8032faa1a30SJean-Jacques Hiblot irq_mask &= ~(IE_DEB | IE_DCRC | IE_CIE | IE_CEB | IE_CCRC);
8042faa1a30SJean-Jacques Hiblot
8052faa1a30SJean-Jacques Hiblot writel(irq_mask, &mmc_base->ie);
8062faa1a30SJean-Jacques Hiblot }
8072faa1a30SJean-Jacques Hiblot
omap_hsmmc_init_setup(struct mmc * mmc)808ab769f22SPantelis Antoniou static int omap_hsmmc_init_setup(struct mmc *mmc)
809de941241SSukumar Ghorai {
810ae000e23SJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
811cc22b0c0SNikita Kiryanov struct hsmmc *mmc_base;
812de941241SSukumar Ghorai unsigned int reg_val;
813de941241SSukumar Ghorai unsigned int dsor;
814eb9a28f6SNishanth Menon ulong start;
815de941241SSukumar Ghorai
816ae000e23SJean-Jacques Hiblot mmc_base = priv->base_addr;
81714fa2dd0SBalaji T K mmc_board_init(mmc);
818de941241SSukumar Ghorai
819de941241SSukumar Ghorai writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
820de941241SSukumar Ghorai &mmc_base->sysconfig);
821eb9a28f6SNishanth Menon start = get_timer(0);
822eb9a28f6SNishanth Menon while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
823eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
824eb9a28f6SNishanth Menon printf("%s: timedout waiting for cc2!\n", __func__);
825915ffa52SJaehoon Chung return -ETIMEDOUT;
826eb9a28f6SNishanth Menon }
827eb9a28f6SNishanth Menon }
828de941241SSukumar Ghorai writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
829eb9a28f6SNishanth Menon start = get_timer(0);
830eb9a28f6SNishanth Menon while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
831eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
832eb9a28f6SNishanth Menon printf("%s: timedout waiting for softresetall!\n",
833eb9a28f6SNishanth Menon __func__);
834915ffa52SJaehoon Chung return -ETIMEDOUT;
835eb9a28f6SNishanth Menon }
836eb9a28f6SNishanth Menon }
83727a4b3bcSJean-Jacques Hiblot #ifdef CONFIG_MMC_OMAP_HS_ADMA
838f0d53e88SKishon Vijay Abraham I reg_val = readl(&mmc_base->hl_hwinfo);
839f0d53e88SKishon Vijay Abraham I if (reg_val & MADMA_EN)
840f0d53e88SKishon Vijay Abraham I priv->controller_flags |= OMAP_HSMMC_USE_ADMA;
841f0d53e88SKishon Vijay Abraham I #endif
842b5944817SKishon Vijay Abraham I
843b5944817SKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC)
84404f9f8beSJean-Jacques Hiblot reg_val = omap_hsmmc_set_capabilities(mmc);
84504f9f8beSJean-Jacques Hiblot omap_hsmmc_conf_bus_power(mmc, (reg_val & VS30_3V0SUP) ?
84604f9f8beSJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_330 : MMC_SIGNAL_VOLTAGE_180);
847b5944817SKishon Vijay Abraham I #else
848de941241SSukumar Ghorai writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
849de941241SSukumar Ghorai writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
850de941241SSukumar Ghorai &mmc_base->capa);
851b5944817SKishon Vijay Abraham I #endif
852de941241SSukumar Ghorai
853de941241SSukumar Ghorai reg_val = readl(&mmc_base->con) & RESERVED_MASK;
854de941241SSukumar Ghorai
855de941241SSukumar Ghorai writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
856de941241SSukumar Ghorai MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
857de941241SSukumar Ghorai HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
858de941241SSukumar Ghorai
859de941241SSukumar Ghorai dsor = 240;
860de941241SSukumar Ghorai mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
86129171dcfSKishon Vijay Abraham I (ICE_STOP | DTO_15THDTO));
862de941241SSukumar Ghorai mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
863de941241SSukumar Ghorai (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
864eb9a28f6SNishanth Menon start = get_timer(0);
865eb9a28f6SNishanth Menon while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
866eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
867eb9a28f6SNishanth Menon printf("%s: timedout waiting for ics!\n", __func__);
868915ffa52SJaehoon Chung return -ETIMEDOUT;
869eb9a28f6SNishanth Menon }
870eb9a28f6SNishanth Menon }
871de941241SSukumar Ghorai writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
872de941241SSukumar Ghorai
873de941241SSukumar Ghorai writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
874de941241SSukumar Ghorai
8752faa1a30SJean-Jacques Hiblot mmc_enable_irq(mmc, NULL);
87642182c9bSJean-Jacques Hiblot
87742182c9bSJean-Jacques Hiblot #if !CONFIG_IS_ENABLED(DM_MMC)
878de941241SSukumar Ghorai mmc_init_stream(mmc_base);
87942182c9bSJean-Jacques Hiblot #endif
880de941241SSukumar Ghorai
881de941241SSukumar Ghorai return 0;
882de941241SSukumar Ghorai }
883de941241SSukumar Ghorai
88425c719e2SGrazvydas Ignotas /*
88525c719e2SGrazvydas Ignotas * MMC controller internal finite state machine reset
88625c719e2SGrazvydas Ignotas *
88725c719e2SGrazvydas Ignotas * Used to reset command or data internal state machines, using respectively
88825c719e2SGrazvydas Ignotas * SRC or SRD bit of SYSCTL register
88925c719e2SGrazvydas Ignotas */
mmc_reset_controller_fsm(struct hsmmc * mmc_base,u32 bit)89025c719e2SGrazvydas Ignotas static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
89125c719e2SGrazvydas Ignotas {
89225c719e2SGrazvydas Ignotas ulong start;
89325c719e2SGrazvydas Ignotas
89425c719e2SGrazvydas Ignotas mmc_reg_out(&mmc_base->sysctl, bit, bit);
89525c719e2SGrazvydas Ignotas
89661a6cc27SOleksandr Tyshchenko /*
89761a6cc27SOleksandr Tyshchenko * CMD(DAT) lines reset procedures are slightly different
89861a6cc27SOleksandr Tyshchenko * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
89961a6cc27SOleksandr Tyshchenko * According to OMAP3 TRM:
90061a6cc27SOleksandr Tyshchenko * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
90161a6cc27SOleksandr Tyshchenko * returns to 0x0.
90261a6cc27SOleksandr Tyshchenko * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
90361a6cc27SOleksandr Tyshchenko * procedure steps must be as follows:
90461a6cc27SOleksandr Tyshchenko * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
90561a6cc27SOleksandr Tyshchenko * MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
90661a6cc27SOleksandr Tyshchenko * 2. Poll the SRC(SRD) bit until it is set to 0x1.
90761a6cc27SOleksandr Tyshchenko * 3. Wait until the SRC (SRD) bit returns to 0x0
90861a6cc27SOleksandr Tyshchenko * (reset procedure is completed).
90961a6cc27SOleksandr Tyshchenko */
91061a6cc27SOleksandr Tyshchenko #if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
911dce55b93SNikita Kiryanov defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX)
91261a6cc27SOleksandr Tyshchenko if (!(readl(&mmc_base->sysctl) & bit)) {
91361a6cc27SOleksandr Tyshchenko start = get_timer(0);
91461a6cc27SOleksandr Tyshchenko while (!(readl(&mmc_base->sysctl) & bit)) {
915a4efd737SJean-Jacques Hiblot if (get_timer(0) - start > MMC_TIMEOUT_MS)
91661a6cc27SOleksandr Tyshchenko return;
91761a6cc27SOleksandr Tyshchenko }
91861a6cc27SOleksandr Tyshchenko }
91961a6cc27SOleksandr Tyshchenko #endif
92025c719e2SGrazvydas Ignotas start = get_timer(0);
92125c719e2SGrazvydas Ignotas while ((readl(&mmc_base->sysctl) & bit) != 0) {
92225c719e2SGrazvydas Ignotas if (get_timer(0) - start > MAX_RETRY_MS) {
92325c719e2SGrazvydas Ignotas printf("%s: timedout waiting for sysctl %x to clear\n",
92425c719e2SGrazvydas Ignotas __func__, bit);
92525c719e2SGrazvydas Ignotas return;
92625c719e2SGrazvydas Ignotas }
92725c719e2SGrazvydas Ignotas }
92825c719e2SGrazvydas Ignotas }
929f0d53e88SKishon Vijay Abraham I
93027a4b3bcSJean-Jacques Hiblot #ifdef CONFIG_MMC_OMAP_HS_ADMA
omap_hsmmc_adma_desc(struct mmc * mmc,char * buf,u16 len,bool end)931f0d53e88SKishon Vijay Abraham I static void omap_hsmmc_adma_desc(struct mmc *mmc, char *buf, u16 len, bool end)
932f0d53e88SKishon Vijay Abraham I {
933f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
934f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_adma_desc *desc;
935f0d53e88SKishon Vijay Abraham I u8 attr;
936f0d53e88SKishon Vijay Abraham I
937f0d53e88SKishon Vijay Abraham I desc = &priv->adma_desc_table[priv->desc_slot];
938f0d53e88SKishon Vijay Abraham I
939f0d53e88SKishon Vijay Abraham I attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
940f0d53e88SKishon Vijay Abraham I if (!end)
941f0d53e88SKishon Vijay Abraham I priv->desc_slot++;
942f0d53e88SKishon Vijay Abraham I else
943f0d53e88SKishon Vijay Abraham I attr |= ADMA_DESC_ATTR_END;
944f0d53e88SKishon Vijay Abraham I
945f0d53e88SKishon Vijay Abraham I desc->len = len;
946f0d53e88SKishon Vijay Abraham I desc->addr = (u32)buf;
947f0d53e88SKishon Vijay Abraham I desc->reserved = 0;
948f0d53e88SKishon Vijay Abraham I desc->attr = attr;
949f0d53e88SKishon Vijay Abraham I }
950f0d53e88SKishon Vijay Abraham I
omap_hsmmc_prepare_adma_table(struct mmc * mmc,struct mmc_data * data)951f0d53e88SKishon Vijay Abraham I static void omap_hsmmc_prepare_adma_table(struct mmc *mmc,
952f0d53e88SKishon Vijay Abraham I struct mmc_data *data)
953f0d53e88SKishon Vijay Abraham I {
954f0d53e88SKishon Vijay Abraham I uint total_len = data->blocksize * data->blocks;
955f0d53e88SKishon Vijay Abraham I uint desc_count = DIV_ROUND_UP(total_len, ADMA_MAX_LEN);
956f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
957f0d53e88SKishon Vijay Abraham I int i = desc_count;
958f0d53e88SKishon Vijay Abraham I char *buf;
959f0d53e88SKishon Vijay Abraham I
960f0d53e88SKishon Vijay Abraham I priv->desc_slot = 0;
961f0d53e88SKishon Vijay Abraham I priv->adma_desc_table = (struct omap_hsmmc_adma_desc *)
962f0d53e88SKishon Vijay Abraham I memalign(ARCH_DMA_MINALIGN, desc_count *
963f0d53e88SKishon Vijay Abraham I sizeof(struct omap_hsmmc_adma_desc));
964f0d53e88SKishon Vijay Abraham I
965f0d53e88SKishon Vijay Abraham I if (data->flags & MMC_DATA_READ)
966f0d53e88SKishon Vijay Abraham I buf = data->dest;
967f0d53e88SKishon Vijay Abraham I else
968f0d53e88SKishon Vijay Abraham I buf = (char *)data->src;
969f0d53e88SKishon Vijay Abraham I
970f0d53e88SKishon Vijay Abraham I while (--i) {
971f0d53e88SKishon Vijay Abraham I omap_hsmmc_adma_desc(mmc, buf, ADMA_MAX_LEN, false);
972f0d53e88SKishon Vijay Abraham I buf += ADMA_MAX_LEN;
973f0d53e88SKishon Vijay Abraham I total_len -= ADMA_MAX_LEN;
974f0d53e88SKishon Vijay Abraham I }
975f0d53e88SKishon Vijay Abraham I
976f0d53e88SKishon Vijay Abraham I omap_hsmmc_adma_desc(mmc, buf, total_len, true);
977f0d53e88SKishon Vijay Abraham I
978f0d53e88SKishon Vijay Abraham I flush_dcache_range((long)priv->adma_desc_table,
979f0d53e88SKishon Vijay Abraham I (long)priv->adma_desc_table +
980f0d53e88SKishon Vijay Abraham I ROUND(desc_count *
981f0d53e88SKishon Vijay Abraham I sizeof(struct omap_hsmmc_adma_desc),
982f0d53e88SKishon Vijay Abraham I ARCH_DMA_MINALIGN));
983f0d53e88SKishon Vijay Abraham I }
984f0d53e88SKishon Vijay Abraham I
omap_hsmmc_prepare_data(struct mmc * mmc,struct mmc_data * data)985f0d53e88SKishon Vijay Abraham I static void omap_hsmmc_prepare_data(struct mmc *mmc, struct mmc_data *data)
986f0d53e88SKishon Vijay Abraham I {
987f0d53e88SKishon Vijay Abraham I struct hsmmc *mmc_base;
988f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
989f0d53e88SKishon Vijay Abraham I u32 val;
990f0d53e88SKishon Vijay Abraham I char *buf;
991f0d53e88SKishon Vijay Abraham I
992f0d53e88SKishon Vijay Abraham I mmc_base = priv->base_addr;
993f0d53e88SKishon Vijay Abraham I omap_hsmmc_prepare_adma_table(mmc, data);
994f0d53e88SKishon Vijay Abraham I
995f0d53e88SKishon Vijay Abraham I if (data->flags & MMC_DATA_READ)
996f0d53e88SKishon Vijay Abraham I buf = data->dest;
997f0d53e88SKishon Vijay Abraham I else
998f0d53e88SKishon Vijay Abraham I buf = (char *)data->src;
999f0d53e88SKishon Vijay Abraham I
1000f0d53e88SKishon Vijay Abraham I val = readl(&mmc_base->hctl);
1001f0d53e88SKishon Vijay Abraham I val |= DMA_SELECT;
1002f0d53e88SKishon Vijay Abraham I writel(val, &mmc_base->hctl);
1003f0d53e88SKishon Vijay Abraham I
1004f0d53e88SKishon Vijay Abraham I val = readl(&mmc_base->con);
1005f0d53e88SKishon Vijay Abraham I val |= DMA_MASTER;
1006f0d53e88SKishon Vijay Abraham I writel(val, &mmc_base->con);
1007f0d53e88SKishon Vijay Abraham I
1008f0d53e88SKishon Vijay Abraham I writel((u32)priv->adma_desc_table, &mmc_base->admasal);
1009f0d53e88SKishon Vijay Abraham I
1010f0d53e88SKishon Vijay Abraham I flush_dcache_range((u32)buf,
1011f0d53e88SKishon Vijay Abraham I (u32)buf +
1012f0d53e88SKishon Vijay Abraham I ROUND(data->blocksize * data->blocks,
1013f0d53e88SKishon Vijay Abraham I ARCH_DMA_MINALIGN));
1014f0d53e88SKishon Vijay Abraham I }
1015f0d53e88SKishon Vijay Abraham I
omap_hsmmc_dma_cleanup(struct mmc * mmc)1016f0d53e88SKishon Vijay Abraham I static void omap_hsmmc_dma_cleanup(struct mmc *mmc)
1017f0d53e88SKishon Vijay Abraham I {
1018f0d53e88SKishon Vijay Abraham I struct hsmmc *mmc_base;
1019f0d53e88SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1020f0d53e88SKishon Vijay Abraham I u32 val;
1021f0d53e88SKishon Vijay Abraham I
1022f0d53e88SKishon Vijay Abraham I mmc_base = priv->base_addr;
1023f0d53e88SKishon Vijay Abraham I
1024f0d53e88SKishon Vijay Abraham I val = readl(&mmc_base->con);
1025f0d53e88SKishon Vijay Abraham I val &= ~DMA_MASTER;
1026f0d53e88SKishon Vijay Abraham I writel(val, &mmc_base->con);
1027f0d53e88SKishon Vijay Abraham I
1028f0d53e88SKishon Vijay Abraham I val = readl(&mmc_base->hctl);
1029f0d53e88SKishon Vijay Abraham I val &= ~DMA_SELECT;
1030f0d53e88SKishon Vijay Abraham I writel(val, &mmc_base->hctl);
1031f0d53e88SKishon Vijay Abraham I
1032f0d53e88SKishon Vijay Abraham I kfree(priv->adma_desc_table);
1033f0d53e88SKishon Vijay Abraham I }
1034f0d53e88SKishon Vijay Abraham I #else
1035f0d53e88SKishon Vijay Abraham I #define omap_hsmmc_adma_desc
1036f0d53e88SKishon Vijay Abraham I #define omap_hsmmc_prepare_adma_table
1037f0d53e88SKishon Vijay Abraham I #define omap_hsmmc_prepare_data
1038f0d53e88SKishon Vijay Abraham I #define omap_hsmmc_dma_cleanup
1039f0d53e88SKishon Vijay Abraham I #endif
1040f0d53e88SKishon Vijay Abraham I
1041c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
omap_hsmmc_send_cmd(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)1042ab769f22SPantelis Antoniou static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
1043de941241SSukumar Ghorai struct mmc_data *data)
1044de941241SSukumar Ghorai {
1045ae000e23SJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1046b5511d6cSJean-Jacques Hiblot #else
1047b5511d6cSJean-Jacques Hiblot static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
1048b5511d6cSJean-Jacques Hiblot struct mmc_data *data)
1049b5511d6cSJean-Jacques Hiblot {
1050b5511d6cSJean-Jacques Hiblot struct omap_hsmmc_data *priv = dev_get_priv(dev);
1051f0d53e88SKishon Vijay Abraham I struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
1052f0d53e88SKishon Vijay Abraham I struct mmc *mmc = upriv->mmc;
1053f0d53e88SKishon Vijay Abraham I #endif
1054cc22b0c0SNikita Kiryanov struct hsmmc *mmc_base;
1055de941241SSukumar Ghorai unsigned int flags, mmc_stat;
1056eb9a28f6SNishanth Menon ulong start;
105704f9f8beSJean-Jacques Hiblot priv->last_cmd = cmd->cmdidx;
1058de941241SSukumar Ghorai
1059ae000e23SJean-Jacques Hiblot mmc_base = priv->base_addr;
1060866bb984SKishon Vijay Abraham I
1061866bb984SKishon Vijay Abraham I if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
1062866bb984SKishon Vijay Abraham I return 0;
1063866bb984SKishon Vijay Abraham I
1064eb9a28f6SNishanth Menon start = get_timer(0);
1065a7778f8fSTom Rini while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
1066eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
1067a7778f8fSTom Rini printf("%s: timedout waiting on cmd inhibit to clear\n",
1068a7778f8fSTom Rini __func__);
1069915ffa52SJaehoon Chung return -ETIMEDOUT;
1070eb9a28f6SNishanth Menon }
1071eb9a28f6SNishanth Menon }
1072de941241SSukumar Ghorai writel(0xFFFFFFFF, &mmc_base->stat);
1073eb9a28f6SNishanth Menon start = get_timer(0);
1074eb9a28f6SNishanth Menon while (readl(&mmc_base->stat)) {
1075eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
107615ceb1deSGrazvydas Ignotas printf("%s: timedout waiting for STAT (%x) to clear\n",
107715ceb1deSGrazvydas Ignotas __func__, readl(&mmc_base->stat));
1078915ffa52SJaehoon Chung return -ETIMEDOUT;
1079eb9a28f6SNishanth Menon }
1080eb9a28f6SNishanth Menon }
1081de941241SSukumar Ghorai /*
1082de941241SSukumar Ghorai * CMDREG
1083de941241SSukumar Ghorai * CMDIDX[13:8] : Command index
1084de941241SSukumar Ghorai * DATAPRNT[5] : Data Present Select
1085de941241SSukumar Ghorai * ENCMDIDX[4] : Command Index Check Enable
1086de941241SSukumar Ghorai * ENCMDCRC[3] : Command CRC Check Enable
1087de941241SSukumar Ghorai * RSPTYP[1:0]
1088de941241SSukumar Ghorai * 00 = No Response
1089de941241SSukumar Ghorai * 01 = Length 136
1090de941241SSukumar Ghorai * 10 = Length 48
1091de941241SSukumar Ghorai * 11 = Length 48 Check busy after response
1092de941241SSukumar Ghorai */
1093de941241SSukumar Ghorai /* Delay added before checking the status of frq change
1094de941241SSukumar Ghorai * retry not supported by mmc.c(core file)
1095de941241SSukumar Ghorai */
1096de941241SSukumar Ghorai if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
1097de941241SSukumar Ghorai udelay(50000); /* wait 50 ms */
1098de941241SSukumar Ghorai
1099de941241SSukumar Ghorai if (!(cmd->resp_type & MMC_RSP_PRESENT))
1100de941241SSukumar Ghorai flags = 0;
1101de941241SSukumar Ghorai else if (cmd->resp_type & MMC_RSP_136)
1102de941241SSukumar Ghorai flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
1103de941241SSukumar Ghorai else if (cmd->resp_type & MMC_RSP_BUSY)
1104de941241SSukumar Ghorai flags = RSP_TYPE_LGHT48B;
1105de941241SSukumar Ghorai else
1106de941241SSukumar Ghorai flags = RSP_TYPE_LGHT48;
1107de941241SSukumar Ghorai
1108de941241SSukumar Ghorai /* enable default flags */
1109de941241SSukumar Ghorai flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
111029171dcfSKishon Vijay Abraham I MSBS_SGLEBLK);
111129171dcfSKishon Vijay Abraham I flags &= ~(ACEN_ENABLE | BCE_ENABLE | DE_ENABLE);
1112de941241SSukumar Ghorai
1113de941241SSukumar Ghorai if (cmd->resp_type & MMC_RSP_CRC)
1114de941241SSukumar Ghorai flags |= CCCE_CHECK;
1115de941241SSukumar Ghorai if (cmd->resp_type & MMC_RSP_OPCODE)
1116de941241SSukumar Ghorai flags |= CICE_CHECK;
1117de941241SSukumar Ghorai
1118de941241SSukumar Ghorai if (data) {
1119de941241SSukumar Ghorai if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
1120de941241SSukumar Ghorai (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
1121866bb984SKishon Vijay Abraham I flags |= (MSBS_MULTIBLK | BCE_ENABLE | ACEN_ENABLE);
1122de941241SSukumar Ghorai data->blocksize = 512;
1123de941241SSukumar Ghorai writel(data->blocksize | (data->blocks << 16),
1124de941241SSukumar Ghorai &mmc_base->blk);
1125de941241SSukumar Ghorai } else
1126de941241SSukumar Ghorai writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
1127de941241SSukumar Ghorai
1128de941241SSukumar Ghorai if (data->flags & MMC_DATA_READ)
1129de941241SSukumar Ghorai flags |= (DP_DATA | DDIR_READ);
1130de941241SSukumar Ghorai else
1131de941241SSukumar Ghorai flags |= (DP_DATA | DDIR_WRITE);
1132f0d53e88SKishon Vijay Abraham I
113327a4b3bcSJean-Jacques Hiblot #ifdef CONFIG_MMC_OMAP_HS_ADMA
1134f0d53e88SKishon Vijay Abraham I if ((priv->controller_flags & OMAP_HSMMC_USE_ADMA) &&
1135f0d53e88SKishon Vijay Abraham I !mmc_is_tuning_cmd(cmd->cmdidx)) {
1136f0d53e88SKishon Vijay Abraham I omap_hsmmc_prepare_data(mmc, data);
1137f0d53e88SKishon Vijay Abraham I flags |= DE_ENABLE;
1138f0d53e88SKishon Vijay Abraham I }
1139f0d53e88SKishon Vijay Abraham I #endif
1140de941241SSukumar Ghorai }
1141de941241SSukumar Ghorai
11422faa1a30SJean-Jacques Hiblot mmc_enable_irq(mmc, cmd);
11432faa1a30SJean-Jacques Hiblot
1144de941241SSukumar Ghorai writel(cmd->cmdarg, &mmc_base->arg);
1145152ba363SLubomir Popov udelay(20); /* To fix "No status update" error on eMMC */
1146de941241SSukumar Ghorai writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
1147de941241SSukumar Ghorai
1148eb9a28f6SNishanth Menon start = get_timer(0);
1149de941241SSukumar Ghorai do {
1150de941241SSukumar Ghorai mmc_stat = readl(&mmc_base->stat);
1151f0d53e88SKishon Vijay Abraham I if (get_timer(start) > MAX_RETRY_MS) {
1152de941241SSukumar Ghorai printf("%s : timeout: No status update\n", __func__);
1153915ffa52SJaehoon Chung return -ETIMEDOUT;
1154de941241SSukumar Ghorai }
1155eb9a28f6SNishanth Menon } while (!mmc_stat);
1156de941241SSukumar Ghorai
115725c719e2SGrazvydas Ignotas if ((mmc_stat & IE_CTO) != 0) {
115825c719e2SGrazvydas Ignotas mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
1159915ffa52SJaehoon Chung return -ETIMEDOUT;
116025c719e2SGrazvydas Ignotas } else if ((mmc_stat & ERRI_MASK) != 0)
1161de941241SSukumar Ghorai return -1;
1162de941241SSukumar Ghorai
1163de941241SSukumar Ghorai if (mmc_stat & CC_MASK) {
1164de941241SSukumar Ghorai writel(CC_MASK, &mmc_base->stat);
1165de941241SSukumar Ghorai if (cmd->resp_type & MMC_RSP_PRESENT) {
1166de941241SSukumar Ghorai if (cmd->resp_type & MMC_RSP_136) {
1167de941241SSukumar Ghorai /* response type 2 */
1168de941241SSukumar Ghorai cmd->response[3] = readl(&mmc_base->rsp10);
1169de941241SSukumar Ghorai cmd->response[2] = readl(&mmc_base->rsp32);
1170de941241SSukumar Ghorai cmd->response[1] = readl(&mmc_base->rsp54);
1171de941241SSukumar Ghorai cmd->response[0] = readl(&mmc_base->rsp76);
1172de941241SSukumar Ghorai } else
1173de941241SSukumar Ghorai /* response types 1, 1b, 3, 4, 5, 6 */
1174de941241SSukumar Ghorai cmd->response[0] = readl(&mmc_base->rsp10);
1175de941241SSukumar Ghorai }
1176de941241SSukumar Ghorai }
1177de941241SSukumar Ghorai
117827a4b3bcSJean-Jacques Hiblot #ifdef CONFIG_MMC_OMAP_HS_ADMA
1179f0d53e88SKishon Vijay Abraham I if ((priv->controller_flags & OMAP_HSMMC_USE_ADMA) && data &&
1180f0d53e88SKishon Vijay Abraham I !mmc_is_tuning_cmd(cmd->cmdidx)) {
1181f0d53e88SKishon Vijay Abraham I u32 sz_mb, timeout;
1182f0d53e88SKishon Vijay Abraham I
1183f0d53e88SKishon Vijay Abraham I if (mmc_stat & IE_ADMAE) {
1184f0d53e88SKishon Vijay Abraham I omap_hsmmc_dma_cleanup(mmc);
1185f0d53e88SKishon Vijay Abraham I return -EIO;
1186f0d53e88SKishon Vijay Abraham I }
1187f0d53e88SKishon Vijay Abraham I
1188f0d53e88SKishon Vijay Abraham I sz_mb = DIV_ROUND_UP(data->blocksize * data->blocks, 1 << 20);
1189f0d53e88SKishon Vijay Abraham I timeout = sz_mb * DMA_TIMEOUT_PER_MB;
1190f0d53e88SKishon Vijay Abraham I if (timeout < MAX_RETRY_MS)
1191f0d53e88SKishon Vijay Abraham I timeout = MAX_RETRY_MS;
1192f0d53e88SKishon Vijay Abraham I
1193f0d53e88SKishon Vijay Abraham I start = get_timer(0);
1194f0d53e88SKishon Vijay Abraham I do {
1195f0d53e88SKishon Vijay Abraham I mmc_stat = readl(&mmc_base->stat);
1196f0d53e88SKishon Vijay Abraham I if (mmc_stat & TC_MASK) {
1197f0d53e88SKishon Vijay Abraham I writel(readl(&mmc_base->stat) | TC_MASK,
1198f0d53e88SKishon Vijay Abraham I &mmc_base->stat);
1199f0d53e88SKishon Vijay Abraham I break;
1200f0d53e88SKishon Vijay Abraham I }
1201f0d53e88SKishon Vijay Abraham I if (get_timer(start) > timeout) {
1202f0d53e88SKishon Vijay Abraham I printf("%s : DMA timeout: No status update\n",
1203f0d53e88SKishon Vijay Abraham I __func__);
1204f0d53e88SKishon Vijay Abraham I return -ETIMEDOUT;
1205f0d53e88SKishon Vijay Abraham I }
1206f0d53e88SKishon Vijay Abraham I } while (1);
1207f0d53e88SKishon Vijay Abraham I
1208f0d53e88SKishon Vijay Abraham I omap_hsmmc_dma_cleanup(mmc);
1209f0d53e88SKishon Vijay Abraham I return 0;
1210f0d53e88SKishon Vijay Abraham I }
1211f0d53e88SKishon Vijay Abraham I #endif
1212f0d53e88SKishon Vijay Abraham I
1213de941241SSukumar Ghorai if (data && (data->flags & MMC_DATA_READ)) {
1214de941241SSukumar Ghorai mmc_read_data(mmc_base, data->dest,
1215de941241SSukumar Ghorai data->blocksize * data->blocks);
1216de941241SSukumar Ghorai } else if (data && (data->flags & MMC_DATA_WRITE)) {
1217de941241SSukumar Ghorai mmc_write_data(mmc_base, data->src,
1218de941241SSukumar Ghorai data->blocksize * data->blocks);
1219de941241SSukumar Ghorai }
1220de941241SSukumar Ghorai return 0;
1221de941241SSukumar Ghorai }
1222de941241SSukumar Ghorai
1223933efe64SSricharan static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
1224de941241SSukumar Ghorai {
1225de941241SSukumar Ghorai unsigned int *output_buf = (unsigned int *)buf;
1226de941241SSukumar Ghorai unsigned int mmc_stat;
1227de941241SSukumar Ghorai unsigned int count;
1228de941241SSukumar Ghorai
1229de941241SSukumar Ghorai /*
1230de941241SSukumar Ghorai * Start Polled Read
1231de941241SSukumar Ghorai */
1232de941241SSukumar Ghorai count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
1233de941241SSukumar Ghorai count /= 4;
1234de941241SSukumar Ghorai
1235de941241SSukumar Ghorai while (size) {
1236eb9a28f6SNishanth Menon ulong start = get_timer(0);
1237de941241SSukumar Ghorai do {
1238de941241SSukumar Ghorai mmc_stat = readl(&mmc_base->stat);
1239eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
1240eb9a28f6SNishanth Menon printf("%s: timedout waiting for status!\n",
1241eb9a28f6SNishanth Menon __func__);
1242915ffa52SJaehoon Chung return -ETIMEDOUT;
1243eb9a28f6SNishanth Menon }
1244de941241SSukumar Ghorai } while (mmc_stat == 0);
1245de941241SSukumar Ghorai
124625c719e2SGrazvydas Ignotas if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
124725c719e2SGrazvydas Ignotas mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
124825c719e2SGrazvydas Ignotas
1249de941241SSukumar Ghorai if ((mmc_stat & ERRI_MASK) != 0)
1250de941241SSukumar Ghorai return 1;
1251de941241SSukumar Ghorai
1252de941241SSukumar Ghorai if (mmc_stat & BRR_MASK) {
1253de941241SSukumar Ghorai unsigned int k;
1254de941241SSukumar Ghorai
1255de941241SSukumar Ghorai writel(readl(&mmc_base->stat) | BRR_MASK,
1256de941241SSukumar Ghorai &mmc_base->stat);
1257de941241SSukumar Ghorai for (k = 0; k < count; k++) {
1258de941241SSukumar Ghorai *output_buf = readl(&mmc_base->data);
1259de941241SSukumar Ghorai output_buf++;
1260de941241SSukumar Ghorai }
1261de941241SSukumar Ghorai size -= (count*4);
1262de941241SSukumar Ghorai }
1263de941241SSukumar Ghorai
1264de941241SSukumar Ghorai if (mmc_stat & BWR_MASK)
1265de941241SSukumar Ghorai writel(readl(&mmc_base->stat) | BWR_MASK,
1266de941241SSukumar Ghorai &mmc_base->stat);
1267de941241SSukumar Ghorai
1268de941241SSukumar Ghorai if (mmc_stat & TC_MASK) {
1269de941241SSukumar Ghorai writel(readl(&mmc_base->stat) | TC_MASK,
1270de941241SSukumar Ghorai &mmc_base->stat);
1271de941241SSukumar Ghorai break;
1272de941241SSukumar Ghorai }
1273de941241SSukumar Ghorai }
1274de941241SSukumar Ghorai return 0;
1275de941241SSukumar Ghorai }
1276de941241SSukumar Ghorai
1277c7d08d80SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
1278933efe64SSricharan static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
1279933efe64SSricharan unsigned int size)
1280de941241SSukumar Ghorai {
1281de941241SSukumar Ghorai unsigned int *input_buf = (unsigned int *)buf;
1282de941241SSukumar Ghorai unsigned int mmc_stat;
1283de941241SSukumar Ghorai unsigned int count;
1284de941241SSukumar Ghorai
1285de941241SSukumar Ghorai /*
1286152ba363SLubomir Popov * Start Polled Write
1287de941241SSukumar Ghorai */
1288de941241SSukumar Ghorai count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
1289de941241SSukumar Ghorai count /= 4;
1290de941241SSukumar Ghorai
1291de941241SSukumar Ghorai while (size) {
1292eb9a28f6SNishanth Menon ulong start = get_timer(0);
1293de941241SSukumar Ghorai do {
1294de941241SSukumar Ghorai mmc_stat = readl(&mmc_base->stat);
1295eb9a28f6SNishanth Menon if (get_timer(0) - start > MAX_RETRY_MS) {
1296eb9a28f6SNishanth Menon printf("%s: timedout waiting for status!\n",
1297eb9a28f6SNishanth Menon __func__);
1298915ffa52SJaehoon Chung return -ETIMEDOUT;
1299eb9a28f6SNishanth Menon }
1300de941241SSukumar Ghorai } while (mmc_stat == 0);
1301de941241SSukumar Ghorai
130225c719e2SGrazvydas Ignotas if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
130325c719e2SGrazvydas Ignotas mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
130425c719e2SGrazvydas Ignotas
1305de941241SSukumar Ghorai if ((mmc_stat & ERRI_MASK) != 0)
1306de941241SSukumar Ghorai return 1;
1307de941241SSukumar Ghorai
1308de941241SSukumar Ghorai if (mmc_stat & BWR_MASK) {
1309de941241SSukumar Ghorai unsigned int k;
1310de941241SSukumar Ghorai
1311de941241SSukumar Ghorai writel(readl(&mmc_base->stat) | BWR_MASK,
1312de941241SSukumar Ghorai &mmc_base->stat);
1313de941241SSukumar Ghorai for (k = 0; k < count; k++) {
1314de941241SSukumar Ghorai writel(*input_buf, &mmc_base->data);
1315de941241SSukumar Ghorai input_buf++;
1316de941241SSukumar Ghorai }
1317de941241SSukumar Ghorai size -= (count*4);
1318de941241SSukumar Ghorai }
1319de941241SSukumar Ghorai
1320de941241SSukumar Ghorai if (mmc_stat & BRR_MASK)
1321de941241SSukumar Ghorai writel(readl(&mmc_base->stat) | BRR_MASK,
1322de941241SSukumar Ghorai &mmc_base->stat);
1323de941241SSukumar Ghorai
1324de941241SSukumar Ghorai if (mmc_stat & TC_MASK) {
1325de941241SSukumar Ghorai writel(readl(&mmc_base->stat) | TC_MASK,
1326de941241SSukumar Ghorai &mmc_base->stat);
1327de941241SSukumar Ghorai break;
1328de941241SSukumar Ghorai }
1329de941241SSukumar Ghorai }
1330de941241SSukumar Ghorai return 0;
1331de941241SSukumar Ghorai }
1332c7d08d80SJean-Jacques Hiblot #else
1333c7d08d80SJean-Jacques Hiblot static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
1334c7d08d80SJean-Jacques Hiblot unsigned int size)
1335c7d08d80SJean-Jacques Hiblot {
1336c7d08d80SJean-Jacques Hiblot return -ENOTSUPP;
1337c7d08d80SJean-Jacques Hiblot }
1338c7d08d80SJean-Jacques Hiblot #endif
13395baf543eSJean-Jacques Hiblot static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base)
13405baf543eSJean-Jacques Hiblot {
13415baf543eSJean-Jacques Hiblot writel(readl(&mmc_base->sysctl) & ~CEN_ENABLE, &mmc_base->sysctl);
13425baf543eSJean-Jacques Hiblot }
13435baf543eSJean-Jacques Hiblot
13445baf543eSJean-Jacques Hiblot static void omap_hsmmc_start_clock(struct hsmmc *mmc_base)
13455baf543eSJean-Jacques Hiblot {
13465baf543eSJean-Jacques Hiblot writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
13475baf543eSJean-Jacques Hiblot }
13485baf543eSJean-Jacques Hiblot
13495baf543eSJean-Jacques Hiblot static void omap_hsmmc_set_clock(struct mmc *mmc)
13505baf543eSJean-Jacques Hiblot {
13515baf543eSJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
13525baf543eSJean-Jacques Hiblot struct hsmmc *mmc_base;
13535baf543eSJean-Jacques Hiblot unsigned int dsor = 0;
13545baf543eSJean-Jacques Hiblot ulong start;
13555baf543eSJean-Jacques Hiblot
13565baf543eSJean-Jacques Hiblot mmc_base = priv->base_addr;
13575baf543eSJean-Jacques Hiblot omap_hsmmc_stop_clock(mmc_base);
13585baf543eSJean-Jacques Hiblot
13595baf543eSJean-Jacques Hiblot /* TODO: Is setting DTO required here? */
13605baf543eSJean-Jacques Hiblot mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK),
13615baf543eSJean-Jacques Hiblot (ICE_STOP | DTO_15THDTO));
13625baf543eSJean-Jacques Hiblot
13635baf543eSJean-Jacques Hiblot if (mmc->clock != 0) {
13645baf543eSJean-Jacques Hiblot dsor = DIV_ROUND_UP(MMC_CLOCK_REFERENCE * 1000000, mmc->clock);
13655baf543eSJean-Jacques Hiblot if (dsor > CLKD_MAX)
13665baf543eSJean-Jacques Hiblot dsor = CLKD_MAX;
13675baf543eSJean-Jacques Hiblot } else {
13685baf543eSJean-Jacques Hiblot dsor = CLKD_MAX;
13695baf543eSJean-Jacques Hiblot }
13705baf543eSJean-Jacques Hiblot
13715baf543eSJean-Jacques Hiblot mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
13725baf543eSJean-Jacques Hiblot (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
13735baf543eSJean-Jacques Hiblot
13745baf543eSJean-Jacques Hiblot start = get_timer(0);
13755baf543eSJean-Jacques Hiblot while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
13765baf543eSJean-Jacques Hiblot if (get_timer(0) - start > MAX_RETRY_MS) {
13775baf543eSJean-Jacques Hiblot printf("%s: timedout waiting for ics!\n", __func__);
13785baf543eSJean-Jacques Hiblot return;
13795baf543eSJean-Jacques Hiblot }
13805baf543eSJean-Jacques Hiblot }
13815baf543eSJean-Jacques Hiblot
13823149c13aSJean-Jacques Hiblot priv->clock = MMC_CLOCK_REFERENCE * 1000000 / dsor;
13833149c13aSJean-Jacques Hiblot mmc->clock = priv->clock;
13845baf543eSJean-Jacques Hiblot omap_hsmmc_start_clock(mmc_base);
13855baf543eSJean-Jacques Hiblot }
13865baf543eSJean-Jacques Hiblot
138748a2f114SKishon Vijay Abraham I static void omap_hsmmc_set_bus_width(struct mmc *mmc)
1388de941241SSukumar Ghorai {
1389ae000e23SJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1390cc22b0c0SNikita Kiryanov struct hsmmc *mmc_base;
1391de941241SSukumar Ghorai
1392ae000e23SJean-Jacques Hiblot mmc_base = priv->base_addr;
1393de941241SSukumar Ghorai /* configue bus width */
1394de941241SSukumar Ghorai switch (mmc->bus_width) {
1395de941241SSukumar Ghorai case 8:
1396de941241SSukumar Ghorai writel(readl(&mmc_base->con) | DTW_8_BITMODE,
1397de941241SSukumar Ghorai &mmc_base->con);
1398de941241SSukumar Ghorai break;
1399de941241SSukumar Ghorai
1400de941241SSukumar Ghorai case 4:
1401de941241SSukumar Ghorai writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
1402de941241SSukumar Ghorai &mmc_base->con);
1403de941241SSukumar Ghorai writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
1404de941241SSukumar Ghorai &mmc_base->hctl);
1405de941241SSukumar Ghorai break;
1406de941241SSukumar Ghorai
1407de941241SSukumar Ghorai case 1:
1408de941241SSukumar Ghorai default:
1409de941241SSukumar Ghorai writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
1410de941241SSukumar Ghorai &mmc_base->con);
1411de941241SSukumar Ghorai writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
1412de941241SSukumar Ghorai &mmc_base->hctl);
1413de941241SSukumar Ghorai break;
1414de941241SSukumar Ghorai }
1415de941241SSukumar Ghorai
141648a2f114SKishon Vijay Abraham I priv->bus_width = mmc->bus_width;
141748a2f114SKishon Vijay Abraham I }
141848a2f114SKishon Vijay Abraham I
141948a2f114SKishon Vijay Abraham I #if !CONFIG_IS_ENABLED(DM_MMC)
142048a2f114SKishon Vijay Abraham I static int omap_hsmmc_set_ios(struct mmc *mmc)
142148a2f114SKishon Vijay Abraham I {
142248a2f114SKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
142348a2f114SKishon Vijay Abraham I #else
142448a2f114SKishon Vijay Abraham I static int omap_hsmmc_set_ios(struct udevice *dev)
142548a2f114SKishon Vijay Abraham I {
142648a2f114SKishon Vijay Abraham I struct omap_hsmmc_data *priv = dev_get_priv(dev);
142748a2f114SKishon Vijay Abraham I struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
142848a2f114SKishon Vijay Abraham I struct mmc *mmc = upriv->mmc;
142948a2f114SKishon Vijay Abraham I #endif
143090321dceSKishon Vijay Abraham I struct hsmmc *mmc_base = priv->base_addr;
143104f9f8beSJean-Jacques Hiblot int ret = 0;
143248a2f114SKishon Vijay Abraham I
143348a2f114SKishon Vijay Abraham I if (priv->bus_width != mmc->bus_width)
143448a2f114SKishon Vijay Abraham I omap_hsmmc_set_bus_width(mmc);
143548a2f114SKishon Vijay Abraham I
14365baf543eSJean-Jacques Hiblot if (priv->clock != mmc->clock)
14375baf543eSJean-Jacques Hiblot omap_hsmmc_set_clock(mmc);
143807b0b9c0SJaehoon Chung
143990321dceSKishon Vijay Abraham I if (mmc->clk_disable)
144090321dceSKishon Vijay Abraham I omap_hsmmc_stop_clock(mmc_base);
144190321dceSKishon Vijay Abraham I else
144290321dceSKishon Vijay Abraham I omap_hsmmc_start_clock(mmc_base);
144390321dceSKishon Vijay Abraham I
14448fc238bfSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_MMC)
14458fc238bfSJean-Jacques Hiblot if (priv->mode != mmc->selected_mode)
14468fc238bfSJean-Jacques Hiblot omap_hsmmc_set_timing(mmc);
144704f9f8beSJean-Jacques Hiblot
144804f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
144904f9f8beSJean-Jacques Hiblot if (priv->signal_voltage != mmc->signal_voltage)
145004f9f8beSJean-Jacques Hiblot ret = omap_hsmmc_set_signal_voltage(mmc);
14518fc238bfSJean-Jacques Hiblot #endif
145204f9f8beSJean-Jacques Hiblot #endif
145304f9f8beSJean-Jacques Hiblot return ret;
1454de941241SSukumar Ghorai }
1455de941241SSukumar Ghorai
1456ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
1457c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
1458b5511d6cSJean-Jacques Hiblot static int omap_hsmmc_getcd(struct udevice *dev)
1459a9d6a7e2SMugunthan V N {
1460307a2143SAdam Ford int value = -1;
1461307a2143SAdam Ford #if CONFIG_IS_ENABLED(DM_GPIO)
1462f4df405fSAdam Ford struct omap_hsmmc_data *priv = dev_get_priv(dev);
1463a9d6a7e2SMugunthan V N value = dm_gpio_get_value(&priv->cd_gpio);
1464307a2143SAdam Ford #endif
1465a9d6a7e2SMugunthan V N /* if no CD return as 1 */
1466a9d6a7e2SMugunthan V N if (value < 0)
1467a9d6a7e2SMugunthan V N return 1;
1468a9d6a7e2SMugunthan V N
1469a9d6a7e2SMugunthan V N return value;
1470a9d6a7e2SMugunthan V N }
1471a9d6a7e2SMugunthan V N
1472b5511d6cSJean-Jacques Hiblot static int omap_hsmmc_getwp(struct udevice *dev)
1473a9d6a7e2SMugunthan V N {
1474307a2143SAdam Ford int value = 0;
1475307a2143SAdam Ford #if CONFIG_IS_ENABLED(DM_GPIO)
1476b5511d6cSJean-Jacques Hiblot struct omap_hsmmc_data *priv = dev_get_priv(dev);
1477a9d6a7e2SMugunthan V N value = dm_gpio_get_value(&priv->wp_gpio);
1478307a2143SAdam Ford #endif
1479a9d6a7e2SMugunthan V N /* if no WP return as 0 */
1480a9d6a7e2SMugunthan V N if (value < 0)
1481a9d6a7e2SMugunthan V N return 0;
1482a9d6a7e2SMugunthan V N return value;
1483a9d6a7e2SMugunthan V N }
1484a9d6a7e2SMugunthan V N #else
1485ab769f22SPantelis Antoniou static int omap_hsmmc_getcd(struct mmc *mmc)
1486ab769f22SPantelis Antoniou {
1487ae000e23SJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1488ab769f22SPantelis Antoniou int cd_gpio;
1489ab769f22SPantelis Antoniou
1490ab769f22SPantelis Antoniou /* if no CD return as 1 */
1491ae000e23SJean-Jacques Hiblot cd_gpio = priv->cd_gpio;
1492ab769f22SPantelis Antoniou if (cd_gpio < 0)
1493ab769f22SPantelis Antoniou return 1;
1494ab769f22SPantelis Antoniou
14950b03a931SIgor Grinberg /* NOTE: assumes card detect signal is active-low */
14960b03a931SIgor Grinberg return !gpio_get_value(cd_gpio);
1497ab769f22SPantelis Antoniou }
1498ab769f22SPantelis Antoniou
1499ab769f22SPantelis Antoniou static int omap_hsmmc_getwp(struct mmc *mmc)
1500ab769f22SPantelis Antoniou {
1501ae000e23SJean-Jacques Hiblot struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
1502ab769f22SPantelis Antoniou int wp_gpio;
1503ab769f22SPantelis Antoniou
1504ab769f22SPantelis Antoniou /* if no WP return as 0 */
1505ae000e23SJean-Jacques Hiblot wp_gpio = priv->wp_gpio;
1506ab769f22SPantelis Antoniou if (wp_gpio < 0)
1507ab769f22SPantelis Antoniou return 0;
1508ab769f22SPantelis Antoniou
15090b03a931SIgor Grinberg /* NOTE: assumes write protect signal is active-high */
1510ab769f22SPantelis Antoniou return gpio_get_value(wp_gpio);
1511ab769f22SPantelis Antoniou }
1512ab769f22SPantelis Antoniou #endif
1513a9d6a7e2SMugunthan V N #endif
1514ab769f22SPantelis Antoniou
1515c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
1516b5511d6cSJean-Jacques Hiblot static const struct dm_mmc_ops omap_hsmmc_ops = {
1517b5511d6cSJean-Jacques Hiblot .send_cmd = omap_hsmmc_send_cmd,
1518b5511d6cSJean-Jacques Hiblot .set_ios = omap_hsmmc_set_ios,
1519b5511d6cSJean-Jacques Hiblot #ifdef OMAP_HSMMC_USE_GPIO
1520b5511d6cSJean-Jacques Hiblot .get_cd = omap_hsmmc_getcd,
1521b5511d6cSJean-Jacques Hiblot .get_wp = omap_hsmmc_getwp,
1522b5511d6cSJean-Jacques Hiblot #endif
152314761caeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
152414761caeSJean-Jacques Hiblot .execute_tuning = omap_hsmmc_execute_tuning,
152514761caeSJean-Jacques Hiblot #endif
152642182c9bSJean-Jacques Hiblot .send_init_stream = omap_hsmmc_send_init_stream,
152704f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
152804f9f8beSJean-Jacques Hiblot .wait_dat0 = omap_hsmmc_wait_dat0,
152904f9f8beSJean-Jacques Hiblot #endif
1530b5511d6cSJean-Jacques Hiblot };
1531b5511d6cSJean-Jacques Hiblot #else
1532ab769f22SPantelis Antoniou static const struct mmc_ops omap_hsmmc_ops = {
1533ab769f22SPantelis Antoniou .send_cmd = omap_hsmmc_send_cmd,
1534ab769f22SPantelis Antoniou .set_ios = omap_hsmmc_set_ios,
1535ab769f22SPantelis Antoniou .init = omap_hsmmc_init_setup,
1536ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
1537ab769f22SPantelis Antoniou .getcd = omap_hsmmc_getcd,
1538ab769f22SPantelis Antoniou .getwp = omap_hsmmc_getwp,
1539ab769f22SPantelis Antoniou #endif
1540ab769f22SPantelis Antoniou };
1541b5511d6cSJean-Jacques Hiblot #endif
1542ab769f22SPantelis Antoniou
1543c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1544e3913f56SNikita Kiryanov int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
1545e3913f56SNikita Kiryanov int wp_gpio)
1546de941241SSukumar Ghorai {
154793bfd616SPantelis Antoniou struct mmc *mmc;
1548ae000e23SJean-Jacques Hiblot struct omap_hsmmc_data *priv;
154993bfd616SPantelis Antoniou struct mmc_config *cfg;
155093bfd616SPantelis Antoniou uint host_caps_val;
1551de941241SSukumar Ghorai
15524a41fec5SAlex Kiernan priv = calloc(1, sizeof(*priv));
1553ae000e23SJean-Jacques Hiblot if (priv == NULL)
155493bfd616SPantelis Antoniou return -1;
155593bfd616SPantelis Antoniou
15565a20397bSRob Herring host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
1557de941241SSukumar Ghorai
1558de941241SSukumar Ghorai switch (dev_index) {
1559de941241SSukumar Ghorai case 0:
1560ae000e23SJean-Jacques Hiblot priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
1561de941241SSukumar Ghorai break;
15621037d585STom Rini #ifdef OMAP_HSMMC2_BASE
1563de941241SSukumar Ghorai case 1:
1564ae000e23SJean-Jacques Hiblot priv->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
1565152ba363SLubomir Popov #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
15663891a54fSNishanth Menon defined(CONFIG_DRA7XX) || defined(CONFIG_AM33XX) || \
15673b68939fSRoger Quadros defined(CONFIG_AM43XX) || defined(CONFIG_SOC_KEYSTONE)) && \
15683b68939fSRoger Quadros defined(CONFIG_HSMMC2_8BIT)
1569152ba363SLubomir Popov /* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
1570152ba363SLubomir Popov host_caps_val |= MMC_MODE_8BIT;
1571152ba363SLubomir Popov #endif
1572de941241SSukumar Ghorai break;
15731037d585STom Rini #endif
15741037d585STom Rini #ifdef OMAP_HSMMC3_BASE
1575de941241SSukumar Ghorai case 2:
1576ae000e23SJean-Jacques Hiblot priv->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
15773891a54fSNishanth Menon #if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT)
1578152ba363SLubomir Popov /* Enable 8-bit interface for eMMC on DRA7XX */
1579152ba363SLubomir Popov host_caps_val |= MMC_MODE_8BIT;
1580152ba363SLubomir Popov #endif
1581de941241SSukumar Ghorai break;
15821037d585STom Rini #endif
1583de941241SSukumar Ghorai default:
1584ae000e23SJean-Jacques Hiblot priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
1585de941241SSukumar Ghorai return 1;
1586de941241SSukumar Ghorai }
1587ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
1588ab769f22SPantelis Antoniou /* on error gpio values are set to -1, which is what we want */
1589ae000e23SJean-Jacques Hiblot priv->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
1590ae000e23SJean-Jacques Hiblot priv->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
1591ab769f22SPantelis Antoniou #endif
1592173ddc5bSPeter Korsgaard
1593ae000e23SJean-Jacques Hiblot cfg = &priv->cfg;
1594de941241SSukumar Ghorai
159593bfd616SPantelis Antoniou cfg->name = "OMAP SD/MMC";
159693bfd616SPantelis Antoniou cfg->ops = &omap_hsmmc_ops;
159793bfd616SPantelis Antoniou
159893bfd616SPantelis Antoniou cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
159993bfd616SPantelis Antoniou cfg->host_caps = host_caps_val & ~host_caps_mask;
160093bfd616SPantelis Antoniou
160193bfd616SPantelis Antoniou cfg->f_min = 400000;
1602bbbc1ae9SJonathan Solnit
1603bbbc1ae9SJonathan Solnit if (f_max != 0)
160493bfd616SPantelis Antoniou cfg->f_max = f_max;
1605bbbc1ae9SJonathan Solnit else {
160693bfd616SPantelis Antoniou if (cfg->host_caps & MMC_MODE_HS) {
160793bfd616SPantelis Antoniou if (cfg->host_caps & MMC_MODE_HS_52MHz)
160893bfd616SPantelis Antoniou cfg->f_max = 52000000;
1609bbbc1ae9SJonathan Solnit else
161093bfd616SPantelis Antoniou cfg->f_max = 26000000;
1611bbbc1ae9SJonathan Solnit } else
161293bfd616SPantelis Antoniou cfg->f_max = 20000000;
1613bbbc1ae9SJonathan Solnit }
1614de941241SSukumar Ghorai
161593bfd616SPantelis Antoniou cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
16168feafcc4SJohn Rigby
16174ca9244dSJohn Rigby #if defined(CONFIG_OMAP34XX)
16184ca9244dSJohn Rigby /*
16194ca9244dSJohn Rigby * Silicon revs 2.1 and older do not support multiblock transfers.
16204ca9244dSJohn Rigby */
16214ca9244dSJohn Rigby if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
162293bfd616SPantelis Antoniou cfg->b_max = 1;
16234ca9244dSJohn Rigby #endif
16242d28eedaSKishon Vijay Abraham I
1625ae000e23SJean-Jacques Hiblot mmc = mmc_create(cfg, priv);
162693bfd616SPantelis Antoniou if (mmc == NULL)
162793bfd616SPantelis Antoniou return -1;
1628de941241SSukumar Ghorai
1629de941241SSukumar Ghorai return 0;
1630de941241SSukumar Ghorai }
1631a9d6a7e2SMugunthan V N #else
163233c1d77fSKishon Vijay Abraham I
163333c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
163433c1d77fSKishon Vijay Abraham I static struct pad_conf_entry *
163533c1d77fSKishon Vijay Abraham I omap_hsmmc_get_pad_conf_entry(const fdt32_t *pinctrl, int count)
163633c1d77fSKishon Vijay Abraham I {
163733c1d77fSKishon Vijay Abraham I int index = 0;
163833c1d77fSKishon Vijay Abraham I struct pad_conf_entry *padconf;
163933c1d77fSKishon Vijay Abraham I
164033c1d77fSKishon Vijay Abraham I padconf = (struct pad_conf_entry *)malloc(sizeof(*padconf) * count);
164133c1d77fSKishon Vijay Abraham I if (!padconf) {
164233c1d77fSKishon Vijay Abraham I debug("failed to allocate memory\n");
164333c1d77fSKishon Vijay Abraham I return 0;
164433c1d77fSKishon Vijay Abraham I }
164533c1d77fSKishon Vijay Abraham I
164633c1d77fSKishon Vijay Abraham I while (index < count) {
164733c1d77fSKishon Vijay Abraham I padconf[index].offset = fdt32_to_cpu(pinctrl[2 * index]);
164833c1d77fSKishon Vijay Abraham I padconf[index].val = fdt32_to_cpu(pinctrl[2 * index + 1]);
164933c1d77fSKishon Vijay Abraham I index++;
165033c1d77fSKishon Vijay Abraham I }
165133c1d77fSKishon Vijay Abraham I
165233c1d77fSKishon Vijay Abraham I return padconf;
165333c1d77fSKishon Vijay Abraham I }
165433c1d77fSKishon Vijay Abraham I
165533c1d77fSKishon Vijay Abraham I static struct iodelay_cfg_entry *
165633c1d77fSKishon Vijay Abraham I omap_hsmmc_get_iodelay_cfg_entry(const fdt32_t *pinctrl, int count)
165733c1d77fSKishon Vijay Abraham I {
165833c1d77fSKishon Vijay Abraham I int index = 0;
165933c1d77fSKishon Vijay Abraham I struct iodelay_cfg_entry *iodelay;
166033c1d77fSKishon Vijay Abraham I
166133c1d77fSKishon Vijay Abraham I iodelay = (struct iodelay_cfg_entry *)malloc(sizeof(*iodelay) * count);
166233c1d77fSKishon Vijay Abraham I if (!iodelay) {
166333c1d77fSKishon Vijay Abraham I debug("failed to allocate memory\n");
166433c1d77fSKishon Vijay Abraham I return 0;
166533c1d77fSKishon Vijay Abraham I }
166633c1d77fSKishon Vijay Abraham I
166733c1d77fSKishon Vijay Abraham I while (index < count) {
166833c1d77fSKishon Vijay Abraham I iodelay[index].offset = fdt32_to_cpu(pinctrl[3 * index]);
166933c1d77fSKishon Vijay Abraham I iodelay[index].a_delay = fdt32_to_cpu(pinctrl[3 * index + 1]);
167033c1d77fSKishon Vijay Abraham I iodelay[index].g_delay = fdt32_to_cpu(pinctrl[3 * index + 2]);
167133c1d77fSKishon Vijay Abraham I index++;
167233c1d77fSKishon Vijay Abraham I }
167333c1d77fSKishon Vijay Abraham I
167433c1d77fSKishon Vijay Abraham I return iodelay;
167533c1d77fSKishon Vijay Abraham I }
167633c1d77fSKishon Vijay Abraham I
167733c1d77fSKishon Vijay Abraham I static const fdt32_t *omap_hsmmc_get_pinctrl_entry(u32 phandle,
167833c1d77fSKishon Vijay Abraham I const char *name, int *len)
167933c1d77fSKishon Vijay Abraham I {
168033c1d77fSKishon Vijay Abraham I const void *fdt = gd->fdt_blob;
168133c1d77fSKishon Vijay Abraham I int offset;
168233c1d77fSKishon Vijay Abraham I const fdt32_t *pinctrl;
168333c1d77fSKishon Vijay Abraham I
168433c1d77fSKishon Vijay Abraham I offset = fdt_node_offset_by_phandle(fdt, phandle);
168533c1d77fSKishon Vijay Abraham I if (offset < 0) {
168633c1d77fSKishon Vijay Abraham I debug("failed to get pinctrl node %s.\n",
168733c1d77fSKishon Vijay Abraham I fdt_strerror(offset));
168833c1d77fSKishon Vijay Abraham I return 0;
168933c1d77fSKishon Vijay Abraham I }
169033c1d77fSKishon Vijay Abraham I
169133c1d77fSKishon Vijay Abraham I pinctrl = fdt_getprop(fdt, offset, name, len);
169233c1d77fSKishon Vijay Abraham I if (!pinctrl) {
169333c1d77fSKishon Vijay Abraham I debug("failed to get property %s\n", name);
169433c1d77fSKishon Vijay Abraham I return 0;
169533c1d77fSKishon Vijay Abraham I }
169633c1d77fSKishon Vijay Abraham I
169733c1d77fSKishon Vijay Abraham I return pinctrl;
169833c1d77fSKishon Vijay Abraham I }
169933c1d77fSKishon Vijay Abraham I
170033c1d77fSKishon Vijay Abraham I static uint32_t omap_hsmmc_get_pad_conf_phandle(struct mmc *mmc,
170133c1d77fSKishon Vijay Abraham I char *prop_name)
170233c1d77fSKishon Vijay Abraham I {
170333c1d77fSKishon Vijay Abraham I const void *fdt = gd->fdt_blob;
170433c1d77fSKishon Vijay Abraham I const __be32 *phandle;
170533c1d77fSKishon Vijay Abraham I int node = dev_of_offset(mmc->dev);
170633c1d77fSKishon Vijay Abraham I
170733c1d77fSKishon Vijay Abraham I phandle = fdt_getprop(fdt, node, prop_name, NULL);
170833c1d77fSKishon Vijay Abraham I if (!phandle) {
170933c1d77fSKishon Vijay Abraham I debug("failed to get property %s\n", prop_name);
171033c1d77fSKishon Vijay Abraham I return 0;
171133c1d77fSKishon Vijay Abraham I }
171233c1d77fSKishon Vijay Abraham I
171333c1d77fSKishon Vijay Abraham I return fdt32_to_cpu(*phandle);
171433c1d77fSKishon Vijay Abraham I }
171533c1d77fSKishon Vijay Abraham I
171633c1d77fSKishon Vijay Abraham I static uint32_t omap_hsmmc_get_iodelay_phandle(struct mmc *mmc,
171733c1d77fSKishon Vijay Abraham I char *prop_name)
171833c1d77fSKishon Vijay Abraham I {
171933c1d77fSKishon Vijay Abraham I const void *fdt = gd->fdt_blob;
172033c1d77fSKishon Vijay Abraham I const __be32 *phandle;
172133c1d77fSKishon Vijay Abraham I int len;
172233c1d77fSKishon Vijay Abraham I int count;
172333c1d77fSKishon Vijay Abraham I int node = dev_of_offset(mmc->dev);
172433c1d77fSKishon Vijay Abraham I
172533c1d77fSKishon Vijay Abraham I phandle = fdt_getprop(fdt, node, prop_name, &len);
172633c1d77fSKishon Vijay Abraham I if (!phandle) {
172733c1d77fSKishon Vijay Abraham I debug("failed to get property %s\n", prop_name);
172833c1d77fSKishon Vijay Abraham I return 0;
172933c1d77fSKishon Vijay Abraham I }
173033c1d77fSKishon Vijay Abraham I
173133c1d77fSKishon Vijay Abraham I /* No manual mode iodelay values if count < 2 */
173233c1d77fSKishon Vijay Abraham I count = len / sizeof(*phandle);
173333c1d77fSKishon Vijay Abraham I if (count < 2)
173433c1d77fSKishon Vijay Abraham I return 0;
173533c1d77fSKishon Vijay Abraham I
173633c1d77fSKishon Vijay Abraham I return fdt32_to_cpu(*(phandle + 1));
173733c1d77fSKishon Vijay Abraham I }
173833c1d77fSKishon Vijay Abraham I
173933c1d77fSKishon Vijay Abraham I static struct pad_conf_entry *
174033c1d77fSKishon Vijay Abraham I omap_hsmmc_get_pad_conf(struct mmc *mmc, char *prop_name, int *npads)
174133c1d77fSKishon Vijay Abraham I {
174233c1d77fSKishon Vijay Abraham I int len;
174333c1d77fSKishon Vijay Abraham I int count;
174433c1d77fSKishon Vijay Abraham I struct pad_conf_entry *padconf;
174533c1d77fSKishon Vijay Abraham I u32 phandle;
174633c1d77fSKishon Vijay Abraham I const fdt32_t *pinctrl;
174733c1d77fSKishon Vijay Abraham I
174833c1d77fSKishon Vijay Abraham I phandle = omap_hsmmc_get_pad_conf_phandle(mmc, prop_name);
174933c1d77fSKishon Vijay Abraham I if (!phandle)
175033c1d77fSKishon Vijay Abraham I return ERR_PTR(-EINVAL);
175133c1d77fSKishon Vijay Abraham I
175233c1d77fSKishon Vijay Abraham I pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-single,pins",
175333c1d77fSKishon Vijay Abraham I &len);
175433c1d77fSKishon Vijay Abraham I if (!pinctrl)
175533c1d77fSKishon Vijay Abraham I return ERR_PTR(-EINVAL);
175633c1d77fSKishon Vijay Abraham I
175733c1d77fSKishon Vijay Abraham I count = (len / sizeof(*pinctrl)) / 2;
175833c1d77fSKishon Vijay Abraham I padconf = omap_hsmmc_get_pad_conf_entry(pinctrl, count);
175933c1d77fSKishon Vijay Abraham I if (!padconf)
176033c1d77fSKishon Vijay Abraham I return ERR_PTR(-EINVAL);
176133c1d77fSKishon Vijay Abraham I
176233c1d77fSKishon Vijay Abraham I *npads = count;
176333c1d77fSKishon Vijay Abraham I
176433c1d77fSKishon Vijay Abraham I return padconf;
176533c1d77fSKishon Vijay Abraham I }
176633c1d77fSKishon Vijay Abraham I
176733c1d77fSKishon Vijay Abraham I static struct iodelay_cfg_entry *
176833c1d77fSKishon Vijay Abraham I omap_hsmmc_get_iodelay(struct mmc *mmc, char *prop_name, int *niodelay)
176933c1d77fSKishon Vijay Abraham I {
177033c1d77fSKishon Vijay Abraham I int len;
177133c1d77fSKishon Vijay Abraham I int count;
177233c1d77fSKishon Vijay Abraham I struct iodelay_cfg_entry *iodelay;
177333c1d77fSKishon Vijay Abraham I u32 phandle;
177433c1d77fSKishon Vijay Abraham I const fdt32_t *pinctrl;
177533c1d77fSKishon Vijay Abraham I
177633c1d77fSKishon Vijay Abraham I phandle = omap_hsmmc_get_iodelay_phandle(mmc, prop_name);
177733c1d77fSKishon Vijay Abraham I /* Not all modes have manual mode iodelay values. So its not fatal */
177833c1d77fSKishon Vijay Abraham I if (!phandle)
177933c1d77fSKishon Vijay Abraham I return 0;
178033c1d77fSKishon Vijay Abraham I
178133c1d77fSKishon Vijay Abraham I pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-pin-array",
178233c1d77fSKishon Vijay Abraham I &len);
178333c1d77fSKishon Vijay Abraham I if (!pinctrl)
178433c1d77fSKishon Vijay Abraham I return ERR_PTR(-EINVAL);
178533c1d77fSKishon Vijay Abraham I
178633c1d77fSKishon Vijay Abraham I count = (len / sizeof(*pinctrl)) / 3;
178733c1d77fSKishon Vijay Abraham I iodelay = omap_hsmmc_get_iodelay_cfg_entry(pinctrl, count);
178833c1d77fSKishon Vijay Abraham I if (!iodelay)
178933c1d77fSKishon Vijay Abraham I return ERR_PTR(-EINVAL);
179033c1d77fSKishon Vijay Abraham I
179133c1d77fSKishon Vijay Abraham I *niodelay = count;
179233c1d77fSKishon Vijay Abraham I
179333c1d77fSKishon Vijay Abraham I return iodelay;
179433c1d77fSKishon Vijay Abraham I }
179533c1d77fSKishon Vijay Abraham I
179633c1d77fSKishon Vijay Abraham I static struct omap_hsmmc_pinctrl_state *
179733c1d77fSKishon Vijay Abraham I omap_hsmmc_get_pinctrl_by_mode(struct mmc *mmc, char *mode)
179833c1d77fSKishon Vijay Abraham I {
179933c1d77fSKishon Vijay Abraham I int index;
180033c1d77fSKishon Vijay Abraham I int npads = 0;
180133c1d77fSKishon Vijay Abraham I int niodelays = 0;
180233c1d77fSKishon Vijay Abraham I const void *fdt = gd->fdt_blob;
180333c1d77fSKishon Vijay Abraham I int node = dev_of_offset(mmc->dev);
180433c1d77fSKishon Vijay Abraham I char prop_name[11];
180533c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *pinctrl_state;
180633c1d77fSKishon Vijay Abraham I
180733c1d77fSKishon Vijay Abraham I pinctrl_state = (struct omap_hsmmc_pinctrl_state *)
180833c1d77fSKishon Vijay Abraham I malloc(sizeof(*pinctrl_state));
180933c1d77fSKishon Vijay Abraham I if (!pinctrl_state) {
181033c1d77fSKishon Vijay Abraham I debug("failed to allocate memory\n");
181133c1d77fSKishon Vijay Abraham I return 0;
181233c1d77fSKishon Vijay Abraham I }
181333c1d77fSKishon Vijay Abraham I
181433c1d77fSKishon Vijay Abraham I index = fdt_stringlist_search(fdt, node, "pinctrl-names", mode);
181533c1d77fSKishon Vijay Abraham I if (index < 0) {
181633c1d77fSKishon Vijay Abraham I debug("fail to find %s mode %s\n", mode, fdt_strerror(index));
181733c1d77fSKishon Vijay Abraham I goto err_pinctrl_state;
181833c1d77fSKishon Vijay Abraham I }
181933c1d77fSKishon Vijay Abraham I
182033c1d77fSKishon Vijay Abraham I sprintf(prop_name, "pinctrl-%d", index);
182133c1d77fSKishon Vijay Abraham I
182233c1d77fSKishon Vijay Abraham I pinctrl_state->padconf = omap_hsmmc_get_pad_conf(mmc, prop_name,
182333c1d77fSKishon Vijay Abraham I &npads);
182433c1d77fSKishon Vijay Abraham I if (IS_ERR(pinctrl_state->padconf))
182533c1d77fSKishon Vijay Abraham I goto err_pinctrl_state;
182633c1d77fSKishon Vijay Abraham I pinctrl_state->npads = npads;
182733c1d77fSKishon Vijay Abraham I
182833c1d77fSKishon Vijay Abraham I pinctrl_state->iodelay = omap_hsmmc_get_iodelay(mmc, prop_name,
182933c1d77fSKishon Vijay Abraham I &niodelays);
183033c1d77fSKishon Vijay Abraham I if (IS_ERR(pinctrl_state->iodelay))
183133c1d77fSKishon Vijay Abraham I goto err_padconf;
183233c1d77fSKishon Vijay Abraham I pinctrl_state->niodelays = niodelays;
183333c1d77fSKishon Vijay Abraham I
183433c1d77fSKishon Vijay Abraham I return pinctrl_state;
183533c1d77fSKishon Vijay Abraham I
183633c1d77fSKishon Vijay Abraham I err_padconf:
183733c1d77fSKishon Vijay Abraham I kfree(pinctrl_state->padconf);
183833c1d77fSKishon Vijay Abraham I
183933c1d77fSKishon Vijay Abraham I err_pinctrl_state:
184033c1d77fSKishon Vijay Abraham I kfree(pinctrl_state);
184133c1d77fSKishon Vijay Abraham I return 0;
184233c1d77fSKishon Vijay Abraham I }
184333c1d77fSKishon Vijay Abraham I
1844bcc6bd84SJean-Jacques Hiblot #define OMAP_HSMMC_SETUP_PINCTRL(capmask, mode, optional) \
184533c1d77fSKishon Vijay Abraham I do { \
18462d28eedaSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *s = NULL; \
18472d28eedaSKishon Vijay Abraham I char str[20]; \
184833c1d77fSKishon Vijay Abraham I if (!(cfg->host_caps & capmask)) \
184933c1d77fSKishon Vijay Abraham I break; \
185033c1d77fSKishon Vijay Abraham I \
18512d28eedaSKishon Vijay Abraham I if (priv->hw_rev) { \
18522d28eedaSKishon Vijay Abraham I sprintf(str, "%s-%s", #mode, priv->hw_rev); \
18532d28eedaSKishon Vijay Abraham I s = omap_hsmmc_get_pinctrl_by_mode(mmc, str); \
18542d28eedaSKishon Vijay Abraham I } \
18552d28eedaSKishon Vijay Abraham I \
18562d28eedaSKishon Vijay Abraham I if (!s) \
185733c1d77fSKishon Vijay Abraham I s = omap_hsmmc_get_pinctrl_by_mode(mmc, #mode); \
18582d28eedaSKishon Vijay Abraham I \
1859bcc6bd84SJean-Jacques Hiblot if (!s && !optional) { \
186033c1d77fSKishon Vijay Abraham I debug("%s: no pinctrl for %s\n", \
186133c1d77fSKishon Vijay Abraham I mmc->dev->name, #mode); \
186233c1d77fSKishon Vijay Abraham I cfg->host_caps &= ~(capmask); \
186333c1d77fSKishon Vijay Abraham I } else { \
186433c1d77fSKishon Vijay Abraham I priv->mode##_pinctrl_state = s; \
186533c1d77fSKishon Vijay Abraham I } \
186633c1d77fSKishon Vijay Abraham I } while (0)
186733c1d77fSKishon Vijay Abraham I
186833c1d77fSKishon Vijay Abraham I static int omap_hsmmc_get_pinctrl_state(struct mmc *mmc)
186933c1d77fSKishon Vijay Abraham I {
187033c1d77fSKishon Vijay Abraham I struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
187133c1d77fSKishon Vijay Abraham I struct mmc_config *cfg = omap_hsmmc_get_cfg(mmc);
187233c1d77fSKishon Vijay Abraham I struct omap_hsmmc_pinctrl_state *default_pinctrl;
187333c1d77fSKishon Vijay Abraham I
187433c1d77fSKishon Vijay Abraham I if (!(priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY))
187533c1d77fSKishon Vijay Abraham I return 0;
187633c1d77fSKishon Vijay Abraham I
187733c1d77fSKishon Vijay Abraham I default_pinctrl = omap_hsmmc_get_pinctrl_by_mode(mmc, "default");
187833c1d77fSKishon Vijay Abraham I if (!default_pinctrl) {
187933c1d77fSKishon Vijay Abraham I printf("no pinctrl state for default mode\n");
188033c1d77fSKishon Vijay Abraham I return -EINVAL;
188133c1d77fSKishon Vijay Abraham I }
188233c1d77fSKishon Vijay Abraham I
188333c1d77fSKishon Vijay Abraham I priv->default_pinctrl_state = default_pinctrl;
188433c1d77fSKishon Vijay Abraham I
1885bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR104), sdr104, false);
1886bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR50), sdr50, false);
1887bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_DDR50), ddr50, false);
1888bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR25), sdr25, false);
1889bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR12), sdr12, false);
189033c1d77fSKishon Vijay Abraham I
1891bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_HS_200), hs200_1_8v, false);
1892bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_DDR_52), ddr_1_8v, false);
1893bcc6bd84SJean-Jacques Hiblot OMAP_HSMMC_SETUP_PINCTRL(MMC_MODE_HS, hs, true);
189433c1d77fSKishon Vijay Abraham I
189533c1d77fSKishon Vijay Abraham I return 0;
189633c1d77fSKishon Vijay Abraham I }
189733c1d77fSKishon Vijay Abraham I #endif
189833c1d77fSKishon Vijay Abraham I
18992558c049SLokesh Vutla #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
19002d28eedaSKishon Vijay Abraham I #ifdef CONFIG_OMAP54XX
19012d28eedaSKishon Vijay Abraham I __weak const struct mmc_platform_fixups *platform_fixups_mmc(uint32_t addr)
19022d28eedaSKishon Vijay Abraham I {
19032d28eedaSKishon Vijay Abraham I return NULL;
19042d28eedaSKishon Vijay Abraham I }
19052d28eedaSKishon Vijay Abraham I #endif
19062d28eedaSKishon Vijay Abraham I
1907a9d6a7e2SMugunthan V N static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
1908a9d6a7e2SMugunthan V N {
19093d673ffcSJean-Jacques Hiblot struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
191033c1d77fSKishon Vijay Abraham I struct omap_mmc_of_data *of_data = (void *)dev_get_driver_data(dev);
191133c1d77fSKishon Vijay Abraham I
19123d673ffcSJean-Jacques Hiblot struct mmc_config *cfg = &plat->cfg;
19132d28eedaSKishon Vijay Abraham I #ifdef CONFIG_OMAP54XX
19142d28eedaSKishon Vijay Abraham I const struct mmc_platform_fixups *fixups;
19152d28eedaSKishon Vijay Abraham I #endif
1916a9d6a7e2SMugunthan V N const void *fdt = gd->fdt_blob;
1917e160f7d4SSimon Glass int node = dev_of_offset(dev);
19182d7482cfSKishon Vijay Abraham I int ret;
1919a9d6a7e2SMugunthan V N
1920a821c4afSSimon Glass plat->base_addr = map_physmem(devfdt_get_addr(dev),
1921a821c4afSSimon Glass sizeof(struct hsmmc *),
1922741726aeSJean-Jacques Hiblot MAP_NOCACHE);
1923a9d6a7e2SMugunthan V N
19242d7482cfSKishon Vijay Abraham I ret = mmc_of_parse(dev, cfg);
19252d7482cfSKishon Vijay Abraham I if (ret < 0)
19262d7482cfSKishon Vijay Abraham I return ret;
1927a9d6a7e2SMugunthan V N
1928beac7d33SJean-Jacques Hiblot if (!cfg->f_max)
1929beac7d33SJean-Jacques Hiblot cfg->f_max = 52000000;
19302d7482cfSKishon Vijay Abraham I cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
1931a9d6a7e2SMugunthan V N cfg->f_min = 400000;
1932a9d6a7e2SMugunthan V N cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
1933a9d6a7e2SMugunthan V N cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1934b5944817SKishon Vijay Abraham I if (fdtdec_get_bool(fdt, node, "ti,dual-volt"))
1935b5944817SKishon Vijay Abraham I plat->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
1936b5944817SKishon Vijay Abraham I if (fdtdec_get_bool(fdt, node, "no-1-8-v"))
1937b5944817SKishon Vijay Abraham I plat->controller_flags |= OMAP_HSMMC_NO_1_8_V;
193833c1d77fSKishon Vijay Abraham I if (of_data)
193933c1d77fSKishon Vijay Abraham I plat->controller_flags |= of_data->controller_flags;
1940a9d6a7e2SMugunthan V N
19412d28eedaSKishon Vijay Abraham I #ifdef CONFIG_OMAP54XX
19422d28eedaSKishon Vijay Abraham I fixups = platform_fixups_mmc(devfdt_get_addr(dev));
19432d28eedaSKishon Vijay Abraham I if (fixups) {
19442d28eedaSKishon Vijay Abraham I plat->hw_rev = fixups->hw_rev;
19452d28eedaSKishon Vijay Abraham I cfg->host_caps &= ~fixups->unsupported_caps;
19462d28eedaSKishon Vijay Abraham I cfg->f_max = fixups->max_freq;
19472d28eedaSKishon Vijay Abraham I }
19482d28eedaSKishon Vijay Abraham I #endif
19492d28eedaSKishon Vijay Abraham I
1950a9d6a7e2SMugunthan V N return 0;
1951a9d6a7e2SMugunthan V N }
19522558c049SLokesh Vutla #endif
1953a9d6a7e2SMugunthan V N
195417c9a1c1SJean-Jacques Hiblot #ifdef CONFIG_BLK
195517c9a1c1SJean-Jacques Hiblot
195617c9a1c1SJean-Jacques Hiblot static int omap_hsmmc_bind(struct udevice *dev)
195717c9a1c1SJean-Jacques Hiblot {
195817c9a1c1SJean-Jacques Hiblot struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
195945530e39SJean-Jacques Hiblot plat->mmc = calloc(1, sizeof(struct mmc));
196045530e39SJean-Jacques Hiblot return mmc_bind(dev, plat->mmc, &plat->cfg);
196117c9a1c1SJean-Jacques Hiblot }
196217c9a1c1SJean-Jacques Hiblot #endif
1963a9d6a7e2SMugunthan V N static int omap_hsmmc_probe(struct udevice *dev)
1964a9d6a7e2SMugunthan V N {
19653d673ffcSJean-Jacques Hiblot struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
1966a9d6a7e2SMugunthan V N struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
1967a9d6a7e2SMugunthan V N struct omap_hsmmc_data *priv = dev_get_priv(dev);
19683d673ffcSJean-Jacques Hiblot struct mmc_config *cfg = &plat->cfg;
1969a9d6a7e2SMugunthan V N struct mmc *mmc;
197033c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
197133c1d77fSKishon Vijay Abraham I int ret;
197233c1d77fSKishon Vijay Abraham I #endif
1973a9d6a7e2SMugunthan V N
1974a9d6a7e2SMugunthan V N cfg->name = "OMAP SD/MMC";
19752558c049SLokesh Vutla priv->base_addr = plat->base_addr;
197633c1d77fSKishon Vijay Abraham I priv->controller_flags = plat->controller_flags;
19772d28eedaSKishon Vijay Abraham I priv->hw_rev = plat->hw_rev;
1978a9d6a7e2SMugunthan V N
197917c9a1c1SJean-Jacques Hiblot #ifdef CONFIG_BLK
198045530e39SJean-Jacques Hiblot mmc = plat->mmc;
198117c9a1c1SJean-Jacques Hiblot #else
1982a9d6a7e2SMugunthan V N mmc = mmc_create(cfg, priv);
1983a9d6a7e2SMugunthan V N if (mmc == NULL)
1984a9d6a7e2SMugunthan V N return -1;
198517c9a1c1SJean-Jacques Hiblot #endif
198604f9f8beSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
198704f9f8beSJean-Jacques Hiblot device_get_supply_regulator(dev, "pbias-supply",
198804f9f8beSJean-Jacques Hiblot &priv->pbias_supply);
198904f9f8beSJean-Jacques Hiblot #endif
1990307a2143SAdam Ford #if defined(OMAP_HSMMC_USE_GPIO)
1991307a2143SAdam Ford #if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_GPIO)
19925cc6a245SMugunthan V N gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
19935cc6a245SMugunthan V N gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
19945cc6a245SMugunthan V N #endif
1995307a2143SAdam Ford #endif
19965cc6a245SMugunthan V N
1997cffe5d86SSimon Glass mmc->dev = dev;
1998a9d6a7e2SMugunthan V N upriv->mmc = mmc;
1999a9d6a7e2SMugunthan V N
200033c1d77fSKishon Vijay Abraham I #ifdef CONFIG_IODELAY_RECALIBRATION
200133c1d77fSKishon Vijay Abraham I ret = omap_hsmmc_get_pinctrl_state(mmc);
200233c1d77fSKishon Vijay Abraham I /*
200333c1d77fSKishon Vijay Abraham I * disable high speed modes for the platforms that require IO delay
200433c1d77fSKishon Vijay Abraham I * and for which we don't have this information
200533c1d77fSKishon Vijay Abraham I */
200633c1d77fSKishon Vijay Abraham I if ((ret < 0) &&
200733c1d77fSKishon Vijay Abraham I (priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY)) {
200833c1d77fSKishon Vijay Abraham I priv->controller_flags &= ~OMAP_HSMMC_REQUIRE_IODELAY;
200933c1d77fSKishon Vijay Abraham I cfg->host_caps &= ~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_DDR_52) |
201033c1d77fSKishon Vijay Abraham I UHS_CAPS);
201133c1d77fSKishon Vijay Abraham I }
201233c1d77fSKishon Vijay Abraham I #endif
201333c1d77fSKishon Vijay Abraham I
2014b5511d6cSJean-Jacques Hiblot return omap_hsmmc_init_setup(mmc);
2015a9d6a7e2SMugunthan V N }
2016a9d6a7e2SMugunthan V N
20172558c049SLokesh Vutla #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
201833c1d77fSKishon Vijay Abraham I
201933c1d77fSKishon Vijay Abraham I static const struct omap_mmc_of_data dra7_mmc_of_data = {
202033c1d77fSKishon Vijay Abraham I .controller_flags = OMAP_HSMMC_REQUIRE_IODELAY,
202133c1d77fSKishon Vijay Abraham I };
202233c1d77fSKishon Vijay Abraham I
2023a9d6a7e2SMugunthan V N static const struct udevice_id omap_hsmmc_ids[] = {
2024741726aeSJean-Jacques Hiblot { .compatible = "ti,omap3-hsmmc" },
2025741726aeSJean-Jacques Hiblot { .compatible = "ti,omap4-hsmmc" },
2026741726aeSJean-Jacques Hiblot { .compatible = "ti,am33xx-hsmmc" },
202733c1d77fSKishon Vijay Abraham I { .compatible = "ti,dra7-hsmmc", .data = (ulong)&dra7_mmc_of_data },
2028a9d6a7e2SMugunthan V N { }
2029a9d6a7e2SMugunthan V N };
20302558c049SLokesh Vutla #endif
2031a9d6a7e2SMugunthan V N
2032a9d6a7e2SMugunthan V N U_BOOT_DRIVER(omap_hsmmc) = {
2033a9d6a7e2SMugunthan V N .name = "omap_hsmmc",
2034a9d6a7e2SMugunthan V N .id = UCLASS_MMC,
20352558c049SLokesh Vutla #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
2036a9d6a7e2SMugunthan V N .of_match = omap_hsmmc_ids,
2037a9d6a7e2SMugunthan V N .ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata,
20382558c049SLokesh Vutla .platdata_auto_alloc_size = sizeof(struct omap_hsmmc_plat),
20392558c049SLokesh Vutla #endif
204017c9a1c1SJean-Jacques Hiblot #ifdef CONFIG_BLK
204117c9a1c1SJean-Jacques Hiblot .bind = omap_hsmmc_bind,
204217c9a1c1SJean-Jacques Hiblot #endif
2043b5511d6cSJean-Jacques Hiblot .ops = &omap_hsmmc_ops,
2044a9d6a7e2SMugunthan V N .probe = omap_hsmmc_probe,
2045a9d6a7e2SMugunthan V N .priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
2046223b10caSBin Meng #if !CONFIG_IS_ENABLED(OF_CONTROL)
2047cbcb1701SLokesh Vutla .flags = DM_FLAG_PRE_RELOC,
2048223b10caSBin Meng #endif
2049a9d6a7e2SMugunthan V N };
2050a9d6a7e2SMugunthan V N #endif
2051