1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017 MediaTek Inc. 4 * Weiyi Lu <weiyi.lu@mediatek.com> 5 * Copyright (c) 2023 Collabora Ltd. 6 * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 7 */ 8 #include <linux/clk.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 12 #include "clk-pll.h" 13 #include "clk-mtk.h" 14 15 #include <dt-bindings/clock/mt2712-clk.h> 16 17 #define MT2712_PLL_FMAX (3000UL * MHZ) 18 19 #define CON0_MT2712_RST_BAR BIT(24) 20 21 #define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ 22 _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ 23 _tuner_en_bit, _pcw_reg, _pcw_shift, \ 24 _div_table) { \ 25 .id = _id, \ 26 .name = _name, \ 27 .reg = _reg, \ 28 .pwr_reg = _pwr_reg, \ 29 .en_mask = _en_mask, \ 30 .flags = _flags, \ 31 .rst_bar_mask = CON0_MT2712_RST_BAR, \ 32 .fmax = MT2712_PLL_FMAX, \ 33 .pcwbits = _pcwbits, \ 34 .pd_reg = _pd_reg, \ 35 .pd_shift = _pd_shift, \ 36 .tuner_reg = _tuner_reg, \ 37 .tuner_en_reg = _tuner_en_reg, \ 38 .tuner_en_bit = _tuner_en_bit, \ 39 .pcw_reg = _pcw_reg, \ 40 .pcw_shift = _pcw_shift, \ 41 .div_table = _div_table, \ 42 } 43 44 #define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ 45 _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ 46 _tuner_en_bit, _pcw_reg, _pcw_shift) \ 47 PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ 48 _pcwbits, _pd_reg, _pd_shift, _tuner_reg, \ 49 _tuner_en_reg, _tuner_en_bit, _pcw_reg, \ 50 _pcw_shift, NULL) 51 52 static const struct mtk_pll_div_table armca35pll_div_table[] = { 53 { .div = 0, .freq = MT2712_PLL_FMAX }, 54 { .div = 1, .freq = 1202500000 }, 55 { .div = 2, .freq = 500500000 }, 56 { .div = 3, .freq = 315250000 }, 57 { .div = 4, .freq = 157625000 }, 58 { /* sentinel */ } 59 }; 60 61 static const struct mtk_pll_div_table armca72pll_div_table[] = { 62 { .div = 0, .freq = MT2712_PLL_FMAX }, 63 { .div = 1, .freq = 994500000 }, 64 { .div = 2, .freq = 520000000 }, 65 { .div = 3, .freq = 315250000 }, 66 { .div = 4, .freq = 157625000 }, 67 { /* sentinel */ } 68 }; 69 70 static const struct mtk_pll_div_table mmpll_div_table[] = { 71 { .div = 0, .freq = MT2712_PLL_FMAX }, 72 { .div = 1, .freq = 1001000000 }, 73 { .div = 2, .freq = 601250000 }, 74 { .div = 3, .freq = 250250000 }, 75 { .div = 4, .freq = 125125000 }, 76 { /* sentinel */ } 77 }; 78 79 static const struct mtk_pll_data plls[] = { 80 PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0230, 0x023C, 0xf0000100, 81 HAVE_RST_BAR, 31, 0x0230, 4, 0, 0, 0, 0x0234, 0), 82 PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0240, 0x024C, 0xfe000100, 83 HAVE_RST_BAR, 31, 0x0240, 4, 0, 0, 0, 0x0244, 0), 84 PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x0320, 0x032C, 0xc0000100, 85 0, 31, 0x0320, 4, 0, 0, 0, 0x0324, 0), 86 PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x0280, 0x028C, 0x00000100, 87 0, 31, 0x0280, 4, 0, 0, 0, 0x0284, 0), 88 PLL(CLK_APMIXED_APLL1, "apll1", 0x0330, 0x0340, 0x00000100, 89 0, 31, 0x0330, 4, 0x0338, 0x0014, 0, 0x0334, 0), 90 PLL(CLK_APMIXED_APLL2, "apll2", 0x0350, 0x0360, 0x00000100, 91 0, 31, 0x0350, 4, 0x0358, 0x0014, 1, 0x0354, 0), 92 PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x0370, 0x037c, 0x00000100, 93 0, 31, 0x0370, 4, 0, 0, 0, 0x0374, 0), 94 PLL(CLK_APMIXED_LVDSPLL2, "lvdspll2", 0x0390, 0x039C, 0x00000100, 95 0, 31, 0x0390, 4, 0, 0, 0, 0x0394, 0), 96 PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0270, 0x027C, 0x00000100, 97 0, 31, 0x0270, 4, 0, 0, 0, 0x0274, 0), 98 PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x0410, 0x041C, 0x00000100, 99 0, 31, 0x0410, 4, 0, 0, 0, 0x0414, 0), 100 PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0290, 0x029C, 0xc0000100, 101 0, 31, 0x0290, 4, 0, 0, 0, 0x0294, 0), 102 PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0250, 0x0260, 0x00000100, 103 0, 31, 0x0250, 4, 0, 0, 0, 0x0254, 0, mmpll_div_table), 104 PLL_B(CLK_APMIXED_ARMCA35PLL, "armca35pll", 0x0100, 0x0110, 0xf0000100, 105 HAVE_RST_BAR, 31, 0x0100, 4, 0, 0, 0, 0x0104, 0, armca35pll_div_table), 106 PLL_B(CLK_APMIXED_ARMCA72PLL, "armca72pll", 0x0210, 0x0220, 0x00000100, 107 0, 31, 0x0210, 4, 0, 0, 0, 0x0214, 0, armca72pll_div_table), 108 PLL(CLK_APMIXED_ETHERPLL, "etherpll", 0x0300, 0x030C, 0xc0000100, 109 0, 31, 0x0300, 4, 0, 0, 0, 0x0304, 0), 110 }; 111 112 static int clk_mt2712_apmixed_probe(struct platform_device *pdev) 113 { 114 struct clk_hw_onecell_data *clk_data; 115 int r; 116 struct device_node *node = pdev->dev.of_node; 117 118 clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); 119 if (!clk_data) 120 return -ENOMEM; 121 122 r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); 123 if (r) 124 goto free_clk_data; 125 126 r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); 127 if (r) { 128 dev_err(&pdev->dev, "Cannot register clock provider: %d\n", r); 129 goto unregister_plls; 130 } 131 132 return 0; 133 134 unregister_plls: 135 mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); 136 free_clk_data: 137 mtk_free_clk_data(clk_data); 138 return r; 139 } 140 141 static void clk_mt2712_apmixed_remove(struct platform_device *pdev) 142 { 143 struct device_node *node = pdev->dev.of_node; 144 struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); 145 146 of_clk_del_provider(node); 147 mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); 148 mtk_free_clk_data(clk_data); 149 } 150 151 static const struct of_device_id of_match_clk_mt2712_apmixed[] = { 152 { .compatible = "mediatek,mt2712-apmixedsys" }, 153 { /* sentinel */ } 154 }; 155 MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_apmixed); 156 157 static struct platform_driver clk_mt2712_apmixed_drv = { 158 .probe = clk_mt2712_apmixed_probe, 159 .remove_new = clk_mt2712_apmixed_remove, 160 .driver = { 161 .name = "clk-mt2712-apmixed", 162 .of_match_table = of_match_clk_mt2712_apmixed, 163 }, 164 }; 165 module_platform_driver(clk_mt2712_apmixed_drv) 166 MODULE_LICENSE("GPL"); 167