Page MenuHomeFreeBSD

D8407.diff
No OneTemporary

D8407.diff

Index: head/sys/conf/files.powerpc
===================================================================
--- head/sys/conf/files.powerpc
+++ head/sys/conf/files.powerpc
@@ -63,6 +63,7 @@
dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac
dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx
dev/scc/scc_bfe_macio.c optional scc powermac
+dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci
dev/sec/sec.c optional sec mpc85xx
dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac
dev/sound/macio/davbus.c optional snd_davbus powermac
@@ -137,7 +138,6 @@
powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 fdt
powerpc/mpc85xx/ds1553_core.c optional ds1553
powerpc/mpc85xx/fsl_diu.c optional mpc85xx diu
-powerpc/mpc85xx/fsl_sdhc.c optional mpc85xx sdhc
powerpc/mpc85xx/i2c.c optional iicbus fdt
powerpc/mpc85xx/isa.c optional mpc85xx isa
powerpc/mpc85xx/lbc.c optional mpc85xx
Index: head/sys/dev/sdhci/fsl_sdhci.c
===================================================================
--- head/sys/dev/sdhci/fsl_sdhci.c
+++ head/sys/dev/sdhci/fsl_sdhci.c
@@ -28,7 +28,7 @@
__FBSDID("$FreeBSD$");
/*
- * SDHCI driver glue for Freescale i.MX SoC family.
+ * SDHCI driver glue for Freescale i.MX SoC and QorIQ families.
*
* This supports both eSDHC (earlier SoCs) and uSDHC (more recent SoCs).
*/
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/callout.h>
+#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/libkern.h>
#include <sys/lock.h>
@@ -52,9 +53,11 @@
#include <machine/bus.h>
#include <machine/resource.h>
+#ifdef __arm__
#include <machine/intr.h>
#include <arm/freescale/imx/imx_ccmvar.h>
+#endif
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@@ -146,7 +149,6 @@
#define SDHC_PROT_CDSS (1 << 7)
#define SDHC_SYS_CTRL 0x2c
-#define SDHC_INT_STATUS 0x30
/*
* The clock enable bits exist in different registers for ESDHC vs USDHC, but
@@ -169,6 +171,7 @@
{"fsl,imx6sl-usdhc", HWTYPE_USDHC},
{"fsl,imx53-esdhc", HWTYPE_ESDHC},
{"fsl,imx51-esdhc", HWTYPE_ESDHC},
+ {"fsl,esdhc", HWTYPE_ESDHC},
{NULL, HWTYPE_NONE},
};
@@ -397,6 +400,11 @@
if (off == SDHCI_POWER_CONTROL) {
return;
}
+#ifdef __powerpc__
+ /* XXX Reset doesn't seem to work as expected. Do nothing for now. */
+ if (off == SDHCI_SOFTWARE_RESET)
+ return;
+#endif
val32 = RD4(sc, off & ~3);
val32 &= ~(0xff << (off & 3) * 8);
@@ -531,17 +539,20 @@
val |= SDHCI_CLOCK_INT_STABLE;
/*
- * On ESDHC hardware the card bus clock enable is in the usual sdhci
- * register but it's a different bit, so transcribe it (note the
+ * On i.MX ESDHC hardware the card bus clock enable is in the usual
+ * sdhci register but it's a different bit, so transcribe it (note the
* difference between standard SDHCI_ and Freescale SDHC_ prefixes
- * here). On USDHC hardware there is a force-on bit, but no force-off
- * for the card bus clock (the hardware runs the clock when transfers
- * are active no matter what), so we always say the clock is on.
+ * here). On USDHC and QorIQ ESDHC hardware there is a force-on bit, but
+ * no force-off for the card bus clock (the hardware runs the clock when
+ * transfers are active no matter what), so we always say the clock is
+ * on.
* XXX Maybe we should say it's in whatever state the sdhci driver last
* set it to.
*/
if (sc->hwtype == HWTYPE_ESDHC) {
+#ifdef __arm__
if (RD4(sc, SDHC_SYS_CTRL) & SDHC_CLK_SDCLKEN)
+#endif
val |= SDHCI_CLOCK_CARD_EN;
} else {
val |= SDHCI_CLOCK_CARD_EN;
@@ -565,15 +576,18 @@
sc->sdclockreg_freq_bits = val & SDHCI_DIVIDERS_MASK;
if (sc->hwtype == HWTYPE_ESDHC) {
/*
- * The ESDHC hardware requires the driver to manually start and
- * stop the sd bus clock. If the enable bit is not set, turn
- * off the clock in hardware and we're done, otherwise decode
- * the requested frequency. ESDHC hardware is sdhci 2.0; the
- * sdhci driver will use the original 8-bit divisor field and
- * the "base / 2^N" divisor scheme.
+ * The i.MX5 ESDHC hardware requires the driver to manually
+ * start and stop the sd bus clock. If the enable bit is not
+ * set, turn off the clock in hardware and we're done, otherwise
+ * decode the requested frequency. ESDHC hardware is sdhci 2.0;
+ * the sdhci driver will use the original 8-bit divisor field
+ * and the "base / 2^N" divisor scheme.
*/
if ((val & SDHCI_CLOCK_CARD_EN) == 0) {
+#ifdef __arm__
+ /* On QorIQ, this is a reserved bit. */
WR4(sc, SDHCI_CLOCK_CONTROL, val32 & ~SDHC_CLK_SDCLKEN);
+#endif
return;
}
@@ -625,6 +639,7 @@
val32 &= ~(SDHC_CLK_DIVISOR_MASK | SDHC_CLK_PRESCALE_MASK);
val32 |= divisor << SDHC_CLK_DIVISOR_SHIFT;
val32 |= prescale << SDHC_CLK_PRESCALE_SHIFT;
+ val32 |= SDHC_CLK_IPGEN;
WR4(sc, SDHCI_CLOCK_CONTROL, val32);
}
@@ -710,10 +725,10 @@
*/
switch (sc->r1bfix_type) {
case R1BFIX_NODATA:
- intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_RESPONSE;
+ intmask = RD4(sc, SDHCI_INT_STATUS) & SDHCI_INT_RESPONSE;
break;
case R1BFIX_AC12:
- intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_DATA_END;
+ intmask = RD4(sc, SDHCI_INT_STATUS) & SDHCI_INT_DATA_END;
break;
default:
intmask = 0;
@@ -722,8 +737,8 @@
if (intmask) {
sc->r1bfix_timeout_at = getsbinuptime() + 250 * SBT_1MS;
if (!fsl_sdhci_r1bfix_is_wait_done(sc)) {
- WR4(sc, SDHC_INT_STATUS, intmask);
- bus_barrier(sc->mem_res, SDHC_INT_STATUS, 4,
+ WR4(sc, SDHCI_INT_STATUS, intmask);
+ bus_barrier(sc->mem_res, SDHCI_INT_STATUS, 4,
BUS_SPACE_BARRIER_WRITE);
}
}
@@ -735,9 +750,53 @@
static int
fsl_sdhci_get_ro(device_t bus, device_t child)
{
+ struct fsl_sdhci_softc *sc = device_get_softc(bus);
+
+ if (RD4(sc, SDHCI_PRESENT_STATE) & SDHC_PRES_WPSPL)
+ return (false);
+ return (true);
+}
+
+#ifdef __powerpc__
+static uint32_t
+fsl_sdhci_get_platform_clock(device_t dev)
+{
+ device_t parent;
+ phandle_t node;
+ uint32_t clock;
+
+ node = ofw_bus_get_node(dev);
- return (false);
+ /* Get sdhci node properties */
+ if((OF_getprop(node, "clock-frequency", (void *)&clock,
+ sizeof(clock)) <= 0) || (clock == 0)) {
+
+ /*
+ * Trying to get clock from parent device (soc) if correct
+ * clock cannot be acquired from sdhci node.
+ */
+ parent = device_get_parent(dev);
+ node = ofw_bus_get_node(parent);
+
+ /* Get soc properties */
+ if ((OF_getprop(node, "bus-frequency", (void *)&clock,
+ sizeof(clock)) <= 0) || (clock == 0)) {
+ device_printf(dev,"Cannot acquire correct sdhci "
+ "frequency from DTS.\n");
+
+ return (0);
+ }
+ /* eSDHC clock is 1/2 platform clock. */
+ clock /= 2;
+ }
+
+ if (bootverbose)
+ device_printf(dev, "Acquired clock: %d from DTS\n", clock);
+
+ return (clock);
}
+#endif
+
static int
fsl_sdhci_detach(device_t dev)
@@ -752,6 +811,7 @@
struct fsl_sdhci_softc *sc = device_get_softc(dev);
int rid, err;
phandle_t node;
+ uint32_t protctl;
sc->dev = dev;
@@ -807,9 +867,23 @@
*
* XXX need named constants for this stuff.
*/
- WR4(sc, SDHC_WTMK_LVL, 0x08800880);
+#ifdef __powerpc__
+ /* P1022 has the '*_BRST_LEN' fields as reserved, always reading 0x10 */
+ if ((SVR_VER(mfspr(SPR_SVR)) & 0xfff6) == SVR_P1022 )
+ WR4(sc, SDHC_WTMK_LVL, 0x10801080);
+ else
+#endif
+ WR4(sc, SDHC_WTMK_LVL, 0x08800880);
+ /*
+ * We read in native byte order in the main driver, but the register
+ * defaults to little endian.
+ */
+#ifdef __powerpc__
+ sc->baseclk_hz = fsl_sdhci_get_platform_clock(dev);
+#else
sc->baseclk_hz = imx_ccm_sdhci_hz();
+#endif
sc->slot.max_clk = sc->baseclk_hz;
/*
@@ -830,6 +904,16 @@
/* XXX put real gpio hookup here. */
sc->force_card_present = true;
}
+#ifdef __powerpc__
+ /* Default to big-endian on powerpc */
+ protctl = RD4(sc, SDHC_PROT_CTRL);
+ protctl &= ~SDHC_PROT_EMODE_MASK;
+ if (OF_hasprop(node, "little-endian"))
+ protctl |= SDHC_PROT_EMODE_LITTLE;
+ else
+ protctl |= SDHC_PROT_EMODE_BIG;
+ WR4(sc, SDHC_PROT_CTRL, protctl);
+#endif
callout_init(&sc->r1bfix_callout, 1);
sdhci_init_slot(dev, &sc->slot, 0);
Index: head/sys/powerpc/mpc85xx/fsl_sdhc.h
===================================================================
--- head/sys/powerpc/mpc85xx/fsl_sdhc.h
+++ head/sys/powerpc/mpc85xx/fsl_sdhc.h
@@ -1,297 +0,0 @@
-/*-
- * Copyright (c) 2011-2012 Semihalf
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef FSL_SDHC_H_
-#define FSL_SDHC_H_
-
-#include <sys/cdefs.h>
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/rman.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/taskqueue.h>
-
-#include <machine/bus.h>
-
-#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
-#include <dev/mmc/mmcvar.h>
-#include <dev/mmc/mmcbrvar.h>
-
-#include "mmcbr_if.h"
-
-
-/*****************************************************************************
- * Private defines
- *****************************************************************************/
-struct slot {
- uint32_t clock;
-};
-
-struct fsl_sdhc_softc {
- device_t self;
- device_t child;
-
- bus_space_handle_t bsh;
- bus_space_tag_t bst;
-
- struct resource *mem_resource;
- int mem_rid;
- struct resource *irq_resource;
- int irq_rid;
- void *ihl;
-
- bus_dma_tag_t dma_tag;
- bus_dmamap_t dma_map;
- uint32_t* dma_mem;
- bus_addr_t dma_phys;
-
- struct mtx mtx;
-
- struct task card_detect_task;
- struct callout card_detect_callout;
-
- struct mmc_host mmc_host;
-
- struct slot slot;
- uint32_t bus_busy;
- uint32_t platform_clock;
-
- struct mmc_request *request;
- int data_done;
- int command_done;
- int use_dma;
- uint32_t* data_ptr;
- uint32_t data_offset;
-};
-
-#define FSL_SDHC_RESET_DELAY 50
-
-#define FSL_SDHC_BASE_CLOCK_DIV (2)
-#define FSL_SDHC_MAX_DIV (FSL_SDHC_BASE_CLOCK_DIV * 256 * 16)
-#define FSL_SDHC_MIN_DIV (FSL_SDHC_BASE_CLOCK_DIV * 2)
-#define FSL_SDHC_MAX_CLOCK (50000000)
-
-#define FSL_SDHC_MAX_BLOCK_COUNT (65535)
-#define FSL_SDHC_MAX_BLOCK_SIZE (4096)
-
-#define FSL_SDHC_FIFO_BUF_SIZE (64) /* Water-mark level. */
-#define FSL_SDHC_FIFO_BUF_WORDS (FSL_SDHC_FIFO_BUF_SIZE / 4)
-
-#define FSL_SDHC_DMA_SEGMENT_SIZE (1024)
-#define FSL_SDHC_DMA_ALIGNMENT (4)
-#define FSL_SDHC_DMA_BLOCK_SIZE FSL_SDHC_MAX_BLOCK_SIZE
-
-
-/*
- * Offsets of SD HC registers
- */
-enum sdhc_reg_off {
- SDHC_DSADDR = 0x000,
- SDHC_BLKATTR = 0x004,
- SDHC_CMDARG = 0x008,
- SDHC_XFERTYP = 0x00c,
- SDHC_CMDRSP0 = 0x010,
- SDHC_CMDRSP1 = 0x014,
- SDHC_CMDRSP2 = 0x018,
- SDHC_CMDRSP3 = 0x01c,
- SDHC_DATPORT = 0x020,
- SDHC_PRSSTAT = 0x024,
- SDHC_PROCTL = 0x028,
- SDHC_SYSCTL = 0x02c,
- SDHC_IRQSTAT = 0x030,
- SDHC_IRQSTATEN = 0x034,
- SDHC_IRQSIGEN = 0x038,
- SDHC_AUTOC12ERR = 0x03c,
- SDHC_HOSTCAPBLT = 0x040,
- SDHC_WML = 0x044,
- SDHC_FEVT = 0x050,
- SDHC_HOSTVER = 0x0fc,
- SDHC_DCR = 0x40c
-};
-
-enum sysctl_bit {
- SYSCTL_INITA = 0x08000000,
- SYSCTL_RSTD = 0x04000000,
- SYSCTL_RSTC = 0x02000000,
- SYSCTL_RSTA = 0x01000000,
- SYSCTL_DTOCV = 0x000f0000,
- SYSCTL_SDCLKFS = 0x0000ff00,
- SYSCTL_DVS = 0x000000f0,
- SYSCTL_PEREN = 0x00000004,
- SYSCTL_HCKEN = 0x00000002,
- SYSCTL_IPGEN = 0x00000001
-};
-
-#define HEX_LEFT_SHIFT(x) (4 * x)
-enum sysctl_shift {
- SHIFT_DTOCV = HEX_LEFT_SHIFT(4),
- SHIFT_SDCLKFS = HEX_LEFT_SHIFT(2),
- SHIFT_DVS = HEX_LEFT_SHIFT(1)
-};
-
-enum proctl_bit {
- PROCTL_WECRM = 0x04000000,
- PROCTL_WECINS = 0x02000000,
- PROCTL_WECINT = 0x01000000,
- PROCTL_RWCTL = 0x00040000,
- PROCTL_CREQ = 0x00020000,
- PROCTL_SABGREQ = 0x00010000,
- PROCTL_CDSS = 0x00000080,
- PROCTL_CDTL = 0x00000040,
- PROCTL_EMODE = 0x00000030,
- PROCTL_D3CD = 0x00000008,
- PROCTL_DTW = 0x00000006
-};
-
-enum dtw {
- DTW_1 = 0x00000000,
- DTW_4 = 0x00000002,
- DTW_8 = 0x00000004
-};
-
-enum prsstat_bit {
- PRSSTAT_DLSL = 0xff000000,
- PRSSTAT_CLSL = 0x00800000,
- PRSSTAT_WPSPL = 0x00080000,
- PRSSTAT_CDPL = 0x00040000,
- PRSSTAT_CINS = 0x00010000,
- PRSSTAT_BREN = 0x00000800,
- PRSSTAT_BWEN = 0x00000400,
- PRSSTAT_RTA = 0x00000200,
- PRSSTAT_WTA = 0x00000100,
- PRSSTAT_SDOFF = 0x00000080,
- PRSSTAT_PEROFF = 0x00000040,
- PRSSTAT_HCKOFF = 0x00000020,
- PRSSTAT_IPGOFF = 0x00000010,
- PRSSTAT_DLA = 0x00000004,
- PRSSTAT_CDIHB = 0x00000002,
- PRSSTAT_CIHB = 0x00000001
-
-};
-
-enum irq_bits {
- IRQ_DMAE = 0x10000000,
- IRQ_AC12E = 0x01000000,
- IRQ_DEBE = 0x00400000,
- IRQ_DCE = 0x00200000,
- IRQ_DTOE = 0x00100000,
- IRQ_CIE = 0x00080000,
- IRQ_CEBE = 0x00040000,
- IRQ_CCE = 0x00020000,
- IRQ_CTOE = 0x00010000,
- IRQ_CINT = 0x00000100,
- IRQ_CRM = 0x00000080,
- IRQ_CINS = 0x00000040,
- IRQ_BRR = 0x00000020,
- IRQ_BWR = 0x00000010,
- IRQ_DINT = 0x00000008,
- IRQ_BGE = 0x00000004,
- IRQ_TC = 0x00000002,
- IRQ_CC = 0x00000001
-};
-
-enum irq_masks {
- IRQ_ERROR_DATA_MASK = IRQ_DMAE | IRQ_DEBE | IRQ_DCE | IRQ_DTOE,
- IRQ_ERROR_CMD_MASK = IRQ_AC12E | IRQ_CIE | IRQ_CTOE | IRQ_CCE |
- IRQ_CEBE
-};
-
-enum dcr_bits {
- DCR_PRI = 0x0000c000,
- DCR_SNOOP = 0x00000040,
- DCR_AHB2MAG_BYPASS = 0x00000020,
- DCR_RD_SAFE = 0x00000004,
- DCR_RD_PFE = 0x00000002,
- DCR_RD_PF_SIZE = 0x00000001
-};
-
-#define DCR_PRI_SHIFT (14)
-
-enum xfertyp_bits {
- XFERTYP_CMDINX = 0x3f000000,
- XFERTYP_CMDTYP = 0x00c00000,
- XFERTYP_DPSEL = 0x00200000,
- XFERTYP_CICEN = 0x00100000,
- XFERTYP_CCCEN = 0x00080000,
- XFERTYP_RSPTYP = 0x00030000,
- XFERTYP_MSBSEL = 0x00000020,
- XFERTYP_DTDSEL = 0x00000010,
- XFERTYP_AC12EN = 0x00000004,
- XFERTYP_BCEN = 0x00000002,
- XFERTYP_DMAEN = 0x00000001
-};
-
-#define CMDINX_SHIFT (24)
-
-enum xfertyp_cmdtyp {
- CMDTYP_NORMAL = 0x00000000,
- CMDYTP_SUSPEND = 0x00400000,
- CMDTYP_RESUME = 0x00800000,
- CMDTYP_ABORT = 0x00c00000
-};
-
-enum xfertyp_rsptyp {
- RSPTYP_NONE = 0x00000000,
- RSPTYP_136 = 0x00010000,
- RSPTYP_48 = 0x00020000,
- RSPTYP_48_BUSY = 0x00030000
-};
-
-enum blkattr_bits {
- BLKATTR_BLKSZE = 0x00001fff,
- BLKATTR_BLKCNT = 0xffff0000
-};
-#define BLKATTR_BLOCK_COUNT(x) (x << 16)
-
-enum wml_bits {
- WR_WML = 0x00ff0000,
- RD_WML = 0x000000ff,
-};
-
-enum sdhc_bit_mask {
- MASK_CLOCK_CONTROL = 0x0000ffff,
- MASK_IRQ_ALL = IRQ_DMAE | IRQ_AC12E | IRQ_DEBE | IRQ_DCE |
- IRQ_DTOE | IRQ_CIE | IRQ_CEBE | IRQ_CCE |
- IRQ_CTOE | IRQ_CINT | IRQ_CRM | IRQ_CINS |
- IRQ_BRR | IRQ_BWR | IRQ_DINT | IRQ_BGE |
- IRQ_TC | IRQ_CC,
-};
-
-enum sdhc_line {
- SDHC_DAT_LINE = 0x2,
- SDHC_CMD_LINE = 0x1
-};
-
-#endif /* FSL_SDHC_H_ */
Index: head/sys/powerpc/mpc85xx/fsl_sdhc.c
===================================================================
--- head/sys/powerpc/mpc85xx/fsl_sdhc.c
+++ head/sys/powerpc/mpc85xx/fsl_sdhc.c
@@ -1,1303 +0,0 @@
-/*-
- * Copyright (c) 2011-2012 Semihalf
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Driver for Freescale integrated eSDHC controller.
- * Limitations:
- * - No support for multi-block transfers.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/rman.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/taskqueue.h>
-
-#include <machine/bus.h>
-#include <machine/vmparam.h>
-
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
-
-#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
-#include <dev/mmc/mmcvar.h>
-#include <dev/mmc/mmcbrvar.h>
-
-#include <powerpc/mpc85xx/mpc85xx.h>
-
-#include "opt_platform.h"
-
-#include "mmcbr_if.h"
-
-#include "fsl_sdhc.h"
-
-#ifdef DEBUG
-#define DPRINTF(fmt, arg...) printf("DEBUG %s(): " fmt, __FUNCTION__, ##arg)
-#else
-#define DPRINTF(fmt, arg...)
-#endif
-
-
-/*****************************************************************************
- * Register the driver
- *****************************************************************************/
-/* Forward declarations */
-static int fsl_sdhc_probe(device_t);
-static int fsl_sdhc_attach(device_t);
-static int fsl_sdhc_detach(device_t);
-
-static int fsl_sdhc_read_ivar(device_t, device_t, int, uintptr_t *);
-static int fsl_sdhc_write_ivar(device_t, device_t, int, uintptr_t);
-
-static int fsl_sdhc_update_ios(device_t, device_t);
-static int fsl_sdhc_request(device_t, device_t, struct mmc_request *);
-static int fsl_sdhc_get_ro(device_t, device_t);
-static int fsl_sdhc_acquire_host(device_t, device_t);
-static int fsl_sdhc_release_host(device_t, device_t);
-
-static device_method_t fsl_sdhc_methods[] = {
- /* device_if */
- DEVMETHOD(device_probe, fsl_sdhc_probe),
- DEVMETHOD(device_attach, fsl_sdhc_attach),
- DEVMETHOD(device_detach, fsl_sdhc_detach),
-
- /* Bus interface */
- DEVMETHOD(bus_read_ivar, fsl_sdhc_read_ivar),
- DEVMETHOD(bus_write_ivar, fsl_sdhc_write_ivar),
-
- /* OFW bus interface */
- DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
- DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
- DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
- DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
- DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
-
- /* mmcbr_if */
- DEVMETHOD(mmcbr_update_ios, fsl_sdhc_update_ios),
- DEVMETHOD(mmcbr_request, fsl_sdhc_request),
- DEVMETHOD(mmcbr_get_ro, fsl_sdhc_get_ro),
- DEVMETHOD(mmcbr_acquire_host, fsl_sdhc_acquire_host),
- DEVMETHOD(mmcbr_release_host, fsl_sdhc_release_host),
-
- {0, 0},
-};
-
-/* kobj_class definition */
-static driver_t fsl_sdhc_driver = {
- "sdhci_fsl",
- fsl_sdhc_methods,
- sizeof(struct fsl_sdhc_softc)
-};
-
-static devclass_t fsl_sdhc_devclass;
-
-DRIVER_MODULE(sdhci_fsl, simplebus, fsl_sdhc_driver, fsl_sdhc_devclass, 0, 0);
-DRIVER_MODULE(mmc, sdhci_fsl, mmc_driver, mmc_devclass, NULL, NULL);
-MODULE_DEPEND(sdhci_fsl, mmc, 1, 1, 1);
-
-/*****************************************************************************
- * Private methods
- *****************************************************************************/
-static inline int
-read4(struct fsl_sdhc_softc *sc, unsigned int offset)
-{
-
- return bus_space_read_4(sc->bst, sc->bsh, offset);
-}
-
-static inline void
-write4(struct fsl_sdhc_softc *sc, unsigned int offset, int value)
-{
-
- bus_space_write_4(sc->bst, sc->bsh, offset, value);
-}
-
-static inline void
-set_bit(struct fsl_sdhc_softc *sc, uint32_t offset, uint32_t mask)
-{
- uint32_t x = read4(sc, offset);
-
- write4(sc, offset, x | mask);
-}
-
-static inline void
-clear_bit(struct fsl_sdhc_softc *sc, uint32_t offset, uint32_t mask)
-{
- uint32_t x = read4(sc, offset);
-
- write4(sc, offset, x & ~mask);
-}
-
-static int
-wait_for_bit_clear(struct fsl_sdhc_softc *sc, enum sdhc_reg_off reg,
- uint32_t bit)
-{
- uint32_t timeout = 10;
- uint32_t stat;
-
- stat = read4(sc, reg);
- while (stat & bit) {
- if (timeout == 0) {
- return (-1);
- }
- --timeout;
- DELAY(1000);
- stat = read4(sc, reg);
- }
-
- return (0);
-}
-
-static int
-wait_for_free_line(struct fsl_sdhc_softc *sc, enum sdhc_line line)
-{
- uint32_t timeout = 100;
- uint32_t stat;
-
- stat = read4(sc, SDHC_PRSSTAT);
- while (stat & line) {
- if (timeout == 0) {
- return (-1);
- }
- --timeout;
- DELAY(1000);
- stat = read4(sc, SDHC_PRSSTAT);
- }
-
- return (0);
-}
-
-static uint32_t
-get_platform_clock(struct fsl_sdhc_softc *sc)
-{
- device_t self, parent;
- phandle_t node;
- uint32_t clock;
-
- self = sc->self;
- node = ofw_bus_get_node(self);
-
- /* Get sdhci node properties */
- if((OF_getprop(node, "clock-frequency", (void *)&clock,
- sizeof(clock)) <= 0) || (clock == 0)) {
-
- /*
- * Trying to get clock from parent device (soc) if correct
- * clock cannot be acquired from sdhci node.
- */
- parent = device_get_parent(self);
- node = ofw_bus_get_node(parent);
-
- /* Get soc properties */
- if ((OF_getprop(node, "bus-frequency", (void *)&clock,
- sizeof(clock)) <= 0) || (clock == 0)) {
- device_printf(self,"Cannot acquire correct sdhci "
- "frequency from DTS.\n");
-
- return (0);
- }
- }
-
- DPRINTF("Acquired clock: %d from DTS\n", clock);
-
- return (clock);
-}
-
-/**
- * Set clock driving card.
- * @param sc
- * @param clock Desired clock frequency in Hz
- */
-static void
-set_clock(struct fsl_sdhc_softc *sc, uint32_t clock)
-{
- uint32_t base_clock;
- uint32_t divisor, prescaler = 1;
- uint32_t round = 0;
-
- if (clock == sc->slot.clock)
- return;
-
- if (clock == 0) {
- clear_bit(sc, SDHC_SYSCTL, MASK_CLOCK_CONTROL | SYSCTL_PEREN |
- SYSCTL_HCKEN | SYSCTL_IPGEN);
- return;
- }
-
- base_clock = sc->platform_clock;
- round = base_clock & 0x2;
- base_clock >>= 2;
- base_clock += round;
- round = 0;
-
- /* SD specification 1.1 doesn't allow frequences above 50 MHz */
- if (clock > FSL_SDHC_MAX_CLOCK)
- clock = FSL_SDHC_MAX_CLOCK;
-
- /*
- * divisor = ceil(base_clock / clock)
- * TODO: Reconsider symmetric rounding here instead of ceiling.
- */
- divisor = howmany(base_clock, clock);
-
- while (divisor > 16) {
- round = divisor & 0x1;
- divisor >>= 1;
-
- prescaler <<= 1;
- }
- divisor += round - 1;
-
- /* Turn off the clock. */
- clear_bit(sc, SDHC_SYSCTL, MASK_CLOCK_CONTROL);
-
- /* Write clock settings. */
- set_bit(sc, SDHC_SYSCTL, (prescaler << SHIFT_SDCLKFS) |
- (divisor << SHIFT_DVS));
-
- /*
- * Turn on clocks.
- * TODO: This actually disables clock automatic gating off feature of
- * the controller which eventually should be enabled but as for now
- * it prevents controller from generating card insertion/removal
- * interrupts correctly.
- */
- set_bit(sc, SDHC_SYSCTL, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN);
-
- sc->slot.clock = clock;
-
- DPRINTF("given clock = %d, computed clock = %d\n", clock,
- (base_clock / prescaler) / (divisor + 1));
-}
-
-static inline void
-send_80_clock_ticks(struct fsl_sdhc_softc *sc)
-{
- int err;
-
- err = wait_for_free_line(sc, SDHC_CMD_LINE | SDHC_DAT_LINE);
- if (err != 0) {
- device_printf(sc->self, "Can't acquire data/cmd lines\n");
- return;
- }
-
- set_bit(sc, SDHC_SYSCTL, SYSCTL_INITA);
- err = wait_for_bit_clear(sc, SDHC_SYSCTL, SYSCTL_INITA);
- if (err != 0) {
- device_printf(sc->self, "Can't send 80 clocks to the card.\n");
- }
-}
-
-static void
-set_bus_width(struct fsl_sdhc_softc *sc, enum mmc_bus_width width)
-{
-
- DPRINTF("setting bus width to %d\n", width);
- switch (width) {
- case bus_width_1:
- set_bit(sc, SDHC_PROCTL, DTW_1);
- break;
- case bus_width_4:
- set_bit(sc, SDHC_PROCTL, DTW_4);
- break;
- case bus_width_8:
- set_bit(sc, SDHC_PROCTL, DTW_8);
- break;
- default:
- device_printf(sc->self, "Unsupported bus width\n");
- }
-}
-
-static void
-reset_controller_all(struct fsl_sdhc_softc *sc)
-{
- uint32_t count = 5;
-
- set_bit(sc, SDHC_SYSCTL, SYSCTL_RSTA);
- while (read4(sc, SDHC_SYSCTL) & SYSCTL_RSTA) {
- DELAY(FSL_SDHC_RESET_DELAY);
- --count;
- if (count == 0) {
- device_printf(sc->self,
- "Can't reset the controller\n");
- return;
- }
- }
-}
-
-static void
-reset_controller_dat_cmd(struct fsl_sdhc_softc *sc)
-{
- int err;
-
- set_bit(sc, SDHC_SYSCTL, SYSCTL_RSTD | SYSCTL_RSTC);
- err = wait_for_bit_clear(sc, SDHC_SYSCTL, SYSCTL_RSTD | SYSCTL_RSTC);
- if (err != 0) {
- device_printf(sc->self, "Can't reset data & command part!\n");
- return;
- }
-}
-
-static void
-init_controller(struct fsl_sdhc_softc *sc)
-{
-
- /* Enable interrupts. */
-#ifdef FSL_SDHC_NO_DMA
- write4(sc, SDHC_IRQSTATEN, MASK_IRQ_ALL & ~IRQ_DINT & ~IRQ_DMAE);
- write4(sc, SDHC_IRQSIGEN, MASK_IRQ_ALL & ~IRQ_DINT & ~IRQ_DMAE);
-#else
- write4(sc, SDHC_IRQSTATEN, MASK_IRQ_ALL & ~IRQ_BRR & ~IRQ_BWR);
- write4(sc, SDHC_IRQSIGEN, MASK_IRQ_ALL & ~IRQ_BRR & ~IRQ_BWR);
-
- /* Write DMA address */
- write4(sc, SDHC_DSADDR, sc->dma_phys);
-
- /* Enable snooping and fix for AHB2MAG bypass. */
- write4(sc, SDHC_DCR, DCR_SNOOP | DCR_AHB2MAG_BYPASS);
-#endif
- /* Set data timeout. */
- set_bit(sc, SDHC_SYSCTL, 0xe << SHIFT_DTOCV);
-
- /* Set water-mark levels (FIFO buffer size). */
- write4(sc, SDHC_WML, (FSL_SDHC_FIFO_BUF_WORDS << 16) |
- FSL_SDHC_FIFO_BUF_WORDS);
-}
-
-static void
-init_mmc_host_struct(struct fsl_sdhc_softc *sc)
-{
- struct mmc_host *host = &sc->mmc_host;
-
- /* Clear host structure. */
- bzero(host, sizeof(struct mmc_host));
-
- /* Calculate minimum and maximum operating frequencies. */
- host->f_min = sc->platform_clock / FSL_SDHC_MAX_DIV;
- host->f_max = FSL_SDHC_MAX_CLOCK;
-
- /* Set operation conditions (voltage). */
- host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
-
- /* Set additional host controller capabilities. */
- host->caps = MMC_CAP_4_BIT_DATA;
-
- /* Set mode. */
- host->mode = mode_sd;
-}
-
-static void
-card_detect_task(void *arg, int pending)
-{
- struct fsl_sdhc_softc *sc = (struct fsl_sdhc_softc *)arg;
- int err;
- int insert;
-
- insert = read4(sc, SDHC_PRSSTAT) & PRSSTAT_CINS;
-
- mtx_lock(&sc->mtx);
-
- if (insert) {
- if (sc->child != NULL) {
- mtx_unlock(&sc->mtx);
- return;
- }
-
- sc->child = device_add_child(sc->self, "mmc", -1);
- if (sc->child == NULL) {
- device_printf(sc->self, "Couldn't add MMC bus!\n");
- mtx_unlock(&sc->mtx);
- return;
- }
-
- /* Initialize MMC bus host structure. */
- init_mmc_host_struct(sc);
- device_set_ivars(sc->child, &sc->mmc_host);
-
- } else {
- if (sc->child == NULL) {
- mtx_unlock(&sc->mtx);
- return;
- }
- }
-
- mtx_unlock(&sc->mtx);
-
- if (insert) {
- if ((err = device_probe_and_attach(sc->child)) != 0) {
- device_printf(sc->self, "MMC bus failed on probe "
- "and attach! error %d\n", err);
- device_delete_child(sc->self, sc->child);
- sc->child = NULL;
- }
- } else {
- if (device_delete_child(sc->self, sc->child) != 0)
- device_printf(sc->self, "Could not delete MMC bus!\n");
- sc->child = NULL;
- }
-}
-
-static void
-card_detect_delay(void *arg)
-{
- struct fsl_sdhc_softc *sc = arg;
-
- taskqueue_enqueue(taskqueue_swi_giant, &sc->card_detect_task);
-}
-
-static void
-finalize_request(struct fsl_sdhc_softc *sc)
-{
-
- DPRINTF("finishing request %p\n", sc->request);
-
- sc->request->done(sc->request);
- sc->request = NULL;
-}
-
-/**
- * Read response from card.
- * @todo Implement Auto-CMD responses being held in R3 for multi-block xfers.
- * @param sc
- */
-static void
-get_response(struct fsl_sdhc_softc *sc)
-{
- struct mmc_command *cmd = sc->request->cmd;
- int i;
- uint32_t val;
- uint8_t ext = 0;
-
- if (cmd->flags & MMC_RSP_136) {
- /* CRC is stripped, need to shift one byte left. */
- for (i = 0; i < 4; i++) {
- val = read4(sc, SDHC_CMDRSP0 + i * 4);
- cmd->resp[3 - i] = (val << 8) + ext;
- ext = val >> 24;
- }
- } else {
- cmd->resp[0] = read4(sc, SDHC_CMDRSP0);
- }
-}
-
-#ifdef FSL_SDHC_NO_DMA
-/**
- * Read all content of a fifo buffer.
- * @warning Assumes data buffer is 32-bit aligned.
- * @param sc
- */
-static void
-read_block_pio(struct fsl_sdhc_softc *sc)
-{
- struct mmc_data *data = sc->request->cmd->data;
- size_t left = min(FSL_SDHC_FIFO_BUF_SIZE, data->len);
- uint8_t *buf = data->data;
- uint32_t word;
-
- buf += sc->data_offset;
- bus_space_read_multi_4(sc->bst, sc->bsh, SDHC_DATPORT, (uint32_t *)buf,
- left >> 2);
-
- sc->data_offset += left;
-
- /* Handle 32-bit unaligned size case. */
- left &= 0x3;
- if (left > 0) {
- buf = (uint8_t *)data->data + (sc->data_offset & ~0x3);
- word = read4(sc, SDHC_DATPORT);
- while (left > 0) {
- *(buf++) = word;
- word >>= 8;
- --left;
- }
- }
-}
-
-/**
- * Write a fifo buffer.
- * @warning Assumes data buffer size is 32-bit aligned.
- * @param sc
- */
-static void
-write_block_pio(struct fsl_sdhc_softc *sc)
-{
- struct mmc_data *data = sc->request->cmd->data;
- size_t left = min(FSL_SDHC_FIFO_BUF_SIZE, data->len);
- uint8_t *buf = data->data;
- uint32_t word = 0;
-
- DPRINTF("sc->data_offset %d\n", sc->data_offset);
-
- buf += sc->data_offset;
- bus_space_write_multi_4(sc->bst, sc->bsh, SDHC_DATPORT, (uint32_t *)buf,
- left >> 2);
-
- sc->data_offset += left;
-
- /* Handle 32-bit unaligned size case. */
- left &= 0x3;
- if (left > 0) {
- buf = (uint8_t *)data->data + (sc->data_offset & ~0x3);
- while (left > 0) {
- word += *(buf++);
- word <<= 8;
- --left;
- }
- write4(sc, SDHC_DATPORT, word);
- }
-}
-
-static void
-pio_read_transfer(struct fsl_sdhc_softc *sc)
-{
-
- while (read4(sc, SDHC_PRSSTAT) & PRSSTAT_BREN) {
- read_block_pio(sc);
-
- /*
- * TODO: should we check here whether data_offset >= data->len?
- */
- }
-}
-
-static void
-pio_write_transfer(struct fsl_sdhc_softc *sc)
-{
-
- while (read4(sc, SDHC_PRSSTAT) & PRSSTAT_BWEN) {
- write_block_pio(sc);
-
- /*
- * TODO: should we check here whether data_offset >= data->len?
- */
- }
-}
-#endif /* FSL_SDHC_USE_DMA */
-
-static inline void
-handle_command_intr(struct fsl_sdhc_softc *sc, uint32_t irq_stat)
-{
- struct mmc_command *cmd = sc->request->cmd;
-
- /* Handle errors. */
- if (irq_stat & IRQ_CTOE) {
- cmd->error = MMC_ERR_TIMEOUT;
- } else if (irq_stat & IRQ_CCE) {
- cmd->error = MMC_ERR_BADCRC;
- } else if (irq_stat & (IRQ_CEBE | IRQ_CIE)) {
- cmd->error = MMC_ERR_FIFO;
- }
-
- if (cmd->error) {
- device_printf(sc->self, "Error interrupt occured\n");
- reset_controller_dat_cmd(sc);
- return;
- }
-
- if (sc->command_done)
- return;
-
- if (irq_stat & IRQ_CC) {
- sc->command_done = 1;
-
- if (cmd->flags & MMC_RSP_PRESENT)
- get_response(sc);
- }
-}
-
-static inline void
-handle_data_intr(struct fsl_sdhc_softc *sc, uint32_t irq_stat)
-{
- struct mmc_command *cmd = sc->request->cmd;
-
- /* Handle errors. */
- if (irq_stat & IRQ_DTOE) {
- cmd->error = MMC_ERR_TIMEOUT;
- } else if (irq_stat & (IRQ_DCE | IRQ_DEBE)) {
- cmd->error = MMC_ERR_BADCRC;
- } else if (irq_stat & IRQ_ERROR_DATA_MASK) {
- cmd->error = MMC_ERR_FAILED;
- }
-
- if (cmd->error) {
- device_printf(sc->self, "Error interrupt occured\n");
- sc->data_done = 1;
- reset_controller_dat_cmd(sc);
- return;
- }
-
- if (sc->data_done)
- return;
-
-#ifdef FSL_SDHC_NO_DMA
- if (irq_stat & IRQ_BRR) {
- pio_read_transfer(sc);
- }
-
- if (irq_stat & IRQ_BWR) {
- pio_write_transfer(sc);
- }
-#else
- if (irq_stat & IRQ_DINT) {
- struct mmc_data *data = sc->request->cmd->data;
-
- /* Synchronize DMA. */
- if (data->flags & MMC_DATA_READ) {
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_POSTREAD);
- memcpy(data->data, sc->dma_mem, data->len);
- } else {
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_POSTWRITE);
- }
-
- /*
- * TODO: For multiple block transfers, address of dma memory
- * in DSADDR register should be set to the beginning of the
- * segment here. Also offset to data pointer should be handled.
- */
- }
-#endif
-
- if (irq_stat & IRQ_TC)
- sc->data_done = 1;
-}
-
-static void
-interrupt_handler(void *arg)
-{
- struct fsl_sdhc_softc *sc = (struct fsl_sdhc_softc *)arg;
- uint32_t irq_stat;
-
- mtx_lock(&sc->mtx);
-
- irq_stat = read4(sc, SDHC_IRQSTAT);
-
- /* Card interrupt. */
- if (irq_stat & IRQ_CINT) {
- DPRINTF("Card interrupt recievied\n");
-
- }
-
- /* Card insertion interrupt. */
- if (irq_stat & IRQ_CINS) {
- clear_bit(sc, SDHC_IRQSIGEN, IRQ_CINS);
- clear_bit(sc, SDHC_IRQSTATEN, IRQ_CINS);
- set_bit(sc, SDHC_IRQSIGEN, IRQ_CRM);
- set_bit(sc, SDHC_IRQSTATEN, IRQ_CRM);
-
- callout_reset(&sc->card_detect_callout, hz / 2,
- card_detect_delay, sc);
- }
-
- /* Card removal interrupt. */
- if (irq_stat & IRQ_CRM) {
- clear_bit(sc, SDHC_IRQSIGEN, IRQ_CRM);
- clear_bit(sc, SDHC_IRQSTATEN, IRQ_CRM);
- set_bit(sc, SDHC_IRQSIGEN, IRQ_CINS);
- set_bit(sc, SDHC_IRQSTATEN, IRQ_CINS);
-
- callout_stop(&sc->card_detect_callout);
- taskqueue_enqueue(taskqueue_swi_giant, &sc->card_detect_task);
- }
-
- /* Handle request interrupts. */
- if (sc->request) {
- handle_command_intr(sc, irq_stat);
- handle_data_intr(sc, irq_stat);
-
- /*
- * Finalize request when transfer is done successfully
- * or was interrupted due to error.
- */
- if ((sc->data_done && sc->command_done) ||
- (sc->request->cmd->error))
- finalize_request(sc);
- }
-
- /* Clear status register. */
- write4(sc, SDHC_IRQSTAT, irq_stat);
-
- mtx_unlock(&sc->mtx);
-}
-
-#ifndef FSL_SDHC_NO_DMA
-static void
-dma_get_phys_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
-{
-
- if (error != 0)
- return;
-
- /* Get first segment's physical address. */
- *(bus_addr_t *)arg = segs->ds_addr;
-}
-
-static int
-init_dma(struct fsl_sdhc_softc *sc)
-{
- device_t self = sc->self;
- int err;
-
- err = bus_dma_tag_create(bus_get_dma_tag(self),
- FSL_SDHC_DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL, FSL_SDHC_DMA_BLOCK_SIZE, 1,
- FSL_SDHC_DMA_BLOCK_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL,
- &sc->dma_tag);
-
- if (err) {
- device_printf(self, "Could not create DMA tag!\n");
- return (-1);
- }
-
- err = bus_dmamem_alloc(sc->dma_tag, (void **)&(sc->dma_mem),
- BUS_DMA_NOWAIT | BUS_DMA_NOCACHE, &sc->dma_map);
- if (err) {
- device_printf(self, "Could not allocate DMA memory!\n");
- goto fail1;
- }
-
- err = bus_dmamap_load(sc->dma_tag, sc->dma_map, (void *)sc->dma_mem,
- FSL_SDHC_DMA_BLOCK_SIZE, dma_get_phys_addr, &sc->dma_phys, 0);
- if (err) {
- device_printf(self, "Could not load DMA map!\n");
- goto fail2;
- }
-
- return (0);
-
-fail2:
- bus_dmamem_free(sc->dma_tag, sc->dma_mem, sc->dma_map);
-fail1:
- bus_dma_tag_destroy(sc->dma_tag);
-
- return (-1);
-}
-#endif /* FSL_SDHC_NO_DMA */
-
-static uint32_t
-set_xfertyp_register(const struct mmc_command *cmd)
-{
- uint32_t xfertyp = 0;
-
- /* Set command index. */
- xfertyp |= cmd->opcode << CMDINX_SHIFT;
-
- /* Set command type. */
- if (cmd->opcode == MMC_STOP_TRANSMISSION)
- xfertyp |= CMDTYP_ABORT;
-
- /* Set data preset select. */
- if (cmd->data) {
- xfertyp |= XFERTYP_DPSEL;
-
- /* Set transfer direction. */
- if (cmd->data->flags & MMC_DATA_READ)
- xfertyp |= XFERTYP_DTDSEL;
- }
-
- /* Set command index check. */
- if (cmd->flags & MMC_RSP_OPCODE)
- xfertyp |= XFERTYP_CICEN;
-
- /* Set command CRC check. */
- if (cmd->flags & MMC_RSP_CRC)
- xfertyp |= XFERTYP_CCCEN;
-
- /* Set response type */
- if (!(cmd->flags & MMC_RSP_PRESENT))
- xfertyp |= RSPTYP_NONE;
- else if (cmd->flags & MMC_RSP_136)
- xfertyp |= RSPTYP_136;
- else if (cmd->flags & MMC_RSP_BUSY)
- xfertyp |= RSPTYP_48_BUSY;
- else
- xfertyp |= RSPTYP_48;
-
-#ifndef FSL_SDHC_NO_DMA
- /* Enable DMA */
- xfertyp |= XFERTYP_DMAEN;
-#endif
-
- return (xfertyp);
-}
-
-static uint32_t
-set_blkattr_register(const struct mmc_data *data)
-{
-
- if (data->len <= FSL_SDHC_MAX_BLOCK_SIZE) {
- /* One block transfer. */
- return (BLKATTR_BLOCK_COUNT(1) | ((data->len) &
- BLKATTR_BLKSZE));
- }
-
- /* TODO: Write code here for multi-block transfers. */
- return (0);
-}
-
-/**
- * Initiate data transfer. Interrupt handler will finalize it.
- * @todo Implement multi-block transfers.
- * @param sc
- * @param cmd
- */
-static int
-start_data(struct fsl_sdhc_softc *sc, struct mmc_data *data)
-{
- uint32_t reg;
-
- if ((uint32_t)data->data & 0x3) {
- device_printf(sc->self, "32-bit unaligned data pointer in "
- "request\n");
- return (-1);
- }
-
- sc->data_done = 0;
-
-#ifdef FSL_SDHC_NO_DMA
- sc->data_ptr = data->data;
- sc->data_offset = 0;
-#else
- /* Write DMA address register. */
- write4(sc, SDHC_DSADDR, sc->dma_phys);
-
- /* Synchronize DMA. */
- if (data->flags & MMC_DATA_READ) {
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_PREREAD);
- } else {
- memcpy(sc->dma_mem, data->data, data->len);
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_PREWRITE);
- }
-#endif
- /* Set block size and count. */
- reg = set_blkattr_register(data);
- if (reg == 0) {
- device_printf(sc->self, "Requested unsupported multi-block "
- "transfer.\n");
- return (-1);
- }
- write4(sc, SDHC_BLKATTR, reg);
-
- return (0);
-}
-
-static int
-start_command(struct fsl_sdhc_softc *sc, struct mmc_command *cmd)
-{
- struct mmc_request *req = sc->request;
- uint32_t mask;
- uint32_t xfertyp;
- int err;
-
- DPRINTF("opcode %d, flags 0x%08x\n", cmd->opcode, cmd->flags);
- DPRINTF("PRSSTAT = 0x%08x\n", read4(sc, SDHC_PRSSTAT));
-
- sc->command_done = 0;
-
- cmd->error = MMC_ERR_NONE;
-
- /* TODO: should we check here for card presence and clock settings? */
-
- /* Always wait for free CMD line. */
- mask = SDHC_CMD_LINE;
- /* Wait for free DAT if we have data or busy signal. */
- if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
- mask |= SDHC_DAT_LINE;
- /* We shouldn't wait for DAT for stop commands. */
- if (cmd == req->stop)
- mask &= ~SDHC_DAT_LINE;
- err = wait_for_free_line(sc, mask);
- if (err != 0) {
- device_printf(sc->self, "Controller never released inhibit "
- "bit(s).\n");
- reset_controller_dat_cmd(sc);
- cmd->error = MMC_ERR_FAILED;
- sc->request = NULL;
- req->done(req);
- return (-1);
- }
-
- xfertyp = set_xfertyp_register(cmd);
-
- if (cmd->data != NULL) {
- err = start_data(sc, cmd->data);
- if (err != 0) {
- device_printf(sc->self,
- "Data transfer request failed\n");
- reset_controller_dat_cmd(sc);
- cmd->error = MMC_ERR_FAILED;
- sc->request = NULL;
- req->done(req);
- return (-1);
- }
- }
-
- write4(sc, SDHC_CMDARG, cmd->arg);
- write4(sc, SDHC_XFERTYP, xfertyp);
-
- DPRINTF("XFERTYP = 0x%08x\n", xfertyp);
- DPRINTF("CMDARG = 0x%08x\n", cmd->arg);
-
- return (0);
-}
-
-#ifdef DEBUG
-static void
-dump_registers(struct fsl_sdhc_softc *sc)
-{
- printf("PRSSTAT = 0x%08x\n", read4(sc, SDHC_PRSSTAT));
- printf("PROCTL = 0x%08x\n", read4(sc, SDHC_PROCTL));
- printf("HOSTCAPBLT = 0x%08x\n", read4(sc, SDHC_HOSTCAPBLT));
- printf("IRQSTAT = 0x%08x\n", read4(sc, SDHC_IRQSTAT));
- printf("IRQSTATEN = 0x%08x\n", read4(sc, SDHC_IRQSTATEN));
- printf("IRQSIGEN = 0x%08x\n", read4(sc, SDHC_IRQSIGEN));
- printf("WML = 0x%08x\n", read4(sc, SDHC_WML));
- printf("DSADDR = 0x%08x\n", read4(sc, SDHC_DSADDR));
- printf("XFERTYP = 0x%08x\n", read4(sc, SDHC_XFERTYP));
- printf("DCR = 0x%08x\n", read4(sc, SDHC_DCR));
-}
-#endif
-
-/*****************************************************************************
- * Public methods
- *****************************************************************************/
-/*
- * Device interface methods.
- */
-static int
-fsl_sdhc_probe(device_t self)
-{
- static const char *desc =
- "Freescale Enhanced Secure Digital Host Controller";
-
- if (!ofw_bus_is_compatible(self, "fsl,p2020-esdhc") &&
- !ofw_bus_is_compatible(self, "fsl,esdhc"))
- return (ENXIO);
-
- device_set_desc(self, desc);
-
- return (BUS_PROBE_VENDOR);
-}
-
-static int
-fsl_sdhc_attach(device_t self)
-{
- struct fsl_sdhc_softc *sc;
-
- sc = device_get_softc(self);
-
- sc->self = self;
-
- mtx_init(&sc->mtx, device_get_nameunit(self), NULL, MTX_DEF);
-
- /* Setup memory resource */
- sc->mem_rid = 0;
- sc->mem_resource = bus_alloc_resource_any(self, SYS_RES_MEMORY,
- &sc->mem_rid, RF_ACTIVE);
- if (sc->mem_resource == NULL) {
- device_printf(self, "Could not allocate memory.\n");
- goto fail;
- }
- sc->bst = rman_get_bustag(sc->mem_resource);
- sc->bsh = rman_get_bushandle(sc->mem_resource);
-
- /* Setup interrupt resource. */
- sc->irq_rid = 0;
- sc->irq_resource = bus_alloc_resource_any(self, SYS_RES_IRQ,
- &sc->irq_rid, RF_ACTIVE);
- if (sc->irq_resource == NULL) {
- device_printf(self, "Could not allocate interrupt.\n");
- goto fail;
- }
- if (bus_setup_intr(self, sc->irq_resource, INTR_TYPE_MISC |
- INTR_MPSAFE, NULL, interrupt_handler, sc, &sc->ihl) != 0) {
- device_printf(self, "Could not setup interrupt.\n");
- goto fail;
- }
-
- /* Setup DMA. */
-#ifndef FSL_SDHC_NO_DMA
- if (init_dma(sc) != 0) {
- device_printf(self, "Could not setup DMA\n");
- }
-#endif
- sc->bus_busy = 0;
- sc->platform_clock = get_platform_clock(sc);
- if (sc->platform_clock == 0) {
- device_printf(self, "Could not get platform clock.\n");
- goto fail;
- }
- sc->command_done = 1;
- sc->data_done = 1;
-
- /* Init card detection task. */
- TASK_INIT(&sc->card_detect_task, 0, card_detect_task, sc);
- callout_init(&sc->card_detect_callout, 1);
-
- reset_controller_all(sc);
- init_controller(sc);
- set_clock(sc, 400000);
- send_80_clock_ticks(sc);
-
-#ifdef DEBUG
- dump_registers(sc);
-#endif
-
- return (0);
-
-fail:
- fsl_sdhc_detach(self);
- return (ENXIO);
-}
-
-static int
-fsl_sdhc_detach(device_t self)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- int err;
-
- if (sc->child)
- device_delete_child(self, sc->child);
-
- taskqueue_drain(taskqueue_swi_giant, &sc->card_detect_task);
-
-#ifndef FSL_SDHC_NO_DMA
- bus_dmamap_unload(sc->dma_tag, sc->dma_map);
- bus_dmamem_free(sc->dma_tag, sc->dma_mem, sc->dma_map);
- bus_dma_tag_destroy(sc->dma_tag);
-#endif
-
- if (sc->ihl != NULL) {
- err = bus_teardown_intr(self, sc->irq_resource, sc->ihl);
- if (err)
- return (err);
- }
- if (sc->irq_resource != NULL) {
- err = bus_release_resource(self, SYS_RES_IRQ, sc->irq_rid,
- sc->irq_resource);
- if (err)
- return (err);
-
- }
- if (sc->mem_resource != NULL) {
- err = bus_release_resource(self, SYS_RES_MEMORY, sc->mem_rid,
- sc->mem_resource);
- if (err)
- return (err);
- }
-
- mtx_destroy(&sc->mtx);
-
- return (0);
-}
-
-
-/*
- * Bus interface methods.
- */
-static int
-fsl_sdhc_read_ivar(device_t self, device_t child, int index,
- uintptr_t *result)
-{
- struct mmc_host *host = device_get_ivars(child);
-
- switch (index) {
- case MMCBR_IVAR_BUS_MODE:
- *(int *)result = host->ios.bus_mode;
- break;
- case MMCBR_IVAR_BUS_WIDTH:
- *(int *)result = host->ios.bus_width;
- break;
- case MMCBR_IVAR_CHIP_SELECT:
- *(int *)result = host->ios.chip_select;
- break;
- case MMCBR_IVAR_CLOCK:
- *(int *)result = host->ios.clock;
- break;
- case MMCBR_IVAR_F_MIN:
- *(int *)result = host->f_min;
- break;
- case MMCBR_IVAR_F_MAX:
- *(int *)result = host->f_max;
- break;
- case MMCBR_IVAR_HOST_OCR:
- *(int *)result = host->host_ocr;
- break;
- case MMCBR_IVAR_MODE:
- *(int *)result = host->mode;
- break;
- case MMCBR_IVAR_OCR:
- *(int *)result = host->ocr;
- break;
- case MMCBR_IVAR_POWER_MODE:
- *(int *)result = host->ios.power_mode;
- break;
- case MMCBR_IVAR_VDD:
- *(int *)result = host->ios.vdd;
- break;
- default:
- return (EINVAL);
- }
-
- return (0);
-}
-
-static int
-fsl_sdhc_write_ivar(device_t self, device_t child, int index,
- uintptr_t value)
-{
- struct mmc_host *host = device_get_ivars(child);
-
- switch (index) {
- case MMCBR_IVAR_BUS_MODE:
- host->ios.bus_mode = value;
- break;
- case MMCBR_IVAR_BUS_WIDTH:
- host->ios.bus_width = value;
- break;
- case MMCBR_IVAR_CHIP_SELECT:
- host->ios.chip_select = value;
- break;
- case MMCBR_IVAR_CLOCK:
- host->ios.clock = value;
- break;
- case MMCBR_IVAR_MODE:
- host->mode = value;
- break;
- case MMCBR_IVAR_OCR:
- host->ocr = value;
- break;
- case MMCBR_IVAR_POWER_MODE:
- host->ios.power_mode = value;
- break;
- case MMCBR_IVAR_VDD:
- host->ios.vdd = value;
- break;
- case MMCBR_IVAR_HOST_OCR:
- case MMCBR_IVAR_F_MIN:
- case MMCBR_IVAR_F_MAX:
- default:
- /* Instance variable not writable. */
- return (EINVAL);
- }
-
- return (0);
-}
-
-
-/*
- * MMC bridge methods.
- */
-static int
-fsl_sdhc_update_ios(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- struct mmc_host *host = device_get_ivars(reqdev);
- struct mmc_ios *ios = &host->ios;
-
- mtx_lock(&sc->mtx);
-
- /* Full reset on bus power down to clear from any state. */
- if (ios->power_mode == power_off) {
- reset_controller_all(sc);
- init_controller(sc);
- }
-
- set_clock(sc, ios->clock);
- set_bus_width(sc, ios->bus_width);
-
- mtx_unlock(&sc->mtx);
-
- return (0);
-}
-
-static int
-fsl_sdhc_request(device_t self, device_t reqdev, struct mmc_request *req)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- int err;
-
- mtx_lock(&sc->mtx);
-
- sc->request = req;
- err = start_command(sc, req->cmd);
-
- mtx_unlock(&sc->mtx);
-
- return (err);
-}
-
-static int
-fsl_sdhc_get_ro(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
-
- /* Wouldn't it be faster using branching (if {}) ?? */
- return (((read4(sc, SDHC_PRSSTAT) & PRSSTAT_WPSPL) >> 19) ^ 0x1);
-}
-
-static int
-fsl_sdhc_acquire_host(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- int retval = 0;
-
- mtx_lock(&sc->mtx);
-
- while (sc->bus_busy)
- retval = mtx_sleep(sc, &sc->mtx, PZERO, "sdhcah", 0);
- ++(sc->bus_busy);
-
- mtx_unlock(&sc->mtx);
-
- return (retval);
-}
-
-static int
-fsl_sdhc_release_host(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
-
- mtx_lock(&sc->mtx);
- --(sc->bus_busy);
- mtx_unlock(&sc->mtx);
- wakeup(sc);
-
- return (0);
-}

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 25, 3:58 AM (8 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15594084
Default Alt Text
D8407.diff (46 KB)

Event Timeline