Commit | Line | Data |
---|---|---|
5175cb58 | 1 | /* |
a8e3ced4 | 2 | * Copyright (c) 2012-2016 Zhang, Keguang <keguang.zhang@gmail.com> |
5175cb58 KC |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation; either version 2 of the License, or (at your | |
7 | * option) any later version. | |
8 | */ | |
9 | ||
10 | #include <linux/clkdev.h> | |
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/io.h> | |
5175cb58 KC |
13 | #include <linux/err.h> |
14 | ||
15 | #include <loongson1.h> | |
a8e3ced4 | 16 | #include "clk.h" |
5175cb58 | 17 | |
3526f74f KC |
18 | #define OSC (33 * 1000000) |
19 | #define DIV_APB 2 | |
5175cb58 KC |
20 | |
21 | static DEFINE_SPINLOCK(_lock); | |
22 | ||
5175cb58 | 23 | static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, |
3526f74f | 24 | unsigned long parent_rate) |
5175cb58 KC |
25 | { |
26 | u32 pll, rate; | |
27 | ||
28 | pll = __raw_readl(LS1X_CLK_PLL_FREQ); | |
f0ffaf18 | 29 | rate = 12 + (pll & GENMASK(5, 0)); |
5175cb58 KC |
30 | rate *= OSC; |
31 | rate >>= 1; | |
32 | ||
33 | return rate; | |
34 | } | |
35 | ||
36 | static const struct clk_ops ls1x_pll_clk_ops = { | |
5175cb58 KC |
37 | .recalc_rate = ls1x_pll_recalc_rate, |
38 | }; | |
39 | ||
c99c7a9a KC |
40 | static const char *const cpu_parents[] = { "cpu_clk_div", "osc_clk", }; |
41 | static const char *const ahb_parents[] = { "ahb_clk_div", "osc_clk", }; | |
42 | static const char *const dc_parents[] = { "dc_clk_div", "osc_clk", }; | |
3526f74f | 43 | |
5175cb58 KC |
44 | void __init ls1x_clk_init(void) |
45 | { | |
944b9a41 | 46 | struct clk_hw *hw; |
5175cb58 | 47 | |
c99c7a9a KC |
48 | hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); |
49 | clk_hw_register_clkdev(hw, "osc_clk", NULL); | |
3526f74f KC |
50 | |
51 | /* clock derived from 33 MHz OSC clk */ | |
c99c7a9a | 52 | hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", |
a8e3ced4 | 53 | &ls1x_pll_clk_ops, 0); |
944b9a41 | 54 | clk_hw_register_clkdev(hw, "pll_clk", NULL); |
3526f74f KC |
55 | |
56 | /* clock derived from PLL clk */ | |
57 | /* _____ | |
58 | * _______________________| | | |
59 | * OSC ___/ | MUX |___ CPU CLK | |
60 | * \___ PLL ___ CPU DIV ___| | | |
61 | * |_____| | |
62 | */ | |
944b9a41 | 63 | hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", |
3526f74f KC |
64 | CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, |
65 | DIV_CPU_SHIFT, DIV_CPU_WIDTH, | |
66 | CLK_DIVIDER_ONE_BASED | | |
67 | CLK_DIVIDER_ROUND_CLOSEST, &_lock); | |
944b9a41 SB |
68 | clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); |
69 | hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, | |
3526f74f KC |
70 | ARRAY_SIZE(cpu_parents), |
71 | CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, | |
72 | BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); | |
944b9a41 | 73 | clk_hw_register_clkdev(hw, "cpu_clk", NULL); |
3526f74f KC |
74 | |
75 | /* _____ | |
76 | * _______________________| | | |
77 | * OSC ___/ | MUX |___ DC CLK | |
78 | * \___ PLL ___ DC DIV ___| | | |
79 | * |_____| | |
80 | */ | |
944b9a41 | 81 | hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", |
3526f74f KC |
82 | 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, |
83 | DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | |
944b9a41 SB |
84 | clk_hw_register_clkdev(hw, "dc_clk_div", NULL); |
85 | hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, | |
3526f74f KC |
86 | ARRAY_SIZE(dc_parents), |
87 | CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, | |
88 | BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); | |
944b9a41 | 89 | clk_hw_register_clkdev(hw, "dc_clk", NULL); |
3526f74f KC |
90 | |
91 | /* _____ | |
92 | * _______________________| | | |
93 | * OSC ___/ | MUX |___ DDR CLK | |
94 | * \___ PLL ___ DDR DIV ___| | | |
95 | * |_____| | |
96 | */ | |
944b9a41 | 97 | hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", |
3526f74f KC |
98 | 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, |
99 | DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, | |
100 | &_lock); | |
944b9a41 SB |
101 | clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); |
102 | hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, | |
3526f74f KC |
103 | ARRAY_SIZE(ahb_parents), |
104 | CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, | |
105 | BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); | |
944b9a41 | 106 | clk_hw_register_clkdev(hw, "ahb_clk", NULL); |
c99c7a9a | 107 | clk_hw_register_clkdev(hw, "ls1x-dma", NULL); |
944b9a41 | 108 | clk_hw_register_clkdev(hw, "stmmaceth", NULL); |
5175cb58 | 109 | |
3526f74f KC |
110 | /* clock derived from AHB clk */ |
111 | /* APB clk is always half of the AHB clk */ | |
944b9a41 | 112 | hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, |
3526f74f | 113 | DIV_APB); |
944b9a41 | 114 | clk_hw_register_clkdev(hw, "apb_clk", NULL); |
c99c7a9a KC |
115 | clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); |
116 | clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); | |
117 | clk_hw_register_clkdev(hw, "ls1x-nand", NULL); | |
118 | clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); | |
119 | clk_hw_register_clkdev(hw, "ls1x-spi", NULL); | |
120 | clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); | |
944b9a41 | 121 | clk_hw_register_clkdev(hw, "serial8250", NULL); |
5175cb58 | 122 | } |