From 36cff03af1b4ad08c72ccc21bbd3903113ef423a Mon Sep 17 00:00:00 2001 From: Stephen Caudle Date: Thu, 27 Oct 2011 23:34:52 -0400 Subject: Add RCC and FLASH support for STM32F2 --- include/libopencm3/cm3/common.h | 2 + include/libopencm3/stm32/f2/flash.h | 153 +++++++++++++ include/libopencm3/stm32/f2/rcc.h | 39 ++++ lib/stm32f2/Makefile | 2 +- lib/stm32f2/flash.c | 250 ++++++++++++++++++++++ lib/stm32f2/rcc.c | 412 ++++++++++++++++++++++++++++++++++++ 6 files changed, 857 insertions(+), 1 deletion(-) create mode 100644 include/libopencm3/stm32/f2/flash.h create mode 100644 lib/stm32f2/flash.c create mode 100644 lib/stm32f2/rcc.c diff --git a/include/libopencm3/cm3/common.h b/include/libopencm3/cm3/common.h index bbd04cb..08f553f 100644 --- a/include/libopencm3/cm3/common.h +++ b/include/libopencm3/cm3/common.h @@ -30,10 +30,12 @@ typedef int32_t s32; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; +typedef uint64_t u64; /* Generic memory-mapped I/O accessor functions */ #define MMIO8(addr) (*(volatile u8 *)(addr)) #define MMIO16(addr) (*(volatile u16 *)(addr)) #define MMIO32(addr) (*(volatile u32 *)(addr)) +#define MMIO64(addr) (*(volatile u64 *)(addr)) #endif diff --git a/include/libopencm3/stm32/f2/flash.h b/include/libopencm3/stm32/f2/flash.h new file mode 100644 index 0000000..15529ea --- /dev/null +++ b/include/libopencm3/stm32/f2/flash.h @@ -0,0 +1,153 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * For details see: + * PM0042 Programming manual: STM32F10xxx Flash programming + * October 2009, Doc ID 13259 Rev 7 + * http://www.st.com/stonline/products/literature/pm/13259.pdf + */ + +#ifndef LIBOPENCM3_FLASH_H +#define LIBOPENCM3_FLASH_H + +#include +#include + +/* --- FLASH registers ----------------------------------------------------- */ + +#define FLASH_ACR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x00) +#define FLASH_KEYR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x04) +#define FLASH_OPTKEYR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x08) +#define FLASH_SR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x0C) +#define FLASH_CR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x10) +#define FLASH_OPTCR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x14) + +/* --- FLASH_ACR values ---------------------------------------------------- */ + +#define FLASH_DCRST (1 << 12) +#define FLASH_ICRST (1 << 11) +#define FLASH_DCE (1 << 10) +#define FLASH_ICE (1 << 9) +#define FLASH_PRFTEN (1 << 8) +#define FLASH_LATENCY_0WS 0x00 +#define FLASH_LATENCY_1WS 0x01 +#define FLASH_LATENCY_2WS 0x02 +#define FLASH_LATENCY_3WS 0x03 +#define FLASH_LATENCY_4WS 0x04 +#define FLASH_LATENCY_5WS 0x05 +#define FLASH_LATENCY_6WS 0x06 +#define FLASH_LATENCY_7WS 0x07 + +/* --- FLASH_SR values ----------------------------------------------------- */ + +#define FLASH_BSY (1 << 16) +#define FLASH_PGSERR (1 << 7) +#define FLASH_PGPERR (1 << 6) +#define FLASH_PGAERR (1 << 5) +#define FLASH_WRPERR (1 << 4) +#define FLASH_OPERR (1 << 1) +#define FLASH_EOP (1 << 0) + +/* --- FLASH_CR values ----------------------------------------------------- */ + +#define FLASH_LOCK (1 << 31) +#define FLASH_ERRIE (1 << 25) +#define FLASH_EOPIE (1 << 24) +#define FLASH_STRT (1 << 16) +#define FLASH_MER (1 << 2) +#define FLASH_SER (1 << 1) +#define FLASH_PG (1 << 0) +#define FLASH_SECTOR_0 (0x00 << 3) +#define FLASH_SECTOR_1 (0x01 << 3) +#define FLASH_SECTOR_2 (0x02 << 3) +#define FLASH_SECTOR_3 (0x03 << 3) +#define FLASH_SECTOR_4 (0x04 << 3) +#define FLASH_SECTOR_5 (0x05 << 3) +#define FLASH_SECTOR_6 (0x06 << 3) +#define FLASH_SECTOR_7 (0x07 << 3) +#define FLASH_SECTOR_8 (0x08 << 3) +#define FLASH_SECTOR_9 (0x09 << 3) +#define FLASH_SECTOR_10 (0x0a << 3) +#define FLASH_SECTOR_11 (0x0b << 3) +#define FLASH_PROGRAM_X8 (0x00 << 8) +#define FLASH_PROGRAM_X16 (0x01 << 8) +#define FLASH_PROGRAM_X32 (0x02 << 8) +#define FLASH_PROGRAM_X64 (0x03 << 8) + +/* --- FLASH_OPTCR values -------------------------------------------------- */ + +/* FLASH_OPTCR[27:16]: nWRP */ +/* FLASH_OBR[15:8]: RDP */ +#define FLASH_NRST_STDBY (1 << 7) +#define FLASH_NRST_STOP (1 << 6) +#define FLASH_WDG_SW (1 << 5) +#define FLASH_OPTSTRT (1 << 1) +#define FLASH_OPTLOCK (1 << 0) +#define FLASH_BOR_LEVEL_3 (0x00 << 2) +#define FLASH_BOR_LEVEL_2 (0x01 << 2) +#define FLASH_BOR_LEVEL_1 (0x02 << 2) +#define FLASH_BOR_OFF (0x03 << 2) + +/* --- FLASH Keys -----------------------------------------------------------*/ + +#define FLASH_KEY1 ((u32)0x45670123) +#define FLASH_KEY2 ((u32)0xcdef89ab) +#define FLASH_OPTKEY1 ((u32)0x08192a3b) +#define FLASH_OPTKEY2 ((u32)0x4c5d6e7f) + +/* --- Function prototypes ------------------------------------------------- */ + +void flash_dcache_enable(void); +void flash_dcache_disable(void); +void flash_icache_enable(void); +void flash_icache_disable(void); +void flash_prefetch_enable(void); +void flash_prefetch_disable(void); +void flash_dcache_reset(void); +void flash_icache_reset(void); +void flash_set_ws(u32 ws); +void flash_unlock(void); +void flash_lock(void); +void flash_clear_pgserr_flag(void); +void flash_clear_pgperr_flag(void); +void flash_clear_pgaerr_flag(void); +void flash_clear_eop_flag(void); +void flash_clear_wrperr_flag(void); +void flash_clear_bsy_flag(void); +void flash_clear_status_flags(void); +void flash_unlock_option_bytes(void); +void flash_lock_option_bytes(void); +void flash_erase_all_sectors(u32 program_size); +void flash_erase_sector(u32 sector, u32 program_size); +void flash_program_double_word(u32 address, u64 data, u32 program_size); +void flash_program_word(u32 address, u32 data, u32 program_size); +void flash_program_half_word(u32 address, u16 data, u32 program_size); +void flash_program_byte(u32 address, u8 data, u32 program_size); +void flash_wait_for_last_operation(void); +void flash_program_option_bytes(u32 data); + +#if 0 +// TODO: Implement support for option bytes +void flash_erase_option_bytes(void); +void flash_program_option_bytes(u32 address, u16 data); +#endif + +#endif diff --git a/include/libopencm3/stm32/f2/rcc.h b/include/libopencm3/stm32/f2/rcc.h index 430ce77..ba24c86 100644 --- a/include/libopencm3/stm32/f2/rcc.h +++ b/include/libopencm3/stm32/f2/rcc.h @@ -449,5 +449,44 @@ /* RCC_PLLI2SCFGR[14:6]: PLLI2SN */ #define RCC_PLLI2SCFGR_PLLI2SN_SHIFT 6 +/* --- Variable definitions ------------------------------------------------ */ +extern u32 rcc_ppre1_frequency; +extern u32 rcc_ppre2_frequency; + +/* --- Function prototypes ------------------------------------------------- */ + +typedef enum { + PLL, HSE, HSI, LSE, LSI +} osc_t; + +void rcc_osc_ready_int_clear(osc_t osc); +void rcc_osc_ready_int_enable(osc_t osc); +void rcc_osc_ready_int_disable(osc_t osc); +int rcc_osc_ready_int_flag(osc_t osc); +void rcc_css_int_clear(void); +int rcc_css_int_flag(void); +void rcc_wait_for_osc_ready(osc_t osc); +void rcc_wait_for_sysclk_status(osc_t osc); +void rcc_osc_on(osc_t osc); +void rcc_osc_off(osc_t osc); +void rcc_css_enable(void); +void rcc_css_disable(void); +void rcc_osc_bypass_enable(osc_t osc); +void rcc_osc_bypass_disable(osc_t osc); +void rcc_peripheral_enable_clock(volatile u32 *reg, u32 en); +void rcc_peripheral_disable_clock(volatile u32 *reg, u32 en); +void rcc_peripheral_reset(volatile u32 *reg, u32 reset); +void rcc_peripheral_clear_reset(volatile u32 *reg, u32 clear_reset); +void rcc_set_sysclk_source(u32 clk); +void rcc_set_pll_source(u32 pllsrc); +void rcc_set_ppre2(u32 ppre2); +void rcc_set_ppre1(u32 ppre1); +void rcc_set_hpre(u32 hpre); +void rcc_set_rtcpre(u32 rtcpre); +void rcc_set_main_pll_hsi(u32 pllm, u32 plln, u32 pllp, u32 pllq); +void rcc_set_main_pll_hse(u32 pllm, u32 plln, u32 pllp, u32 pllq); +u32 rcc_get_system_clock_source(int i); +void rcc_clock_setup_in_hse_8mhz_out_120mhz(void); +void rcc_backupdomain_reset(void); #endif diff --git a/lib/stm32f2/Makefile b/lib/stm32f2/Makefile index 5da64ab..98ba878 100644 --- a/lib/stm32f2/Makefile +++ b/lib/stm32f2/Makefile @@ -28,7 +28,7 @@ CFLAGS = -Os -g -Wall -Wextra -I../../include -fno-common \ -ffunction-sections -fdata-sections -MD -DSTM32F2 # ARFLAGS = rcsv ARFLAGS = rcs -OBJS = vector.o gpio.o systick.o i2c.o spi.o nvic.o usart.o +OBJS = vector.o gpio.o systick.o i2c.o spi.o nvic.o usart.o rcc.o flash.o #VPATH += ../usb VPATH += ../stm32_common diff --git a/lib/stm32f2/flash.c b/lib/stm32f2/flash.c new file mode 100644 index 0000000..e9bc73e --- /dev/null +++ b/lib/stm32f2/flash.c @@ -0,0 +1,250 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +static inline void flash_set_program_size(u32 psize) +{ + FLASH_CR &= ~(((1 << 0) | (1 << 1)) << 8); + FLASH_CR |= psize; +} + +void flash_data_cache_enable(void) +{ + FLASH_ACR |= FLASH_DCE; +} + +void flash_dcache_disable(void) +{ + FLASH_ACR &= ~FLASH_DCE; +} + +void flash_icache_enable(void) +{ + FLASH_ACR |= FLASH_ICE; +} + +void flash_icache_disable(void) +{ + FLASH_ACR &= ~FLASH_ICE; +} + +void flash_prefetch_enable(void) +{ + FLASH_ACR |= FLASH_PRFTEN; +} + +void flash_prefetch_disable(void) +{ + FLASH_ACR &= ~FLASH_PRFTEN; +} + +void flash_dcache_reset(void) +{ + FLASH_ACR |= FLASH_DCRST; +} + +void flash_icache_reset(void) +{ + FLASH_ACR |= FLASH_ICRST; +} + +void flash_set_ws(u32 ws) +{ + u32 reg32; + + reg32 = FLASH_ACR; + reg32 &= ~((1 << 0) | (1 << 1) | (1 << 2)); + reg32 |= ws; + FLASH_ACR = reg32; +} + +void flash_unlock(void) +{ + /* Authorize the FPEC access. */ + FLASH_KEYR = FLASH_KEY1; + FLASH_KEYR = FLASH_KEY2; +} + +void flash_lock(void) +{ + FLASH_CR |= FLASH_LOCK; +} + +void flash_clear_pgserr_flag(void) +{ + FLASH_SR |= FLASH_PGSERR; +} + +void flash_clear_pgperr_flag(void) +{ + FLASH_SR |= FLASH_PGPERR; +} + +void flash_clear_pgaerr_flag(void) +{ + FLASH_SR |= FLASH_PGAERR; +} + +void flash_clear_eop_flag(void) +{ + FLASH_SR |= FLASH_EOP; +} + +void flash_clear_wrperr_flag(void) +{ + FLASH_SR |= FLASH_WRPERR; +} + +void flash_clear_bsy_flag(void) +{ + FLASH_SR &= ~FLASH_BSY; +} + +void flash_clear_status_flags(void) +{ + flash_clear_pgserr_flag(); + flash_clear_pgperr_flag(); + flash_clear_pgaerr_flag(); + flash_clear_eop_flag(); + flash_clear_wrperr_flag(); + flash_clear_bsy_flag(); +} + +void flash_unlock_option_bytes(void) +{ + FLASH_OPTKEYR = FLASH_OPTKEY1; + FLASH_OPTKEYR = FLASH_OPTKEY2; +} + +void flash_lock_option_bytes(void) +{ + FLASH_OPTCR |= FLASH_OPTLOCK; +} + +void flash_wait_for_last_operation(void) +{ + while ((FLASH_SR & FLASH_BSY) == FLASH_BSY) + ; +} + +void flash_program_double_word(u32 address, u64 data, u32 program_size) +{ + /* Ensure that all flash operations are complete. */ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + /* Enable writes to flash. */ + FLASH_CR |= FLASH_PG; + + /* Program the first half of the word. */ + MMIO64(address) = data; + + /* Wait for the write to complete. */ + flash_wait_for_last_operation(); + + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_PG; +} + +void flash_program_word(u32 address, u32 data, u32 program_size) +{ + /* Ensure that all flash operations are complete. */ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + /* Enable writes to flash. */ + FLASH_CR |= FLASH_PG; + + /* Program the first half of the word. */ + MMIO32(address) = data; + + /* Wait for the write to complete. */ + flash_wait_for_last_operation(); + + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_PG; +} + +void flash_program_half_word(u32 address, u16 data, u32 program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR |= FLASH_PG; + + MMIO16(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_PG; /* Disable the PG bit. */ +} + +void flash_program_byte(u32 address, u8 data, u32 program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR |= FLASH_PG; + + MMIO8(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_PG; /* Disable the PG bit. */ +} + +void flash_erase_sector(u32 sector, u32 program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR &= ~(((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) << 3); + FLASH_CR |= sector; + FLASH_CR |= FLASH_STRT; + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_SER; + FLASH_CR &= ~(((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) << 3); +} + +void flash_erase_all_sectors(u32 program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR |= FLASH_MER; /* Enable mass erase. */ + FLASH_CR |= FLASH_STRT; /* Trigger the erase. */ + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_MER; /* Disable mass erase. */ +} + +void flash_program_option_bytes(u32 data) +{ + flash_wait_for_last_operation(); + + if (FLASH_OPTCR & FLASH_OPTLOCK) + flash_unlock_option_bytes(); + + FLASH_OPTCR = data & ~0x3; + FLASH_OPTCR |= FLASH_OPTSTRT; /* Enable option byte programming. */ + flash_wait_for_last_operation(); +} diff --git a/lib/stm32f2/rcc.c b/lib/stm32f2/rcc.c new file mode 100644 index 0000000..048f0ff --- /dev/null +++ b/lib/stm32f2/rcc.c @@ -0,0 +1,412 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Federico Ruiz-Ugalde + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2010 Thomas Otto + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset */ +u32 rcc_ppre1_frequency = 8000000; +u32 rcc_ppre2_frequency = 8000000; + +/* TODO: Create a table for these values */ +#define RCC_PLL_M 8 +#define RCC_PLL_N 336 +#define RCC_PLL_P 2 +#define RCC_PLL_Q 7 +#define RCC_PLLI2S_N 192 +#define RCC_PLLI2S_R 5 + +void rcc_osc_ready_int_clear(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYC; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYC; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYC; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYC; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYC; + break; + } +} + +void rcc_osc_ready_int_enable(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR |= RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR |= RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR |= RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR |= RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR |= RCC_CIR_LSIRDYIE; + break; + } +} + +void rcc_osc_ready_int_disable(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CIR &= ~RCC_CIR_PLLRDYIE; + break; + case HSE: + RCC_CIR &= ~RCC_CIR_HSERDYIE; + break; + case HSI: + RCC_CIR &= ~RCC_CIR_HSIRDYIE; + break; + case LSE: + RCC_CIR &= ~RCC_CIR_LSERDYIE; + break; + case LSI: + RCC_CIR &= ~RCC_CIR_LSIRDYIE; + break; + } +} + +int rcc_osc_ready_int_flag(osc_t osc) +{ + switch (osc) { + case PLL: + return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0); + break; + case HSE: + return ((RCC_CIR & RCC_CIR_HSERDYF) != 0); + break; + case HSI: + return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0); + break; + case LSE: + return ((RCC_CIR & RCC_CIR_LSERDYF) != 0); + break; + case LSI: + return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0); + break; + } + + /* Shouldn't be reached. */ + return -1; +} + +void rcc_css_int_clear(void) +{ + RCC_CIR |= RCC_CIR_CSSC; +} + +int rcc_css_int_flag(void) +{ + return ((RCC_CIR & RCC_CIR_CSSF) != 0); +} + +void rcc_wait_for_osc_ready(osc_t osc) +{ + switch (osc) { + case PLL: + while ((RCC_CR & RCC_CR_PLLRDY) == 0); + break; + case HSE: + while ((RCC_CR & RCC_CR_HSERDY) == 0); + break; + case HSI: + while ((RCC_CR & RCC_CR_HSIRDY) == 0); + break; + case LSE: + while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0); + break; + case LSI: + while ((RCC_CSR & RCC_CSR_LSIRDY) == 0); + break; + } +} + +void rcc_wait_for_sysclk_status(osc_t osc) +{ + switch (osc) { + case PLL: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL); + break; + case HSE: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE); + break; + case HSI: + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI); + break; + default: + /* Shouldn't be reached. */ + break; + } +} + +void rcc_osc_on(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CR |= RCC_CR_PLLON; + break; + case HSE: + RCC_CR |= RCC_CR_HSEON; + break; + case HSI: + RCC_CR |= RCC_CR_HSION; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR |= RCC_CSR_LSION; + break; + } +} + +void rcc_osc_off(osc_t osc) +{ + switch (osc) { + case PLL: + RCC_CR &= ~RCC_CR_PLLON; + break; + case HSE: + RCC_CR &= ~RCC_CR_HSEON; + break; + case HSI: + RCC_CR &= ~RCC_CR_HSION; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEON; + break; + case LSI: + RCC_CSR &= ~RCC_CSR_LSION; + break; + } +} + +void rcc_css_enable(void) +{ + RCC_CR |= RCC_CR_CSSON; +} + +void rcc_css_disable(void) +{ + RCC_CR &= ~RCC_CR_CSSON; +} + +void rcc_osc_bypass_enable(osc_t osc) +{ + switch (osc) { + case HSE: + RCC_CR |= RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR |= RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_osc_bypass_disable(osc_t osc) +{ + switch (osc) { + case HSE: + RCC_CR &= ~RCC_CR_HSEBYP; + break; + case LSE: + RCC_BDCR &= ~RCC_BDCR_LSEBYP; + break; + case PLL: + case HSI: + case LSI: + /* Do nothing, only HSE/LSE allowed here. */ + break; + } +} + +void rcc_peripheral_enable_clock(volatile u32 *reg, u32 en) +{ + *reg |= en; +} + +void rcc_peripheral_disable_clock(volatile u32 *reg, u32 en) +{ + *reg &= ~en; +} + +void rcc_peripheral_reset(volatile u32 *reg, u32 reset) +{ + *reg |= reset; +} + +void rcc_peripheral_clear_reset(volatile u32 *reg, u32 clear_reset) +{ + *reg &= ~clear_reset; +} + +void rcc_set_sysclk_source(u32 clk) +{ + u32 reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | clk); +} + +void rcc_set_pll_source(u32 pllsrc) +{ + u32 reg32; + + reg32 = RCC_PLLCFGR; + reg32 &= ~(1 << 22); + RCC_PLLCFGR = (reg32 | (pllsrc << 22)); +} + +void rcc_set_ppre2(u32 ppre2) +{ + u32 reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 11) | (1 << 12) | (1 << 13)); + RCC_CFGR = (reg32 | (ppre2 << 11)); +} + +void rcc_set_ppre1(u32 ppre1) +{ + u32 reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 8) | (1 << 9) | (1 << 10)); + RCC_CFGR = (reg32 | (ppre1 << 8)); +} + +void rcc_set_hpre(u32 hpre) +{ + u32 reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)); + RCC_CFGR = (reg32 | (hpre << 4)); +} + +void rcc_set_rtcpre(u32 rtcpre) +{ + u32 reg32; + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); + RCC_CFGR = (reg32 | (rtcpre << 16)); +} + +void rcc_set_main_pll_hsi(u32 pllm, u32 plln, u32 pllp, u32 pllq) +{ + RCC_PLLCFGR = pllm | + (plln << 6) | + (((pllp >> 1) - 1) << 16) | + (pllq << 24); +} + +void rcc_set_main_pll_hse(u32 pllm, u32 plln, u32 pllp, u32 pllq) +{ + RCC_PLLCFGR = pllm | + (plln << 6) | + (((pllp >> 1) - 1) << 16) | + RCC_PLLCFGR_PLLSRC | + (pllq << 24); +} + +u32 rcc_system_clock_source(void) +{ + /* Return the clock source which is used as system clock. */ + return ((RCC_CFGR & 0x000c) >> 2); +} + +void rcc_clock_setup_in_hse_8mhz_out_120mhz(void) +{ + /* Enable internal high-speed oscillator. */ + rcc_osc_on(HSI); + rcc_wait_for_osc_ready(HSI); + + /* Select HSI as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_HSI); + + /* Enable external high-speed oscillator 8MHz. */ + rcc_osc_on(HSE); + rcc_wait_for_osc_ready(HSE); + rcc_set_sysclk_source(RCC_CFGR_SW_HSE); + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + * Do this before touching the PLL (TODO: why?). + */ + rcc_set_hpre(RCC_CFGR_HPRE_DIV_NONE); /* Set. 120MHz Max. 120MHz */ + rcc_set_ppre1(RCC_CFGR_PPRE_DIV_4); /* Set. 30MHz Max. 30MHz */ + rcc_set_ppre2(RCC_CFGR_PPRE_DIV_2); /* Set. 60MHz Max. 60MHz */ + + rcc_set_main_pll_hse(RCC_PLL_M, RCC_PLL_N, RCC_PLL_P, RCC_PLL_Q); + + /* Enable PLL oscillator and wait for it to stabilize. */ + rcc_osc_on(PLL); + rcc_wait_for_osc_ready(PLL); + + /* + * @3.3V + * Sysclk runs with 120MHz -> 3 waitstates. + * 0WS from 0-30MHz + * 1WS from 30-60MHz + * 2WS from 60-90MHz + * 3WS from 90-120MHz + */ + flash_set_ws(FLASH_PRFTEN | FLASH_ICE | FLASH_DCE | FLASH_LATENCY_3WS); + + /* Select PLL as SYSCLK source. */ + rcc_set_sysclk_source(RCC_CFGR_SW_PLL); + + /* Wait for PLL clock to be selected. */ + rcc_wait_for_sysclk_status(PLL); + + /* Set the peripheral clock frequencies used */ + rcc_ppre1_frequency = 30000000; + rcc_ppre2_frequency = 60000000; +} + +void rcc_backupdomain_reset(void) +{ + /* Set the backup domain software reset. */ + RCC_BDCR |= RCC_BDCR_BDRST; + + /* Clear the backup domain software reset. */ + RCC_BDCR &= ~RCC_BDCR_BDRST; +} -- cgit v1.2.3