blob: 2e263fb2cd2862a68ba29edfbfd7acc3e69e2b22 [file] [log] [blame]
developer2bef3c52019-09-25 17:45:21 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2019 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
6 */
7
developer2bef3c52019-09-25 17:45:21 +08008#include <clk-uclass.h>
9#include <dm.h>
10#include <dt-bindings/clock/mt7628-clk.h>
11#include <linux/bitops.h>
12#include <linux/io.h>
13
14/* SYSCFG0 */
15#define XTAL_40M_SEL BIT(6)
16
17/* CLKCFG0 */
18#define CLKCFG0_REG 0x0
19#define PERI_CLK_FROM_XTAL_SEL BIT(4)
20#define CPU_PLL_FROM_BBP BIT(1)
21#define CPU_PLL_FROM_XTAL BIT(0)
22
23/* CLKCFG1 */
24#define CLKCFG1_REG 0x4
25
26#define CLK_SRC_CPU -1
27#define CLK_SRC_CPU_D2 -2
28#define CLK_SRC_SYS -3
29#define CLK_SRC_XTAL -4
30#define CLK_SRC_PERI -5
31
32struct mt7628_clk_priv {
33 void __iomem *base;
34 int cpu_clk;
35 int sys_clk;
36 int xtal_clk;
37};
38
39static const int mt7628_clks[] = {
40 [CLK_SYS] = CLK_SRC_SYS,
41 [CLK_CPU] = CLK_SRC_CPU,
42 [CLK_XTAL] = CLK_SRC_XTAL,
43 [CLK_PWM] = CLK_SRC_PERI,
44 [CLK_MIPS_CNT] = CLK_SRC_CPU_D2,
45 [CLK_UART2] = CLK_SRC_PERI,
46 [CLK_UART1] = CLK_SRC_PERI,
47 [CLK_UART0] = CLK_SRC_PERI,
48 [CLK_SPI] = CLK_SRC_SYS,
49 [CLK_I2C] = CLK_SRC_PERI,
50};
51
52static ulong mt7628_clk_get_rate(struct clk *clk)
53{
54 struct mt7628_clk_priv *priv = dev_get_priv(clk->dev);
55 u32 val;
56
57 if (clk->id >= ARRAY_SIZE(mt7628_clks))
58 return 0;
59
60 switch (mt7628_clks[clk->id]) {
61 case CLK_SRC_CPU:
62 return priv->cpu_clk;
63 case CLK_SRC_CPU_D2:
64 return priv->cpu_clk / 2;
65 case CLK_SRC_SYS:
66 return priv->sys_clk;
67 case CLK_SRC_XTAL:
68 return priv->xtal_clk;
69 case CLK_SRC_PERI:
70 val = readl(priv->base + CLKCFG0_REG);
71 if (val & PERI_CLK_FROM_XTAL_SEL)
72 return priv->xtal_clk;
73 else
74 return 40000000;
75 default:
76 return mt7628_clks[clk->id];
77 }
78}
79
80static int mt7628_clk_enable(struct clk *clk)
81{
82 struct mt7628_clk_priv *priv = dev_get_priv(clk->dev);
83
84 if (clk->id > 31)
85 return -1;
86
87 setbits_32(priv->base + CLKCFG1_REG, BIT(clk->id));
88
89 return 0;
90}
91
92static int mt7628_clk_disable(struct clk *clk)
93{
94 struct mt7628_clk_priv *priv = dev_get_priv(clk->dev);
95
96 if (clk->id > 31)
97 return -1;
98
99 clrbits_32(priv->base + CLKCFG1_REG, BIT(clk->id));
100
101 return 0;
102}
103
104const struct clk_ops mt7628_clk_ops = {
105 .enable = mt7628_clk_enable,
106 .disable = mt7628_clk_disable,
107 .get_rate = mt7628_clk_get_rate,
108};
109
110static int mt7628_clk_probe(struct udevice *dev)
111{
112 struct mt7628_clk_priv *priv = dev_get_priv(dev);
113 void __iomem *syscfg_base;
114 u32 val;
115
116 priv->base = (void __iomem *)dev_remap_addr_index(dev, 0);
117 if (!priv->base)
118 return -EINVAL;
119
120 syscfg_base = (void __iomem *)dev_remap_addr_index(dev, 1);
121 if (!syscfg_base)
122 return -EINVAL;
123
124 val = readl(syscfg_base);
125 if (val & XTAL_40M_SEL)
126 priv->xtal_clk = 40000000;
127 else
128 priv->xtal_clk = 25000000;
129
130 val = readl(priv->base + CLKCFG0_REG);
131 if (val & CPU_PLL_FROM_BBP)
132 priv->cpu_clk = 480000000;
133 else if (val & CPU_PLL_FROM_XTAL)
134 priv->cpu_clk = priv->xtal_clk;
135 else if (priv->xtal_clk == 40000000)
136 priv->cpu_clk = 580000000; /* (xtal_freq / 2) * 29 */
137 else
138 priv->cpu_clk = 575000000; /* xtal_freq * 23 */
139
140 priv->sys_clk = priv->cpu_clk / 3;
141
142 return 0;
143}
144
145static const struct udevice_id mt7628_clk_ids[] = {
146 { .compatible = "mediatek,mt7628-clk" },
147 { }
148};
149
150U_BOOT_DRIVER(mt7628_clk) = {
151 .name = "mt7628-clk",
152 .id = UCLASS_CLK,
153 .of_match = mt7628_clk_ids,
154 .probe = mt7628_clk_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700155 .priv_auto = sizeof(struct mt7628_clk_priv),
developer2bef3c52019-09-25 17:45:21 +0800156 .ops = &mt7628_clk_ops,
157};