1 /* 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 <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 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 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