]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
b4626a7f YL |
2 | /* |
3 | * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com> | |
b4626a7f YL |
4 | */ |
5 | ||
6 | #include <linux/clkdev.h> | |
7 | #include <linux/clk-provider.h> | |
62e59c4e | 8 | #include <linux/io.h> |
b4626a7f YL |
9 | |
10 | #include <loongson1.h> | |
11 | #include "clk.h" | |
12 | ||
13 | #define OSC (24 * 1000000) | |
14 | #define DIV_APB 1 | |
15 | ||
16 | static DEFINE_SPINLOCK(_lock); | |
17 | ||
18 | static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, | |
19 | unsigned long parent_rate) | |
20 | { | |
21 | u32 pll, rate; | |
22 | ||
23 | pll = __raw_readl(LS1X_CLK_PLL_FREQ); | |
24 | rate = ((pll >> 8) & 0xff) + ((pll >> 16) & 0xff); | |
25 | rate *= OSC; | |
26 | rate >>= 2; | |
27 | ||
28 | return rate; | |
29 | } | |
30 | ||
31 | static const struct clk_ops ls1x_pll_clk_ops = { | |
32 | .recalc_rate = ls1x_pll_recalc_rate, | |
33 | }; | |
34 | ||
35 | static const struct clk_div_table ahb_div_table[] = { | |
36 | [0] = { .val = 0, .div = 2 }, | |
37 | [1] = { .val = 1, .div = 4 }, | |
38 | [2] = { .val = 2, .div = 3 }, | |
39 | [3] = { .val = 3, .div = 3 }, | |
e0eeb52c | 40 | [4] = { /* sentinel */ } |
b4626a7f YL |
41 | }; |
42 | ||
43 | void __init ls1x_clk_init(void) | |
44 | { | |
45 | struct clk_hw *hw; | |
46 | ||
47 | hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); | |
48 | clk_hw_register_clkdev(hw, "osc_clk", NULL); | |
49 | ||
50 | /* clock derived from 24 MHz OSC clk */ | |
51 | hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", | |
52 | &ls1x_pll_clk_ops, 0); | |
53 | clk_hw_register_clkdev(hw, "pll_clk", NULL); | |
54 | ||
55 | hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", | |
56 | CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, | |
57 | DIV_CPU_SHIFT, DIV_CPU_WIDTH, | |
58 | CLK_DIVIDER_ONE_BASED | | |
59 | CLK_DIVIDER_ROUND_CLOSEST, &_lock); | |
60 | clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); | |
61 | hw = clk_hw_register_fixed_factor(NULL, "cpu_clk", "cpu_clk_div", | |
62 | 0, 1, 1); | |
63 | clk_hw_register_clkdev(hw, "cpu_clk", NULL); | |
64 | ||
65 | hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", | |
66 | 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, | |
67 | DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | |
68 | clk_hw_register_clkdev(hw, "dc_clk_div", NULL); | |
69 | hw = clk_hw_register_fixed_factor(NULL, "dc_clk", "dc_clk_div", | |
70 | 0, 1, 1); | |
71 | clk_hw_register_clkdev(hw, "dc_clk", NULL); | |
72 | ||
73 | hw = clk_hw_register_divider_table(NULL, "ahb_clk_div", "cpu_clk_div", | |
74 | 0, LS1X_CLK_PLL_FREQ, DIV_DDR_SHIFT, | |
75 | DIV_DDR_WIDTH, CLK_DIVIDER_ALLOW_ZERO, | |
76 | ahb_div_table, &_lock); | |
77 | clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); | |
78 | hw = clk_hw_register_fixed_factor(NULL, "ahb_clk", "ahb_clk_div", | |
79 | 0, 1, 1); | |
80 | clk_hw_register_clkdev(hw, "ahb_clk", NULL); | |
81 | clk_hw_register_clkdev(hw, "ls1x-dma", NULL); | |
82 | clk_hw_register_clkdev(hw, "stmmaceth", NULL); | |
83 | ||
84 | /* clock derived from AHB clk */ | |
85 | hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, | |
86 | DIV_APB); | |
87 | clk_hw_register_clkdev(hw, "apb_clk", NULL); | |
88 | clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); | |
89 | clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); | |
90 | clk_hw_register_clkdev(hw, "ls1x-nand", NULL); | |
91 | clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); | |
92 | clk_hw_register_clkdev(hw, "ls1x-spi", NULL); | |
93 | clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); | |
94 | clk_hw_register_clkdev(hw, "serial8250", NULL); | |
95 | } |