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