/* * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc * Andy Fleming * * Based vaguely on the pxa mmc code: * (C) Copyright 2003 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; struct fsl_esdhc { uint dsaddr; /* SDMA system address register */ uint blkattr; /* Block attributes register */ uint cmdarg; /* Command argument register */ uint xfertyp; /* Transfer type register */ uint cmdrsp0; /* Command response 0 register */ uint cmdrsp1; /* Command response 1 register */ uint cmdrsp2; /* Command response 2 register */ uint cmdrsp3; /* Command response 3 register */ uint datport; /* Buffer data port register */ uint prsstat; /* Present state register */ uint proctl; /* Protocol control register */ uint sysctl; /* System Control Register */ uint irqstat; /* Interrupt status register */ uint irqstaten; /* Interrupt status enable register */ uint irqsigen; /* Interrupt signal enable register */ uint autoc12err; /* Auto CMD error status register */ uint hostcapblt; /* Host controller capabilities register */ uint wml; /* Watermark level register */ uint mixctrl; /* For USDHC */ char reserved1[4]; /* reserved */ uint fevt; /* Force event register */ uint admaes; /* ADMA error status register */ uint adsaddr; /* ADMA system address register */ char reserved2[160]; /* reserved */ uint hostver; /* Host controller version register */ char reserved3[4]; /* reserved */ uint dmaerraddr; /* DMA error address register */ char reserved4[4]; /* reserved */ uint dmaerrattr; /* DMA error attribute register */ char reserved5[4]; /* reserved */ uint hostcapblt2; /* Host controller capabilities register 2 */ char reserved6[8]; /* reserved */ uint tcr; /* Tuning control register */ char reserved7[28]; /* reserved */ uint sddirctl; /* SD direction control register */ char reserved8[712]; /* reserved */ uint scr; /* eSDHC control register */ }; /* Return the XFERTYP flags for a given command and data packet */ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) { uint xfertyp = 0; if (data) { xfertyp |= XFERTYP_DPSEL; #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO xfertyp |= XFERTYP_DMAEN; #endif if (data->blocks > 1) { xfertyp |= XFERTYP_MSBSEL; xfertyp |= XFERTYP_BCEN; #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 xfertyp |= XFERTYP_AC12EN; #endif } if (data->flags & MMC_DATA_READ) xfertyp |= XFERTYP_DTDSEL; } if (cmd->resp_type & MMC_RSP_CRC) xfertyp |= XFERTYP_CCCEN; if (cmd->resp_type & MMC_RSP_OPCODE) xfertyp |= XFERTYP_CICEN; if (cmd->resp_type & MMC_RSP_136) xfertyp |= XFERTYP_RSPTYP_136; else if (cmd->resp_type & MMC_RSP_BUSY) xfertyp |= XFERTYP_RSPTYP_48_BUSY; else if (cmd->resp_type & MMC_RSP_PRESENT) xfertyp |= XFERTYP_RSPTYP_48; #if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) xfertyp |= XFERTYP_CMDTYP_ABORT; #endif return XFERTYP_CMD(cmd->cmdidx) | xfertyp; } #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO /* * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. */ static void esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data) { struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; uint blocks; char *buffer; uint databuf; uint size; uint irqstat; uint timeout; if (data->flags & MMC_DATA_READ) { blocks = data->blocks; buffer = data->dest; while (blocks) { timeout = PIO_TIMEOUT; size = data->blocksize; irqstat = esdhc_read32(®s->irqstat); while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BREN) && --timeout); if (timeout <= 0) { printf("\nData Read Failed in PIO Mode."); return; } while (size && (!(irqstat & IRQSTAT_TC))) { udelay(10
/*
             LUFA Library
     Copyright (C) Dean Camera, 2018.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
*/

/*
  Copyright 2018  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaims all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

#include "Modules.h"
k; if (clock < mmc->cfg->f_min) clock = mmc->cfg->f_min; if (sdhc_clk / 16 > clock) { for (pre_div = 2; pre_div < 256; pre_div *= 2) if ((sdhc_clk / pre_div) <= (clock * 16)) break; } else pre_div = 2; for (div = 1; div <= 16; div++) if ((sdhc_clk / (div * pre_div)) <= clock) break; pre_div >>= 1; div -= 1; clk = (pre_div << 8) | (div << 4); esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); udelay(10000); clk = SYSCTL_PEREN | SYSCTL_CKEN; esdhc_setbits32(®s->sysctl, clk); } static void esdhc_set_ios(struct mmc *mmc) { struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; /* Set the clock speed */ set_sysctl(mmc, mmc->clock); /* Set the bus width */ esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); if (mmc->bus_width == 4) esdhc_setbits32(®s->proctl, PROCTL_DTW_4); else if (mmc->bus_width == 8) esdhc_setbits32(®s->proctl, PROCTL_DTW_8); } static int esdhc_init(struct mmc *mmc) { struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; /* Reset the entire host controller */ esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); /* Wait until the controller is available */ while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) udelay(1000); #ifndef ARCH_MXC /* Enable cache snooping */ esdhc_write32(®s->scr, 0x00000040); #endif esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); /* Set the initial clock speed */ mmc_set_clock(mmc, 400000); /* Disable the BRR and BWR bits in IRQSTAT */ esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); /* Put the PROCTL reg back to the default */ esdhc_write32(®s->proctl, PROCTL_INIT); /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); return 0; } static int esdhc_getcd(struct mmc *mmc) { struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; int timeout = 1000; #ifdef CONFIG_ESDHC_DETECT_QUIRK if (CONFIG_ESDHC_DETECT_QUIRK) return 1; #endif while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout) udelay(1000); return timeout > 0; } static void esdhc_reset(struct fsl_esdhc *regs) { unsigned long timeout = 100; /* wait max 100 ms */ /* reset the controller */ esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); /* hardware clears the bit when it is done */ while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) udelay(1000); if (!timeout) printf("MMC/SD: Reset never completed.\n"); } static const struct mmc_ops esdhc_ops = { .send_cmd = esdhc_send_cmd, .set_ios = esdhc_set_ios, .init = esdhc_init, .getcd = esdhc_getcd, }; int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { struct fsl_esdhc *regs; struct mmc *mmc; u32 caps, voltage_caps; if (!cfg) return -1; regs = (struct fsl_esdhc *)cfg->esdhc_base; /* First reset the eSDHC controller */ esdhc_reset(regs); esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN | SYSCTL_CKEN); memset(&cfg->cfg, 0, sizeof(cfg->cfg)); voltage_caps = 0; caps = regs->hostcapblt; #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 caps = caps & ~(ESDHC_HOSTCAPBLT_SRS | ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30); #endif /* T4240 host controller capabilities register should have VS33 bit */ #ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 caps = caps | ESDHC_HOSTCAPBLT_VS33; #endif if (caps & ESDHC_HOSTCAPBLT_VS18) voltage_caps |= MMC_VDD_165_195; if (caps & ESDHC_HOSTCAPBLT_VS30) voltage_caps |= MMC_VDD_29_30 | MMC_VDD_30_31; if (caps & ESDHC_HOSTCAPBLT_VS33) voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34; cfg->cfg.name = "FSL_SDHC"; cfg->cfg.ops = &esdhc_ops; #ifdef CONFIG_SYS_SD_VOLTAGE cfg->cfg.voltages = CONFIG_SYS_SD_VOLTAGE; #else cfg->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; #endif if ((cfg->cfg.voltages & voltage_caps) == 0) { printf("voltage not supported by controller\n"); return -1; } cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC; if (cfg->max_bus_width > 0) { if (cfg->max_bus_width < 8) cfg->cfg.host_caps &= ~MMC_MODE_8BIT; if (cfg->max_bus_width < 4) cfg->cfg.host_caps &= ~MMC_MODE_4BIT; } if (caps & ESDHC_HOSTCAPBLT_HSS) cfg->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; #ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) cfg->cfg.host_caps &= ~MMC_MODE_8BIT; #endif cfg->cfg.f_min = 400000; cfg->cfg.f_max = MIN(gd->arch.sdhc_clk, 52000000); cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; mmc = mmc_create(&cfg->cfg, cfg); if (mmc == NULL) return -1; return 0; } int fsl_esdhc_mmc_init(bd_t *bis) { struct fsl_esdhc_cfg *cfg; cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1); cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR; cfg->sdhc_clk = gd->arch.sdhc_clk; return fsl_esdhc_initialize(bis, cfg); } #ifdef CONFIG_OF_LIBFDT void fdt_fixup_esdhc(void *blob, bd_t *bd) { const char *compat = "fsl,esdhc"; #ifdef CONFIG_FSL_ESDHC_PIN_MUX if (!hwconfig("esdhc")) { do_fixup_by_compat(blob, compat, "status", "disabled", 8 + 1, 1); return; } #endif do_fixup_by_compat_u32(blob, compat, "clock-frequency", gd->arch.sdhc_clk, 1); do_fixup_by_compat(blob, compat, "status", "okay", 4 + 1, 1); } #endif