From 321a7a64af60aefee3201389de8dc8fb574d61b5 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 19 Dec 2017 14:05:36 -0600 Subject: [PATCH] arch/arm/src/lpc54xx and configs/lpcxpresso-lpc54628: Correct some SD/MMC clock divider logic. --- arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h | 10 ++++-- arch/arm/src/lpc54xx/lpc54_sdmmc.c | 39 +++++++++------------ configs/lpcxpresso-lpc54628/include/board.h | 30 ++++++++++++++-- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h b/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h index bf3746bc35..a30e730c14 100644 --- a/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h +++ b/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h @@ -154,10 +154,16 @@ #define SDMMC_PWREN (1 << 0) /* Bit 0: Power on/off switch */ /* Bits 1-31: Reserved */ -/* Clock divider register CLKDIV */ +/* Clock divider register CLKDIV + * + * Clock division is 2*n. For example, value of 0 means divide by 2 * 0 = 0 (no division, + * bypass), value of 1 means divide by 2 * 1 = 2, value of 255 means divide by 2 * 255 = 510, + * and so on. + */ #define SDMMC_CLKDIV0_SHIFT (0) /* Bits 0-7: Clock divider 0 value */ #define SDMMC_CLKDIV0_MASK (255 << SDMMC_CLKDIV0_SHIFT) +# define SDMMC_CLKDIV0_MASK(n) ((((n) + 1) >> 1) << SDMMC_CLKDIV0_SHIFT) /* Bits 8-31: Reserved */ /* Clock enable register CLKENA */ @@ -166,7 +172,7 @@ /* Bits 1-15: Reserved */ #define SDMMC_CLKENA_LOWPOWER (1 << 16) /* Bit 16: Low-power mode */ /* Bits 17-31: Reserved */ -/*Timeout register TMOUT */ +/* Timeout register TMOUT */ #define SDMMC_TMOUT_RESPONSE_SHIFT (0) /* Bits 0-7: Response timeout value */ #define SDMMC_TMOUT_RESPONSE_MASK (255 << SDMMC_TMOUT_RESPONSE_SHIFT) diff --git a/arch/arm/src/lpc54xx/lpc54_sdmmc.c b/arch/arm/src/lpc54xx/lpc54_sdmmc.c index d79c631264..bb7823d83c 100644 --- a/arch/arm/src/lpc54xx/lpc54_sdmmc.c +++ b/arch/arm/src/lpc54xx/lpc54_sdmmc.c @@ -115,13 +115,6 @@ # error "Callback support requires CONFIG_SCHED_WORKQUEUE" #endif -/* Clock Division */ - -#define LPC54_CLKDIV_INIT 165 /* Divide by 165 = 400KHz */ -#define SDCARD_CLOCK_MMCXFR 2 /* SDCARD_MMCXFR_CLKDIV */ -#define SDCARD_CLOCK_SDWIDEXFR 2 /* SDCARD_SDXFR_CLKDIV */ -#define SDCARD_CLOCK_SDXFR 2 /* SDCARD_SDXFR_CLKDIV */ - /* Timing */ #define SDCARD_CMDTIMEOUT (10000) @@ -536,7 +529,7 @@ static inline void lpc54_setclock(uint32_t clkdiv) /* Set Divider0 to desired value */ - lpc54_putreg(clkdiv & SDMMC_CLKDIV0_MASK, LPC54_SDMMC_CLKDIV); + lpc54_putreg(clkdiv, LPC54_SDMMC_CLKDIV); /* Inform CIU */ @@ -555,7 +548,7 @@ static inline void lpc54_setclock(uint32_t clkdiv) * Name: lpc54_settype * * Description: Define the Bus Size of SDCard (1, 4 or 8-bit) - * + * * Input Parameters: * ctype - A new CTYPE (Card Type Register) value * @@ -574,7 +567,7 @@ static inline void lpc54_settype(uint32_t ctype) * Name: lpc54_sdcard_clock * * Description: Enable/Disable the SDCard clock - * + * * Input Parameters: * enable - False = clock disabled; True = clock enabled. * @@ -1145,7 +1138,7 @@ static void lpc54_reset(FAR struct sdio_dev_s *dev) regval = SDMMC_BMOD_DE; regval |= SDMMC_BMOD_PBL_4XFRS; - regval |= ((4) << SDMMC_BMOD_DSL_SHIFT) & SDMMC_BMOD_DSL_MASK; + regval |= ((4) << SDMMC_BMOD_DSL_SHIFT); lpc54_putreg(regval, LPC54_SDMMC_BMOD); /* Disable clock to CIU (needs latch) */ @@ -1260,8 +1253,8 @@ static void lpc54_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) default: case CLOCK_SDIO_DISABLED: - clkdiv = LPC54_CLKDIV_INIT; - ctype = SDCARD_BUS_D1; + clkdiv = SDMMC_CLKDIV0(BOARD_CLKDIV_INIT); + ctype = SDCARD_BUS_D1; enabled = false; return; break; @@ -1269,16 +1262,16 @@ static void lpc54_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) /* Enable in initial ID mode clocking (<400KHz) */ case CLOCK_IDMODE: - clkdiv = LPC54_CLKDIV_INIT; - ctype = SDCARD_BUS_D1; + clkdiv = SDMMC_CLKDIV0(BOARD_CLKDIV_INIT); + ctype = SDCARD_BUS_D1; enabled = true; break; /* Enable in MMC normal operation clocking */ case CLOCK_MMC_TRANSFER: - clkdiv = SDCARD_CLOCK_MMCXFR; - ctype = SDCARD_BUS_D1; + clkdiv = SDMMC_CLKDIV0(BOARD_CLKDIV_MMCXFR); + ctype = SDCARD_BUS_D1; enabled = true; break; @@ -1286,8 +1279,8 @@ static void lpc54_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) case CLOCK_SD_TRANSFER_4BIT: #ifndef CONFIG_LPC54_SDMMC_WIDTH_D1_ONLY - clkdiv = SDCARD_CLOCK_SDWIDEXFR; - ctype = SDCARD_BUS_D4; + clkdiv = SDMMC_CLKDIV0(BOARD_CLKDIV_SDWIDEXFR); + ctype = SDCARD_BUS_D4; enabled = true; break; #endif @@ -1295,8 +1288,8 @@ static void lpc54_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) /* SD normal operation clocking (narrow 1-bit mode) */ case CLOCK_SD_TRANSFER_1BIT: - clkdiv = SDCARD_CLOCK_SDXFR; - ctype = SDCARD_BUS_D1; + clkdiv = SDMMC_CLKDIV0(BOARD_CLKDIV_SDXFR); + ctype = SDCARD_BUS_D1; enabled = true; break; } @@ -2318,7 +2311,7 @@ static int lpc54_dmasendsetup(FAR struct sdio_dev_s *dev, g_sdmmc_dmadd[0].des1 = 512; g_sdmmc_dmadd[0].des2 = priv->buffer; g_sdmmc_dmadd[0].des3 = (uint32_t) &g_sdmmc_dmadd[1]; - + lpc54_putreg((uint32_t) &g_sdmmc_dmadd[0], LPC54_SDMMC_DBADDR); } @@ -2443,7 +2436,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno) lpc54_putreg(BOARD_SDMMC_CLKSRC, LPC54_SYSCON_SDIOCLKSEL); - /* Set up the clock divider to obtain the desired clock rate. + /* Set up the clock divider to obtain the desired clock rate. * NOTE: The SDIO function clock to the interface can be up to 50 MHZ. */ diff --git a/configs/lpcxpresso-lpc54628/include/board.h b/configs/lpcxpresso-lpc54628/include/board.h index aa7ae4ef7a..1c81b8e0d7 100644 --- a/configs/lpcxpresso-lpc54628/include/board.h +++ b/configs/lpcxpresso-lpc54628/include/board.h @@ -193,10 +193,11 @@ #endif #define BOARD_EMC_FREQUENCY (BOARD_CPU_FREQUENCY / BOARD_EMC_CLKDIV) -/* SD/MMC or SDIO interface +/* SD/MMC or SDIO interface/ +/* SD/MMC function clock * * NOTE: The SDIO function clock to the interface can be up to 50 MHZ. - * Example: BOARD_MAIN_CLK=220MHz, CLKDIV=5, Fsdmmc=44MHz. + * Example: BOARD_MAIN_CLK=220MHz, CLKDIV=5, Finput=44MHz. */ #define BOARD_SDMMC_MAXFREQ 50000000 @@ -206,6 +207,29 @@ #define BOARD_SDMMC_CLKDIV BOARD_SDMMC_CEIL(BOARD_MAIN_CLK, BOARD_SDMMC_MAXFREQ) #define BOARD_SDMMC_FREQUENCY (BOARD_MAIN_CLK / BOARD_SDMMC_CLKDIV) +/* Mode-dependent function clock division + * + * Example: BOARD_SDMMC_FREQUENCY=44MHz + * BOARD_CLKDIV_INIT=110, Fsdmmc=400KHz (400KHz max) + * BOARD_CLKDIV_MMCXFR=4[3], Fsdmmc=11Mhz (20MHz max) See NOTE: + * BOARD_CLKDIV_SDWIDEXFR=2, Fsdmmc=22MHz (25MHz max) + * BOARD_CLKDIV_SDXFR=2, Fsdmmc=22MHz (25MHz max) + * + * NOTE: *lock division is 2*n. For example, value of 0 means divide by + * 2 * 0 = 0 (no division, bypass), value of 1 means divide by 2 * 1 = 2, value + * of 255 means divide by 2 * 255 = 510, and so on. + * + * SD/MMC logic will write the value ((clkdiv + 1) >> 1) as the divisor. So an + * odd value calculated below will be moved up to next higher divider value. So + * the value 3 will cause 2 to be written as the divider value and the effective + * divider will be 4. + */ + +#define BOARD_CLKDIV_INIT BOARD_SDMMC_CEIL(BOARD_SDMMC_FREQUENCY, 400000) +#define BOARD_CLKDIV_MMCXFR BOARD_SDMMC_CEIL(BOARD_SDMMC_FREQUENCY, 20000000) +#define BOARD_CLKDIV_SDWIDEXFR BOARD_SDMMC_CEIL(BOARD_SDMMC_FREQUENCY, 25000000) +#define BOARD_CLKDIV_SDXFR BOARD_SDMMC_CEIL(BOARD_SDMMC_FREQUENCY, 25000000) + /* LED definitions *********************************************************/ /* The LPCXpress-LPC54628 has three user LEDs: D9, D11, and D12. These * LEDs are for application use. They are illuminated when the driving @@ -352,7 +376,7 @@ /* LCD * - * There are no alternatives for LCD pins except for the VD0-VD3 pins. + * There are no alternatives for LCD pins except for the VD0-VD3 pins. * VD0-VD2 are not used in this hardware configuration. VD3 is on * P2.21. */