]>
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 }, | |
40 | }; | |
41 | ||
42 | void __init ls1x_clk_init(void) | |
43 | { | |
44 | struct clk_hw *hw; | |
45 | ||
46 | hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); | |
47 | clk_hw_register_clkdev(hw, "osc_clk", NULL); | |
48 | ||
49 | /* clock derived from 24 MHz OSC clk */ | |
50 | hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", | |
51 | &ls1x_pll_clk_ops, 0); | |
52 | clk_hw_register_clkdev(hw, "pll_clk", NULL); | |
53 | ||
54 | hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", | |
55 | CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, | |
56 | DIV_CPU_SHIFT, DIV_CPU_WIDTH, | |
57 | CLK_DIVIDER_ONE_BASED | | |
58 | CLK_DIVIDER_ROUND_CLOSEST, &_lock); | |
59 | clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); | |
60 | hw = clk_hw_register_fixed_factor(NULL, "cpu_clk", "cpu_clk_div", | |
61 | 0, 1, 1); | |
62 | clk_hw_register_clkdev(hw, "cpu_clk", NULL); | |
63 | ||
64 | hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", | |
65 | 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, | |
66 | DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); | |
67 | clk_hw_register_clkdev(hw, "dc_clk_div", NULL); | |
68 | hw = clk_hw_register_fixed_factor(NULL, "dc_clk", "dc_clk_div", | |
69 | 0, 1, 1); | |
70 | clk_hw_register_clkdev(hw, "dc_clk", NULL); | |
71 | ||
72 | hw = clk_hw_register_divider_table(NULL, "ahb_clk_div", "cpu_clk_div", | |
73 | 0, LS1X_CLK_PLL_FREQ, DIV_DDR_SHIFT, | |
74 | DIV_DDR_WIDTH, CLK_DIVIDER_ALLOW_ZERO, | |
75 | ahb_div_table, &_lock); | |
76 | clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); | |
77 | hw = clk_hw_register_fixed_factor(NULL, "ahb_clk", "ahb_clk_div", | |
78 | 0, 1, 1); | |
79 | clk_hw_register_clkdev(hw, "ahb_clk", NULL); | |
80 | clk_hw_register_clkdev(hw, "ls1x-dma", NULL); | |
81 | clk_hw_register_clkdev(hw, "stmmaceth", NULL); | |
82 | ||
83 | /* clock derived from AHB clk */ | |
84 | hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, | |
85 | DIV_APB); | |
86 | clk_hw_register_clkdev(hw, "apb_clk", NULL); | |
87 | clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); | |
88 | clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); | |
89 | clk_hw_register_clkdev(hw, "ls1x-nand", NULL); | |
90 | clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); | |
91 | clk_hw_register_clkdev(hw, "ls1x-spi", NULL); | |
92 | clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); | |
93 | clk_hw_register_clkdev(hw, "serial8250", NULL); | |
94 | } |