f5e1f2cbbd32fbf5af8cab6a1de2a3a5a74a4557
[oweals/u-boot.git] / drivers / mmc / kona_sdhci.c
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 }