Skip to content

Commit d78485d

Browse files
laura-naobebarino
authored andcommitted
clk: mediatek: Add MT8196 apmixedsys clock support
Add support for the MT8196 apmixedsys clock controller, which provides PLLs generated from SoC 26m. Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Laura Nao <laura.nao@collabora.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent dd240e9 commit d78485d

3 files changed

Lines changed: 213 additions & 0 deletions

File tree

drivers/clk/mediatek/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,14 @@ config COMMON_CLK_MT8195_VENCSYS
10021002
help
10031003
This driver supports MediaTek MT8195 vencsys clocks.
10041004

1005+
config COMMON_CLK_MT8196
1006+
tristate "Clock driver for MediaTek MT8196"
1007+
depends on ARM64 || COMPILE_TEST
1008+
select COMMON_CLK_MEDIATEK
1009+
default ARCH_MEDIATEK
1010+
help
1011+
This driver supports MediaTek MT8196 basic clocks.
1012+
10051013
config COMMON_CLK_MT8365
10061014
tristate "Clock driver for MediaTek MT8365"
10071015
depends on ARCH_MEDIATEK || COMPILE_TEST

drivers/clk/mediatek/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o
150150
obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o
151151
obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o
152152
obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o
153+
obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o
153154
obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o
154155
obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o
155156
obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2025 MediaTek Inc.
4+
* Guangjie Song <guangjie.song@mediatek.com>
5+
* Copyright (c) 2025 Collabora Ltd.
6+
* Laura Nao <laura.nao@collabora.com>
7+
*/
8+
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
9+
10+
#include <linux/clk.h>
11+
#include <linux/module.h>
12+
#include <linux/of.h>
13+
#include <linux/of_address.h>
14+
#include <linux/of_device.h>
15+
#include <linux/platform_device.h>
16+
17+
#include "clk-mtk.h"
18+
#include "clk-pll.h"
19+
20+
/* APMIXEDSYS PLL control register offsets */
21+
#define MAINPLL_CON0 0x250
22+
#define MAINPLL_CON1 0x254
23+
#define UNIVPLL_CON0 0x264
24+
#define UNIVPLL_CON1 0x268
25+
#define MSDCPLL_CON0 0x278
26+
#define MSDCPLL_CON1 0x27c
27+
#define ADSPPLL_CON0 0x28c
28+
#define ADSPPLL_CON1 0x290
29+
#define EMIPLL_CON0 0x2a0
30+
#define EMIPLL_CON1 0x2a4
31+
#define EMIPLL2_CON0 0x2b4
32+
#define EMIPLL2_CON1 0x2b8
33+
#define NET1PLL_CON0 0x2c8
34+
#define NET1PLL_CON1 0x2cc
35+
#define SGMIIPLL_CON0 0x2dc
36+
#define SGMIIPLL_CON1 0x2e0
37+
38+
/* APMIXEDSYS_GP2 PLL control register offsets*/
39+
#define MAINPLL2_CON0 0x250
40+
#define MAINPLL2_CON1 0x254
41+
#define UNIVPLL2_CON0 0x264
42+
#define UNIVPLL2_CON1 0x268
43+
#define MMPLL2_CON0 0x278
44+
#define MMPLL2_CON1 0x27c
45+
#define IMGPLL_CON0 0x28c
46+
#define IMGPLL_CON1 0x290
47+
#define TVDPLL1_CON0 0x2a0
48+
#define TVDPLL1_CON1 0x2a4
49+
#define TVDPLL2_CON0 0x2b4
50+
#define TVDPLL2_CON1 0x2b8
51+
#define TVDPLL3_CON0 0x2c8
52+
#define TVDPLL3_CON1 0x2cc
53+
54+
#define PLLEN_ALL 0x080
55+
#define PLLEN_ALL_SET 0x084
56+
#define PLLEN_ALL_CLR 0x088
57+
58+
#define FENC_STATUS_CON0 0x03c
59+
60+
#define MT8196_PLL_FMAX (3800UL * MHZ)
61+
#define MT8196_PLL_FMIN (1500UL * MHZ)
62+
#define MT8196_INTEGER_BITS 8
63+
64+
#define PLL_FENC(_id, _name, _reg, _fenc_sta_ofs, _fenc_sta_bit,\
65+
_flags, _pd_reg, _pd_shift, \
66+
_pcw_reg, _pcw_shift, _pcwbits, \
67+
_pll_en_bit) { \
68+
.id = _id, \
69+
.name = _name, \
70+
.reg = _reg, \
71+
.fenc_sta_ofs = _fenc_sta_ofs, \
72+
.fenc_sta_bit = _fenc_sta_bit, \
73+
.flags = _flags, \
74+
.fmax = MT8196_PLL_FMAX, \
75+
.fmin = MT8196_PLL_FMIN, \
76+
.pd_reg = _pd_reg, \
77+
.pd_shift = _pd_shift, \
78+
.pcw_reg = _pcw_reg, \
79+
.pcw_shift = _pcw_shift, \
80+
.pcwbits = _pcwbits, \
81+
.pcwibits = MT8196_INTEGER_BITS, \
82+
.en_reg = PLLEN_ALL, \
83+
.en_set_reg = PLLEN_ALL_SET, \
84+
.en_clr_reg = PLLEN_ALL_CLR, \
85+
.pll_en_bit = _pll_en_bit, \
86+
.ops = &mtk_pll_fenc_clr_set_ops, \
87+
}
88+
89+
struct mtk_pll_desc {
90+
const struct mtk_pll_data *clks;
91+
size_t num_clks;
92+
};
93+
94+
static const struct mtk_pll_data apmixed_plls[] = {
95+
PLL_FENC(CLK_APMIXED_MAINPLL, "mainpll", MAINPLL_CON0, FENC_STATUS_CON0,
96+
7, PLL_AO, MAINPLL_CON1, 24, MAINPLL_CON1, 0, 22, 0),
97+
PLL_FENC(CLK_APMIXED_UNIVPLL, "univpll", UNIVPLL_CON0, FENC_STATUS_CON0,
98+
6, 0, UNIVPLL_CON1, 24, UNIVPLL_CON1, 0, 22, 1),
99+
PLL_FENC(CLK_APMIXED_MSDCPLL, "msdcpll", MSDCPLL_CON0, FENC_STATUS_CON0,
100+
5, 0, MSDCPLL_CON1, 24, MSDCPLL_CON1, 0, 22, 2),
101+
PLL_FENC(CLK_APMIXED_ADSPPLL, "adsppll", ADSPPLL_CON0, FENC_STATUS_CON0,
102+
4, 0, ADSPPLL_CON1, 24, ADSPPLL_CON1, 0, 22, 3),
103+
PLL_FENC(CLK_APMIXED_EMIPLL, "emipll", EMIPLL_CON0, FENC_STATUS_CON0, 3,
104+
PLL_AO, EMIPLL_CON1, 24, EMIPLL_CON1, 0, 22, 4),
105+
PLL_FENC(CLK_APMIXED_EMIPLL2, "emipll2", EMIPLL2_CON0, FENC_STATUS_CON0,
106+
2, PLL_AO, EMIPLL2_CON1, 24, EMIPLL2_CON1, 0, 22, 5),
107+
PLL_FENC(CLK_APMIXED_NET1PLL, "net1pll", NET1PLL_CON0, FENC_STATUS_CON0,
108+
1, 0, NET1PLL_CON1, 24, NET1PLL_CON1, 0, 22, 6),
109+
PLL_FENC(CLK_APMIXED_SGMIIPLL, "sgmiipll", SGMIIPLL_CON0, FENC_STATUS_CON0,
110+
0, 0, SGMIIPLL_CON1, 24, SGMIIPLL_CON1, 0, 22, 7),
111+
};
112+
113+
static const struct mtk_pll_desc apmixed_desc = {
114+
.clks = apmixed_plls,
115+
.num_clks = ARRAY_SIZE(apmixed_plls),
116+
};
117+
118+
static const struct mtk_pll_data apmixed2_plls[] = {
119+
PLL_FENC(CLK_APMIXED2_MAINPLL2, "mainpll2", MAINPLL2_CON0, FENC_STATUS_CON0,
120+
6, 0, MAINPLL2_CON1, 24, MAINPLL2_CON1, 0, 22, 0),
121+
PLL_FENC(CLK_APMIXED2_UNIVPLL2, "univpll2", UNIVPLL2_CON0, FENC_STATUS_CON0,
122+
5, 0, UNIVPLL2_CON1, 24, UNIVPLL2_CON1, 0, 22, 1),
123+
PLL_FENC(CLK_APMIXED2_MMPLL2, "mmpll2", MMPLL2_CON0, FENC_STATUS_CON0,
124+
4, 0, MMPLL2_CON1, 24, MMPLL2_CON1, 0, 22, 2),
125+
PLL_FENC(CLK_APMIXED2_IMGPLL, "imgpll", IMGPLL_CON0, FENC_STATUS_CON0,
126+
3, 0, IMGPLL_CON1, 24, IMGPLL_CON1, 0, 22, 3),
127+
PLL_FENC(CLK_APMIXED2_TVDPLL1, "tvdpll1", TVDPLL1_CON0, FENC_STATUS_CON0,
128+
2, 0, TVDPLL1_CON1, 24, TVDPLL1_CON1, 0, 22, 4),
129+
PLL_FENC(CLK_APMIXED2_TVDPLL2, "tvdpll2", TVDPLL2_CON0, FENC_STATUS_CON0,
130+
1, 0, TVDPLL2_CON1, 24, TVDPLL2_CON1, 0, 22, 5),
131+
PLL_FENC(CLK_APMIXED2_TVDPLL3, "tvdpll3", TVDPLL3_CON0, FENC_STATUS_CON0,
132+
0, 0, TVDPLL3_CON1, 24, TVDPLL3_CON1, 0, 22, 6),
133+
};
134+
135+
static const struct mtk_pll_desc apmixed2_desc = {
136+
.clks = apmixed2_plls,
137+
.num_clks = ARRAY_SIZE(apmixed2_plls),
138+
};
139+
140+
static int clk_mt8196_apmixed_probe(struct platform_device *pdev)
141+
{
142+
struct clk_hw_onecell_data *clk_data;
143+
struct device_node *node = pdev->dev.of_node;
144+
const struct mtk_pll_desc *mcd;
145+
int r;
146+
147+
mcd = device_get_match_data(&pdev->dev);
148+
if (!mcd)
149+
return -EINVAL;
150+
151+
clk_data = mtk_alloc_clk_data(mcd->num_clks);
152+
if (!clk_data)
153+
return -ENOMEM;
154+
155+
r = mtk_clk_register_plls(node, mcd->clks, mcd->num_clks, clk_data);
156+
if (r)
157+
goto free_apmixed_data;
158+
159+
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
160+
if (r)
161+
goto unregister_plls;
162+
163+
platform_set_drvdata(pdev, clk_data);
164+
165+
return r;
166+
167+
unregister_plls:
168+
mtk_clk_unregister_plls(mcd->clks, mcd->num_clks, clk_data);
169+
free_apmixed_data:
170+
mtk_free_clk_data(clk_data);
171+
return r;
172+
}
173+
174+
static void clk_mt8196_apmixed_remove(struct platform_device *pdev)
175+
{
176+
const struct mtk_pll_desc *mcd = device_get_match_data(&pdev->dev);
177+
struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
178+
struct device_node *node = pdev->dev.of_node;
179+
180+
of_clk_del_provider(node);
181+
mtk_clk_unregister_plls(mcd->clks, mcd->num_clks, clk_data);
182+
mtk_free_clk_data(clk_data);
183+
}
184+
185+
static const struct of_device_id of_match_clk_mt8196_apmixed[] = {
186+
{ .compatible = "mediatek,mt8196-apmixedsys", .data = &apmixed_desc },
187+
{ .compatible = "mediatek,mt8196-apmixedsys-gp2",
188+
.data = &apmixed2_desc },
189+
{ /* sentinel */ }
190+
};
191+
MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_apmixed);
192+
193+
static struct platform_driver clk_mt8196_apmixed_drv = {
194+
.probe = clk_mt8196_apmixed_probe,
195+
.remove = clk_mt8196_apmixed_remove,
196+
.driver = {
197+
.name = "clk-mt8196-apmixed",
198+
.of_match_table = of_match_clk_mt8196_apmixed,
199+
},
200+
};
201+
module_platform_driver(clk_mt8196_apmixed_drv);
202+
203+
MODULE_DESCRIPTION("MediaTek MT8196 apmixedsys clocks driver");
204+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)