1 /* 2 * (C) Copyright 2012 SAMSUNG Electronics 3 * Jaehoon Chung <jh80.chung@samsung.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20 #include <common.h> 21 #include <malloc.h> 22 #include <sdhci.h> 23 #include <asm/arch/mmc.h> 24 25 static char *S5P_NAME = "SAMSUNG SDHCI"; 26 static void s5p_sdhci_set_control_reg(struct sdhci_host *host) 27 { 28 unsigned long val, ctrl; 29 /* 30 * SELCLKPADDS[17:16] 31 * 00 = 2mA 32 * 01 = 4mA 33 * 10 = 7mA 34 * 11 = 9mA 35 */ 36 sdhci_writel(host, SDHCI_CTRL4_DRIVE_MASK(0x3), SDHCI_CONTROL4); 37 38 val = sdhci_readl(host, SDHCI_CONTROL2); 39 val &= SDHCI_CTRL2_SELBASECLK_SHIFT; 40 41 val |= SDHCI_CTRL2_ENSTAASYNCCLR | 42 SDHCI_CTRL2_ENCMDCNFMSK | 43 SDHCI_CTRL2_ENFBCLKRX | 44 SDHCI_CTRL2_ENCLKOUTHOLD; 45 46 sdhci_writel(host, val, SDHCI_CONTROL2); 47 48 /* 49 * FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7] 50 * FCSel[1:0] : Rx Feedback Clock Delay Control 51 * Inverter delay means10ns delay if SDCLK 50MHz setting 52 * 01 = Delay1 (basic delay) 53 * 11 = Delay2 (basic delay + 2ns) 54 * 00 = Delay3 (inverter delay) 55 * 10 = Delay4 (inverter delay + 2ns) 56 */ 57 val = SDHCI_CTRL3_FCSEL3 | SDHCI_CTRL3_FCSEL1; 58 sdhci_writel(host, val, SDHCI_CONTROL3); 59 60 /* 61 * SELBASECLK[5:4] 62 * 00/01 = HCLK 63 * 10 = EPLL 64 * 11 = XTI or XEXTCLK 65 */ 66 ctrl = sdhci_readl(host, SDHCI_CONTROL2); 67 ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK(0x3); 68 ctrl |= SDHCI_CTRL2_SELBASECLK_MASK(0x2); 69 sdhci_writel(host, ctrl, SDHCI_CONTROL2); 70 } 71 72 int s5p_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks) 73 { 74 struct sdhci_host *host = NULL; 75 host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); 76 if (!host) { 77 printf("sdhci__host malloc fail!\n"); 78 return 1; 79 } 80 81 host->name = S5P_NAME; 82 host->ioaddr = (void *)regbase; 83 host->quirks = quirks; 84 85 host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE; 86 host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; 87 if (quirks & SDHCI_QUIRK_REG32_RW) 88 host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16; 89 else 90 host->version = sdhci_readw(host, SDHCI_HOST_VERSION); 91 92 host->set_control_reg = &s5p_sdhci_set_control_reg; 93 94 host->host_caps = MMC_MODE_HC; 95 96 add_sdhci(host, max_clk, min_clk); 97 return 0; 98 } 99