17657c3a7SAlbert Herranz /* 27657c3a7SAlbert Herranz * Freescale eSDHC controller driver. 37657c3a7SAlbert Herranz * 47657c3a7SAlbert Herranz * Copyright (c) 2007 Freescale Semiconductor, Inc. 57657c3a7SAlbert Herranz * Copyright (c) 2009 MontaVista Software, Inc. 67657c3a7SAlbert Herranz * 77657c3a7SAlbert Herranz * Authors: Xiaobo Xie <X.Xie@freescale.com> 87657c3a7SAlbert Herranz * Anton Vorontsov <avorontsov@ru.mvista.com> 97657c3a7SAlbert Herranz * 107657c3a7SAlbert Herranz * This program is free software; you can redistribute it and/or modify 117657c3a7SAlbert Herranz * it under the terms of the GNU General Public License as published by 127657c3a7SAlbert Herranz * the Free Software Foundation; either version 2 of the License, or (at 137657c3a7SAlbert Herranz * your option) any later version. 147657c3a7SAlbert Herranz */ 157657c3a7SAlbert Herranz 167657c3a7SAlbert Herranz #include <linux/io.h> 177657c3a7SAlbert Herranz #include <linux/delay.h> 187657c3a7SAlbert Herranz #include <linux/mmc/host.h> 197657c3a7SAlbert Herranz #include "sdhci-of.h" 207657c3a7SAlbert Herranz #include "sdhci.h" 217657c3a7SAlbert Herranz 227657c3a7SAlbert Herranz /* 237657c3a7SAlbert Herranz * Ops and quirks for the Freescale eSDHC controller. 247657c3a7SAlbert Herranz */ 257657c3a7SAlbert Herranz 267657c3a7SAlbert Herranz #define ESDHC_DMA_SYSCTL 0x40c 277657c3a7SAlbert Herranz #define ESDHC_DMA_SNOOP 0x00000040 287657c3a7SAlbert Herranz 297657c3a7SAlbert Herranz #define ESDHC_SYSTEM_CONTROL 0x2c 307657c3a7SAlbert Herranz #define ESDHC_CLOCK_MASK 0x0000fff0 317657c3a7SAlbert Herranz #define ESDHC_PREDIV_SHIFT 8 327657c3a7SAlbert Herranz #define ESDHC_DIVIDER_SHIFT 4 337657c3a7SAlbert Herranz #define ESDHC_CLOCK_PEREN 0x00000004 347657c3a7SAlbert Herranz #define ESDHC_CLOCK_HCKEN 0x00000002 357657c3a7SAlbert Herranz #define ESDHC_CLOCK_IPGEN 0x00000001 367657c3a7SAlbert Herranz 377657c3a7SAlbert Herranz #define ESDHC_HOST_CONTROL_RES 0x05 387657c3a7SAlbert Herranz 397657c3a7SAlbert Herranz static u16 esdhc_readw(struct sdhci_host *host, int reg) 407657c3a7SAlbert Herranz { 417657c3a7SAlbert Herranz u16 ret; 427657c3a7SAlbert Herranz 437657c3a7SAlbert Herranz if (unlikely(reg == SDHCI_HOST_VERSION)) 447657c3a7SAlbert Herranz ret = in_be16(host->ioaddr + reg); 457657c3a7SAlbert Herranz else 467657c3a7SAlbert Herranz ret = sdhci_be32bs_readw(host, reg); 477657c3a7SAlbert Herranz return ret; 487657c3a7SAlbert Herranz } 497657c3a7SAlbert Herranz 507657c3a7SAlbert Herranz static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) 517657c3a7SAlbert Herranz { 527657c3a7SAlbert Herranz if (reg == SDHCI_BLOCK_SIZE) { 537657c3a7SAlbert Herranz /* 547657c3a7SAlbert Herranz * Two last DMA bits are reserved, and first one is used for 557657c3a7SAlbert Herranz * non-standard blksz of 4096 bytes that we don't support 567657c3a7SAlbert Herranz * yet. So clear the DMA boundary bits. 577657c3a7SAlbert Herranz */ 587657c3a7SAlbert Herranz val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 597657c3a7SAlbert Herranz } 607657c3a7SAlbert Herranz sdhci_be32bs_writew(host, val, reg); 617657c3a7SAlbert Herranz } 627657c3a7SAlbert Herranz 637657c3a7SAlbert Herranz static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) 647657c3a7SAlbert Herranz { 657657c3a7SAlbert Herranz /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ 667657c3a7SAlbert Herranz if (reg == SDHCI_HOST_CONTROL) 677657c3a7SAlbert Herranz val &= ~ESDHC_HOST_CONTROL_RES; 687657c3a7SAlbert Herranz sdhci_be32bs_writeb(host, val, reg); 697657c3a7SAlbert Herranz } 707657c3a7SAlbert Herranz 717657c3a7SAlbert Herranz static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) 727657c3a7SAlbert Herranz { 737657c3a7SAlbert Herranz int pre_div = 2; 747657c3a7SAlbert Herranz int div = 1; 757657c3a7SAlbert Herranz 767657c3a7SAlbert Herranz clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | 777657c3a7SAlbert Herranz ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); 787657c3a7SAlbert Herranz 797657c3a7SAlbert Herranz if (clock == 0) 807657c3a7SAlbert Herranz goto out; 817657c3a7SAlbert Herranz 827657c3a7SAlbert Herranz while (host->max_clk / pre_div / 16 > clock && pre_div < 256) 837657c3a7SAlbert Herranz pre_div *= 2; 847657c3a7SAlbert Herranz 857657c3a7SAlbert Herranz while (host->max_clk / pre_div / div > clock && div < 16) 867657c3a7SAlbert Herranz div++; 877657c3a7SAlbert Herranz 887657c3a7SAlbert Herranz dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", 897657c3a7SAlbert Herranz clock, host->max_clk / pre_div / div); 907657c3a7SAlbert Herranz 917657c3a7SAlbert Herranz pre_div >>= 1; 927657c3a7SAlbert Herranz div--; 937657c3a7SAlbert Herranz 947657c3a7SAlbert Herranz setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | 957657c3a7SAlbert Herranz ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | 967657c3a7SAlbert Herranz div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT); 977657c3a7SAlbert Herranz mdelay(100); 987657c3a7SAlbert Herranz out: 997657c3a7SAlbert Herranz host->clock = clock; 1007657c3a7SAlbert Herranz } 1017657c3a7SAlbert Herranz 1027657c3a7SAlbert Herranz static int esdhc_enable_dma(struct sdhci_host *host) 1037657c3a7SAlbert Herranz { 1047657c3a7SAlbert Herranz setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); 1057657c3a7SAlbert Herranz return 0; 1067657c3a7SAlbert Herranz } 1077657c3a7SAlbert Herranz 1087657c3a7SAlbert Herranz static unsigned int esdhc_get_max_clock(struct sdhci_host *host) 1097657c3a7SAlbert Herranz { 1107657c3a7SAlbert Herranz struct sdhci_of_host *of_host = sdhci_priv(host); 1117657c3a7SAlbert Herranz 1127657c3a7SAlbert Herranz return of_host->clock; 1137657c3a7SAlbert Herranz } 1147657c3a7SAlbert Herranz 1157657c3a7SAlbert Herranz static unsigned int esdhc_get_min_clock(struct sdhci_host *host) 1167657c3a7SAlbert Herranz { 1177657c3a7SAlbert Herranz struct sdhci_of_host *of_host = sdhci_priv(host); 1187657c3a7SAlbert Herranz 1197657c3a7SAlbert Herranz return of_host->clock / 256 / 16; 1207657c3a7SAlbert Herranz } 1217657c3a7SAlbert Herranz 1227657c3a7SAlbert Herranz struct sdhci_of_data sdhci_esdhc = { 1237657c3a7SAlbert Herranz .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 | 1247657c3a7SAlbert Herranz SDHCI_QUIRK_BROKEN_CARD_DETECTION | 1257657c3a7SAlbert Herranz SDHCI_QUIRK_NO_BUSY_IRQ | 1267657c3a7SAlbert Herranz SDHCI_QUIRK_NONSTANDARD_CLOCK | 1277657c3a7SAlbert Herranz SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | 1287657c3a7SAlbert Herranz SDHCI_QUIRK_PIO_NEEDS_DELAY | 1297657c3a7SAlbert Herranz SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | 1307657c3a7SAlbert Herranz SDHCI_QUIRK_NO_CARD_NO_RESET, 1317657c3a7SAlbert Herranz .ops = { 132*dc297c92SMatt Fleming .read_l = sdhci_be32bs_readl, 133*dc297c92SMatt Fleming .read_w = esdhc_readw, 134*dc297c92SMatt Fleming .read_b = sdhci_be32bs_readb, 135*dc297c92SMatt Fleming .write_l = sdhci_be32bs_writel, 136*dc297c92SMatt Fleming .write_w = esdhc_writew, 137*dc297c92SMatt Fleming .write_b = esdhc_writeb, 1387657c3a7SAlbert Herranz .set_clock = esdhc_set_clock, 1397657c3a7SAlbert Herranz .enable_dma = esdhc_enable_dma, 1407657c3a7SAlbert Herranz .get_max_clock = esdhc_get_max_clock, 1417657c3a7SAlbert Herranz .get_min_clock = esdhc_get_min_clock, 1427657c3a7SAlbert Herranz }, 1437657c3a7SAlbert Herranz }; 144