mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-07 16:11:43 +00:00
On stm32f412, AHB prescaler must be 1 in order for stm32f412 to be clocked at greater than 50MHz. APBX prescaler must be 2 so the clocks can be in the right range. When APBX prescaler != 1, it results in 2x timer clocks on both APB1 and APB2. We added a new clock_get_timer_freq() function for stm32 to get timer specific clock frequency so we can return 2x timer clocks when APBX != 1. Flash latencies also need to be changed when we clock at 96MHz, the FLASH_ACR_LATENCY defines are moved into the variant-specific switches so each board can defined latency when setting CPU clocks. BUG=b:38077127 TEST=`make BOARD=rose -j`, touch performance improved by 2x. Change-Id: Ieb211ad80c168d3f57e72a8d16b954b703ee1444 Reviewed-on: https://chromium-review.googlesource.com/539375 Commit-Ready: Wei-Ning Huang <wnhuang@chromium.org> Tested-by: Wei-Ning Huang <wnhuang@chromium.org> Reviewed-by: Rong Chang <rongchang@chromium.org>
231 lines
5.3 KiB
C
231 lines
5.3 KiB
C
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
/* Clocks and power management settings */
|
|
|
|
#include "chipset.h"
|
|
#include "clock.h"
|
|
#include "clock-f.h"
|
|
#include "common.h"
|
|
#include "console.h"
|
|
#include "cpu.h"
|
|
#include "hooks.h"
|
|
#include "hwtimer.h"
|
|
#include "registers.h"
|
|
#include "system.h"
|
|
#include "task.h"
|
|
#include "timer.h"
|
|
#include "util.h"
|
|
|
|
/* Console output macros */
|
|
#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
|
|
#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
|
|
|
|
|
|
/* Convert between RTC regs in BCD and seconds */
|
|
uint32_t rtc_to_sec(uint32_t rtc)
|
|
{
|
|
uint32_t sec;
|
|
|
|
/* convert the hours field */
|
|
sec = (((rtc & 0x300000) >> 20) * 10 + ((rtc & 0xf0000) >> 16)) * 3600;
|
|
/* convert the minutes field */
|
|
sec += (((rtc & 0x7000) >> 12) * 10 + ((rtc & 0xf00) >> 8)) * 60;
|
|
/* convert the seconds field */
|
|
sec += ((rtc & 0x70) >> 4) * 10 + (rtc & 0xf);
|
|
|
|
return sec;
|
|
}
|
|
uint32_t sec_to_rtc(uint32_t sec)
|
|
{
|
|
uint32_t rtc;
|
|
|
|
/* convert the hours field */
|
|
rtc = ((sec / 36000) << 20) | (((sec / 3600) % 10) << 16);
|
|
/* convert the minutes field */
|
|
rtc |= (((sec % 3600) / 600) << 12) | (((sec % 600) / 60) << 8);
|
|
/* convert the seconds field */
|
|
rtc |= (((sec % 60) / 10) << 4) | (sec % 10);
|
|
|
|
return rtc;
|
|
}
|
|
|
|
/* Return time diff between two rtc readings */
|
|
int32_t get_rtc_diff(uint32_t rtc0, uint32_t rtc0ss,
|
|
uint32_t rtc1, uint32_t rtc1ss)
|
|
{
|
|
int32_t diff;
|
|
|
|
/* Note: this only looks at the diff mod 10 seconds */
|
|
diff = ((rtc1 & 0xf) * SECOND +
|
|
rtcss_to_us(rtc1ss)) -
|
|
((rtc0 & 0xf) * SECOND +
|
|
rtcss_to_us(rtc0ss));
|
|
|
|
return (diff < 0) ? (diff + 10*SECOND) : diff;
|
|
}
|
|
|
|
void rtc_read(uint32_t *rtc, uint32_t *rtcss)
|
|
{
|
|
/* Read current time synchronously */
|
|
do {
|
|
*rtc = STM32_RTC_TR;
|
|
/*
|
|
* RTC_SSR must be read twice with identical values because
|
|
* glitches may occur for reads close to the RTCCLK edge.
|
|
*/
|
|
do {
|
|
*rtcss = STM32_RTC_SSR;
|
|
} while (*rtcss != STM32_RTC_SSR);
|
|
} while (*rtc != STM32_RTC_TR);
|
|
}
|
|
|
|
void set_rtc_alarm(uint32_t delay_s, uint32_t delay_us,
|
|
uint32_t *rtc, uint32_t *rtcss)
|
|
{
|
|
uint32_t alarm_sec, alarm_us;
|
|
|
|
/* Alarm must be within 1 day (86400 seconds) */
|
|
ASSERT((delay_s + delay_us / SECOND) < 86400);
|
|
|
|
rtc_unlock_regs();
|
|
|
|
/* Make sure alarm is disabled */
|
|
STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE;
|
|
while (!(STM32_RTC_ISR & STM32_RTC_ISR_ALRAWF))
|
|
;
|
|
STM32_RTC_ISR &= ~STM32_RTC_ISR_ALRAF;
|
|
|
|
rtc_read(rtc, rtcss);
|
|
|
|
/* Calculate alarm time */
|
|
alarm_sec = rtc_to_sec(*rtc) + delay_s;
|
|
alarm_us = rtcss_to_us(*rtcss) + delay_us;
|
|
alarm_sec = alarm_sec + alarm_us / SECOND;
|
|
alarm_us = alarm_us % 1000000;
|
|
/*
|
|
* If seconds is greater than 1 day, subtract by 1 day to deal with
|
|
* 24-hour rollover.
|
|
*/
|
|
if (alarm_sec >= 86400)
|
|
alarm_sec -= 86400;
|
|
|
|
/* Set alarm time */
|
|
STM32_RTC_ALRMAR = sec_to_rtc(alarm_sec);
|
|
STM32_RTC_ALRMASSR = us_to_rtcss(alarm_us);
|
|
/* Check for match on hours, minutes, seconds, and subsecond */
|
|
STM32_RTC_ALRMAR |= 0xc0000000;
|
|
STM32_RTC_ALRMASSR |= 0x0f000000;
|
|
|
|
/* Enable alarm and alarm interrupt */
|
|
STM32_EXTI_PR = EXTI_RTC_ALR_EVENT;
|
|
STM32_EXTI_IMR |= EXTI_RTC_ALR_EVENT;
|
|
STM32_RTC_CR |= STM32_RTC_CR_ALRAE;
|
|
|
|
rtc_lock_regs();
|
|
}
|
|
|
|
void reset_rtc_alarm(uint32_t *rtc, uint32_t *rtcss)
|
|
{
|
|
rtc_unlock_regs();
|
|
|
|
/* Disable alarm */
|
|
STM32_RTC_CR &= ~STM32_RTC_CR_ALRAE;
|
|
STM32_RTC_ISR &= ~STM32_RTC_ISR_ALRAF;
|
|
|
|
/* Disable RTC alarm interrupt */
|
|
STM32_EXTI_IMR &= ~EXTI_RTC_ALR_EVENT;
|
|
STM32_EXTI_PR = EXTI_RTC_ALR_EVENT;
|
|
|
|
/* Read current time */
|
|
rtc_read(rtc, rtcss);
|
|
|
|
rtc_lock_regs();
|
|
}
|
|
|
|
void __rtc_alarm_irq(void)
|
|
{
|
|
uint32_t rtc, rtcss;
|
|
|
|
reset_rtc_alarm(&rtc, &rtcss);
|
|
}
|
|
DECLARE_IRQ(STM32_IRQ_RTC_ALARM, __rtc_alarm_irq, 1);
|
|
|
|
__attribute__((weak))
|
|
int clock_get_timer_freq(void)
|
|
{
|
|
return clock_get_freq();
|
|
}
|
|
|
|
void clock_init(void)
|
|
{
|
|
/*
|
|
* The initial state :
|
|
* SYSCLK from HSI (=8MHz), no divider on AHB, APB1, APB2
|
|
* PLL unlocked, RTC enabled on LSE
|
|
*/
|
|
|
|
/*
|
|
* put 1 Wait-State for flash access to ensure proper reads at 48Mhz
|
|
* and enable prefetch buffer.
|
|
*/
|
|
STM32_FLASH_ACR = STM32_FLASH_ACR_LATENCY | STM32_FLASH_ACR_PRFTEN;
|
|
|
|
#ifdef CHIP_FAMILY_STM32F4
|
|
/* Enable data and instruction cache. */
|
|
STM32_FLASH_ACR |= STM32_FLASH_ACR_DCEN | STM32_FLASH_ACR_ICEN;
|
|
#endif
|
|
|
|
config_hispeed_clock();
|
|
|
|
rtc_init();
|
|
}
|
|
|
|
#ifdef CHIP_FAMILY_STM32F4
|
|
void reset_flash_cache(void)
|
|
{
|
|
/* Disable data and instruction cache. */
|
|
STM32_FLASH_ACR &= ~(STM32_FLASH_ACR_DCEN | STM32_FLASH_ACR_ICEN);
|
|
|
|
/* Reset data and instruction cache */
|
|
STM32_FLASH_ACR |= STM32_FLASH_ACR_DCRST | STM32_FLASH_ACR_ICRST;
|
|
}
|
|
DECLARE_HOOK(HOOK_SYSJUMP, reset_flash_cache, HOOK_PRIO_DEFAULT);
|
|
#endif
|
|
|
|
/*****************************************************************************/
|
|
/* Console commands */
|
|
|
|
#ifdef CONFIG_CMD_RTC_ALARM
|
|
static int command_rtc_alarm_test(int argc, char **argv)
|
|
{
|
|
int s = 1, us = 0;
|
|
uint32_t rtc, rtcss;
|
|
char *e;
|
|
|
|
ccprintf("Setting RTC alarm\n");
|
|
|
|
if (argc > 1) {
|
|
s = strtoi(argv[1], &e, 10);
|
|
if (*e)
|
|
return EC_ERROR_PARAM1;
|
|
|
|
}
|
|
if (argc > 2) {
|
|
us = strtoi(argv[2], &e, 10);
|
|
if (*e)
|
|
return EC_ERROR_PARAM2;
|
|
|
|
}
|
|
|
|
set_rtc_alarm(s, us, &rtc, &rtcss);
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test,
|
|
"[seconds [microseconds]]",
|
|
"Test alarm");
|
|
#endif /* CONFIG_CMD_RTC_ALARM */
|
|
|