// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
//
// This file contains essentials required by the CMSIS:
// uint32_t SystemCoreClock - holds the system core clock value
// SystemInit() - initialises the system, e.g. sets up clocks

#include "hal.h"

uint32_t SystemCoreClock = SYS_FREQUENCY;

void SystemInit(void) {  // Called automatically by startup code
  SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2));  // Enable FPU
  asm("DSB");
  asm("ISB");
  SETBITS(SYSCTL->MOSCCTL, BIT(3) | BIT(2),
          BIT(4));  // Enable MOSC circuit (clear NOXTAL and PWRDN, set >10MHz
                    // range)
  SETBITS(SYSCTL->MEMTIM0,
          BIT(21) | BIT(5) | 0x1F << 21 | 0xF << 16 | 0x1F << 5 | 0xF << 0,
          FLASH_CLKHIGH << 22 | FLASH_WAITST << 16 | FLASH_CLKHIGH << 5 |
              FLASH_WAITST << 0);  // Configure flash timing (not yet applied)
  SETBITS(SYSCTL->RSCLKCFG, 0xF << 24 | (BIT(9) - 1),
          3 << 24);  // Clear PLL divider, set MOSC as PLL source
  SYSCTL->PLLFREQ1 = (PLL_Q - 1) << 8 | (PLL_N - 1)
                                            << 0;  // Set PLL_Q and PLL_N
  SYSCTL->PLLFREQ0 =
      BIT(23) | PLL_M << 0;  // Set PLL_Q, power up PLL (if it were on, we'd
                             // need to set NEWFREQ in RSCLKCFG instead)
  while ((SYSCTL->PLLSTAT & BIT(0)) == 0) spin(1);  // Wait for lock
  SYSCTL->RSCLKCFG |=
      BIT(31) | BIT(28) |
      (PSYSDIV - 1) << 0;  // Update memory timing, use PLL, set clock divisor

  SysTick_Config(SystemCoreClock / 1000);  // Sys tick every 1ms
}