mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-04-11 16:37:45 -04:00
Unlinking the FMC from the bus clock should make it simpler to do CPU frequency scaling later on. Change-Id: Ia87bbe3dd01ff25ea1520309680017b400471bfe
213 lines
6.1 KiB
C
213 lines
6.1 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2025 Aidan MacDonald
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
#include "clock-stm32h7.h"
|
|
#include "lcd-echoplayer.h"
|
|
#include "panic.h"
|
|
#include "regs/stm32h743/flash.h"
|
|
#include "regs/stm32h743/fmc.h"
|
|
#include "regs/stm32h743/pwr.h"
|
|
#include "regs/stm32h743/rcc.h"
|
|
#include "regs/stm32h743/syscfg.h"
|
|
|
|
#define PLL1Q_FREQ 240000000
|
|
#define PLL3R_FREQ 6000000
|
|
|
|
/* Flag to use VOS0 */
|
|
#define STM32H743_USE_VOS0 (CPU_FREQ > 400000000)
|
|
|
|
INIT_ATTR static void init_hse(void)
|
|
{
|
|
reg_writef(RCC_CR, HSEON(1));
|
|
|
|
while (!reg_readf(RCC_CR, HSERDY));
|
|
}
|
|
|
|
INIT_ATTR static void init_pll(void)
|
|
{
|
|
/* For simplicity, PLL parameters are hardcoded */
|
|
_Static_assert(STM32_HSE_FREQ == 24000000,
|
|
"HSE frequency not correct");
|
|
_Static_assert(LCD_DOTCLOCK_FREQ <= PLL3R_FREQ,
|
|
"PLL3R too slow for LCD");
|
|
_Static_assert(PLL1Q_FREQ == 240000000,
|
|
"PLL1Q parameters not correct");
|
|
|
|
/*
|
|
* Use HSE/4 input for PLL1
|
|
* Use HSE/12 input for PLL3
|
|
* PLL2 reserved for audio; configured in target PCM code
|
|
*/
|
|
reg_writef(RCC_PLLCKSELR,
|
|
PLLSRC_V(HSE),
|
|
DIVM1(4),
|
|
DIVM2(0),
|
|
DIVM3(12));
|
|
|
|
/* Enable PLL1P, PLL1Q, PLL3R */
|
|
reg_writef(RCC_PLLCFGR,
|
|
DIVP1EN(1),
|
|
DIVQ1EN(1),
|
|
DIVR1EN(0),
|
|
DIVP2EN(0),
|
|
DIVQ2EN(0),
|
|
DIVR2EN(0),
|
|
DIVP3EN(0),
|
|
DIVQ3EN(0),
|
|
DIVR3EN(1),
|
|
PLL1RGE_V(4_8MHZ),
|
|
PLL1VCOSEL_V(WIDE),
|
|
PLL1FRACEN(0),
|
|
PLL3RGE_V(1_2MHZ),
|
|
PLL3VCOSEL_V(MEDIUM),
|
|
PLL3FRACEN(0));
|
|
|
|
reg_writef(RCC_PLL1DIVR,
|
|
DIVN(80 - 1), /* 6 * 80 = 480 MHz */
|
|
DIVP(1 - 1), /* 480 / 1 = 480 MHz */
|
|
DIVQ(2 - 1), /* 480 / 2 = 240 MHz */
|
|
DIVR(1 - 1));
|
|
|
|
reg_writef(RCC_PLL3DIVR,
|
|
DIVN(90 - 1), /* 2 * 90 = 180 MHz */
|
|
DIVP(1 - 1),
|
|
DIVQ(1 - 1),
|
|
DIVR(30 - 1)); /* 180 / 30 = 6 MHz */
|
|
|
|
reg_writef(RCC_CR, PLL1ON(1), PLL3ON(1));
|
|
while (!reg_readf(RCC_CR, PLL1RDY));
|
|
while (!reg_readf(RCC_CR, PLL3RDY));
|
|
}
|
|
|
|
INIT_ATTR static void init_vos(void)
|
|
{
|
|
reg_writef(PWR_D3CR, VOS_V(VOS1));
|
|
while (!reg_readf(PWR_D3CR, VOSRDY));
|
|
|
|
if (STM32H743_USE_VOS0)
|
|
{
|
|
reg_writef(RCC_APB4ENR, SYSCFGEN(1));
|
|
|
|
/* Set ODEN bit to enter VOS0 */
|
|
reg_writef(SYSCFG_PWRCFG, ODEN(1));
|
|
while (!reg_readf(PWR_D3CR, VOSRDY));
|
|
|
|
reg_writef(RCC_APB4ENR, SYSCFGEN(0));
|
|
}
|
|
}
|
|
|
|
INIT_ATTR static void init_system_clock(void)
|
|
{
|
|
/* Enable HCLK /2 divider (CPU is at 480 MHz, HCLK limit is 240 MHz) */
|
|
reg_writef(RCC_D1CFGR, HPRE(8));
|
|
while (reg_readf(RCC_D1CFGR, HPRE) != 8);
|
|
|
|
/* Enable ABP /2 dividers (HCLK/2, APB limit is 120 MHz) */
|
|
reg_writef(RCC_D1CFGR, D1PPRE(4));
|
|
reg_writef(RCC_D2CFGR, D2PPRE1(4), D2PPRE2(4));
|
|
reg_writef(RCC_D3CFGR, D3PPRE(4));
|
|
|
|
/* Switch to PLL1P system clock source */
|
|
reg_writef(RCC_CFGR, SW_V(PLL1P));
|
|
while (reg_readf(RCC_CFGR, SWS) != BV_RCC_CFGR_SWS_PLL1P);
|
|
|
|
/* Reduce flash access latency */
|
|
reg_writef(FLASH_ACR, LATENCY(4), WRHIGHFREQ(2));
|
|
while (reg_readf(FLASH_ACR, LATENCY) != 4);
|
|
}
|
|
|
|
INIT_ATTR static void init_lse(void)
|
|
{
|
|
/*
|
|
* Skip if LSE and RTC are already enabled.
|
|
*/
|
|
if (reg_readf(RCC_BDCR, LSERDY) &&
|
|
reg_readf(RCC_BDCR, RTCEN))
|
|
return;
|
|
|
|
/*
|
|
* Enable LSE and set it as RTC clock source,
|
|
* then re-enable backup domain write protection.
|
|
*/
|
|
|
|
reg_writef(PWR_CR1, DBP(1));
|
|
|
|
/* Reset backup domain */
|
|
reg_writef(RCC_BDCR, BDRST(1));
|
|
reg_writef(RCC_BDCR, BDRST(0));
|
|
|
|
reg_writef(RCC_BDCR, LSEON(1), LSEDRV(3));
|
|
while (!reg_readf(RCC_BDCR, LSERDY));
|
|
|
|
reg_writef(RCC_BDCR, RTCEN(1), RTCSEL_V(LSE));
|
|
reg_writef(PWR_CR1, DBP(0));
|
|
}
|
|
|
|
INIT_ATTR static void init_periph_clock(void)
|
|
{
|
|
reg_writef(RCC_D1CCIPR, SDMMCSEL_V(PLL1Q));
|
|
reg_writef(RCC_D2CCIP1R, SAI1SEL_V(PLL2P), SPI45SEL_V(HSE));
|
|
reg_writef(RCC_D2CCIP2R, I2C123SEL_V(HSI));
|
|
|
|
/* Enable AXI SRAM in sleep mode to allow DMA'ing out of it */
|
|
reg_writef(RCC_AHB3LPENR, AXISRAMEN(1));
|
|
}
|
|
|
|
void echoplayer_clock_init(void)
|
|
{
|
|
init_hse();
|
|
init_pll();
|
|
init_vos();
|
|
init_system_clock();
|
|
init_lse();
|
|
init_periph_clock();
|
|
}
|
|
|
|
const struct stm32_clock sdmmc1_ker_clock = {
|
|
.frequency = PLL1Q_FREQ,
|
|
.en_reg = ITA_RCC_AHB3ENR,
|
|
.en_bit = BM_RCC_AHB3ENR_SDMMC1EN,
|
|
.lpen_reg = ITA_RCC_AHB3LPENR,
|
|
.lpen_bit = BM_RCC_AHB3LPENR_SDMMC1EN,
|
|
};
|
|
|
|
const struct stm32_clock ltdc_ker_clock = {
|
|
.frequency = PLL3R_FREQ,
|
|
.en_reg = ITA_RCC_APB3ENR,
|
|
.en_bit = BM_RCC_APB3ENR_LTDCEN,
|
|
.lpen_reg = ITA_RCC_APB3LPENR,
|
|
.lpen_bit = BM_RCC_APB3ENR_LTDCEN,
|
|
};
|
|
|
|
const struct stm32_clock spi5_ker_clock = {
|
|
.frequency = STM32_HSE_FREQ,
|
|
.en_reg = ITA_RCC_APB2ENR,
|
|
.en_bit = BM_RCC_APB2ENR_SPI5EN,
|
|
.lpen_reg = ITA_RCC_APB2LPENR,
|
|
.lpen_bit = BM_RCC_APB2ENR_SPI5EN,
|
|
};
|
|
|
|
const struct stm32_clock i2c1_ker_clock = {
|
|
.frequency = STM32_HSI_FREQ,
|
|
.en_reg = ITA_RCC_APB1LENR,
|
|
.en_bit = BM_RCC_APB1LENR_I2C1EN,
|
|
.lpen_reg = ITA_RCC_APB1LLPENR,
|
|
.lpen_bit = BM_RCC_APB1LENR_I2C1EN,
|
|
};
|