Port-arm archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: OMAP3 + sdmmc
Hi! OMAP-guys,
From: KIYOHARA Takashi <kiyohara%kk.iij4u.or.jp@localhost>
Date: Sat, 13 Oct 2012 19:34:18 +0900 (JST)
> Do you work sdmmc on your board? (BEAGLEBOARD, etc...)
>
> My OVERO's sdmmc works with some changes now.
> Current status is:
Status is not change. :-)
> - 8bit width not support yet.
I not have 8bit witdh MMC... X-<
> - CRC error happen when block I/O, if SMC_CAPS_SINGLE_ONLY without.
> I don't know this reason.
> - Board-dependent card detect and write protect not yet.
OVERO (and IGEPV2?) not has card-detect and write-protect pins.
Maybe BEAGLEBOARD and DEVKIT8000 has both pins. Please implement
yourself. :-)
> - DMA not support yet.
> - Power control not yet. (Required regulator(TWL) driver)
>
> - And very noisy when boot time. :)
Remove debug print.
> If you need sdmmc on your omap board then you can try with my patch.
> Or wait more days. :)
I will commit next weekend.
Thanks,
--
kiyohara
My next target is frame-buffer or USB. Or DuOvero or *STORM boards. :-)
? arch/arm/omap/omapiic.c
? arch/arm/omap/omapiicreg.h
Index: arch/arm/omap/omap3_sdhc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/omap/omap3_sdhc.c,v
retrieving revision 1.1
diff -u -r1.1 omap3_sdhc.c
--- arch/arm/omap/omap3_sdhc.c 12 Jul 2012 03:08:26 -0000 1.1
+++ arch/arm/omap/omap3_sdhc.c 21 Oct 2012 07:34:07 -0000
@@ -48,8 +48,20 @@
#include <dev/sdmmc/sdhcreg.h>
#include <dev/sdmmc/sdhcvar.h>
+#define CLKD(kz) (sc->sc.sc_clkbase / (kz))
+
+#define SDHC_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_sdhc_bsh, (reg))
+#define SDHC_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_sdhc_bsh, (reg), (val))
+
static int obiosdhc_match(device_t, cfdata_t, void *);
static void obiosdhc_attach(device_t, device_t, void *);
+static int obiosdhc_detach(device_t, int);
+
+static int obiosdhc_rod(struct sdhc_softc *, int);
+static int obiosdhc_write_protect(struct sdhc_softc *);
+static int obiosdhc_card_detect(struct sdhc_softc *);
struct obiosdhc_softc {
struct sdhc_softc sc;
@@ -61,7 +73,7 @@
};
CFATTACH_DECL_NEW(obiosdhc, sizeof(struct obiosdhc_softc),
- obiosdhc_match, obiosdhc_attach, NULL, NULL);
+ obiosdhc_match, obiosdhc_attach, obiosdhc_detach, NULL);
static int
obiosdhc_match(device_t parent, cfdata_t cf, void *aux)
@@ -85,18 +97,26 @@
{
struct obiosdhc_softc * const sc = device_private(self);
struct obio_attach_args * const oa = aux;
- int error;
+ uint32_t clkd, stat;
+ int error, timo, clksft, n;
sc->sc.sc_dmat = oa->obio_dmat;
sc->sc.sc_dev = self;
//sc->sc.sc_flags |= SDHC_FLAG_USE_DMA;
sc->sc.sc_flags |= SDHC_FLAG_32BIT_ACCESS;
- sc->sc.sc_flags |= SDHC_FLAG_HAVE_CGM;
sc->sc.sc_flags |= SDHC_FLAG_NO_LED_ON;
+ sc->sc.sc_flags |= SDHC_FLAG_RSP136_CRC;
+ sc->sc.sc_flags |= SDHC_FLAG_SINGLE_ONLY;
sc->sc.sc_host = sc->sc_hosts;
sc->sc.sc_clkbase = 96000; /* 96MHZ */
+ sc->sc.sc_clkmsk = 0x0000ffc0;
+ sc->sc.sc_vendor_rod = obiosdhc_rod;
+ sc->sc.sc_vendor_write_protect = obiosdhc_write_protect;
+ sc->sc.sc_vendor_card_detect = obiosdhc_card_detect;
sc->sc_bst = oa->obio_iot;
+ clksft = ffs(sc->sc.sc_clkmsk) - 1;
+
error = bus_space_map(sc->sc_bst, oa->obio_addr, oa->obio_size, 0,
&sc->sc_bsh);
if (error) {
@@ -111,7 +131,25 @@
aprint_naive(": SDHC controller\n");
aprint_normal(": SDHC controller\n");
- sc->sc_ih = intr_establish(oa->obio_intr, IPL_VM, IST_LEVEL,
+ /* XXXXXX: Turn-on regurator via I2C. */
+ /* XXXXXX: And enable ICLOCK/FCLOCK. */
+
+ /* MMCHS Soft reset */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSCONFIG,
+ SYSCONFIG_SOFTRESET);
+ timo = 3000000; /* XXXX 3 sec. */
+ while (timo--) {
+ if (bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSSTATUS) &
+ SYSSTATUS_RESETDONE)
+ break;
+ delay(1);
+ }
+ if (timo == 0)
+ aprint_error_dev(self, "Soft reset timeout\n");
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSCONFIG,
+ SYSCONFIG_ENAWAKEUP | SYSCONFIG_AUTOIDLE);
+
+ sc->sc_ih = intr_establish(oa->obio_intr, IPL_VM, IST_LEVEL,
sdhc_intr, &sc->sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "failed to establish interrupt %d\n",
@@ -128,6 +166,74 @@
error);
goto fail;
}
+
+ /* Set SDVS 1.8v and DTW 1bit mode */
+ SDHC_WRITE(sc, SDHC_HOST_CTL,
+ SDHC_VOLTAGE_1_8V << (SDHC_VOLTAGE_SHIFT + 8));
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON,
+ bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) | CON_OD);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_INTCLK_ENABLE |
+ SDHC_SDCLK_ENABLE);
+ SDHC_WRITE(sc, SDHC_HOST_CTL,
+ SDHC_READ(sc, SDHC_HOST_CTL) | SDHC_BUS_POWER << 8);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft);
+
+ /*
+ * 22.6.1.3.1.5 MMCHS Controller INIT Procedure Start
+ * from 'OMAP35x Applications Processor Technical Reference Manual'.
+ *
+ * During the INIT procedure, the MMCHS controller generates 80 clock
+ * periods. In order to keep the 1ms gap, the MMCHS controller should
+ * be configured to generate a clock whose frequency is smaller or
+ * equal to 80 KHz.
+ */
+
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) & ~SDHC_SDCLK_ENABLE);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) & ~sc->sc.sc_clkmsk);
+ clkd = CLKD(80);
+ n = 1;
+ while (clkd & ~(sc->sc.sc_clkmsk >> clksft)) {
+ clkd >>= 1;
+ n <<= 1;
+ }
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) | (clkd << clksft));
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE);
+
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON,
+ bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) | CON_INIT);
+ for (; n > 0; n--) {
+ SDHC_WRITE(sc, SDHC_TRANSFER_MODE, 0x00000000);
+ timo = 3000000; /* XXXX 3 sec. */
+ stat = 0;
+ while (!(stat & SDHC_COMMAND_COMPLETE)) {
+ stat = SDHC_READ(sc, SDHC_NINTR_STATUS);
+ if (--timo == 0)
+ break;
+ delay(1);
+ }
+ if (timo == 0) {
+ aprint_error_dev(self, "INIT Procedure timeout\n");
+ break;
+ }
+ SDHC_WRITE(sc, SDHC_NINTR_STATUS, stat);
+ }
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON,
+ bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) & ~CON_INIT);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) & ~SDHC_SDCLK_ENABLE);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) & ~sc->sc.sc_clkmsk);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft);
+ SDHC_WRITE(sc, SDHC_CLOCK_CTL,
+ SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE);
+
return;
fail:
@@ -137,3 +243,49 @@
}
bus_space_unmap(sc->sc_bst, sc->sc_bsh, oa->obio_size);
}
+
+static int
+obiosdhc_detach(device_t self, int flags)
+{
+// struct obiosdhc_softc *sc = device_private(self);
+ int error;
+
+ error = config_detach_children(self, flags);
+
+ /* XXXXXX: Regurator turn-off via I2C. */
+ /* XXXXXX: And disable ICLOCK/FCLOCK. */
+
+ return error;
+}
+
+static int
+obiosdhc_rod(struct sdhc_softc *sc, int on)
+{
+ struct obiosdhc_softc *osc = (struct obiosdhc_softc *)sc;
+ uint32_t con;
+
+ con = bus_space_read_4(osc->sc_bst, osc->sc_bsh, MMCHS_CON);
+ if (on)
+ con |= CON_OD;
+ else
+ con &= ~CON_OD;
+ bus_space_write_4(osc->sc_bst, osc->sc_bsh, MMCHS_CON, con);
+
+ return 0;
+}
+
+static int
+obiosdhc_write_protect(struct sdhc_softc *sc)
+{
+
+ /* Maybe board dependent, using GPIO. Get GPIO-pin from prop? */
+ return 0; /* XXXXXXX */
+}
+
+static int
+obiosdhc_card_detect(struct sdhc_softc *sc)
+{
+
+ /* Maybe board dependent, using GPIO. Get GPIO-pin from prop? */
+ return 1; /* XXXXXXXX */
+}
Index: arch/arm/omap/omap3_sdmmcreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/omap/omap3_sdmmcreg.h,v
retrieving revision 1.1
diff -u -r1.1 omap3_sdmmcreg.h
--- arch/arm/omap/omap3_sdmmcreg.h 12 Jul 2012 03:08:26 -0000 1.1
+++ arch/arm/omap/omap3_sdmmcreg.h 21 Oct 2012 07:34:07 -0000
@@ -37,4 +37,38 @@
#define OMAP3_SDMMC_SDHC_OFFSET 0x100
#define OMAP3_SDMMC_SDHC_SIZE 0x100
+
+#define MMCHS_SYSCONFIG 0x010 /* System Configuration */
+# define SYSCONFIG_CLOCKACTIVITY_MASK (3 << 8)
+# define SYSCONFIG_CLOCKACTIVITY_FCLK (2 << 8)
+# define SYSCONFIG_CLOCKACTIVITY_ICLK (1 << 8)
+# define SYSCONFIG_ENAWAKEUP (1 << 2)
+# define SYSCONFIG_SOFTRESET (1 << 1)
+# define SYSCONFIG_AUTOIDLE (1 << 0)
+#define MMCHS_SYSSTATUS 0x014 /* System Status */
+# define SYSSTATUS_RESETDONE (1 << 0)
+#define MMCHS_CSRE 0x024 /* Card status response error */
+#define MMCHS_SYSTEST 0x028 /* System Test */
+#define MMCHS_CON 0x02c /* Configuration */
+# define CON_CLKEXTFREE (1 << 16)
+# define CON_PADEN (1 << 15) /* Ctrl Pow for MMC */
+# define CON_OBIE (1 << 14) /* Out-of-Band Intr */
+# define CON_OBIP (1 << 13) /*O-of-B Intr Polarity*/
+# define CON_CEATA (1 << 12) /* CE-ATA */
+# define CON_CTPL (1 << 11) /* Ctrl Power dat[1] */
+# define CON_DVAL_33US (0 << 9) /* debounce
filter val*/
+# define CON_DVAL_231US (1 << 9) /* debounce filter val*/
+# define CON_DVAL_1MS (2 << 9) /* debounce filter val*/
+# define CON_DVAL_8_4MS (3 << 9) /* 8.4ms */
+# define CON_WPP (1 << 8) /* Write protect pol */
+# define CON_CDP (1 << 7) /*Card detect polarity*/
+# define CON_MIT (1 << 6) /* MMC interrupt cmd */
+# define CON_DW8 (1 << 5) /* 8-bit mode */
+# define CON_MODE (1 << 4) /* SYSTEST mode */
+# define CON_STR (1 << 3) /* Stream command */
+# define CON_HR (1 << 2) /* Broadcast host rsp */
+# define CON_INIT (1 << 1) /* Send init stream */
+# define CON_OD (1 << 0) /* Card open drain */
+#define MMCHS_PWCNT 0x030 /* Power counter */
+
#endif
Index: dev/sdmmc/sdhc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdhc.c,v
retrieving revision 1.31
diff -u -r1.31 sdhc.c
--- dev/sdmmc/sdhc.c 13 Sep 2012 21:44:50 -0000 1.31
+++ dev/sdmmc/sdhc.c 21 Oct 2012 07:34:08 -0000
@@ -413,6 +413,8 @@
saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA;
}
}
+ if (ISSET(sc->sc_flags, SDHC_FLAG_SINGLE_ONLY))
+ saa.saa_caps |= SMC_CAPS_SINGLE_ONLY;
hp->sdmmc = config_found(sc->sc_dev, &saa, sdhc_cfprint);
return 0;
@@ -625,6 +627,9 @@
struct sdhc_host *hp = (struct sdhc_host *)sch;
int r;
+ if (hp->sc->sc_vendor_card_detect)
+ return (*hp->sc->sc_vendor_card_detect)(hp->sc);
+
mutex_enter(&hp->host_mtx);
r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED);
mutex_exit(&hp->host_mtx);
@@ -641,6 +646,9 @@
struct sdhc_host *hp = (struct sdhc_host *)sch;
int r;
+ if (hp->sc->sc_vendor_write_protect)
+ return (*hp->sc->sc_vendor_write_protect)(hp->sc);
+
mutex_enter(&hp->host_mtx);
r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_WRITE_PROTECT_SWITCH);
mutex_exit(&hp->host_mtx);
@@ -658,6 +666,8 @@
struct sdhc_host *hp = (struct sdhc_host *)sch;
uint8_t vdd;
int error = 0;
+ const uint32_t pcmask =
+ ~(SDHC_BUS_POWER | (SDHC_VOLTAGE_MASK << SDHC_VOLTAGE_SHIFT));
mutex_enter(&hp->host_mtx);
@@ -696,7 +706,11 @@
* voltage ramp until power rises.
*/
HWRITE1(hp, SDHC_POWER_CTL,
- (vdd << SDHC_VOLTAGE_SHIFT) | SDHC_BUS_POWER);
+ HREAD1(hp, SDHC_POWER_CTL) & pcmask);
+ sdmmc_delay(1);
+ HWRITE1(hp, SDHC_POWER_CTL, (vdd << SDHC_VOLTAGE_SHIFT));
+ sdmmc_delay(1);
+ HSET1(hp, SDHC_POWER_CTL, SDHC_BUS_POWER);
sdmmc_delay(10000);
/*
@@ -760,13 +774,12 @@
/* No divisor found. */
return false;
} else {
- for (div = 1; div <= 256; div *= 2) {
- if ((hp->clkbase / div) <= freq) {
- *divp = (div / 2) << SDHC_SDCLK_DIV_SHIFT;
- //freq = hp->clkbase / div;
- return true;
- }
- }
+ if (hp->sc->sc_clkmsk != 0)
+ *divp = (hp->clkbase / freq) <<
+ (ffs(hp->sc->sc_clkmsk) - 1);
+ else
+ *divp = (hp->clkbase / freq) << SDHC_SDCLK_DIV_SHIFT;
+ return true;
}
/* No divisor found. */
return false;
@@ -782,6 +795,7 @@
struct sdhc_host *hp = (struct sdhc_host *)sch;
u_int div;
u_int timo;
+ int16_t reg;
int error = 0;
#ifdef DIAGNOSTIC
bool present;
@@ -809,7 +823,7 @@
goto out;
}
} else {
- HWRITE2(hp, SDHC_CLOCK_CTL, 0);
+ HCLR2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
if (freq == SDMMC_SDCLK_OFF)
goto out;
}
@@ -826,7 +840,9 @@
HWRITE4(hp, SDHC_CLOCK_CTL,
div | (SDHC_TIMEOUT_MAX << 16));
} else {
- HWRITE2(hp, SDHC_CLOCK_CTL, div);
+ reg = HREAD2(hp, SDHC_CLOCK_CTL);
+ reg &= (SDHC_INTCLK_STABLE | SDHC_INTCLK_ENABLE);
+ HWRITE2(hp, SDHC_CLOCK_CTL, reg | div);
}
/*
@@ -931,8 +947,11 @@
static int
sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on)
{
+ struct sdhc_host *hp = (struct sdhc_host *)sch;
+
+ if (hp->sc->sc_vendor_rod)
+ return (*hp->sc->sc_vendor_rod)(hp->sc, on);
- /* Nothing ?? */
return 0;
}
@@ -1031,6 +1050,15 @@
cmd->c_resp[1] = HREAD4(hp, SDHC_RESPONSE + 4);
cmd->c_resp[2] = HREAD4(hp, SDHC_RESPONSE + 8);
cmd->c_resp[3] = HREAD4(hp, SDHC_RESPONSE + 12);
+ if (ISSET(hp->sc->sc_flags, SDHC_FLAG_RSP136_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);
+ }
}
}
mutex_exit(&hp->host_mtx);
Index: dev/sdmmc/sdhcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdhcvar.h,v
retrieving revision 1.8
diff -u -r1.8 sdhcvar.h
--- dev/sdmmc/sdhcvar.h 21 Jul 2012 16:14:05 -0000 1.8
+++ dev/sdmmc/sdhcvar.h 21 Oct 2012 07:34:08 -0000
@@ -45,9 +45,16 @@
#define SDHC_FLAG_HAVE_CGM 0x0080 /* Netlogic XLP */
#define SDHC_FLAG_NO_LED_ON 0x0100 /* LED_ON unsupported in
HOST_CTL */
#define SDHC_FLAG_HOSTCAPS 0x0200 /* No device provided
capabilities */
+#define SDHC_FLAG_RSP136_CRC 0x0400 /* Resp 136 with CRC and
end-bit */
+#define SDHC_FLAG_SINGLE_ONLY 0x0800 /* Single transfer only */
uint32_t sc_clkbase;
+ int sc_clkmsk; /* Mask for SDCLK */
uint32_t sc_caps;/* attachment provided capabilities */
+
+ int (*sc_vendor_rod)(struct sdhc_softc *, int);
+ int (*sc_vendor_write_protect)(struct sdhc_softc *);
+ int (*sc_vendor_card_detect)(struct sdhc_softc *);
};
/* Host controller functions called by the attachment driver. */
Home |
Main Index |
Thread Index |
Old Index