1
2
3
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
23static 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
34 mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET;
35 sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
36
37
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
51 mask = mask & ~SDHCI_CORECTRL_RESET;
52 sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
53
54
55 mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET);
56 sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET);
57
58
59 sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET);
60
61
62 mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET);
63 sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET);
64
65
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
78int 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