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