.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> |
---|
3 | | - * |
---|
4 | | - * This software is licensed under the terms of the GNU General Public |
---|
5 | | - * License version 2, as published by the Free Software Foundation, and |
---|
6 | | - * may be copied, distributed, and modified under those terms. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, |
---|
9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | | - * GNU General Public License for more details. |
---|
12 | 4 | */ |
---|
13 | 5 | |
---|
14 | 6 | #include <linux/clk-provider.h> |
---|
| 7 | +#include <linux/io.h> |
---|
15 | 8 | #include <linux/platform_device.h> |
---|
16 | 9 | #include <linux/regmap.h> |
---|
17 | 10 | |
---|
.. | .. |
---|
52 | 45 | * the base (2x, 4x and 8x), and one variable divider (the one true |
---|
53 | 46 | * pll audio). |
---|
54 | 47 | * |
---|
55 | | - * We don't have any need for the variable divider for now, so we just |
---|
56 | | - * hardcode it to match with the clock names |
---|
| 48 | + * With sigma-delta modulation for fractional-N on the audio PLL, |
---|
| 49 | + * we have to use specific dividers. This means the variable divider |
---|
| 50 | + * can no longer be used, as the audio codec requests the exact clock |
---|
| 51 | + * rates we support through this mechanism. So we now hard code the |
---|
| 52 | + * variable divider to 1. This means the clock rates will no longer |
---|
| 53 | + * match the clock names. |
---|
57 | 54 | */ |
---|
58 | 55 | #define SUN8I_R40_PLL_AUDIO_REG 0x008 |
---|
59 | 56 | |
---|
60 | | -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", |
---|
61 | | - "osc24M", 0x008, |
---|
62 | | - 8, 7, /* N */ |
---|
63 | | - 0, 5, /* M */ |
---|
64 | | - BIT(31), /* gate */ |
---|
65 | | - BIT(28), /* lock */ |
---|
66 | | - CLK_SET_RATE_UNGATE); |
---|
| 57 | +static struct ccu_sdm_setting pll_audio_sdm_table[] = { |
---|
| 58 | + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, |
---|
| 59 | + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, |
---|
| 60 | +}; |
---|
67 | 61 | |
---|
68 | | -/* TODO: The result of N/M is required to be in [8, 25] range. */ |
---|
69 | | -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0", |
---|
70 | | - "osc24M", 0x0010, |
---|
71 | | - 192000000, /* Minimum rate */ |
---|
72 | | - 8, 7, /* N */ |
---|
73 | | - 0, 4, /* M */ |
---|
74 | | - BIT(24), /* frac enable */ |
---|
75 | | - BIT(25), /* frac select */ |
---|
76 | | - 270000000, /* frac rate 0 */ |
---|
77 | | - 297000000, /* frac rate 1 */ |
---|
78 | | - BIT(31), /* gate */ |
---|
79 | | - BIT(28), /* lock */ |
---|
80 | | - CLK_SET_RATE_UNGATE); |
---|
| 62 | +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", |
---|
| 63 | + "osc24M", 0x008, |
---|
| 64 | + 8, 7, /* N */ |
---|
| 65 | + 0, 5, /* M */ |
---|
| 66 | + pll_audio_sdm_table, BIT(24), |
---|
| 67 | + 0x284, BIT(31), |
---|
| 68 | + BIT(31), /* gate */ |
---|
| 69 | + BIT(28), /* lock */ |
---|
| 70 | + CLK_SET_RATE_UNGATE); |
---|
| 71 | + |
---|
| 72 | +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0", |
---|
| 73 | + "osc24M", 0x0010, |
---|
| 74 | + 192000000, /* Minimum rate */ |
---|
| 75 | + 1008000000, /* Maximum rate */ |
---|
| 76 | + 8, 7, /* N */ |
---|
| 77 | + 0, 4, /* M */ |
---|
| 78 | + BIT(24), /* frac enable */ |
---|
| 79 | + BIT(25), /* frac select */ |
---|
| 80 | + 270000000, /* frac rate 0 */ |
---|
| 81 | + 297000000, /* frac rate 1 */ |
---|
| 82 | + BIT(31), /* gate */ |
---|
| 83 | + BIT(28), /* lock */ |
---|
| 84 | + CLK_SET_RATE_UNGATE); |
---|
81 | 85 | |
---|
82 | 86 | /* TODO: The result of N/M is required to be in [8, 25] range. */ |
---|
83 | 87 | static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", |
---|
.. | .. |
---|
152 | 156 | }, |
---|
153 | 157 | }; |
---|
154 | 158 | |
---|
155 | | -/* TODO: The result of N/M is required to be in [8, 25] range. */ |
---|
156 | | -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1", |
---|
157 | | - "osc24M", 0x030, |
---|
158 | | - 192000000, /* Minimum rate */ |
---|
159 | | - 8, 7, /* N */ |
---|
160 | | - 0, 4, /* M */ |
---|
161 | | - BIT(24), /* frac enable */ |
---|
162 | | - BIT(25), /* frac select */ |
---|
163 | | - 270000000, /* frac rate 0 */ |
---|
164 | | - 297000000, /* frac rate 1 */ |
---|
165 | | - BIT(31), /* gate */ |
---|
166 | | - BIT(28), /* lock */ |
---|
167 | | - CLK_SET_RATE_UNGATE); |
---|
| 159 | +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video1_clk, "pll-video1", |
---|
| 160 | + "osc24M", 0x030, |
---|
| 161 | + 192000000, /* Minimum rate */ |
---|
| 162 | + 1008000000, /* Maximum rate */ |
---|
| 163 | + 8, 7, /* N */ |
---|
| 164 | + 0, 4, /* M */ |
---|
| 165 | + BIT(24), /* frac enable */ |
---|
| 166 | + BIT(25), /* frac select */ |
---|
| 167 | + 270000000, /* frac rate 0 */ |
---|
| 168 | + 297000000, /* frac rate 1 */ |
---|
| 169 | + BIT(31), /* gate */ |
---|
| 170 | + BIT(28), /* lock */ |
---|
| 171 | + CLK_SET_RATE_UNGATE); |
---|
168 | 172 | |
---|
169 | 173 | static struct ccu_nkm pll_sata_clk = { |
---|
170 | 174 | .enable = BIT(31), |
---|
.. | .. |
---|
768 | 772 | .reg = 0x1f0, |
---|
769 | 773 | .features = CCU_FEATURE_FIXED_PREDIV, |
---|
770 | 774 | .hw.init = CLK_HW_INIT_PARENTS("outa", out_parents, |
---|
771 | | - &ccu_mp_ops, 0), |
---|
| 775 | + &ccu_mp_ops, |
---|
| 776 | + CLK_SET_RATE_PARENT), |
---|
772 | 777 | } |
---|
773 | 778 | }; |
---|
774 | 779 | |
---|
.. | .. |
---|
786 | 791 | .reg = 0x1f4, |
---|
787 | 792 | .features = CCU_FEATURE_FIXED_PREDIV, |
---|
788 | 793 | .hw.init = CLK_HW_INIT_PARENTS("outb", out_parents, |
---|
789 | | - &ccu_mp_ops, 0), |
---|
| 794 | + &ccu_mp_ops, |
---|
| 795 | + CLK_SET_RATE_PARENT), |
---|
790 | 796 | } |
---|
791 | 797 | }; |
---|
792 | 798 | |
---|
.. | .. |
---|
951 | 957 | }; |
---|
952 | 958 | |
---|
953 | 959 | /* Fixed Factor clocks */ |
---|
954 | | -static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0); |
---|
| 960 | +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0); |
---|
955 | 961 | |
---|
956 | | -/* We hardcode the divider to 4 for now */ |
---|
957 | | -static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", |
---|
958 | | - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); |
---|
959 | | -static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", |
---|
960 | | - "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); |
---|
961 | | -static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", |
---|
962 | | - "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); |
---|
963 | | -static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", |
---|
964 | | - "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); |
---|
965 | | -static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", |
---|
966 | | - "pll-periph0", 1, 2, 0); |
---|
967 | | -static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x", |
---|
968 | | - "pll-periph1", 1, 2, 0); |
---|
969 | | -static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x", |
---|
970 | | - "pll-video0", 1, 2, 0); |
---|
971 | | -static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x", |
---|
972 | | - "pll-video1", 1, 2, 0); |
---|
| 962 | +static const struct clk_hw *clk_parent_pll_audio[] = { |
---|
| 963 | + &pll_audio_base_clk.common.hw |
---|
| 964 | +}; |
---|
| 965 | + |
---|
| 966 | +/* We hardcode the divider to 1 for now */ |
---|
| 967 | +static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio", |
---|
| 968 | + clk_parent_pll_audio, |
---|
| 969 | + 1, 1, CLK_SET_RATE_PARENT); |
---|
| 970 | +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", |
---|
| 971 | + clk_parent_pll_audio, |
---|
| 972 | + 2, 1, CLK_SET_RATE_PARENT); |
---|
| 973 | +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", |
---|
| 974 | + clk_parent_pll_audio, |
---|
| 975 | + 1, 1, CLK_SET_RATE_PARENT); |
---|
| 976 | +static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x", |
---|
| 977 | + clk_parent_pll_audio, |
---|
| 978 | + 1, 2, CLK_SET_RATE_PARENT); |
---|
| 979 | +static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x", |
---|
| 980 | + &pll_periph0_clk.common.hw, |
---|
| 981 | + 1, 2, 0); |
---|
| 982 | +static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x", |
---|
| 983 | + &pll_periph1_clk.common.hw, |
---|
| 984 | + 1, 2, 0); |
---|
| 985 | +static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x", |
---|
| 986 | + &pll_video0_clk.common.hw, |
---|
| 987 | + 1, 2, 0); |
---|
| 988 | +static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x", |
---|
| 989 | + &pll_video1_clk.common.hw, |
---|
| 990 | + 1, 2, 0); |
---|
973 | 991 | |
---|
974 | 992 | static struct clk_hw_onecell_data sun8i_r40_hw_clks = { |
---|
975 | 993 | .hws = { |
---|
.. | .. |
---|
1284 | 1302 | .writeable_reg = sun8i_r40_ccu_regmap_accessible_reg, |
---|
1285 | 1303 | }; |
---|
1286 | 1304 | |
---|
| 1305 | +#define SUN8I_R40_SYS_32K_CLK_REG 0x310 |
---|
| 1306 | +#define SUN8I_R40_SYS_32K_CLK_KEY (0x16AA << 16) |
---|
| 1307 | + |
---|
1287 | 1308 | static int sun8i_r40_ccu_probe(struct platform_device *pdev) |
---|
1288 | 1309 | { |
---|
1289 | 1310 | struct resource *res; |
---|
.. | .. |
---|
1297 | 1318 | if (IS_ERR(reg)) |
---|
1298 | 1319 | return PTR_ERR(reg); |
---|
1299 | 1320 | |
---|
1300 | | - /* Force the PLL-Audio-1x divider to 4 */ |
---|
| 1321 | + /* Force the PLL-Audio-1x divider to 1 */ |
---|
1301 | 1322 | val = readl(reg + SUN8I_R40_PLL_AUDIO_REG); |
---|
1302 | 1323 | val &= ~GENMASK(19, 16); |
---|
1303 | | - writel(val | (3 << 16), reg + SUN8I_R40_PLL_AUDIO_REG); |
---|
| 1324 | + writel(val | (0 << 16), reg + SUN8I_R40_PLL_AUDIO_REG); |
---|
1304 | 1325 | |
---|
1305 | 1326 | /* Force PLL-MIPI to MIPI mode */ |
---|
1306 | 1327 | val = readl(reg + SUN8I_R40_PLL_MIPI_REG); |
---|
.. | .. |
---|
1312 | 1333 | val &= ~GENMASK(25, 20); |
---|
1313 | 1334 | writel(val, reg + SUN8I_R40_USB_CLK_REG); |
---|
1314 | 1335 | |
---|
| 1336 | + /* |
---|
| 1337 | + * Force SYS 32k (otherwise known as LOSC throughout the CCU) |
---|
| 1338 | + * clock parent to LOSC output from RTC module instead of the |
---|
| 1339 | + * CCU's internal RC oscillator divided output. |
---|
| 1340 | + */ |
---|
| 1341 | + writel(SUN8I_R40_SYS_32K_CLK_KEY | BIT(8), |
---|
| 1342 | + reg + SUN8I_R40_SYS_32K_CLK_REG); |
---|
| 1343 | + |
---|
1315 | 1344 | regmap = devm_regmap_init_mmio(&pdev->dev, reg, |
---|
1316 | 1345 | &sun8i_r40_ccu_regmap_config); |
---|
1317 | 1346 | if (IS_ERR(regmap)) |
---|