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