162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright (c) 2021 MediaTek Inc.
462306a36Sopenharmony_ci// Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "clk-fhctl.h"
762306a36Sopenharmony_ci#include "clk-gate.h"
862306a36Sopenharmony_ci#include "clk-mtk.h"
962306a36Sopenharmony_ci#include "clk-pll.h"
1062306a36Sopenharmony_ci#include "clk-pllfh.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <dt-bindings/clock/mt8195-clk.h>
1362306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic const struct mtk_gate_regs apmixed_cg_regs = {
1762306a36Sopenharmony_ci	.set_ofs = 0x8,
1862306a36Sopenharmony_ci	.clr_ofs = 0x8,
1962306a36Sopenharmony_ci	.sta_ofs = 0x8,
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define GATE_APMIXED(_id, _name, _parent, _shift)			\
2362306a36Sopenharmony_ci	GATE_MTK(_id, _name, _parent, &apmixed_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const struct mtk_gate apmixed_clks[] = {
2662306a36Sopenharmony_ci	GATE_APMIXED(CLK_APMIXED_PLL_SSUSB26M, "pll_ssusb26m", "clk26m", 1),
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define MT8195_PLL_FMAX		(3800UL * MHZ)
3062306a36Sopenharmony_ci#define MT8195_PLL_FMIN		(1500UL * MHZ)
3162306a36Sopenharmony_ci#define MT8195_INTEGER_BITS	8
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags,		\
3462306a36Sopenharmony_ci	    _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift,		\
3562306a36Sopenharmony_ci	    _tuner_reg, _tuner_en_reg, _tuner_en_bit,			\
3662306a36Sopenharmony_ci	    _pcw_reg, _pcw_shift, _pcw_chg_reg,				\
3762306a36Sopenharmony_ci	    _en_reg, _pll_en_bit) {					\
3862306a36Sopenharmony_ci		.id = _id,						\
3962306a36Sopenharmony_ci		.name = _name,						\
4062306a36Sopenharmony_ci		.reg = _reg,						\
4162306a36Sopenharmony_ci		.pwr_reg = _pwr_reg,					\
4262306a36Sopenharmony_ci		.en_mask = _en_mask,					\
4362306a36Sopenharmony_ci		.flags = _flags,					\
4462306a36Sopenharmony_ci		.rst_bar_mask = _rst_bar_mask,				\
4562306a36Sopenharmony_ci		.fmax = MT8195_PLL_FMAX,				\
4662306a36Sopenharmony_ci		.fmin = MT8195_PLL_FMIN,				\
4762306a36Sopenharmony_ci		.pcwbits = _pcwbits,					\
4862306a36Sopenharmony_ci		.pcwibits = MT8195_INTEGER_BITS,			\
4962306a36Sopenharmony_ci		.pd_reg = _pd_reg,					\
5062306a36Sopenharmony_ci		.pd_shift = _pd_shift,					\
5162306a36Sopenharmony_ci		.tuner_reg = _tuner_reg,				\
5262306a36Sopenharmony_ci		.tuner_en_reg = _tuner_en_reg,				\
5362306a36Sopenharmony_ci		.tuner_en_bit = _tuner_en_bit,				\
5462306a36Sopenharmony_ci		.pcw_reg = _pcw_reg,					\
5562306a36Sopenharmony_ci		.pcw_shift = _pcw_shift,				\
5662306a36Sopenharmony_ci		.pcw_chg_reg = _pcw_chg_reg,				\
5762306a36Sopenharmony_ci		.en_reg = _en_reg,					\
5862306a36Sopenharmony_ci		.pll_en_bit = _pll_en_bit,				\
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic const struct mtk_pll_data plls[] = {
6262306a36Sopenharmony_ci	PLL(CLK_APMIXED_NNAPLL, "nnapll", 0x0390, 0x03a0, 0,
6362306a36Sopenharmony_ci	    0, 0, 22, 0x0398, 24, 0, 0, 0, 0x0398, 0, 0x0398, 0, 9),
6462306a36Sopenharmony_ci	PLL(CLK_APMIXED_RESPLL, "respll", 0x0190, 0x0320, 0,
6562306a36Sopenharmony_ci	    0, 0, 22, 0x0198, 24, 0, 0, 0, 0x0198, 0, 0x0198, 0, 9),
6662306a36Sopenharmony_ci	PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x0360, 0x0370, 0,
6762306a36Sopenharmony_ci	    0, 0, 22, 0x0368, 24, 0, 0, 0, 0x0368, 0, 0x0368, 0, 9),
6862306a36Sopenharmony_ci	PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0710, 0x0720, 0,
6962306a36Sopenharmony_ci	    0, 0, 22, 0x0718, 24, 0, 0, 0, 0x0718, 0, 0x0718, 0, 9),
7062306a36Sopenharmony_ci	PLL(CLK_APMIXED_TVDPLL1, "tvdpll1", 0x00a0, 0x00b0, 0,
7162306a36Sopenharmony_ci	    0, 0, 22, 0x00a8, 24, 0, 0, 0, 0x00a8, 0, 0x00a8, 0, 9),
7262306a36Sopenharmony_ci	PLL(CLK_APMIXED_TVDPLL2, "tvdpll2", 0x00c0, 0x00d0, 0,
7362306a36Sopenharmony_ci	    0, 0, 22, 0x00c8, 24, 0, 0, 0, 0x00c8, 0, 0x00c8, 0, 9),
7462306a36Sopenharmony_ci	PLL(CLK_APMIXED_MMPLL, "mmpll", 0x00e0, 0x00f0, 0xff000000,
7562306a36Sopenharmony_ci	    HAVE_RST_BAR, BIT(23), 22, 0x00e8, 24, 0, 0, 0, 0x00e8, 0, 0x00e8, 0, 9),
7662306a36Sopenharmony_ci	PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x01d0, 0x01e0, 0xff000000,
7762306a36Sopenharmony_ci	    HAVE_RST_BAR, BIT(23), 22, 0x01d8, 24, 0, 0, 0, 0x01d8, 0, 0x01d8, 0, 9),
7862306a36Sopenharmony_ci	PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x0890, 0x08a0, 0,
7962306a36Sopenharmony_ci	    0, 0, 22, 0x0898, 24, 0, 0, 0, 0x0898, 0, 0x0898, 0, 9),
8062306a36Sopenharmony_ci	PLL(CLK_APMIXED_IMGPLL, "imgpll", 0x0100, 0x0110, 0,
8162306a36Sopenharmony_ci	    0, 0, 22, 0x0108, 24, 0, 0, 0, 0x0108, 0, 0x0108, 0, 9),
8262306a36Sopenharmony_ci	PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x01f0, 0x0700, 0xff000000,
8362306a36Sopenharmony_ci	    HAVE_RST_BAR, BIT(23), 22, 0x01f8, 24, 0, 0, 0, 0x01f8, 0, 0x01f8, 0, 9),
8462306a36Sopenharmony_ci	PLL(CLK_APMIXED_HDMIPLL1, "hdmipll1", 0x08c0, 0x08d0, 0,
8562306a36Sopenharmony_ci	    0, 0, 22, 0x08c8, 24, 0, 0, 0, 0x08c8, 0, 0x08c8, 0, 9),
8662306a36Sopenharmony_ci	PLL(CLK_APMIXED_HDMIPLL2, "hdmipll2", 0x0870, 0x0880, 0,
8762306a36Sopenharmony_ci	    0, 0, 22, 0x0878, 24, 0, 0, 0, 0x0878, 0, 0x0878, 0, 9),
8862306a36Sopenharmony_ci	PLL(CLK_APMIXED_HDMIRX_APLL, "hdmirx_apll", 0x08e0, 0x0dd4, 0,
8962306a36Sopenharmony_ci	    0, 0, 32, 0x08e8, 24, 0, 0, 0, 0x08ec, 0, 0x08e8, 0, 9),
9062306a36Sopenharmony_ci	PLL(CLK_APMIXED_USB1PLL, "usb1pll", 0x01a0, 0x01b0, 0,
9162306a36Sopenharmony_ci	    0, 0, 22, 0x01a8, 24, 0, 0, 0, 0x01a8, 0, 0x01a8, 0, 9),
9262306a36Sopenharmony_ci	PLL(CLK_APMIXED_ADSPPLL, "adsppll", 0x07e0, 0x07f0, 0,
9362306a36Sopenharmony_ci	    0, 0, 22, 0x07e8, 24, 0, 0, 0, 0x07e8, 0, 0x07e8, 0, 9),
9462306a36Sopenharmony_ci	PLL(CLK_APMIXED_APLL1, "apll1", 0x07c0, 0x0dc0, 0,
9562306a36Sopenharmony_ci	    0, 0, 32, 0x07c8, 24, 0x0470, 0x0000, 12, 0x07cc, 0, 0x07c8, 0, 9),
9662306a36Sopenharmony_ci	PLL(CLK_APMIXED_APLL2, "apll2", 0x0780, 0x0dc4, 0,
9762306a36Sopenharmony_ci	    0, 0, 32, 0x0788, 24, 0x0474, 0x0000, 13, 0x078c, 0, 0x0788, 0, 9),
9862306a36Sopenharmony_ci	PLL(CLK_APMIXED_APLL3, "apll3", 0x0760, 0x0dc8, 0,
9962306a36Sopenharmony_ci	    0, 0, 32, 0x0768, 24, 0x0478, 0x0000, 14, 0x076c, 0, 0x0768, 0, 9),
10062306a36Sopenharmony_ci	PLL(CLK_APMIXED_APLL4, "apll4", 0x0740, 0x0dcc, 0,
10162306a36Sopenharmony_ci	    0, 0, 32, 0x0748, 24, 0x047C, 0x0000, 15, 0x074c, 0, 0x0748, 0, 9),
10262306a36Sopenharmony_ci	PLL(CLK_APMIXED_APLL5, "apll5", 0x07a0, 0x0dd0, 0x100000,
10362306a36Sopenharmony_ci	    0, 0, 32, 0x07a8, 24, 0x0480, 0x0000, 16, 0x07ac, 0, 0x07a8, 0, 9),
10462306a36Sopenharmony_ci	PLL(CLK_APMIXED_MFGPLL, "mfgpll", 0x0340, 0x0350, 0,
10562306a36Sopenharmony_ci	    0, 0, 22, 0x0348, 24, 0, 0, 0, 0x0348, 0, 0x0348, 0, 9),
10662306a36Sopenharmony_ci	PLL(CLK_APMIXED_DGIPLL, "dgipll", 0x0150, 0x0160, 0,
10762306a36Sopenharmony_ci	    0, 0, 22, 0x0158, 24, 0, 0, 0, 0x0158, 0, 0x0158, 0, 9),
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cienum fh_pll_id {
11162306a36Sopenharmony_ci	FH_ARMPLL_LL,
11262306a36Sopenharmony_ci	FH_ARMPLL_BL,
11362306a36Sopenharmony_ci	FH_MEMPLL,
11462306a36Sopenharmony_ci	FH_ADSPPLL,
11562306a36Sopenharmony_ci	FH_NNAPLL,
11662306a36Sopenharmony_ci	FH_CCIPLL,
11762306a36Sopenharmony_ci	FH_MFGPLL,
11862306a36Sopenharmony_ci	FH_TVDPLL2,
11962306a36Sopenharmony_ci	FH_MPLL,
12062306a36Sopenharmony_ci	FH_MMPLL,
12162306a36Sopenharmony_ci	FH_MAINPLL,
12262306a36Sopenharmony_ci	FH_MSDCPLL,
12362306a36Sopenharmony_ci	FH_IMGPLL,
12462306a36Sopenharmony_ci	FH_VDECPLL,
12562306a36Sopenharmony_ci	FH_TVDPLL1,
12662306a36Sopenharmony_ci	FH_NR_FH,
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define FH(_pllid, _fhid, _offset) {					\
13062306a36Sopenharmony_ci		.data = {						\
13162306a36Sopenharmony_ci			.pll_id = _pllid,				\
13262306a36Sopenharmony_ci			.fh_id = _fhid,					\
13362306a36Sopenharmony_ci			.fh_ver = FHCTL_PLLFH_V2,			\
13462306a36Sopenharmony_ci			.fhx_offset = _offset,				\
13562306a36Sopenharmony_ci			.dds_mask = GENMASK(21, 0),			\
13662306a36Sopenharmony_ci			.slope0_value = 0x6003c97,			\
13762306a36Sopenharmony_ci			.slope1_value = 0x6003c97,			\
13862306a36Sopenharmony_ci			.sfstrx_en = BIT(2),				\
13962306a36Sopenharmony_ci			.frddsx_en = BIT(1),				\
14062306a36Sopenharmony_ci			.fhctlx_en = BIT(0),				\
14162306a36Sopenharmony_ci			.tgl_org = BIT(31),				\
14262306a36Sopenharmony_ci			.dvfs_tri = BIT(31),				\
14362306a36Sopenharmony_ci			.pcwchg = BIT(31),				\
14462306a36Sopenharmony_ci			.dt_val = 0x0,					\
14562306a36Sopenharmony_ci			.df_val = 0x9,					\
14662306a36Sopenharmony_ci			.updnlmt_shft = 16,				\
14762306a36Sopenharmony_ci			.msk_frddsx_dys = GENMASK(23, 20),		\
14862306a36Sopenharmony_ci			.msk_frddsx_dts = GENMASK(19, 16),		\
14962306a36Sopenharmony_ci		},							\
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic struct mtk_pllfh_data pllfhs[] = {
15362306a36Sopenharmony_ci	FH(CLK_APMIXED_ADSPPLL, FH_ADSPPLL, 0x78),
15462306a36Sopenharmony_ci	FH(CLK_APMIXED_NNAPLL, FH_NNAPLL, 0x8c),
15562306a36Sopenharmony_ci	FH(CLK_APMIXED_MFGPLL, FH_MFGPLL, 0xb4),
15662306a36Sopenharmony_ci	FH(CLK_APMIXED_TVDPLL2, FH_TVDPLL2, 0xc8),
15762306a36Sopenharmony_ci	FH(CLK_APMIXED_MMPLL, FH_MMPLL, 0xf0),
15862306a36Sopenharmony_ci	FH(CLK_APMIXED_MAINPLL, FH_MAINPLL, 0x104),
15962306a36Sopenharmony_ci	FH(CLK_APMIXED_MSDCPLL, FH_MSDCPLL, 0x118),
16062306a36Sopenharmony_ci	FH(CLK_APMIXED_IMGPLL, FH_IMGPLL, 0x12c),
16162306a36Sopenharmony_ci	FH(CLK_APMIXED_VDECPLL, FH_VDECPLL, 0x140),
16262306a36Sopenharmony_ci	FH(CLK_APMIXED_TVDPLL2, FH_TVDPLL1, 0x154),
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic const struct of_device_id of_match_clk_mt8195_apmixed[] = {
16662306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8195-apmixedsys", },
16762306a36Sopenharmony_ci	{}
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_match_clk_mt8195_apmixed);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int clk_mt8195_apmixed_probe(struct platform_device *pdev)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct clk_hw_onecell_data *clk_data;
17462306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
17562306a36Sopenharmony_ci	const u8 *fhctl_node = "mediatek,mt8195-fhctl";
17662306a36Sopenharmony_ci	int r;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
17962306a36Sopenharmony_ci	if (!clk_data)
18062306a36Sopenharmony_ci		return -ENOMEM;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls),
18562306a36Sopenharmony_ci				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
18662306a36Sopenharmony_ci	if (r)
18762306a36Sopenharmony_ci		goto free_apmixed_data;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	r = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
19062306a36Sopenharmony_ci				   ARRAY_SIZE(apmixed_clks), clk_data);
19162306a36Sopenharmony_ci	if (r)
19262306a36Sopenharmony_ci		goto unregister_plls;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
19562306a36Sopenharmony_ci	if (r)
19662306a36Sopenharmony_ci		goto unregister_gates;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	platform_set_drvdata(pdev, clk_data);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return r;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ciunregister_gates:
20362306a36Sopenharmony_ci	mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
20462306a36Sopenharmony_ciunregister_plls:
20562306a36Sopenharmony_ci	mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs,
20662306a36Sopenharmony_ci				  ARRAY_SIZE(pllfhs), clk_data);
20762306a36Sopenharmony_cifree_apmixed_data:
20862306a36Sopenharmony_ci	mtk_free_clk_data(clk_data);
20962306a36Sopenharmony_ci	return r;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic void clk_mt8195_apmixed_remove(struct platform_device *pdev)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
21562306a36Sopenharmony_ci	struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	of_clk_del_provider(node);
21862306a36Sopenharmony_ci	mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
21962306a36Sopenharmony_ci	mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs,
22062306a36Sopenharmony_ci				  ARRAY_SIZE(pllfhs), clk_data);
22162306a36Sopenharmony_ci	mtk_free_clk_data(clk_data);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic struct platform_driver clk_mt8195_apmixed_drv = {
22562306a36Sopenharmony_ci	.probe = clk_mt8195_apmixed_probe,
22662306a36Sopenharmony_ci	.remove_new = clk_mt8195_apmixed_remove,
22762306a36Sopenharmony_ci	.driver = {
22862306a36Sopenharmony_ci		.name = "clk-mt8195-apmixed",
22962306a36Sopenharmony_ci		.of_match_table = of_match_clk_mt8195_apmixed,
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_cimodule_platform_driver(clk_mt8195_apmixed_drv);
23362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
234