Module Name: src Committed By: kiyohara Date: Mon Oct 29 13:30:25 UTC 2012
Modified Files: src/sys/arch/arm/omap: omap3_sdhc.c omap3_sdmmcreg.h src/sys/dev/sdmmc: sdhc.c sdhcvar.h Log Message: Support omap3 SDHC driver. tested on OVERO only. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/omap/omap3_sdhc.c \ src/sys/arch/arm/omap/omap3_sdmmcreg.h cvs rdiff -u -r1.31 -r1.32 src/sys/dev/sdmmc/sdhc.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/sdmmc/sdhcvar.h 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/omap/omap3_sdhc.c diff -u src/sys/arch/arm/omap/omap3_sdhc.c:1.1 src/sys/arch/arm/omap/omap3_sdhc.c:1.2 --- src/sys/arch/arm/omap/omap3_sdhc.c:1.1 Thu Jul 12 03:08:26 2012 +++ src/sys/arch/arm/omap/omap3_sdhc.c Mon Oct 29 13:30:25 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: omap3_sdhc.c,v 1.1 2012/07/12 03:08:26 matt Exp $ */ +/* $NetBSD: omap3_sdhc.c,v 1.2 2012/10/29 13:30:25 kiyohara Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c,v 1.1 2012/07/12 03:08:26 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c,v 1.2 2012/10/29 13:30:25 kiyohara Exp $"); #include "opt_omap.h" @@ -48,8 +48,20 @@ __KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c #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 @@ struct obiosdhc_softc { }; 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 @@ obiosdhc_attach(device_t parent, device_ { 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 @@ obiosdhc_attach(device_t parent, device_ 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 @@ obiosdhc_attach(device_t parent, device_ 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 @@ fail: } 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: src/sys/arch/arm/omap/omap3_sdmmcreg.h diff -u src/sys/arch/arm/omap/omap3_sdmmcreg.h:1.1 src/sys/arch/arm/omap/omap3_sdmmcreg.h:1.2 --- src/sys/arch/arm/omap/omap3_sdmmcreg.h:1.1 Thu Jul 12 03:08:26 2012 +++ src/sys/arch/arm/omap/omap3_sdmmcreg.h Mon Oct 29 13:30:25 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: omap3_sdmmcreg.h,v 1.1 2012/07/12 03:08:26 matt Exp $ */ +/* $NetBSD: omap3_sdmmcreg.h,v 1.2 2012/10/29 13:30:25 kiyohara Exp $ */ /*- * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. @@ -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: src/sys/dev/sdmmc/sdhc.c diff -u src/sys/dev/sdmmc/sdhc.c:1.31 src/sys/dev/sdmmc/sdhc.c:1.32 --- src/sys/dev/sdmmc/sdhc.c:1.31 Thu Sep 13 21:44:50 2012 +++ src/sys/dev/sdmmc/sdhc.c Mon Oct 29 13:30:25 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.31 2012/09/13 21:44:50 joerg Exp $ */ +/* $NetBSD: sdhc.c,v 1.32 2012/10/29 13:30:25 kiyohara Exp $ */ /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ /* @@ -23,7 +23,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.31 2012/09/13 21:44:50 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.32 2012/10/29 13:30:25 kiyohara Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -413,6 +413,8 @@ sdhc_host_found(struct sdhc_softc *sc, b 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 @@ sdhc_card_detect(sdmmc_chipset_handle_t 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 @@ sdhc_write_protect(sdmmc_chipset_handle_ 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 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc 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 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc * 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 @@ sdhc_clock_divisor(struct sdhc_host *hp, /* 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 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc 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 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc 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 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc 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 @@ sdhc_bus_width(sdmmc_chipset_handle_t sc 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 @@ sdhc_exec_command(sdmmc_chipset_handle_t 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: src/sys/dev/sdmmc/sdhcvar.h diff -u src/sys/dev/sdmmc/sdhcvar.h:1.8 src/sys/dev/sdmmc/sdhcvar.h:1.9 --- src/sys/dev/sdmmc/sdhcvar.h:1.8 Sat Jul 21 16:14:05 2012 +++ src/sys/dev/sdmmc/sdhcvar.h Mon Oct 29 13:30:25 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhcvar.h,v 1.8 2012/07/21 16:14:05 skrll Exp $ */ +/* $NetBSD: sdhcvar.h,v 1.9 2012/10/29 13:30:25 kiyohara Exp $ */ /* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */ /* @@ -45,9 +45,16 @@ struct sdhc_softc { #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. */