1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2013 Broadcom Corporation.
4 */
5
6 #include <common.h>
7 #include <malloc.h>
8 #include <sdhci.h>
9 #include <linux/delay.h>
10 #include <linux/errno.h>
11 #include <asm/kona-common/clk.h>
12
13 #define SDHCI_CORECTRL_OFFSET 0x00008000
14 #define SDHCI_CORECTRL_EN 0x01
15 #define SDHCI_CORECTRL_RESET 0x02
16
17 #define SDHCI_CORESTAT_OFFSET 0x00008004
18 #define SDHCI_CORESTAT_CD_SW 0x01
19
20 #define SDHCI_COREIMR_OFFSET 0x00008008
21 #define SDHCI_COREIMR_IP 0x01
22
init_kona_mmc_core(struct sdhci_host * host)23 static int init_kona_mmc_core(struct sdhci_host *host)
24 {
25 unsigned int mask;
26 unsigned int timeout;
27
28 if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) {
29 printf("%s: sd host controller reset error\n", __func__);
30 return -EBUSY;
31 }
32
33 /* For kona a hardware reset before anything else. */
34 mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET;
35 sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
36
37 /* Wait max 100 ms */
38 timeout = 1000;
39 do {
40 if (timeout == 0) {
41 printf("%s: reset timeout error\n", __func__);
42 return -ETIMEDOUT;
43 }
44 timeout--;
45 udelay(100);
46 } while (0 ==
47 (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) &
48 SDHCI_CORECTRL_RESET));
49
50 /* Clear the reset bit. */
51 mask = mask & ~SDHCI_CORECTRL_RESET;
52 sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
53
54 /* Enable AHB clock */
55 mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET);
56 sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET);
57
58 /* Enable interrupts */
59 sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET);
60
61 /* Make sure Card is detected in controller */
62 mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET);
63 sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET);
64
65 /* Wait max 100 ms */
66 timeout = 1000;
67 while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
68 if (timeout == 0) {
69 printf("%s: CARD DETECT timeout error\n", __func__);
70 return -ETIMEDOUT;
71 }
72 timeout--;
73 udelay(100);
74 }
75 return 0;
76 }
77
kona_sdhci_init(int dev_index,u32 min_clk,u32 quirks)78 int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks)
79 {
80 int ret = 0;
81 u32 max_clk;
82 void *reg_base;
83 struct sdhci_host *host = NULL;
84
85 host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
86 if (!host) {
87 printf("%s: sdhci host malloc fail!\n", __func__);
88 return -ENOMEM;
89 }
90 switch (dev_index) {
91 case 0:
92 reg_base = (void *)CONFIG_SYS_SDIO_BASE0;
93 ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK,
94 &max_clk);
95 break;
96 case 1:
97 reg_base = (void *)CONFIG_SYS_SDIO_BASE1;
98 ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK,
99 &max_clk);
100 break;
101 case 2:
102 reg_base = (void *)CONFIG_SYS_SDIO_BASE2;
103 ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK,
104 &max_clk);
105 break;
106 case 3:
107 reg_base = (void *)CONFIG_SYS_SDIO_BASE3;
108 ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK,
109 &max_clk);
110 break;
111 default:
112 printf("%s: sdio dev index %d not supported\n",
113 __func__, dev_index);
114 ret = -EINVAL;
115 }
116 if (ret) {
117 free(host);
118 return ret;
119 }
120
121 host->name = "kona-sdhci";
122 host->ioaddr = reg_base;
123 host->quirks = quirks;
124 host->max_clk = max_clk;
125
126 if (init_kona_mmc_core(host)) {
127 free(host);
128 return -EINVAL;
129 }
130
131 add_sdhci(host, 0, min_clk);
132 return ret;
133 }
134