1/* Copied from https://wiki.osdev.org/HiFive-1_Bare_Bones#The_kernel_source_code */
2/* Should eventually be rewritten in Zig with proper abstraction for the PRCI. */
3
4#include <stdint.h>
5
6#define PRCI_CTRL_ADDR 0x10008000UL
7#define PRCI_HFROSCCFG (0x0000)
8#define PRCI_PLLCFG (0x0008)
9#define ROSC_EN(x) (((x) & 0x1) << 30)
10#define PLL_REFSEL(x) (((x) & 0x1) << 17)
11#define PLL_BYPASS(x) (((x) & 0x1) << 18)
12#define PLL_SEL(x) (((x) & 0x1) << 16)
13
14static inline uint32_t
15mmio_read_u32(unsigned long reg, unsigned int offset)
16{
17 return (*(volatile uint32_t *) ((reg) + (offset)));
18}
19
20static inline void
21mmio_write_u32(unsigned long reg, unsigned int offset, uint32_t val)
22{
23 (*(volatile uint32_t *) ((reg) + (offset))) = val;
24}
25
26void
27clock_init(void)
28{
29 /* Make sure the HFROSC is on */
30 mmio_write_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG,
31 mmio_read_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG)
32 | ROSC_EN(1));
33
34 /* Run off 16 MHz Crystal for accuracy */
35 mmio_write_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG,
36 mmio_read_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG)
37 | (PLL_REFSEL(1) | PLL_BYPASS(1)));
38 mmio_write_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG,
39 mmio_read_u32(PRCI_CTRL_ADDR, PRCI_PLLCFG)
40 | (PLL_SEL(1)));
41
42 /* Turn off HFROSC to save power */
43 mmio_write_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG,
44 mmio_read_u32(PRCI_CTRL_ADDR, PRCI_HFROSCCFG)
45 & ~(ROSC_EN(1)));
46}