1442d5568SJaehoon Chung /* 2442d5568SJaehoon Chung * (C) Copyright 2012 SAMSUNG Electronics 3442d5568SJaehoon Chung * Jaehoon Chung <jh80.chung@samsung.com> 4442d5568SJaehoon Chung * 5442d5568SJaehoon Chung * This program is free software; you can redistribute it and/or modify 6442d5568SJaehoon Chung * it under the terms of the GNU General Public License as published by 7442d5568SJaehoon Chung * the Free Software Foundation; either version 2 of the License, or 8442d5568SJaehoon Chung * (at your option) any later version. 9442d5568SJaehoon Chung * 10442d5568SJaehoon Chung * This program is distributed in the hope that it will be useful, 11442d5568SJaehoon Chung * but WITHOUT ANY WARRANTY; without even the implied warranty of 12442d5568SJaehoon Chung * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13442d5568SJaehoon Chung * GNU General Public License for more details. 14442d5568SJaehoon Chung * 15442d5568SJaehoon Chung * You should have received a copy of the GNU General Public License 16442d5568SJaehoon Chung * along with this program; if not, write to the Free Software 17442d5568SJaehoon Chung * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18442d5568SJaehoon Chung */ 19442d5568SJaehoon Chung 20442d5568SJaehoon Chung #include <common.h> 21442d5568SJaehoon Chung #include <malloc.h> 22442d5568SJaehoon Chung #include <sdhci.h> 23442d5568SJaehoon Chung #include <asm/arch/mmc.h> 24*b09ed6e4SJaehoon Chung #include <asm/arch/clk.h> 25442d5568SJaehoon Chung 26442d5568SJaehoon Chung static char *S5P_NAME = "SAMSUNG SDHCI"; 27442d5568SJaehoon Chung static void s5p_sdhci_set_control_reg(struct sdhci_host *host) 28442d5568SJaehoon Chung { 29442d5568SJaehoon Chung unsigned long val, ctrl; 30442d5568SJaehoon Chung /* 31442d5568SJaehoon Chung * SELCLKPADDS[17:16] 32442d5568SJaehoon Chung * 00 = 2mA 33442d5568SJaehoon Chung * 01 = 4mA 34442d5568SJaehoon Chung * 10 = 7mA 35442d5568SJaehoon Chung * 11 = 9mA 36442d5568SJaehoon Chung */ 37442d5568SJaehoon Chung sdhci_writel(host, SDHCI_CTRL4_DRIVE_MASK(0x3), SDHCI_CONTROL4); 38442d5568SJaehoon Chung 39442d5568SJaehoon Chung val = sdhci_readl(host, SDHCI_CONTROL2); 40442d5568SJaehoon Chung val &= SDHCI_CTRL2_SELBASECLK_SHIFT; 41442d5568SJaehoon Chung 42442d5568SJaehoon Chung val |= SDHCI_CTRL2_ENSTAASYNCCLR | 43442d5568SJaehoon Chung SDHCI_CTRL2_ENCMDCNFMSK | 44442d5568SJaehoon Chung SDHCI_CTRL2_ENFBCLKRX | 45442d5568SJaehoon Chung SDHCI_CTRL2_ENCLKOUTHOLD; 46442d5568SJaehoon Chung 47442d5568SJaehoon Chung sdhci_writel(host, val, SDHCI_CONTROL2); 48442d5568SJaehoon Chung 49442d5568SJaehoon Chung /* 50442d5568SJaehoon Chung * FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7] 51442d5568SJaehoon Chung * FCSel[1:0] : Rx Feedback Clock Delay Control 52442d5568SJaehoon Chung * Inverter delay means10ns delay if SDCLK 50MHz setting 53442d5568SJaehoon Chung * 01 = Delay1 (basic delay) 54442d5568SJaehoon Chung * 11 = Delay2 (basic delay + 2ns) 55442d5568SJaehoon Chung * 00 = Delay3 (inverter delay) 56442d5568SJaehoon Chung * 10 = Delay4 (inverter delay + 2ns) 57442d5568SJaehoon Chung */ 58b268660cSJaehoon Chung val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1; 59442d5568SJaehoon Chung sdhci_writel(host, val, SDHCI_CONTROL3); 60442d5568SJaehoon Chung 61442d5568SJaehoon Chung /* 62442d5568SJaehoon Chung * SELBASECLK[5:4] 63442d5568SJaehoon Chung * 00/01 = HCLK 64442d5568SJaehoon Chung * 10 = EPLL 65442d5568SJaehoon Chung * 11 = XTI or XEXTCLK 66442d5568SJaehoon Chung */ 67442d5568SJaehoon Chung ctrl = sdhci_readl(host, SDHCI_CONTROL2); 68442d5568SJaehoon Chung ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK(0x3); 69442d5568SJaehoon Chung ctrl |= SDHCI_CTRL2_SELBASECLK_MASK(0x2); 70442d5568SJaehoon Chung sdhci_writel(host, ctrl, SDHCI_CONTROL2); 71442d5568SJaehoon Chung } 72442d5568SJaehoon Chung 738458e028SJaehoon Chung int s5p_sdhci_init(u32 regbase, int index, int bus_width) 74442d5568SJaehoon Chung { 75442d5568SJaehoon Chung struct sdhci_host *host = NULL; 76442d5568SJaehoon Chung host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); 77442d5568SJaehoon Chung if (!host) { 78442d5568SJaehoon Chung printf("sdhci__host malloc fail!\n"); 79442d5568SJaehoon Chung return 1; 80442d5568SJaehoon Chung } 81442d5568SJaehoon Chung 82442d5568SJaehoon Chung host->name = S5P_NAME; 83442d5568SJaehoon Chung host->ioaddr = (void *)regbase; 84442d5568SJaehoon Chung 85b268660cSJaehoon Chung host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | 86b268660cSJaehoon Chung SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR; 87442d5568SJaehoon Chung host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; 88442d5568SJaehoon Chung host->version = sdhci_readw(host, SDHCI_HOST_VERSION); 89442d5568SJaehoon Chung 90442d5568SJaehoon Chung host->set_control_reg = &s5p_sdhci_set_control_reg; 91*b09ed6e4SJaehoon Chung host->set_clock = set_mmc_clk; 92*b09ed6e4SJaehoon Chung host->index = index; 93442d5568SJaehoon Chung 94442d5568SJaehoon Chung host->host_caps = MMC_MODE_HC; 95442d5568SJaehoon Chung 968458e028SJaehoon Chung add_sdhci(host, 52000000, 400000); 97442d5568SJaehoon Chung return 0; 98442d5568SJaehoon Chung } 99