Module Name: src
Committed By: jmcneill
Date: Sun Jul 30 16:54:36 UTC 2017
Modified Files:
src/sys/arch/arm/broadcom: bcm2835_emmc.c bcm2835_intr.c bcm2835_obio.c
bcm2835reg.h files.bcm2835
src/sys/arch/evbarm/conf: RPI
src/sys/arch/evbarm/rpi: rpi_machdep.c
Added Files:
src/sys/arch/arm/broadcom: bcm2835_sdhost.c
Log Message:
Add driver for the bcm2835 internal SD controller. On boards with SDIO
Wi-Fi, the internal SD controller is used for the SD card slot and the
Arasan SDHCI controller is used for SDIO.
To generate a diff of this commit:
cvs rdiff -u -r1.30 -r1.31 src/sys/arch/arm/broadcom/bcm2835_emmc.c
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/arm/broadcom/bcm2835_intr.c
cvs rdiff -u -r1.26 -r1.27 src/sys/arch/arm/broadcom/bcm2835_obio.c \
src/sys/arch/arm/broadcom/files.bcm2835
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/broadcom/bcm2835_sdhost.c
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/arm/broadcom/bcm2835reg.h
cvs rdiff -u -r1.71 -r1.72 src/sys/arch/evbarm/conf/RPI
cvs rdiff -u -r1.72 -r1.73 src/sys/arch/evbarm/rpi/rpi_machdep.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/broadcom/bcm2835_emmc.c
diff -u src/sys/arch/arm/broadcom/bcm2835_emmc.c:1.30 src/sys/arch/arm/broadcom/bcm2835_emmc.c:1.31
--- src/sys/arch/arm/broadcom/bcm2835_emmc.c:1.30 Thu Jun 22 13:13:51 2017
+++ src/sys/arch/arm/broadcom/bcm2835_emmc.c Sun Jul 30 16:54:36 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_emmc.c,v 1.30 2017/06/22 13:13:51 jmcneill Exp $ */
+/* $NetBSD: bcm2835_emmc.c,v 1.31 2017/07/30 16:54:36 jmcneill Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_emmc.c,v 1.30 2017/06/22 13:13:51 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_emmc.c,v 1.31 2017/07/30 16:54:36 jmcneill Exp $");
#include "bcmdmac.h"
@@ -107,6 +107,7 @@ bcmemmc_attach(device_t parent, device_t
prop_dictionary_t dict = device_properties(self);
struct amba_attach_args *aaa = aux;
prop_number_t frequency;
+ bool disable = false;
int error;
sc->sc.sc_dev = self;
@@ -122,6 +123,13 @@ bcmemmc_attach(device_t parent, device_t
sc->sc.sc_clkbase = 50000; /* Default to 50MHz */
sc->sc_iot = aaa->aaa_iot;
+ prop_dictionary_get_bool(dict, "disable", &disable);
+ if (disable) {
+ aprint_naive(": disabled\n");
+ aprint_normal(": disabled\n");
+ return;
+ }
+
/* Fetch the EMMC clock frequency from property if set. */
frequency = prop_dictionary_get(dict, "frequency");
if (frequency != NULL) {
@@ -131,8 +139,8 @@ bcmemmc_attach(device_t parent, device_t
error = bus_space_map(sc->sc_iot, aaa->aaa_addr, aaa->aaa_size, 0,
&sc->sc_ioh);
if (error) {
- aprint_error_dev(self,
- "can't map registers for %s: %d\n", aaa->aaa_name, error);
+ aprint_error(": can't map registers for %s: %d\n",
+ aaa->aaa_name, error);
return;
}
sc->sc_iob = aaa->aaa_addr;
Index: src/sys/arch/arm/broadcom/bcm2835_intr.c
diff -u src/sys/arch/arm/broadcom/bcm2835_intr.c:1.11 src/sys/arch/arm/broadcom/bcm2835_intr.c:1.12
--- src/sys/arch/arm/broadcom/bcm2835_intr.c:1.11 Sat Aug 1 14:18:00 2015
+++ src/sys/arch/arm/broadcom/bcm2835_intr.c Sun Jul 30 16:54:36 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_intr.c,v 1.11 2015/08/01 14:18:00 skrll Exp $ */
+/* $NetBSD: bcm2835_intr.c,v 1.12 2017/07/30 16:54:36 jmcneill Exp $ */
/*-
* Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.11 2015/08/01 14:18:00 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.12 2017/07/30 16:54:36 jmcneill Exp $");
#define _INTR_PRIVATE
@@ -163,7 +163,7 @@ static const char * const bcm2835_source
"(unused 44)", "pwa0", "pwa1", "(unused 47)",
"smi", "gpio[0]", "gpio[1]", "gpio[2]",
"gpio[3]", "i2c", "spi", "pcm",
- "sdio", "uart", "(unused 58)", "(unused 59)",
+ "sdhost", "uart", "(unused 58)", "(unused 59)",
"(unused 60)", "(unused 61)", "emmc", "(unused 63)",
"Timer", "Mailbox", "Doorbell0", "Doorbell1",
"GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
Index: src/sys/arch/arm/broadcom/bcm2835_obio.c
diff -u src/sys/arch/arm/broadcom/bcm2835_obio.c:1.26 src/sys/arch/arm/broadcom/bcm2835_obio.c:1.27
--- src/sys/arch/arm/broadcom/bcm2835_obio.c:1.26 Sat Nov 21 07:41:29 2015
+++ src/sys/arch/arm/broadcom/bcm2835_obio.c Sun Jul 30 16:54:36 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_obio.c,v 1.26 2015/11/21 07:41:29 mlelstv Exp $ */
+/* $NetBSD: bcm2835_obio.c,v 1.27 2017/07/30 16:54:36 jmcneill Exp $ */
/*-
* Copyright (c) 2012, 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_obio.c,v 1.26 2015/11/21 07:41:29 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_obio.c,v 1.27 2017/07/30 16:54:36 jmcneill Exp $");
#include "locators.h"
#include "obio.h"
@@ -148,6 +148,13 @@ static const struct ambadev_locators bcm
.ad_intr = -1,
},
{
+ /* SD host interface */
+ .ad_name = "sdhost",
+ .ad_addr = BCM2835_SDHOST_BASE,
+ .ad_size = BCM2835_SDHOST_SIZE,
+ .ad_intr = BCM2835_INT_SDHOST,
+ },
+ {
/* eMMC interface */
.ad_name = "emmc",
.ad_addr = BCM2835_EMMC_BASE,
Index: src/sys/arch/arm/broadcom/files.bcm2835
diff -u src/sys/arch/arm/broadcom/files.bcm2835:1.26 src/sys/arch/arm/broadcom/files.bcm2835:1.27
--- src/sys/arch/arm/broadcom/files.bcm2835:1.26 Sat Nov 21 07:41:29 2015
+++ src/sys/arch/arm/broadcom/files.bcm2835 Sun Jul 30 16:54:36 2017
@@ -1,4 +1,4 @@
-# $NetBSD: files.bcm2835,v 1.26 2015/11/21 07:41:29 mlelstv Exp $
+# $NetBSD: files.bcm2835,v 1.27 2017/07/30 16:54:36 jmcneill Exp $
#
# Configuration info for Broadcom BCM2835 ARM Peripherals
#
@@ -61,6 +61,11 @@ file arch/arm/broadcom/bcm2835_plcom.c b
attach sdhc at obio with bcmemmc
file arch/arm/broadcom/bcm2835_emmc.c bcmemmc
+# SD Host Controller (BCM2835_SDHOST_BASE)
+device sdhost: sdmmcbus
+attach sdhost at obio with bcmsdhost
+file arch/arm/broadcom/bcm2835_sdhost.c bcmsdhost needs-flag
+
# DMA Controller (BCM2835_DMA0_BASE)
device bcmdmac
attach bcmdmac at obio with bcmdmac_amba
Index: src/sys/arch/arm/broadcom/bcm2835reg.h
diff -u src/sys/arch/arm/broadcom/bcm2835reg.h:1.18 src/sys/arch/arm/broadcom/bcm2835reg.h:1.19
--- src/sys/arch/arm/broadcom/bcm2835reg.h:1.18 Tue Feb 2 13:55:50 2016
+++ src/sys/arch/arm/broadcom/bcm2835reg.h Sun Jul 30 16:54:36 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835reg.h,v 1.18 2016/02/02 13:55:50 skrll Exp $ */
+/* $NetBSD: bcm2835reg.h,v 1.19 2017/07/30 16:54:36 jmcneill Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -61,6 +61,7 @@
#define BCM2835_RNG_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00104000)
#define BCM2835_GPIO_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00200000)
#define BCM2835_UART0_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00201000)
+#define BCM2835_SDHOST_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00202000)
#define BCM2835_PCM_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00203000)
#define BCM2835_SPI0_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00204000)
#define BCM2835_BSC0_BASE (BCM2835_PERIPHERALS_BASE_BUS + 0x00205000)
@@ -86,6 +87,7 @@
#define BCM2835_BSC_SIZE 0x1000
#define BCM2835_PWM_SIZE 0x28
#define BCM2835_AUX_SIZE 0x1000
+#define BCM2835_SDHOST_SIZE 0x1000
#define BCM2835_EMMC_SIZE 0x1000
#define BCM2835_USB_SIZE 0x20000
#define BCM2835_DMA15_SIZE 0x100
@@ -184,6 +186,7 @@
#define BCM2835_INT_BSC (BCM2835_INT_GPU1BASE + 21)
#define BCM2835_INT_SPI0 (BCM2835_INT_GPU1BASE + 22)
#define BCM2835_INT_PCM (BCM2835_INT_GPU1BASE + 23)
+#define BCM2835_INT_SDHOST (BCM2835_INT_GPU1BASE + 24)
#define BCM2835_INT_UART0 (BCM2835_INT_GPU1BASE + 25)
#define BCM2835_INT_EMMC (BCM2835_INT_GPU1BASE + 30)
Index: src/sys/arch/evbarm/conf/RPI
diff -u src/sys/arch/evbarm/conf/RPI:1.71 src/sys/arch/evbarm/conf/RPI:1.72
--- src/sys/arch/evbarm/conf/RPI:1.71 Tue Dec 13 20:42:17 2016
+++ src/sys/arch/evbarm/conf/RPI Sun Jul 30 16:54:36 2017
@@ -1,5 +1,5 @@
#
-# $NetBSD: RPI,v 1.71 2016/12/13 20:42:17 christos Exp $
+# $NetBSD: RPI,v 1.72 2017/07/30 16:54:36 jmcneill Exp $
#
# RPi -- Raspberry Pi
#
@@ -96,6 +96,10 @@ bcmgpio1 at obio? # pins 32 ... 53
sdhc* at obio?
sdmmc* at sdhc?
+# SD host controller
+#sdhost* at obio?
+#sdmmc* at sdhost?
+
ld* at sdmmc?
# On-board USB
Index: src/sys/arch/evbarm/rpi/rpi_machdep.c
diff -u src/sys/arch/evbarm/rpi/rpi_machdep.c:1.72 src/sys/arch/evbarm/rpi/rpi_machdep.c:1.73
--- src/sys/arch/evbarm/rpi/rpi_machdep.c:1.72 Sat Jun 17 22:50:23 2017
+++ src/sys/arch/evbarm/rpi/rpi_machdep.c Sun Jul 30 16:54:36 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: rpi_machdep.c,v 1.72 2017/06/17 22:50:23 jmcneill Exp $ */
+/* $NetBSD: rpi_machdep.c,v 1.73 2017/07/30 16:54:36 jmcneill Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rpi_machdep.c,v 1.72 2017/06/17 22:50:23 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rpi_machdep.c,v 1.73 2017/07/30 16:54:36 jmcneill Exp $");
#include "opt_arm_debug.h"
#include "opt_bcm283x.h"
@@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: rpi_machdep.
#include "opt_vcprop.h"
#include "sdhc.h"
+#include "bcmsdhost.h"
#include "bcmdwctwo.h"
#include "bcmspi.h"
#include "bsciic.h"
@@ -220,6 +221,7 @@ static struct __aligned(16) {
struct vcprop_tag_cmdline vbt_cmdline;
struct vcprop_tag_clockrate vbt_emmcclockrate;
struct vcprop_tag_clockrate vbt_armclockrate;
+ struct vcprop_tag_clockrate vbt_coreclockrate;
struct vcprop_tag end;
} vb = {
.vb_hdr = {
@@ -298,6 +300,14 @@ static struct __aligned(16) {
},
.id = VCPROP_CLK_ARM
},
+ .vbt_coreclockrate = {
+ .tag = {
+ .vpt_tag = VCPROPTAG_GET_CLOCKRATE,
+ .vpt_len = VCPROPTAG_LEN(vb.vbt_coreclockrate),
+ .vpt_rcode = VCPROPTAG_REQUEST
+ },
+ .id = VCPROP_CLK_CORE
+ },
.end = {
.vpt_tag = VCPROPTAG_NULL
}
@@ -422,6 +432,23 @@ static uint8_t cursor_mask[8 * 64], curs
#endif
#endif
+/*
+ * Return true if this model Raspberry Pi has Bluetooth/Wi-Fi support
+ */
+static bool
+rpi_rev_has_btwifi(uint32_t rev)
+{
+ if ((rev & VCPROP_REV_ENCFLAG) == 0)
+ return false;
+
+ switch (__SHIFTOUT(rev, VCPROP_REV_MODEL)) {
+ case RPI_MODEL_B_PI3:
+ case RPI_MODEL_ZERO_W:
+ return true;
+ default:
+ return false;
+ }
+}
static void
rpi_uartinit(void)
@@ -437,16 +464,11 @@ rpi_uartinit(void)
cpu_dcache_inv_range((vaddr_t)&vb_uart, sizeof(vb_uart));
- if (vcprop_tag_success_p(&vb_uart.vbt_boardrev.tag) &&
- (vb_uart.vbt_boardrev.rev & VCPROP_REV_ENCFLAG) != 0) {
- const uint32_t rev = vb_uart.vbt_boardrev.rev;
- switch (__SHIFTOUT(rev, VCPROP_REV_MODEL)) {
- case RPI_MODEL_B_PI3:
- case RPI_MODEL_ZERO_W:
+ if (vcprop_tag_success_p(&vb_uart.vbt_boardrev.tag)) {
+ if (rpi_rev_has_btwifi(vb_uart.vbt_boardrev.rev)) {
/* Enable UART0 (PL011) on GPIO header */
bcm2835gpio_function_select(14, BCM2835_GPIO_ALT0);
bcm2835gpio_function_select(15, BCM2835_GPIO_ALT0);
- break;
}
}
@@ -455,6 +477,25 @@ rpi_uartinit(void)
}
+static void
+rpi_pinctrl(void)
+{
+#if NBCMSDHOST > 0
+ /*
+ * If the sdhost driver is present, map the SD card slot to the
+ * SD host controller and the sdhci driver to the SDIO pins.
+ */
+ for (int pin = 48; pin <= 53; pin++) {
+ /* Enable SDHOST on SD card slot */
+ bcm2835gpio_function_select(pin, BCM2835_GPIO_ALT0);
+ }
+ for (int pin = 34; pin <= 39; pin++) {
+ /* Enable SDHCI on SDIO */
+ bcm2835gpio_function_select(pin, BCM2835_GPIO_ALT3);
+ }
+#endif
+}
+
static void
rpi_bootparams(void)
@@ -752,6 +793,9 @@ initarm(void *arg)
/* we've a specific device_register routine */
evbarm_device_register = rpi_device_register;
+ /* Change pinctrl settings */
+ rpi_pinctrl();
+
return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, NULL, 0);
}
@@ -1164,12 +1208,23 @@ rpi_device_register(device_t dev, void *
prop_dictionary_set_uint32(dict,
"chanmask", vb.vbt_dmachan.mask);
}
-#if NSDHC > 0
if (device_is_a(dev, "sdhc") &&
vcprop_tag_success_p(&vb.vbt_emmcclockrate.tag) &&
vb.vbt_emmcclockrate.rate > 0) {
prop_dictionary_set_uint32(dict,
"frequency", vb.vbt_emmcclockrate.rate);
+#if NBCMSDHOST > 0
+ if (!rpi_rev_has_btwifi(vb.vbt_boardrev.rev)) {
+ /* No btwifi and sdhost driver is present */
+ prop_dictionary_set_bool(dict, "disable", true);
+ }
+#endif
+ }
+ if (device_is_a(dev, "sdhost") &&
+ vcprop_tag_success_p(&vb.vbt_coreclockrate.tag) &&
+ vb.vbt_coreclockrate.rate > 0) {
+ prop_dictionary_set_uint32(dict,
+ "frequency", vb.vbt_coreclockrate.rate);
}
if (booted_device == NULL &&
device_is_a(dev, "ld") &&
@@ -1177,7 +1232,6 @@ rpi_device_register(device_t dev, void *
booted_partition = 0;
booted_device = dev;
}
-#endif
if (device_is_a(dev, "usmsc") &&
vcprop_tag_success_p(&vb.vbt_macaddr.tag)) {
const uint8_t enaddr[ETHER_ADDR_LEN] = {
@@ -1227,15 +1281,8 @@ rpi_device_register(device_t dev, void *
/* BSC0 is used internally on some boards */
if (device_is_a(dev, "bsciic") &&
((struct amba_attach_args *)aux)->aaa_addr == BCM2835_BSC0_BASE) {
- const uint32_t rev = vb.vbt_boardrev.rev;
-
- if ((rev & VCPROP_REV_ENCFLAG) != 0) {
- switch (__SHIFTOUT(rev, VCPROP_REV_MODEL)) {
- case RPI_MODEL_B_PI3:
- case RPI_MODEL_ZERO_W:
- prop_dictionary_set_bool(dict, "disable", true);
- break;
- }
+ if (rpi_rev_has_btwifi(vb.vbt_boardrev.rev)) {
+ prop_dictionary_set_bool(dict, "disable", true);
}
}
}
Added files:
Index: src/sys/arch/arm/broadcom/bcm2835_sdhost.c
diff -u /dev/null src/sys/arch/arm/broadcom/bcm2835_sdhost.c:1.1
--- /dev/null Sun Jul 30 16:54:36 2017
+++ src/sys/arch/arm/broadcom/bcm2835_sdhost.c Sun Jul 30 16:54:36 2017
@@ -0,0 +1,732 @@
+/* $NetBSD: bcm2835_sdhost.c,v 1.1 2017/07/30 16:54:36 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2017 Jared McNeill <[email protected]>
+ * 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 ``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 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_sdhost.c,v 1.1 2017/07/30 16:54:36 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/gpio.h>
+
+#include <arm/broadcom/bcm2835reg.h>
+#include <arm/broadcom/bcm_amba.h>
+#include <arm/broadcom/bcm2835_dmac.h>
+
+#include <dev/sdmmc/sdmmcvar.h>
+#include <dev/sdmmc/sdmmcchip.h>
+#include <dev/sdmmc/sdmmc_ioreg.h>
+
+#define SDCMD 0x00
+#define SDCMD_NEW __BIT(15)
+#define SDCMD_FAIL __BIT(14)
+#define SDCMD_BUSY __BIT(11)
+#define SDCMD_NORESP __BIT(10)
+#define SDCMD_LONGRESP __BIT(9)
+#define SDCMD_WRITE __BIT(7)
+#define SDCMD_READ __BIT(6)
+#define SDARG 0x04
+#define SDTOUT 0x08
+#define SDTOUT_DEFAULT 0xf00000
+#define SDCDIV 0x0c
+#define SDCDIV_MASK __BITS(10,0)
+#define SDRSP0 0x10
+#define SDRSP1 0x14
+#define SDRSP2 0x18
+#define SDRSP3 0x1c
+#define SDHSTS 0x20
+#define SDHSTS_BUSY __BIT(10)
+#define SDHSTS_BLOCK __BIT(9)
+#define SDHSTS_SDIO __BIT(8)
+#define SDHSTS_REW_TO __BIT(7)
+#define SDHSTS_CMD_TO __BIT(6)
+#define SDHSTS_CRC16_E __BIT(5)
+#define SDHSTS_CRC7_E __BIT(4)
+#define SDHSTS_FIFO_E __BIT(3)
+#define SDHSTS_DATA __BIT(0)
+#define SDVDD 0x30
+#define SDVDD_POWER __BIT(0)
+#define SDEDM 0x34
+#define SDEDM_RD_FIFO __BITS(18,14)
+#define SDEDM_WR_FIFO __BITS(13,9)
+#define SDHCFG 0x38
+#define SDHCFG_BUSY_EN __BIT(10)
+#define SDHCFG_BLOCK_EN __BIT(8)
+#define SDHCFG_SDIO_EN __BIT(5)
+#define SDHCFG_DATA_EN __BIT(4)
+#define SDHCFG_SLOW __BIT(3)
+#define SDHCFG_WIDE_EXT __BIT(2)
+#define SDHCFG_WIDE_INT __BIT(1)
+#define SDHCFG_REL_CMD __BIT(0)
+#define SDHBCT 0x3c
+#define SDDATA 0x40
+#define SDHBLC 0x50
+
+struct sdhost_softc;
+
+static int sdhost_match(device_t, cfdata_t, void *);
+static void sdhost_attach(device_t, device_t, void *);
+static void sdhost_attach_i(device_t);
+
+static int sdhost_intr(void *);
+static int sdhost_dma_setup(struct sdhost_softc *);
+static void sdhost_dma_done(uint32_t, uint32_t, void *);
+
+static int sdhost_host_reset(sdmmc_chipset_handle_t);
+static uint32_t sdhost_host_ocr(sdmmc_chipset_handle_t);
+static int sdhost_host_maxblklen(sdmmc_chipset_handle_t);
+static int sdhost_card_detect(sdmmc_chipset_handle_t);
+static int sdhost_write_protect(sdmmc_chipset_handle_t);
+static int sdhost_bus_power(sdmmc_chipset_handle_t, uint32_t);
+static int sdhost_bus_clock(sdmmc_chipset_handle_t, int, bool);
+static int sdhost_bus_width(sdmmc_chipset_handle_t, int);
+static int sdhost_bus_rod(sdmmc_chipset_handle_t, int);
+static void sdhost_exec_command(sdmmc_chipset_handle_t,
+ struct sdmmc_command *);
+static void sdhost_card_enable_intr(sdmmc_chipset_handle_t, int);
+static void sdhost_card_intr_ack(sdmmc_chipset_handle_t);
+
+void sdhost_dump_regs(void);
+
+static struct sdmmc_chip_functions sdhost_chip_functions = {
+ .host_reset = sdhost_host_reset,
+ .host_ocr = sdhost_host_ocr,
+ .host_maxblklen = sdhost_host_maxblklen,
+ .card_detect = sdhost_card_detect,
+ .write_protect = sdhost_write_protect,
+ .bus_power = sdhost_bus_power,
+ .bus_clock_ddr = sdhost_bus_clock,
+ .bus_width = sdhost_bus_width,
+ .bus_rod = sdhost_bus_rod,
+ .exec_command = sdhost_exec_command,
+ .card_enable_intr = sdhost_card_enable_intr,
+ .card_intr_ack = sdhost_card_intr_ack,
+};
+
+struct sdhost_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ bus_dma_tag_t sc_dmat;
+
+ bus_addr_t sc_addr;
+
+ void *sc_ih;
+ kmutex_t sc_intr_lock;
+ kcondvar_t sc_intr_cv;
+ kcondvar_t sc_dma_cv;
+
+ u_int sc_rate;
+
+ int sc_mmc_width;
+ int sc_mmc_present;
+
+ device_t sc_sdmmc_dev;
+
+ struct bcm_dmac_channel *sc_dmac;
+
+ bus_dmamap_t sc_dmamap;
+ bus_dma_segment_t sc_segs[1];
+ struct bcm_dmac_conblk *sc_cblk;
+
+ uint32_t sc_intr_hsts;
+
+ uint32_t sc_dma_status;
+ uint32_t sc_dma_error;
+};
+
+CFATTACH_DECL_NEW(bcmsdhost, sizeof(struct sdhost_softc),
+ sdhost_match, sdhost_attach, NULL, NULL);
+
+#define SDHOST_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define SDHOST_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+
+static int
+sdhost_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct amba_attach_args * const aaa = aux;
+
+ return strcmp(aaa->aaa_name, "sdhost") == 0;
+}
+
+static void
+sdhost_attach(device_t parent, device_t self, void *aux)
+{
+ struct sdhost_softc * const sc = device_private(self);
+ struct amba_attach_args * const aaa = aux;
+ prop_dictionary_t dict = device_properties(self);
+
+ sc->sc_dev = self;
+ sc->sc_bst = aaa->aaa_iot;
+ sc->sc_dmat = aaa->aaa_dmat;
+ sc->sc_addr = aaa->aaa_addr;
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
+ cv_init(&sc->sc_intr_cv, "sdhostintr");
+ cv_init(&sc->sc_dma_cv, "sdhostdma");
+
+ if (bus_space_map(sc->sc_bst, aaa->aaa_addr, aaa->aaa_size, 0,
+ &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+
+ aprint_naive("\n");
+ aprint_normal(": SD HOST controller\n");
+
+sdhost_dump_regs();
+
+ prop_dictionary_get_uint32(dict, "frequency", &sc->sc_rate);
+ if (sc->sc_rate == 0) {
+ aprint_error_dev(self, "couldn't get clock frequency\n");
+ return;
+ }
+
+ aprint_normal_dev(self, "ref freq %u Hz\n", sc->sc_rate);
+
+ if (sdhost_dma_setup(sc) != 0) {
+ aprint_error_dev(self, "failed to setup DMA\n");
+ return;
+ }
+
+ sc->sc_ih = intr_establish(aaa->aaa_intr, IPL_SDMMC, IST_LEVEL,
+ sdhost_intr, sc);
+ if (sc->sc_ih == NULL) {
+ aprint_error_dev(self, "failed to establish interrupt %d\n",
+ aaa->aaa_intr);
+ return;
+ }
+ aprint_normal_dev(self, "interrupting on intr %d\n", aaa->aaa_intr);
+
+ config_interrupts(self, sdhost_attach_i);
+}
+
+static int
+sdhost_dma_setup(struct sdhost_softc *sc)
+{
+ int error, rseg;
+
+ sc->sc_dmac = bcm_dmac_alloc(BCM_DMAC_TYPE_NORMAL, IPL_SDMMC,
+ sdhost_dma_done, sc);
+ if (sc->sc_dmac == NULL)
+ return ENXIO;
+
+ error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
+ PAGE_SIZE, sc->sc_segs, 1, &rseg, BUS_DMA_WAITOK);
+ if (error)
+ return error;
+
+ error = bus_dmamem_map(sc->sc_dmat, sc->sc_segs, rseg, PAGE_SIZE,
+ (void **)&sc->sc_cblk, BUS_DMA_WAITOK);
+ if (error)
+ return error;
+
+ memset(sc->sc_cblk, 0, PAGE_SIZE);
+
+ error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
+ BUS_DMA_WAITOK, &sc->sc_dmamap);
+ if (error)
+ return error;
+
+ error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_cblk,
+ PAGE_SIZE, NULL, BUS_DMA_WAITOK|BUS_DMA_WRITE);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void
+sdhost_attach_i(device_t self)
+{
+ struct sdhost_softc *sc = device_private(self);
+ struct sdmmcbus_attach_args saa;
+
+ sdhost_host_reset(sc);
+ sdhost_bus_width(sc, 1);
+ sdhost_bus_clock(sc, 400, false);
+
+ memset(&saa, 0, sizeof(saa));
+ saa.saa_busname = "sdmmc";
+ saa.saa_sct = &sdhost_chip_functions;
+ saa.saa_sch = sc;
+ saa.saa_dmat = sc->sc_dmat;
+ saa.saa_clkmin = 400;
+ saa.saa_clkmax = 50000;
+ saa.saa_caps = SMC_CAPS_DMA |
+ SMC_CAPS_MULTI_SEG_DMA |
+ SMC_CAPS_SD_HIGHSPEED |
+ SMC_CAPS_MMC_HIGHSPEED |
+ SMC_CAPS_4BIT_MODE;
+
+ sc->sc_sdmmc_dev = config_found(self, &saa, NULL);
+}
+
+static int
+sdhost_intr(void *priv)
+{
+ struct sdhost_softc * const sc = priv;
+
+ mutex_enter(&sc->sc_intr_lock);
+ const uint32_t hsts = SDHOST_READ(sc, SDHSTS);
+ if (!hsts) {
+ mutex_exit(&sc->sc_intr_lock);
+ return 0;
+ }
+ SDHOST_WRITE(sc, SDHSTS, hsts);
+
+#ifdef SDHOST_DEBUG
+ device_printf(sc->sc_dev, "mmc intr hsts %#x\n", hsts);
+#endif
+
+ if (hsts) {
+ sc->sc_intr_hsts |= hsts;
+ cv_broadcast(&sc->sc_intr_cv);
+ }
+
+ mutex_exit(&sc->sc_intr_lock);
+
+ return 1;
+}
+
+static int
+sdhost_dma_transfer(struct sdhost_softc *sc, struct sdmmc_command *cmd)
+{
+ size_t seg;
+ int error;
+
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
+ for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
+ sc->sc_cblk[seg].cb_ti =
+ __SHIFTIN(13, DMAC_TI_PERMAP); /* SD HOST */
+ sc->sc_cblk[seg].cb_txfr_len =
+ cmd->c_dmamap->dm_segs[seg].ds_len;
+ /*
+ * All transfers are assumed to be multiples of 32-bits.
+ */
+ KASSERTMSG((sc->sc_cblk[seg].cb_txfr_len & 0x3) == 0,
+ "seg %zu len %d", seg, sc->sc_cblk[seg].cb_txfr_len);
+ if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_DEST_INC;
+ /*
+ * Use 128-bit mode if transfer is a multiple of
+ * 16-bytes.
+ */
+ if ((sc->sc_cblk[seg].cb_txfr_len & 0xf) == 0)
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_DEST_WIDTH;
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_SRC_DREQ;
+ sc->sc_cblk[seg].cb_source_ad =
+ sc->sc_addr + SDDATA;
+ sc->sc_cblk[seg].cb_dest_ad =
+ cmd->c_dmamap->dm_segs[seg].ds_addr;
+ } else {
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_SRC_INC;
+ /*
+ * Use 128-bit mode if transfer is a multiple of
+ * 16-bytes.
+ */
+ if ((sc->sc_cblk[seg].cb_txfr_len & 0xf) == 0)
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_SRC_WIDTH;
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_DEST_DREQ;
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_WAIT_RESP;
+ sc->sc_cblk[seg].cb_source_ad =
+ cmd->c_dmamap->dm_segs[seg].ds_addr;
+ sc->sc_cblk[seg].cb_dest_ad =
+ sc->sc_addr + SDDATA;
+ }
+ sc->sc_cblk[seg].cb_stride = 0;
+ if (seg == cmd->c_dmamap->dm_nsegs - 1) {
+ sc->sc_cblk[seg].cb_ti |= DMAC_TI_INTEN;
+ sc->sc_cblk[seg].cb_nextconbk = 0;
+ } else {
+ sc->sc_cblk[seg].cb_nextconbk =
+ sc->sc_dmamap->dm_segs[0].ds_addr +
+ sizeof(struct bcm_dmac_conblk) * (seg+1);
+ }
+ sc->sc_cblk[seg].cb_padding[0] = 0;
+ sc->sc_cblk[seg].cb_padding[1] = 0;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
+ sc->sc_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
+
+ error = 0;
+
+ sc->sc_dma_status = 0;
+ sc->sc_dma_error = 0;
+
+ bcm_dmac_set_conblk_addr(sc->sc_dmac,
+ sc->sc_dmamap->dm_segs[0].ds_addr);
+ error = bcm_dmac_transfer(sc->sc_dmac);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int
+sdhost_dma_wait(struct sdhost_softc *sc, struct sdmmc_command *cmd)
+{
+ int error = 0;
+
+ while (sc->sc_dma_status == 0 && sc->sc_dma_error == 0) {
+ error = cv_timedwait(&sc->sc_dma_cv, &sc->sc_intr_lock, hz*5);
+ if (error == EWOULDBLOCK) {
+ device_printf(sc->sc_dev, "transfer timeout!\n");
+ bcm_dmac_halt(sc->sc_dmac);
+ error = ETIMEDOUT;
+ break;
+ }
+ }
+
+ if (sc->sc_dma_status & DMAC_CS_END) {
+ cmd->c_resid = 0;
+ error = 0;
+ } else {
+ error = EIO;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
+ sc->sc_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+
+ return error;
+}
+
+static void
+sdhost_dma_done(uint32_t status, uint32_t error, void *arg)
+{
+ struct sdhost_softc * const sc = arg;
+
+ if (status != (DMAC_CS_INT|DMAC_CS_END))
+ device_printf(sc->sc_dev, "dma status %#x error %#x\n",
+ status, error);
+
+ mutex_enter(&sc->sc_intr_lock);
+ sc->sc_dma_status = status;
+ sc->sc_dma_error = error;
+ cv_broadcast(&sc->sc_dma_cv);
+ mutex_exit(&sc->sc_intr_lock);
+}
+
+static int
+sdhost_wait_idle(struct sdhost_softc *sc, int timeout)
+{
+ int retry;
+
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
+ retry = timeout * 1000;
+
+ while (--retry > 0) {
+ const uint32_t cmd = SDHOST_READ(sc, SDCMD);
+ if ((cmd & SDCMD_NEW) == 0)
+ return 0;
+ delay(1);
+ }
+
+ return ETIMEDOUT;
+}
+
+static int
+sdhost_host_reset(sdmmc_chipset_handle_t sch)
+{
+ struct sdhost_softc * const sc = sch;
+ uint32_t edm;
+
+ SDHOST_WRITE(sc, SDVDD, 0);
+ SDHOST_WRITE(sc, SDCMD, 0);
+ SDHOST_WRITE(sc, SDARG, 0);
+ SDHOST_WRITE(sc, SDTOUT, SDTOUT_DEFAULT);
+ SDHOST_WRITE(sc, SDCDIV, 0);
+ SDHOST_WRITE(sc, SDHSTS, SDHOST_READ(sc, SDHSTS));
+ SDHOST_WRITE(sc, SDHCFG, 0);
+ SDHOST_WRITE(sc, SDHBCT, 0);
+ SDHOST_WRITE(sc, SDHBLC, 0);
+
+ edm = SDHOST_READ(sc, SDEDM);
+ edm &= ~(SDEDM_RD_FIFO|SDEDM_WR_FIFO);
+ edm |= __SHIFTIN(4, SDEDM_RD_FIFO);
+ edm |= __SHIFTIN(4, SDEDM_WR_FIFO);
+ SDHOST_WRITE(sc, SDEDM, edm);
+ delay(20000);
+ SDHOST_WRITE(sc, SDVDD, SDVDD_POWER);
+ delay(20000);
+
+ SDHOST_WRITE(sc, SDHCFG, 0);
+ SDHOST_WRITE(sc, SDCDIV, SDCDIV_MASK);
+
+ return 0;
+}
+
+static uint32_t
+sdhost_host_ocr(sdmmc_chipset_handle_t sch)
+{
+ return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V | MMC_OCR_HCS;
+}
+
+static int
+sdhost_host_maxblklen(sdmmc_chipset_handle_t sch)
+{
+ return 8192;
+}
+
+static int
+sdhost_card_detect(sdmmc_chipset_handle_t sch)
+{
+ return 1; /* XXX */
+}
+
+static int
+sdhost_write_protect(sdmmc_chipset_handle_t sch)
+{
+ return 0; /* no write protect pin, assume rw */
+}
+
+static int
+sdhost_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
+{
+ return 0;
+}
+
+static int
+sdhost_bus_clock(sdmmc_chipset_handle_t sch, int freq, bool ddr)
+{
+ struct sdhost_softc * const sc = sch;
+ u_int target_rate = freq * 1000;
+ int div;
+
+ if (freq == 0)
+ div = SDCDIV_MASK;
+ else {
+ div = sc->sc_rate / target_rate;
+ if (div < 2)
+ div = 2;
+ if ((sc->sc_rate / div) > target_rate)
+ div++;
+ div -= 2;
+ if (div > SDCDIV_MASK)
+ div = SDCDIV_MASK;
+ }
+
+ SDHOST_WRITE(sc, SDCDIV, div);
+
+ return 0;
+}
+
+static int
+sdhost_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+ struct sdhost_softc * const sc = sch;
+ uint32_t hcfg;
+
+#ifdef SDHOST_DEBUG
+ aprint_normal_dev(sc->sc_dev, "width = %d\n", width);
+#endif
+
+ hcfg = SDHOST_READ(sc, SDHCFG);
+ if (width == 4)
+ hcfg |= SDHCFG_WIDE_EXT;
+ else
+ hcfg &= ~SDHCFG_WIDE_EXT;
+ hcfg |= (SDHCFG_WIDE_INT | SDHCFG_SLOW);
+ SDHOST_WRITE(sc, SDHCFG, hcfg);
+
+ return 0;
+}
+
+static int
+sdhost_bus_rod(sdmmc_chipset_handle_t sch, int on)
+{
+ return -1;
+}
+
+static void
+sdhost_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
+{
+ struct sdhost_softc * const sc = sch;
+ uint32_t cmdval, hcfg;
+ u_int nblks;
+
+#ifdef SDHOST_DEBUG
+ aprint_normal_dev(sc->sc_dev,
+ "opcode %d flags 0x%x data %p datalen %d blklen %d\n",
+ cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen,
+ cmd->c_blklen);
+#endif
+
+ mutex_enter(&sc->sc_intr_lock);
+
+ hcfg = SDHOST_READ(sc, SDHCFG);
+ SDHOST_WRITE(sc, SDHCFG, hcfg | SDHCFG_BUSY_EN);
+
+ sc->sc_intr_hsts = 0;
+
+ cmd->c_error = sdhost_wait_idle(sc, 5000);
+ if (cmd->c_error != 0) {
+#ifdef SDHOST_DEBUG
+ device_printf(sc->sc_dev, "device is busy\n");
+#endif
+ goto done;
+ }
+
+ cmdval = SDCMD_NEW;
+ if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
+ cmdval |= SDCMD_NORESP;
+ if (ISSET(cmd->c_flags, SCF_RSP_136))
+ cmdval |= SDCMD_LONGRESP;
+ if (ISSET(cmd->c_flags, SCF_RSP_BSY))
+ cmdval |= SDCMD_BUSY;
+
+ if (cmd->c_datalen > 0) {
+ if (ISSET(cmd->c_flags, SCF_CMD_READ))
+ cmdval |= SDCMD_READ;
+ else
+ cmdval |= SDCMD_WRITE;
+
+ nblks = cmd->c_datalen / cmd->c_blklen;
+ if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0)
+ ++nblks;
+
+ SDHOST_WRITE(sc, SDHBCT, cmd->c_blklen);
+ SDHOST_WRITE(sc, SDHBLC, nblks);
+
+ cmd->c_resid = cmd->c_datalen;
+ cmd->c_error = sdhost_dma_transfer(sc, cmd);
+ if (cmd->c_error != 0) {
+#ifdef SDHOST_DEBUG
+ device_printf(sc->sc_dev, "dma transfer failed: %d\n",
+ cmd->c_error);
+#endif
+ goto done;
+ }
+ }
+
+ SDHOST_WRITE(sc, SDARG, cmd->c_arg);
+ SDHOST_WRITE(sc, SDCMD, cmdval | cmd->c_opcode);
+
+ if (cmd->c_datalen > 0) {
+ cmd->c_error = sdhost_dma_wait(sc, cmd);
+ if (cmd->c_error != 0) {
+#ifdef SDHOST_DEBUG
+ device_printf(sc->sc_dev,
+ "wait dma failed: %d\n", cmd->c_error);
+#endif
+ goto done;
+ }
+ }
+
+ cmd->c_error = sdhost_wait_idle(sc, 5000);
+ if (cmd->c_error != 0) {
+#ifdef SDHOST_DEBUG
+ device_printf(sc->sc_dev,
+ "wait cmd idle (%#x) failed: %d\n",
+ SDHOST_READ(sc, SDCMD), cmd->c_error);
+#endif
+ }
+
+ if ((SDHOST_READ(sc, SDCMD) & SDCMD_FAIL) != 0) {
+#ifdef SDHOST_DEBUG
+ device_printf(sc->sc_dev, "SDCMD: %#x\n",
+ SDHOST_READ(sc, SDCMD));
+#endif
+ cmd->c_error = EIO;
+ goto done;
+ }
+
+ if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
+ if (ISSET(cmd->c_flags, SCF_RSP_136)) {
+ cmd->c_resp[0] = SDHOST_READ(sc, SDRSP0);
+ cmd->c_resp[1] = SDHOST_READ(sc, SDRSP1);
+ cmd->c_resp[2] = SDHOST_READ(sc, SDRSP2);
+ cmd->c_resp[3] = SDHOST_READ(sc, SDRSP3);
+ if (ISSET(cmd->c_flags, SCF_RSP_CRC)) {
+ cmd->c_resp[0] = (cmd->c_resp[0] >> 8) |
+ (cmd->c_resp[1] << 24);
+ cmd->c_resp[1] = (cmd->c_resp[1] >> 8) |
+ (cmd->c_resp[2] << 24);
+ cmd->c_resp[2] = (cmd->c_resp[2] >> 8) |
+ (cmd->c_resp[3] << 24);
+ cmd->c_resp[3] = (cmd->c_resp[3] >> 8);
+ }
+ } else {
+ cmd->c_resp[0] = SDHOST_READ(sc, SDRSP0);
+ }
+ }
+
+done:
+ cmd->c_flags |= SCF_ITSDONE;
+ SDHOST_WRITE(sc, SDHCFG, hcfg);
+ SDHOST_WRITE(sc, SDHSTS, SDHOST_READ(sc, SDHSTS));
+ mutex_exit(&sc->sc_intr_lock);
+
+#ifdef SDHOST_DEBUG
+ if (cmd->c_error != 0)
+ device_printf(sc->sc_dev, "command failed with error %d\n",
+ cmd->c_error);
+#endif
+}
+
+static void
+sdhost_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
+{
+}
+
+static void
+sdhost_card_intr_ack(sdmmc_chipset_handle_t sch)
+{
+}
+
+void
+sdhost_dump_regs(void)
+{
+ device_t dev = device_find_by_driver_unit("sdhost", 0);
+ if (dev == NULL)
+ return;
+ struct sdhost_softc * const sc = device_private(dev);
+
+ device_printf(dev, "SDCMD = %08x\n", SDHOST_READ(sc, SDCMD));
+ device_printf(dev, "SDARG = %08x\n", SDHOST_READ(sc, SDARG));
+ device_printf(dev, "SDTOUT = %08x\n", SDHOST_READ(sc, SDTOUT));
+ device_printf(dev, "SDCDIV = %08x\n", SDHOST_READ(sc, SDCDIV));
+ device_printf(dev, "SDRSP0 = %08x\n", SDHOST_READ(sc, SDRSP0));
+ device_printf(dev, "SDRSP1 = %08x\n", SDHOST_READ(sc, SDRSP1));
+ device_printf(dev, "SDRSP2 = %08x\n", SDHOST_READ(sc, SDRSP2));
+ device_printf(dev, "SDRSP3 = %08x\n", SDHOST_READ(sc, SDRSP3));
+ device_printf(dev, "SDHSTS = %08x\n", SDHOST_READ(sc, SDHSTS));
+ device_printf(dev, "SDVDD = %08x\n", SDHOST_READ(sc, SDVDD));
+ device_printf(dev, "SDEDM = %08x\n", SDHOST_READ(sc, SDEDM));
+ device_printf(dev, "SDHCFG = %08x\n", SDHOST_READ(sc, SDHCFG));
+ device_printf(dev, "SDHBCT = %08x\n", SDHOST_READ(sc, SDHBCT));
+ device_printf(dev, "SDDATA = ........\n");
+ device_printf(dev, "SDHBLC = %08x\n", SDHOST_READ(sc, SDHBLC));
+}