1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2012-2016 Zhang, Keguang <keguang.zhang@gmail.com>
6 #include <linux/clkdev.h>
7 #include <linux/clk-provider.h>
11 #include <loongson1.h>
14 #define OSC (33 * 1000000)
17 static DEFINE_SPINLOCK(_lock
);
19 static unsigned long ls1x_pll_recalc_rate(struct clk_hw
*hw
,
20 unsigned long parent_rate
)
24 pll
= __raw_readl(LS1X_CLK_PLL_FREQ
);
25 rate
= 12 + (pll
& GENMASK(5, 0));
32 static const struct clk_ops ls1x_pll_clk_ops
= {
33 .recalc_rate
= ls1x_pll_recalc_rate
,
36 static const char *const cpu_parents
[] = { "cpu_clk_div", "osc_clk", };
37 static const char *const ahb_parents
[] = { "ahb_clk_div", "osc_clk", };
38 static const char *const dc_parents
[] = { "dc_clk_div", "osc_clk", };
40 void __init
ls1x_clk_init(void)
44 hw
= clk_hw_register_fixed_rate(NULL
, "osc_clk", NULL
, 0, OSC
);
45 clk_hw_register_clkdev(hw
, "osc_clk", NULL
);
47 /* clock derived from 33 MHz OSC clk */
48 hw
= clk_hw_register_pll(NULL
, "pll_clk", "osc_clk",
49 &ls1x_pll_clk_ops
, 0);
50 clk_hw_register_clkdev(hw
, "pll_clk", NULL
);
52 /* clock derived from PLL clk */
54 * _______________________| |
55 * OSC ___/ | MUX |___ CPU CLK
56 * \___ PLL ___ CPU DIV ___| |
59 hw
= clk_hw_register_divider(NULL
, "cpu_clk_div", "pll_clk",
60 CLK_GET_RATE_NOCACHE
, LS1X_CLK_PLL_DIV
,
61 DIV_CPU_SHIFT
, DIV_CPU_WIDTH
,
62 CLK_DIVIDER_ONE_BASED
|
63 CLK_DIVIDER_ROUND_CLOSEST
, &_lock
);
64 clk_hw_register_clkdev(hw
, "cpu_clk_div", NULL
);
65 hw
= clk_hw_register_mux(NULL
, "cpu_clk", cpu_parents
,
66 ARRAY_SIZE(cpu_parents
),
67 CLK_SET_RATE_NO_REPARENT
, LS1X_CLK_PLL_DIV
,
68 BYPASS_CPU_SHIFT
, BYPASS_CPU_WIDTH
, 0, &_lock
);
69 clk_hw_register_clkdev(hw
, "cpu_clk", NULL
);
72 * _______________________| |
73 * OSC ___/ | MUX |___ DC CLK
74 * \___ PLL ___ DC DIV ___| |
77 hw
= clk_hw_register_divider(NULL
, "dc_clk_div", "pll_clk",
78 0, LS1X_CLK_PLL_DIV
, DIV_DC_SHIFT
,
79 DIV_DC_WIDTH
, CLK_DIVIDER_ONE_BASED
, &_lock
);
80 clk_hw_register_clkdev(hw
, "dc_clk_div", NULL
);
81 hw
= clk_hw_register_mux(NULL
, "dc_clk", dc_parents
,
82 ARRAY_SIZE(dc_parents
),
83 CLK_SET_RATE_NO_REPARENT
, LS1X_CLK_PLL_DIV
,
84 BYPASS_DC_SHIFT
, BYPASS_DC_WIDTH
, 0, &_lock
);
85 clk_hw_register_clkdev(hw
, "dc_clk", NULL
);
88 * _______________________| |
89 * OSC ___/ | MUX |___ DDR CLK
90 * \___ PLL ___ DDR DIV ___| |
93 hw
= clk_hw_register_divider(NULL
, "ahb_clk_div", "pll_clk",
94 0, LS1X_CLK_PLL_DIV
, DIV_DDR_SHIFT
,
95 DIV_DDR_WIDTH
, CLK_DIVIDER_ONE_BASED
,
97 clk_hw_register_clkdev(hw
, "ahb_clk_div", NULL
);
98 hw
= clk_hw_register_mux(NULL
, "ahb_clk", ahb_parents
,
99 ARRAY_SIZE(ahb_parents
),
100 CLK_SET_RATE_NO_REPARENT
, LS1X_CLK_PLL_DIV
,
101 BYPASS_DDR_SHIFT
, BYPASS_DDR_WIDTH
, 0, &_lock
);
102 clk_hw_register_clkdev(hw
, "ahb_clk", NULL
);
103 clk_hw_register_clkdev(hw
, "ls1x-dma", NULL
);
104 clk_hw_register_clkdev(hw
, "stmmaceth", NULL
);
106 /* clock derived from AHB clk */
107 /* APB clk is always half of the AHB clk */
108 hw
= clk_hw_register_fixed_factor(NULL
, "apb_clk", "ahb_clk", 0, 1,
110 clk_hw_register_clkdev(hw
, "apb_clk", NULL
);
111 clk_hw_register_clkdev(hw
, "ls1x-ac97", NULL
);
112 clk_hw_register_clkdev(hw
, "ls1x-i2c", NULL
);
113 clk_hw_register_clkdev(hw
, "ls1x-nand", NULL
);
114 clk_hw_register_clkdev(hw
, "ls1x-pwmtimer", NULL
);
115 clk_hw_register_clkdev(hw
, "ls1x-spi", NULL
);
116 clk_hw_register_clkdev(hw
, "ls1x-wdt", NULL
);
117 clk_hw_register_clkdev(hw
, "serial8250", NULL
);