blob: 77e42c8afe87c1d4cce3abe9fe377df497491c3d [file] [log] [blame]
Darwin Rambo29f2f572014-02-11 11:06:37 -08001/*
2 * Copyright 2013 Broadcom Corporation.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
8#include <malloc.h>
9#include <sdhci.h>
10#include <asm/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 1;
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 1;
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 1;
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 return ret;
118
119 host->name = "kona-sdhci";
120 host->ioaddr = reg_base;
121 host->quirks = quirks;
122 host->host_caps = MMC_MODE_HC;
123
124 if (init_kona_mmc_core(host))
125 return -EINVAL;
126
127 if (quirks & SDHCI_QUIRK_REG32_RW)
128 host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
129 else
130 host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
131
132 add_sdhci(host, max_clk, min_clk);
133 return ret;
134}