summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/beagle/misc/system-clocks.c
blob: 56b5d9aadb77ba2ff2575460e6f6de5169fd6de7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
 * @file
 *
 * @ingroup beagle
 *
 * @brief System clocks.
 */

/*
 * Copyright (c) 2012 Claas Ziemke. All rights reserved.
 *
 *  Claas Ziemke
 *  Kernerstrasse 11
 *  70182 Stuttgart
 *  Germany
 *  <claas.ziemke@gmx.net>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.com/license/LICENSE.
 */

#include <bsp.h>
#include <bsp/beagle.h>

uint32_t beagle_sysclk(void)
{
  uint32_t sysclk_ctrl = BEAGLE_SYSCLK_CTRL;

  return (sysclk_ctrl & 0x1) == 0 ?
    BEAGLE_OSCILLATOR_MAIN
      : (397 * BEAGLE_OSCILLATOR_RTC);
}

uint32_t beagle_hclkpll_clk(void)
{
  uint32_t sysclk = beagle_sysclk();
  uint32_t hclkpll_ctrl = BEAGLE_HCLKPLL_CTRL;
  uint32_t m = HCLK_PLL_M_GET(hclkpll_ctrl) + 1;
  uint32_t n = HCLK_PLL_N_GET(hclkpll_ctrl) + 1;
  uint32_t p = 1U << HCLK_PLL_P_GET(hclkpll_ctrl);
  uint32_t hclkpll_clk = 0;

  if ((hclkpll_ctrl & HCLK_PLL_BYPASS) != 0) {
    if ((hclkpll_ctrl & HCLK_PLL_DIRECT) != 0) {
      hclkpll_clk = sysclk;
    } else {
      hclkpll_clk = sysclk / (2 * p);
    }
  } else {
    if ((hclkpll_ctrl & HCLK_PLL_DIRECT) != 0) {
      hclkpll_clk = (m * sysclk) / n;
    } else {
      if ((hclkpll_ctrl & HCLK_PLL_FBD_FCLKOUT) != 0) {
        hclkpll_clk = m * (sysclk / n);
      } else {
        hclkpll_clk = (m / (2 * p)) * (sysclk / n);
      }
    }
  }

  return hclkpll_clk;
}

uint32_t beagle_periph_clk(void)
{
  uint32_t pwr_ctrl = BEAGLE_PWR_CTRL;
  uint32_t periph_clk = 0;

  if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) {
    uint32_t hclkdiv_ctrl = BEAGLE_HCLKDIV_CTRL;
    uint32_t div = HCLK_DIV_PERIPH_CLK_GET(hclkdiv_ctrl) + 1;

    periph_clk = beagle_hclkpll_clk() / div;
  } else {
    periph_clk = beagle_sysclk();
  }

  return periph_clk;
}

uint32_t beagle_hclk(void)
{
  uint32_t pwr_ctrl = BEAGLE_PWR_CTRL;
  uint32_t hclk = 0;

  if ((pwr_ctrl & PWR_HCLK_USES_PERIPH_CLK) != 0) {
    hclk = beagle_periph_clk();
  } else {
    if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) {
      uint32_t hclkdiv_ctrl = BEAGLE_HCLKDIV_CTRL;
      uint32_t div = 1U << HCLK_DIV_HCLK_GET(hclkdiv_ctrl);

      hclk = beagle_hclkpll_clk() / div;
    } else {
      hclk = beagle_sysclk();
    }
  }

  return hclk;
}

uint32_t beagle_arm_clk(void)
{
  uint32_t pwr_ctrl = BEAGLE_PWR_CTRL;
  uint32_t arm_clk = 0;

  if ((pwr_ctrl & PWR_HCLK_USES_PERIPH_CLK) != 0) {
    arm_clk = beagle_periph_clk();
  } else {
    if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) {
      arm_clk = beagle_hclkpll_clk();
    } else {
      arm_clk = beagle_sysclk();
    }
  }

  return arm_clk;
}

uint32_t beagle_dram_clk(void)
{
  uint32_t hclkdiv_ctrl = BEAGLE_HCLKDIV_CTRL;
  uint32_t div = HCLK_DIV_DDRAM_CLK_GET(hclkdiv_ctrl);
  uint32_t dram_clk = 0;

  if (div != 0) {
    uint32_t pwr_ctrl = BEAGLE_PWR_CTRL;

    if ((pwr_ctrl & PWR_NORMAL_RUN_MODE) != 0) {
      dram_clk = beagle_hclkpll_clk();
    } else {
      dram_clk = beagle_sysclk();
    }

    dram_clk /= div;
  }

  return dram_clk;
}