1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2022 Collabora Ltd.
4 * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
7 #include <dt-bindings/clock/mediatek,mt6795-clk.h>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include "clk-fhctl.h"
13 #include "clk-pllfh.h"
15 #define REG_REF2USB 0x8
16 #define REG_AP_PLL_CON7 0x1c
17 #define MD1_MTCMOS_OFF BIT(0)
18 #define MD1_MEM_OFF BIT(1)
19 #define MD1_CLK_OFF BIT(4)
20 #define MD1_ISO_OFF BIT(8)
22 #define MT6795_PLL_FMAX (3000UL * MHZ)
23 #define MT6795_CON0_EN BIT(0)
24 #define MT6795_CON0_RST_BAR BIT(24)
26 #define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
27 _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \
31 .pwr_reg = _pwr_reg, \
32 .en_mask = MT6795_CON0_EN | _en_mask, \
34 .rst_bar_mask = MT6795_CON0_RST_BAR, \
35 .fmax = MT6795_PLL_FMAX, \
36 .pcwbits = _pcwbits, \
38 .pd_shift = _pd_shift, \
39 .tuner_reg = _tuner_reg, \
40 .pcw_reg = _pcw_reg, \
41 .pcw_shift = _pcw_shift, \
46 static const struct mtk_pll_data plls
[] = {
47 PLL(CLK_APMIXED_ARMCA53PLL
, "armca53pll", 0x200, 0x20c, 0, PLL_AO
,
48 21, 0x204, 24, 0x0, 0x204, 0),
49 PLL(CLK_APMIXED_MAINPLL
, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR
,
50 21, 0x220, 4, 0x0, 0x224, 0),
51 PLL(CLK_APMIXED_UNIVPLL
, "univpll", 0x230, 0x23c, 0xfe000101, HAVE_RST_BAR
,
52 7, 0x230, 4, 0x0, 0x234, 14),
53 PLL(CLK_APMIXED_MMPLL
, "mmpll", 0x240, 0x24c, 0, 0, 21, 0x244, 24, 0x0, 0x244, 0),
54 PLL(CLK_APMIXED_MSDCPLL
, "msdcpll", 0x250, 0x25c, 0, 0, 21, 0x250, 4, 0x0, 0x254, 0),
55 PLL(CLK_APMIXED_VENCPLL
, "vencpll", 0x260, 0x26c, 0, 0, 21, 0x260, 4, 0x0, 0x264, 0),
56 PLL(CLK_APMIXED_TVDPLL
, "tvdpll", 0x270, 0x27c, 0, 0, 21, 0x270, 4, 0x0, 0x274, 0),
57 PLL(CLK_APMIXED_MPLL
, "mpll", 0x280, 0x28c, 0, 0, 21, 0x280, 4, 0x0, 0x284, 0),
58 PLL(CLK_APMIXED_VCODECPLL
, "vcodecpll", 0x290, 0x29c, 0, 0, 21, 0x290, 4, 0x0, 0x294, 0),
59 PLL(CLK_APMIXED_APLL1
, "apll1", 0x2a0, 0x2b0, 0, 0, 31, 0x2a0, 4, 0x2a8, 0x2a4, 0),
60 PLL(CLK_APMIXED_APLL2
, "apll2", 0x2b4, 0x2c4, 0, 0, 31, 0x2b4, 4, 0x2bc, 0x2b8, 0),
76 #define _FH(_pllid, _fhid, _slope, _offset) { \
80 .fh_ver = FHCTL_PLLFH_V1, \
81 .fhx_offset = _offset, \
82 .dds_mask = GENMASK(21, 0), \
83 .slope0_value = _slope, \
84 .slope1_value = _slope, \
85 .sfstrx_en = BIT(2), \
86 .frddsx_en = BIT(1), \
87 .fhctlx_en = BIT(0), \
89 .dvfs_tri = BIT(31), \
94 .msk_frddsx_dys = GENMASK(23, 20), \
95 .msk_frddsx_dts = GENMASK(19, 16), \
99 #define FH(_pllid, _fhid, _offset) _FH(_pllid, _fhid, 0x6003c97, _offset)
100 #define FH_M(_pllid, _fhid, _offset) _FH(_pllid, _fhid, 0x6000140, _offset)
102 static struct mtk_pllfh_data pllfhs
[] = {
103 FH(CLK_APMIXED_ARMCA53PLL
, FH_CA53PLL_BL
, 0x38),
104 FH(CLK_APMIXED_MAINPLL
, FH_MAINPLL
, 0x60),
105 FH_M(CLK_APMIXED_MPLL
, FH_MPLL
, 0x74),
106 FH(CLK_APMIXED_MSDCPLL
, FH_MSDCPLL
, 0x88),
107 FH(CLK_APMIXED_MMPLL
, FH_MMPLL
, 0x9c),
108 FH(CLK_APMIXED_VENCPLL
, FH_VENCPLL
, 0xb0),
109 FH(CLK_APMIXED_TVDPLL
, FH_TVDPLL
, 0xc4),
110 FH(CLK_APMIXED_VCODECPLL
, FH_VCODECPLL
, 0xd8),
113 static void clk_mt6795_apmixed_setup_md1(void __iomem
*base
)
115 void __iomem
*reg
= base
+ REG_AP_PLL_CON7
;
117 /* Turn on MD1 internal clock */
118 writel(readl(reg
) & ~MD1_CLK_OFF
, reg
);
120 /* Unlock MD1's MTCMOS power path */
121 writel(readl(reg
) & ~MD1_MTCMOS_OFF
, reg
);
124 writel(readl(reg
) & ~MD1_ISO_OFF
, reg
);
127 writel(readl(reg
) & ~MD1_MEM_OFF
, reg
);
130 static const struct of_device_id of_match_clk_mt6795_apmixed
[] = {
131 { .compatible
= "mediatek,mt6795-apmixedsys" },
134 MODULE_DEVICE_TABLE(of
, of_match_clk_mt6795_apmixed
);
136 static int clk_mt6795_apmixed_probe(struct platform_device
*pdev
)
138 struct clk_hw_onecell_data
*clk_data
;
139 struct device
*dev
= &pdev
->dev
;
140 struct device_node
*node
= dev
->of_node
;
141 const u8
*fhctl_node
= "mediatek,mt6795-fhctl";
146 base
= devm_platform_ioremap_resource(pdev
, 0);
148 return PTR_ERR(base
);
150 clk_data
= mtk_alloc_clk_data(CLK_APMIXED_NR_CLK
);
154 fhctl_parse_dt(fhctl_node
, pllfhs
, ARRAY_SIZE(pllfhs
));
155 ret
= mtk_clk_register_pllfhs(node
, plls
, ARRAY_SIZE(plls
),
156 pllfhs
, ARRAY_SIZE(pllfhs
), clk_data
);
160 hw
= mtk_clk_register_ref2usb_tx("ref2usb_tx", "clk26m", base
+ REG_REF2USB
);
163 dev_err(dev
, "Failed to register ref2usb_tx: %d\n", ret
);
164 goto unregister_plls
;
166 clk_data
->hws
[CLK_APMIXED_REF2USB_TX
] = hw
;
168 ret
= of_clk_add_hw_provider(node
, of_clk_hw_onecell_get
, clk_data
);
170 dev_err(dev
, "Cannot register clock provider: %d\n", ret
);
171 goto unregister_ref2usb
;
174 /* Setup MD1 to avoid random crashes */
175 dev_dbg(dev
, "Performing initial setup for MD1\n");
176 clk_mt6795_apmixed_setup_md1(base
);
181 mtk_clk_unregister_ref2usb_tx(clk_data
->hws
[CLK_APMIXED_REF2USB_TX
]);
183 mtk_clk_unregister_pllfhs(plls
, ARRAY_SIZE(plls
), pllfhs
,
184 ARRAY_SIZE(pllfhs
), clk_data
);
186 mtk_free_clk_data(clk_data
);
190 static void clk_mt6795_apmixed_remove(struct platform_device
*pdev
)
192 struct device_node
*node
= pdev
->dev
.of_node
;
193 struct clk_hw_onecell_data
*clk_data
= platform_get_drvdata(pdev
);
195 of_clk_del_provider(node
);
196 mtk_clk_unregister_ref2usb_tx(clk_data
->hws
[CLK_APMIXED_REF2USB_TX
]);
197 mtk_clk_unregister_pllfhs(plls
, ARRAY_SIZE(plls
), pllfhs
,
198 ARRAY_SIZE(pllfhs
), clk_data
);
199 mtk_free_clk_data(clk_data
);
202 static struct platform_driver clk_mt6795_apmixed_drv
= {
203 .probe
= clk_mt6795_apmixed_probe
,
204 .remove
= clk_mt6795_apmixed_remove
,
206 .name
= "clk-mt6795-apmixed",
207 .of_match_table
= of_match_clk_mt6795_apmixed
,
210 module_platform_driver(clk_mt6795_apmixed_drv
);
212 MODULE_DESCRIPTION("MediaTek MT6795 apmixed clocks driver");
213 MODULE_LICENSE("GPL");