altos/stm32f1: More stm32f103 work
[fw/altos] / src / stm32f1 / ao_clock.c
1 /*
2  * Copyright © 2023 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 void
22 ao_clock_init(void)
23 {
24         uint32_t        cfgr;
25
26         /* Switch to HSI while messing about */
27         stm_rcc.cr |= (1 << STM_RCC_CR_HSION);
28         while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY)))
29                 ao_arch_nop();
30
31         stm_rcc.cfgr = (stm_rcc.cfgr & ~(uint32_t) (STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) |
32                 (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW);
33
34         /* wait for system to switch to HSI */
35         while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
36                (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS))
37                 ao_arch_nop();
38
39         /* Disable all interrupts */
40         stm_rcc.cir = 0;
41
42 #if AO_HSE
43 #if AO_HSE_BYPASS
44         stm_rcc.cr |= (1 << STM_RCC_CR_HSEBYP);
45 #else
46         stm_rcc.cr &= ~(uint32_t) (1 << STM_RCC_CR_HSEBYP);
47 #endif
48         /* Enable HSE clock */
49         stm_rcc.cr |= (1 << STM_RCC_CR_HSEON);
50         while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSERDY)))
51                 asm("nop");
52
53 #define STM_RCC_CFGR_SWS_TARGET_CLOCK           (STM_RCC_CFGR_SWS_HSE << STM_RCC_CFGR_SWS)
54 #define STM_RCC_CFGR_SW_TARGET_CLOCK            (STM_RCC_CFGR_SW_HSE)
55 #define STM_PLLSRC                              AO_HSE
56 #define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK        (STM_RCC_CFGR_PLLSRC_HSE << STM_RCC_CFGR_PLLSRC)
57 #else
58 #define STM_HSI                                 16000000
59 #define STM_RCC_CFGR_SWS_TARGET_CLOCK           (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)
60 #define STM_RCC_CFGR_SW_TARGET_CLOCK            (STM_RCC_CFGR_SW_HSI)
61 #define STM_PLLSRC                              (STM_HSI/2)
62 #define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK        (STM_RCC_CFGR_PLLSRC_HSI_2 << STM_RCC_CFGR_PLLSRC)
63 #endif
64
65 #if !AO_HSE || HAS_ADC || HAS_ADC_SINGLE
66         /* Enable HSI RC clock 16MHz */
67         stm_rcc.cr |= (1 << STM_RCC_CR_HSION);
68         while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY)))
69                 asm("nop");
70 #endif
71
72         /* Set flash latency to tolerate 72MHz SYSCLK  -> 2 wait states */
73
74         /* Enable 64-bit access and prefetch */
75         stm_flash.acr = ((1 << STM_FLASH_ACR_PRFTBE) |
76                          (0 << STM_FLASH_ACR_HLFCYA) |
77                          (STM_FLASH_ACR_LATENCY_2 << STM_FLASH_ACR_LATENCY));
78
79         /* Enable power interface clock */
80         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
81
82 #if 0
83         /* Set voltage range to 1.8V */
84
85         /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
86         while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
87                 asm("nop");
88
89         /* Configure voltage scaling range */
90         cr = stm_pwr.cr;
91         cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
92         cr |= (STM_PWR_CR_VOS_1_8 << STM_PWR_CR_VOS);
93         stm_pwr.cr = cr;
94
95         /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
96         while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
97                 asm("nop");
98 #endif
99
100         /* HCLK */
101         cfgr = stm_rcc.cfgr;
102         cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
103         cfgr |= (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE);
104         stm_rcc.cfgr = cfgr;
105         while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
106                (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE))
107                 asm ("nop");
108
109         /* APB1 Prescaler = AO_APB1_PRESCALER */
110         cfgr = stm_rcc.cfgr;
111         cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
112         cfgr |= (AO_RCC_CFGR_PPRE1_DIV << STM_RCC_CFGR_PPRE1);
113         stm_rcc.cfgr = cfgr;
114
115         /* APB2 Prescaler = AO_APB2_PRESCALER */
116         cfgr = stm_rcc.cfgr;
117         cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
118         cfgr |= (AO_RCC_CFGR_PPRE2_DIV << STM_RCC_CFGR_PPRE2);
119         stm_rcc.cfgr = cfgr;
120
121         /* Disable the PLL */
122         stm_rcc.cr &= ~(1UL << STM_RCC_CR_PLLON);
123         while (stm_rcc.cr & (1UL << STM_RCC_CR_PLLRDY))
124                 asm("nop");
125
126         /* PLLVCO */
127         cfgr = stm_rcc.cfgr;
128         cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
129
130         cfgr |= (AO_RCC_CFGR_PLLMUL << STM_RCC_CFGR_PLLMUL);
131
132         /* PLL source */
133         cfgr &= ~(1UL << STM_RCC_CFGR_PLLSRC);
134         cfgr |= STM_RCC_CFGR_PLLSRC_TARGET_CLOCK;
135
136         stm_rcc.cfgr = cfgr;
137
138         /* Enable the PLL and wait for it */
139         stm_rcc.cr |= (1 << STM_RCC_CR_PLLON);
140         while (!(stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY)))
141                 asm("nop");
142
143         /* Switch to the PLL for the system clock */
144
145         cfgr = stm_rcc.cfgr;
146         cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
147         cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW);
148         stm_rcc.cfgr = cfgr;
149         for (;;) {
150                 uint32_t        c, part, mask, val;
151
152                 c = stm_rcc.cfgr;
153                 mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
154                 val = (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS);
155                 part = c & mask;
156                 if (part == val)
157                         break;
158         }
159
160 #if 0
161         stm_rcc.apb2rstr = 0xffff;
162         stm_rcc.apb1rstr = 0xffff;
163         stm_rcc.ahbrstr = 0x3f;
164         stm_rcc.ahbenr = (1 << STM_RCC_AHBENR_FLITFEN);
165         stm_rcc.apb2enr = 0;
166         stm_rcc.apb1enr = 0;
167         stm_rcc.ahbrstr = 0;
168         stm_rcc.apb1rstr = 0;
169         stm_rcc.apb2rstr = 0;
170 #endif
171
172         /* Clear reset flags */
173         stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF);
174
175
176 #if DEBUG_THE_CLOCK
177         /* Output SYSCLK on PA8 for measurments */
178
179         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
180
181         stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0);
182         stm_moder_set(&stm_gpioa, 8, STM_MODER_ALTERNATE);
183         stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz);
184
185         stm_rcc.cfgr |= (STM_RCC_CFGR_MCOPRE_DIV_1 << STM_RCC_CFGR_MCOPRE);
186         stm_rcc.cfgr |= (STM_RCC_CFGR_MCOSEL_HSE << STM_RCC_CFGR_MCOSEL);
187 #endif
188 }