diff --git a/arch/arm/src/sam3u/sam3u_hsmci.c b/arch/arm/src/sam3u/sam3u_hsmci.c index 940f30276d8184a81b21174b0bf64aaf5340437c..9aa229bf34b046f56a769ec9132e059a727d7e82 100755 --- a/arch/arm/src/sam3u/sam3u_hsmci.c +++ b/arch/arm/src/sam3u/sam3u_hsmci.c @@ -89,16 +89,6 @@ # undef CONFIG_HSMCI_XFRDEBUG #endif -/* Mode dependent settings. These depend on clock devisor settings that must - * be defined in the board-specific board.h header file: HSMCI_INIT_CLKDIV, - * HSMCI_MMCXFR_CLKDIV, and HSMCI_SDXFR_CLKDIV. - */ - -#define HSMCI_CLCKCR_INIT (((SAM3U_MCK_FREQUENCY / ( 400000 * 2)) - 1) | (7 << HSMCI_MR_PWSDIV_SHIFT)) -#define HSMCI_CLKCR_MMCXFR (((SAM3U_MCK_FREQUENCY / (20000000 * 2)) - 1) | (7 << HSMCI_MR_PWSDIV_SHIFT)) -#define HSMCI_CLCKR_SDXFR (((SAM3U_MCK_FREQUENCY / (25000000 * 2)) - 1) | (7 << HSMCI_MR_PWSDIV_SHIFT)) -#define HSMCI_CLCKR_SDWIDEXFR (((SAM3U_MCK_FREQUENCY / (25000000 * 2)) - 1) | (7 << HSMCI_MR_PWSDIV_SHIFT)) - /* Timing */ #define HSMCI_CMDTIMEOUT (100000) @@ -277,16 +267,16 @@ struct sam3u_sampleregs_s static void sam3u_takesem(struct sam3u_dev_s *priv); #define sam3u_givesem(priv) (sem_post(&priv->waitsem)) -static inline void sam3u_setclkcr(uint32_t clkcr); static void sam3u_enablewaitints(struct sam3u_dev_s *priv, uint32_t waitmask, sdio_eventset_t waitevents); static void sam3u_disablewaitints(struct sam3u_dev_s *priv, sdio_eventset_t wkupevents); static void sam3u_enablexfrints(struct sam3u_dev_s *priv, uint32_t xfrmask); static void sam3u_disablexfrints(struct sam3u_dev_s *priv); +static inline void sam3u_disable(void); +static inline void sam3u_enable(void); /* DMA Helpers **************************************************************/ - #ifdef CONFIG_HSMCI_XFRDEBUG static void sam3u_sampleinit(void); static void sam3u_sdiosample(struct sam3u_hsmciregs_s *regs); @@ -447,42 +437,6 @@ static void sam3u_takesem(struct sam3u_dev_s *priv) } } -/**************************************************************************** - * Name: sam3u_setclkcr - * - * Description: - * Modify oft-changed bits in the CLKCR register. Only the following bit- - * fields are changed: - * - * CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, and HWFC_EN - * - * Input Parameters: - * clkcr - A new CLKCR setting for the above mentions bits (other bits - * are ignored. - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void sam3u_setclkcr(uint32_t clkcr) -{ - uint32_t regval = getreg32(SAM3U_HSMCI_CLKCR); - - /* Clear CLKDIV, PWRSAV, BYPASS, WIDBUS, NEGEDGE, HWFC_EN bits */ - - regval &= ~(HSMCI_CLKCR_CLKDIV_MASK|HSMCI_CLKCR_PWRSAV|HSMCI_CLKCR_BYPASS| - HSMCI_CLKCR_WIDBUS_MASK|HSMCI_CLKCR_NEGEDGE|HSMCI_CLKCR_HWFC_EN); - - /* Replace with user provided settings */ - - clkcr &= (HSMCI_CLKCR_CLKDIV_MASK|HSMCI_CLKCR_PWRSAV|HSMCI_CLKCR_BYPASS| - HSMCI_CLKCR_WIDBUS_MASK|HSMCI_CLKCR_NEGEDGE|HSMCI_CLKCR_HWFC_EN); - regval |= clkcr; - putreg32(regval, SAM3U_HSMCI_CLKCR); - fvdbg("CLKCR: %08x\n", getreg32(SAM3U_HSMCI_CLKCR)); -} - /**************************************************************************** * Name: sam3u_enablewaitints * @@ -594,6 +548,48 @@ static void sam3u_disablexfrints(struct sam3u_dev_s *priv) irqrestore(flags); } +/**************************************************************************** + * Name: sam3u_disable + * + * Description: + * Enable/disable the HSMCI + * + ****************************************************************************/ + +static inline void sam3u_disable(void) +{ + /* Disable the MCI peripheral clock */ + + putreg32((1 << SAM3U_PID_HSMCI), SAM3U_PMC_PCDR); + + /* Disable the MCI */ + + putreg32(HSMCI_CR_MCIDIS, SAM3U_HSMCI_CR); + + /* Disable all the interrupts */ + + putreg32(0xffffffff, SAM3U_HSMCI_IDR); +} + +/**************************************************************************** + * Name: sam3u_enable + * + * Description: + * Enable the HSMCI + * + ****************************************************************************/ + +static inline void sam3u_enable(void) +{ + /* Enable the MCI peripheral clock */ + + putreg32((1 << SAM3U_PID_HSMCI), SAM3U_PMC_PCER); + + /* Enable the MCI and the Power Saving */ + + putreg32(HSMCI_CR_MCIEN, SAM3U_HSMCI_CR); +} + /**************************************************************************** * DMA Helpers ****************************************************************************/ @@ -1134,10 +1130,10 @@ static void sam3u_reset(FAR struct sdio_dev_s *dev) putreg32(HSMCI_DTOR_DTOCYC_MAX | HSMCI_DTOR_DTOMUL_MAX, SAM3U_HSMCI_DTOR); - /* Set the Mode Register: 400KHz for MCK = 48MHz (clkdiv = 58) */ + /* Set the Mode Register for ID mode frequency (probably 400KHz) */ + + sam3u_clock(dev, CLOCK_IDMODE); - putreg32(HSMCI_CLCKCR_INIT, SAM3U_HSMCI_MR); - /* Set the SDCard Register */ putreg32(HSMCI_SDCR_SDCSEL_SLOTA | HSMCI_SDCR_SDCBUS_4BIT, SAM3U_HSMCI_SDCR); @@ -1237,40 +1233,57 @@ static void sam3u_widebus(FAR struct sdio_dev_s *dev, bool wide) static void sam3u_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) { - uint32_t clckr; - uint32_t enable = 1; + uint32_t regval; + bool enable = true; + + /* Fetch the current mode register and mask out the clkdiv (and pwsdiv) */ + regval = getreg32(SAM3U_HSMCI_MR); + regval &= ~(HSMCI_MR_CLKDIV_MASK | HSMCI_MR_PWSDIV_MASK); + + /* These clock devisor values that must be defined in the board-specific + * board.h header file: HSMCI_INIT_CLKDIV, HSMCI_MMCXFR_CLKDIV, + * HSMCI_SDXFR_CLKDIV, and HSMCI_SDWIDEXFR_CLKDIV. + */ + switch (rate) { default: case CLOCK_HSMCI_DISABLED: /* Clock is disabled */ - clckr = HSMCI_CLCKCR_INIT; - enable = 0; + regval |= HSMCI_INIT_CLKDIV | HSMCI_MR_PWSDIV_MAX; + enable = false; return; case CLOCK_IDMODE: /* Initial ID mode clocking (<400KHz) */ - clckr = HSMCI_CLCKCR_INIT; + regval |= HSMCI_INIT_CLKDIV | HSMCI_MR_PWSDIV_MAX; break; case CLOCK_MMC_TRANSFER: /* MMC normal operation clocking */ - clckr = HSMCI_CLKCR_MMCXFR; + regval |= HSMCI_MMCXFR_CLKDIV | HSMCI_MR_PWSDIV_MAX; break; case CLOCK_SD_TRANSFER_1BIT: /* SD normal operation clocking (narrow 1-bit mode) */ - clckr = HSMCI_CLCKR_SDXFR; + regval |= HSMCI_SDXFR_CLKDIV | HSMCI_MR_PWSDIV_MAX; break; case CLOCK_SD_TRANSFER_4BIT: /* SD normal operation clocking (wide 4-bit mode) */ - clckr = HSMCI_CLCKR_SDWIDEXFR; + regval |= HSMCI_SDWIDEXFR_CLKDIV | HSMCI_MR_PWSDIV_MAX; break; }; - /* Set the new clock frequency and make sure that the clock is enabled or - * disabled, whatever the case. + /* Set the new clock diver and make sure that the clock is enabled or + * disabled, whichever the case. */ - sam3u_setclkcr(clckr); - putreg32(enable, HSMCI_CLKCR_CLKEN_BB); + putreg32(regval, SAM3U_HSMCI_MR); + if (enable) + { + sam3u_enable(); + } + else + { + sam3u_disable(); + } } /**************************************************************************** diff --git a/arch/arm/src/sam3u/sam3u_hsmci.h b/arch/arm/src/sam3u/sam3u_hsmci.h index 0088cd2e52bd4220cf6b72e1f1587ada4eba2343..c86be289fdcf9d97a72c627f6c66c8ad2893eca7 100755 --- a/arch/arm/src/sam3u/sam3u_hsmci.h +++ b/arch/arm/src/sam3u/sam3u_hsmci.h @@ -121,6 +121,7 @@ #define HSMCI_MR_CLKDIV_MASK (0xff << HSMCI_MR_CLKDIV_SHIFT) #define HSMCI_MR_PWSDIV_SHIFT (8) /* Bits 8-10: Power Saving Divider */ #define HSMCI_MR_PWSDIV_MASK (7 << HSMCI_MR_PWSDIV_SHIFT) +# define HSMCI_MR_PWSDIV_MAX (7 << HSMCI_MR_PWSDIV_SHIFT) #define HSMCI_MR_RDPROOF (1 << 11) /* Bit 11: Read Proof Enable */ #define HSMCI_MR_WRPROOF (1 << 12) /* Bit 12: Write Proof Enable */ #define HSMCI_MR_FBYTE (1 << 13) /* Bit 13: Force Byte Transfer */ diff --git a/configs/sam3u-ek/include/board.h b/configs/sam3u-ek/include/board.h index 5a07e9d3d5d3082d2912e964780b44c40e4a8645..45335e6b0a4b9faa988e40d32eb2f0267b60d67d 100755 --- a/configs/sam3u-ek/include/board.h +++ b/configs/sam3u-ek/include/board.h @@ -87,6 +87,28 @@ #define SAM3U_PLLA_FREQUENCY (96000000) #define SAM3U_CPU_FREQUENCY (48000000) +/* HSMCI clocking + * + * Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK) + * divided by (2*(CLKDIV+1)). + * + * MCI_SPEED = MCK / (2*(CLKDIV+1)) + * CLKDIV = MCI / MCI_SPEED / 2 - 1 + */ + +/* MCK = 48MHz, CLKDIV = 59, MCI_SPEED = 48MHz / 2 * (59+1) = 400 KHz */ + +#define HSMCI_INIT_CLKDIV (59 << HSMCI_MR_CLKDIV_SHIFT) + +/* MCK = 48MHz, CLKDIV = 1, MCI_SPEED = 48MHz / 2 * (1+1) = 12 MHz */ + +#define HSMCI_MMCXFR_CLKDIV (3 << HSMCI_MR_CLKDIV_SHIFT) + +/* MCK = 48MHz, CLKDIV = 0, MCI_SPEED = 48MHz / 2 * (0+1) = 24 MHz */ + +#define HSMCI_SDXFR_CLKDIV (0 << HSMCI_MR_CLKDIV_SHIFT) +#define HSMCI_SDWIDEXFR_CLKDIV HSMCI_SDXFR_CLKDIV + /* LED definitions ******************************************************************/ #define LED_STARTED 0 /* LED0=OFF LED1=OFF LED2=OFF */