clock.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #include "amt630h.h"
  2. #include "clock.h"
  3. #define PLL_DIV_MASK 0xFF
  4. #define PLL_DIV_OFFSET 0
  5. #define PLL_NO_MASK 0x3
  6. #define PLL_NO_OFFSET 12
  7. #define PLL_ENA (1 << 14)
  8. typedef struct {
  9. uint32_t clkid;
  10. uint32_t clktype;
  11. uint32_t source;
  12. int clksource[MAX_CLK_SOURCE_NUM];
  13. int source_index;
  14. int div;
  15. union {
  16. uint32_t fixed_freq;
  17. struct {
  18. int div;
  19. int mult;
  20. } fixed_fator_property;
  21. struct {
  22. uint32_t cfgreg;
  23. uint32_t refclkreg;
  24. uint32_t offset;
  25. uint32_t mask;
  26. } pll_property;
  27. struct {
  28. uint32_t cfgreg;
  29. uint32_t analogreg;
  30. } dds_property;
  31. struct {
  32. uint32_t cfgreg;
  33. int index_offset;
  34. int index_value;
  35. uint32_t index_mask;
  36. int div_offset;
  37. int div_value;
  38. uint32_t div_mask;
  39. int div_mode;
  40. } sys_property;
  41. } u;
  42. } xClockProperty;
  43. xClockProperty xClocks[] = {
  44. {.clkid = CLK_XTAL24M, .clktype = FIXED_CLOCK, .u.fixed_freq = 24000000},
  45. {.clkid = CLK_12MHZ, .clktype = FIXED_FACTOR_CLOCK, .clksource = {CLK_XTAL24M},
  46. .u.fixed_fator_property.div = 2, .u.fixed_fator_property.mult = 1},
  47. {.clkid = CLK_6MHZ, .clktype = FIXED_FACTOR_CLOCK, .clksource = {CLK_XTAL24M},
  48. .u.fixed_fator_property.div = 4, .u.fixed_fator_property.mult = 1},
  49. {.clkid = CLK_CPUPLL, .clktype = PLL_CLOCK, .clksource = {CLK_6MHZ, CLK_12MHZ},
  50. .u.pll_property.cfgreg = 0x60000088, .u.pll_property.refclkreg = 0x60000040,
  51. .u.pll_property.offset = 24, .u.pll_property.mask = 1},
  52. {.clkid = CLK_SYSPLL, .clktype = PLL_CLOCK, .clksource = {CLK_6MHZ, CLK_12MHZ},
  53. .u.pll_property.cfgreg = 0x6000008c, .u.pll_property.refclkreg = 0x60000040,
  54. .u.pll_property.offset = 25, .u.pll_property.mask = 1},
  55. {.clkid = CLK_LCD, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_CPUPLL, CLK_XTAL24M, CLK_XTAL24M},
  56. .u.sys_property.cfgreg = 0x6000004c, .u.sys_property.index_offset = 0,
  57. .u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 1,
  58. .u.sys_property.div_offset = 3, .u.sys_property.div_mask = 0x1f,
  59. .u.sys_property.div_value = 11, .u.sys_property.div_mode = DIVMODE_PLUSONE,},
  60. };
  61. #define CLOCK_NUM (sizeof(xClocks) / sizeof(xClocks[0]))
  62. static xClockProperty *clk_get(uint32_t clkid)
  63. {
  64. int i;
  65. for (i = 0; i < CLOCK_NUM; i++) {
  66. if (xClocks[i].clkid == clkid) {
  67. return &xClocks[i];
  68. }
  69. }
  70. return NULL;
  71. }
  72. static uint32_t clk_fixed_get_rate(xClockProperty *clk)
  73. {
  74. return clk->u.fixed_freq;
  75. }
  76. static uint32_t clk_fixed_factor_get_rate(xClockProperty *clk)
  77. {
  78. xClockProperty *parentclk = clk_get(clk->clksource[0]);
  79. return clk_fixed_get_rate(parentclk) * clk->u.fixed_fator_property.mult
  80. / clk->u.fixed_fator_property.div;
  81. }
  82. static uint32_t clk_pll_get_rate(xClockProperty *clk)
  83. {
  84. uint32_t parent_rate;
  85. uint32_t div, no, reg;
  86. parent_rate = ulClkGetRate(clk->clksource[clk->source_index]);
  87. reg = readl(clk->u.pll_property.cfgreg);
  88. no = (reg >> PLL_NO_OFFSET) & PLL_NO_MASK;
  89. div = (reg >> PLL_DIV_OFFSET) & PLL_DIV_MASK;
  90. return (parent_rate * div) / (1 << no);
  91. }
  92. static uint32_t clk_sys_get_rate(xClockProperty *clk)
  93. {
  94. uint32_t parent_rate;
  95. parent_rate = ulClkGetRate(clk->clksource[clk->source_index]);
  96. return parent_rate / clk->div;
  97. }
  98. static void clk_pll_init(xClockProperty *clk)
  99. {
  100. clk->source_index = (readl(clk->u.pll_property.refclkreg) >> clk->u.pll_property.offset)
  101. & clk->u.pll_property.mask;
  102. }
  103. static int clk_get_div(int div, int divmode)
  104. {
  105. switch(divmode) {
  106. case DIVMODE_NOZERO:
  107. div = div ? div : 1;
  108. break;
  109. case DIVMODE_PLUSONE:
  110. div = div + 1;
  111. break;
  112. case DIVMODE_DOUBLE:
  113. div *= 2;
  114. break;
  115. case DIVMODE_EXPONENT:
  116. div = 1 << div;
  117. break;
  118. case DIVMODE_PONEDOUBLE:
  119. div = (div + 1) * 2;
  120. break;
  121. }
  122. return div;
  123. }
  124. static int clk_set_div(int div, int divmode)
  125. {
  126. switch(divmode) {
  127. case DIVMODE_PLUSONE:
  128. div = div - 1;
  129. break;
  130. case DIVMODE_DOUBLE:
  131. div /= 2;
  132. break;
  133. case DIVMODE_EXPONENT:
  134. div = fls(div) - 1;
  135. break;
  136. case DIVMODE_PONEDOUBLE:
  137. div = div / 2 - 1;
  138. break;
  139. }
  140. return div;
  141. }
  142. static void clk_sys_set_rate(xClockProperty *clk, uint32_t freq)
  143. {
  144. int div;
  145. uint32_t reg;
  146. uint32_t parent_rate;
  147. parent_rate = ulClkGetRate(clk->clksource[clk->source_index]);
  148. div = DIV_ROUND_UP(parent_rate, freq);
  149. clk->div = div;
  150. div = clk_set_div(div, clk->u.sys_property.div_mode);
  151. reg = readl(clk->u.sys_property.cfgreg);
  152. reg &= ~(clk->u.sys_property.div_mask << clk->u.sys_property.div_offset);
  153. reg |= (div & clk->u.sys_property.div_mask) << clk->u.sys_property.div_offset;
  154. writel(reg, clk->u.sys_property.cfgreg);
  155. }
  156. static void clk_sys_init(xClockProperty *clk)
  157. {
  158. uint32_t reg;
  159. uint32_t val;
  160. if (clk->u.sys_property.index_value >= 0 && clk->u.sys_property.index_mask) {
  161. clk->source_index = clk->u.sys_property.index_value;
  162. val = clk->u.sys_property.index_value == 3 ? 4 : clk->u.sys_property.index_value;
  163. reg = readl(clk->u.sys_property.cfgreg);
  164. reg &= ~(clk->u.sys_property.index_mask << clk->u.sys_property.index_offset);
  165. reg |= (val & clk->u.sys_property.index_mask) << clk->u.sys_property.index_offset;
  166. writel(reg, clk->u.sys_property.cfgreg);
  167. } else if (clk->u.sys_property.index_mask) {
  168. reg = readl(clk->u.sys_property.cfgreg);
  169. val = (reg >> clk->u.sys_property.index_offset) & clk->u.sys_property.index_mask;
  170. clk->source_index = val == 4 ? 3 : val;
  171. }
  172. if (clk->u.sys_property.div_value >= 0 && clk->u.sys_property.div_mask) {
  173. val = clk_set_div(clk->u.sys_property.div_value, clk->u.sys_property.div_mode);
  174. clk->div = clk_get_div(val, clk->u.sys_property.div_mode);
  175. reg = readl(clk->u.sys_property.cfgreg);
  176. reg &= ~(clk->u.sys_property.div_mask << clk->u.sys_property.div_offset);
  177. reg |= (val & clk->u.sys_property.div_mask) << clk->u.sys_property.div_offset;
  178. writel(reg, clk->u.sys_property.cfgreg);
  179. } else if (clk->u.sys_property.div_mask) {
  180. reg = readl(clk->u.sys_property.cfgreg);
  181. val = (reg >> clk->u.sys_property.div_offset) & clk->u.sys_property.div_mask;
  182. clk->div = clk_get_div(val, clk->u.sys_property.div_mode);
  183. } else if (clk->u.sys_property.div_value > 0) {
  184. clk->div = clk->u.sys_property.div_value;
  185. } else {
  186. clk->div = 1;
  187. }
  188. }
  189. void vClkInit(void)
  190. {
  191. int i;
  192. xClockProperty *clk;
  193. for (i = 0; i < CLOCK_NUM; i++) {
  194. clk = &xClocks[i];
  195. if (clk->clktype == PLL_CLOCK) {
  196. clk_pll_init(clk);
  197. } else if (clk->clktype == SYS_CLOCK) {
  198. clk_sys_init(clk);
  199. }
  200. }
  201. }
  202. uint32_t ulClkGetRate(uint32_t clkid)
  203. {
  204. xClockProperty *clk = clk_get(clkid);
  205. if (clk == NULL)
  206. return 0;
  207. switch (clk->clktype) {
  208. case FIXED_CLOCK:
  209. return clk_fixed_get_rate(clk);
  210. case FIXED_FACTOR_CLOCK:
  211. return clk_fixed_factor_get_rate(clk);
  212. case PLL_CLOCK:
  213. return clk_pll_get_rate(clk);
  214. case SYS_CLOCK:
  215. return clk_sys_get_rate(clk);
  216. }
  217. return 0;
  218. }
  219. void vClkSetRate(uint32_t clkid, uint32_t freq)
  220. {
  221. xClockProperty *clk = clk_get(clkid);
  222. if (clk == NULL)
  223. return;
  224. if (clk->clktype == SYS_CLOCK)
  225. clk_sys_set_rate(clk, freq);
  226. }