Update clock logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2576 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2010-04-07 03:00:34 +00:00
parent 5268348bf2
commit 8eb54ceab1
3 changed files with 99 additions and 63 deletions

View File

@ -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();
}
}
/****************************************************************************

View File

@ -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 */

View File

@ -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 */