diff options
author | Nick Sanders <nsanders@chromium.org> | 2016-07-26 13:17:09 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-08-17 16:19:07 -0700 |
commit | 6fcd163da5169bfca36ab8c15cfd9d0624acae19 (patch) | |
tree | cc1e3cd999fa3df95547356e8160fd966aa26bc3 /chip/stm32/clock-f.c | |
parent | 6fad4f8588242cd6202e1177e145073c6aff6b7a (diff) | |
download | chrome-ec-6fcd163da5169bfca36ab8c15cfd9d0624acae19.tar.gz |
stm32f446e-eval: add support for stm32f446
This adds basic support for the stm32f446.
This consists of:
* New DMA model for stm32f4
* New clock domain support.
* MCO oscillator gpio export support.
* Flash support for irregular blocks.
BUG=chromium:608039
TEST=boots w/ correct clock, stm32f0 also boots.
BRANCH=None
Change-Id: I1c5cf6ddca09009c9dac60da8a3d0c5ceedfcf4d
Signed-off-by: Nick Sanders <nsanders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/363992
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Diffstat (limited to 'chip/stm32/clock-f.c')
-rw-r--r-- | chip/stm32/clock-f.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/chip/stm32/clock-f.c b/chip/stm32/clock-f.c new file mode 100644 index 0000000000..02773dc678 --- /dev/null +++ b/chip/stm32/clock-f.c @@ -0,0 +1,209 @@ +/* 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); + +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. + */ + /* Enable data and instruction cache. */ + STM32_FLASH_ACR = STM32_FLASH_ACR_LATENCY | STM32_FLASH_ACR_PRFTEN; + + config_hispeed_clock(); + + rtc_init(); +} + +/*****************************************************************************/ +/* 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", + NULL); +#endif /* CONFIG_CMD_RTC_ALARM */ + |