| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016 Maxime Ripard. All rights reserved. |
|---|
| 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/of_address.h> |
|---|
| 16 | 9 | #include <linux/platform_device.h> |
|---|
| 17 | 10 | |
|---|
| .. | .. |
|---|
| 51 | 44 | * the base (2x, 4x and 8x), and one variable divider (the one true |
|---|
| 52 | 45 | * pll audio). |
|---|
| 53 | 46 | * |
|---|
| 54 | | - * We don't have any need for the variable divider for now, so we just |
|---|
| 55 | | - * hardcode it to match with the clock names |
|---|
| 47 | + * With sigma-delta modulation for fractional-N on the audio PLL, |
|---|
| 48 | + * we have to use specific dividers. This means the variable divider |
|---|
| 49 | + * can no longer be used, as the audio codec requests the exact clock |
|---|
| 50 | + * rates we support through this mechanism. So we now hard code the |
|---|
| 51 | + * variable divider to 1. This means the clock rates will no longer |
|---|
| 52 | + * match the clock names. |
|---|
| 56 | 53 | */ |
|---|
| 57 | 54 | #define SUN50I_A64_PLL_AUDIO_REG 0x008 |
|---|
| 58 | 55 | |
|---|
| 59 | | -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", |
|---|
| 60 | | - "osc24M", 0x008, |
|---|
| 61 | | - 8, 7, /* N */ |
|---|
| 62 | | - 0, 5, /* M */ |
|---|
| 63 | | - BIT(31), /* gate */ |
|---|
| 64 | | - BIT(28), /* lock */ |
|---|
| 65 | | - CLK_SET_RATE_UNGATE); |
|---|
| 56 | +static struct ccu_sdm_setting pll_audio_sdm_table[] = { |
|---|
| 57 | + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, |
|---|
| 58 | + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, |
|---|
| 59 | +}; |
|---|
| 66 | 60 | |
|---|
| 67 | | -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", |
|---|
| 68 | | - "osc24M", 0x010, |
|---|
| 69 | | - 8, 7, /* N */ |
|---|
| 70 | | - 0, 4, /* M */ |
|---|
| 71 | | - BIT(24), /* frac enable */ |
|---|
| 72 | | - BIT(25), /* frac select */ |
|---|
| 73 | | - 270000000, /* frac rate 0 */ |
|---|
| 74 | | - 297000000, /* frac rate 1 */ |
|---|
| 75 | | - BIT(31), /* gate */ |
|---|
| 76 | | - BIT(28), /* lock */ |
|---|
| 77 | | - CLK_SET_RATE_UNGATE); |
|---|
| 61 | +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", |
|---|
| 62 | + "osc24M", 0x008, |
|---|
| 63 | + 8, 7, /* N */ |
|---|
| 64 | + 0, 5, /* M */ |
|---|
| 65 | + pll_audio_sdm_table, BIT(24), |
|---|
| 66 | + 0x284, BIT(31), |
|---|
| 67 | + BIT(31), /* gate */ |
|---|
| 68 | + BIT(28), /* lock */ |
|---|
| 69 | + CLK_SET_RATE_UNGATE); |
|---|
| 70 | + |
|---|
| 71 | +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0", |
|---|
| 72 | + "osc24M", 0x010, |
|---|
| 73 | + 192000000, /* Minimum rate */ |
|---|
| 74 | + 1008000000, /* Maximum rate */ |
|---|
| 75 | + 8, 7, /* N */ |
|---|
| 76 | + 0, 4, /* M */ |
|---|
| 77 | + BIT(24), /* frac enable */ |
|---|
| 78 | + BIT(25), /* frac select */ |
|---|
| 79 | + 270000000, /* frac rate 0 */ |
|---|
| 80 | + 297000000, /* frac rate 1 */ |
|---|
| 81 | + BIT(31), /* gate */ |
|---|
| 82 | + BIT(28), /* lock */ |
|---|
| 83 | + CLK_SET_RATE_UNGATE); |
|---|
| 78 | 84 | |
|---|
| 79 | 85 | static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", |
|---|
| 80 | 86 | "osc24M", 0x018, |
|---|
| .. | .. |
|---|
| 125 | 131 | }, |
|---|
| 126 | 132 | }; |
|---|
| 127 | 133 | |
|---|
| 128 | | -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", |
|---|
| 129 | | - "osc24M", 0x030, |
|---|
| 130 | | - 8, 7, /* N */ |
|---|
| 131 | | - 0, 4, /* M */ |
|---|
| 132 | | - BIT(24), /* frac enable */ |
|---|
| 133 | | - BIT(25), /* frac select */ |
|---|
| 134 | | - 270000000, /* frac rate 0 */ |
|---|
| 135 | | - 297000000, /* frac rate 1 */ |
|---|
| 136 | | - BIT(31), /* gate */ |
|---|
| 137 | | - BIT(28), /* lock */ |
|---|
| 138 | | - CLK_SET_RATE_UNGATE); |
|---|
| 134 | +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video1_clk, "pll-video1", |
|---|
| 135 | + "osc24M", 0x030, |
|---|
| 136 | + 192000000, /* Minimum rate */ |
|---|
| 137 | + 1008000000, /* Maximum rate */ |
|---|
| 138 | + 8, 7, /* N */ |
|---|
| 139 | + 0, 4, /* M */ |
|---|
| 140 | + BIT(24), /* frac enable */ |
|---|
| 141 | + BIT(25), /* frac select */ |
|---|
| 142 | + 270000000, /* frac rate 0 */ |
|---|
| 143 | + 297000000, /* frac rate 1 */ |
|---|
| 144 | + BIT(31), /* gate */ |
|---|
| 145 | + BIT(28), /* lock */ |
|---|
| 146 | + CLK_SET_RATE_UNGATE); |
|---|
| 139 | 147 | |
|---|
| 140 | 148 | static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", |
|---|
| 141 | 149 | "osc24M", 0x038, |
|---|
| .. | .. |
|---|
| 517 | 525 | |
|---|
| 518 | 526 | static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" }; |
|---|
| 519 | 527 | static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, |
|---|
| 520 | | - 0x104, 0, 4, 24, 3, BIT(31), 0); |
|---|
| 528 | + 0x104, 0, 4, 24, 3, BIT(31), |
|---|
| 529 | + CLK_SET_RATE_PARENT); |
|---|
| 521 | 530 | |
|---|
| 522 | 531 | static const char * const tcon0_parents[] = { "pll-mipi", "pll-video0-2x" }; |
|---|
| 523 | 532 | static const u8 tcon0_table[] = { 0, 2, }; |
|---|
| .. | .. |
|---|
| 556 | 565 | 0x134, 0, 5, 8, 3, BIT(15), 0); |
|---|
| 557 | 566 | |
|---|
| 558 | 567 | static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", |
|---|
| 559 | | - 0x13c, 16, 3, BIT(31), 0); |
|---|
| 568 | + 0x13c, 16, 3, BIT(31), CLK_SET_RATE_PARENT); |
|---|
| 560 | 569 | |
|---|
| 561 | 570 | static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", |
|---|
| 562 | 571 | 0x140, BIT(31), CLK_SET_RATE_PARENT); |
|---|
| .. | .. |
|---|
| 589 | 598 | 0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT); |
|---|
| 590 | 599 | |
|---|
| 591 | 600 | /* Fixed Factor clocks */ |
|---|
| 592 | | -static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0); |
|---|
| 601 | +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0); |
|---|
| 593 | 602 | |
|---|
| 594 | | -/* We hardcode the divider to 4 for now */ |
|---|
| 595 | | -static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", |
|---|
| 596 | | - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); |
|---|
| 597 | | -static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", |
|---|
| 598 | | - "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); |
|---|
| 599 | | -static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", |
|---|
| 600 | | - "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); |
|---|
| 601 | | -static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", |
|---|
| 602 | | - "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); |
|---|
| 603 | | -static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", |
|---|
| 604 | | - "pll-periph0", 1, 2, 0); |
|---|
| 605 | | -static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x", |
|---|
| 606 | | - "pll-periph1", 1, 2, 0); |
|---|
| 607 | | -static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x", |
|---|
| 608 | | - "pll-video0", 1, 2, CLK_SET_RATE_PARENT); |
|---|
| 603 | +static const struct clk_hw *clk_parent_pll_audio[] = { |
|---|
| 604 | + &pll_audio_base_clk.common.hw |
|---|
| 605 | +}; |
|---|
| 606 | + |
|---|
| 607 | +/* We hardcode the divider to 1 for now */ |
|---|
| 608 | +static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio", |
|---|
| 609 | + clk_parent_pll_audio, |
|---|
| 610 | + 1, 1, CLK_SET_RATE_PARENT); |
|---|
| 611 | +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", |
|---|
| 612 | + clk_parent_pll_audio, |
|---|
| 613 | + 2, 1, CLK_SET_RATE_PARENT); |
|---|
| 614 | +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", |
|---|
| 615 | + clk_parent_pll_audio, |
|---|
| 616 | + 1, 1, CLK_SET_RATE_PARENT); |
|---|
| 617 | +static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x", |
|---|
| 618 | + clk_parent_pll_audio, |
|---|
| 619 | + 1, 2, CLK_SET_RATE_PARENT); |
|---|
| 620 | +static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x", |
|---|
| 621 | + &pll_periph0_clk.common.hw, |
|---|
| 622 | + 1, 2, 0); |
|---|
| 623 | +static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x", |
|---|
| 624 | + &pll_periph1_clk.common.hw, |
|---|
| 625 | + 1, 2, 0); |
|---|
| 626 | +static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x", |
|---|
| 627 | + &pll_video0_clk.common.hw, |
|---|
| 628 | + 1, 2, CLK_SET_RATE_PARENT); |
|---|
| 609 | 629 | |
|---|
| 610 | 630 | static struct ccu_common *sun50i_a64_ccu_clks[] = { |
|---|
| 611 | 631 | &pll_cpux_clk.common, |
|---|
| .. | .. |
|---|
| 928 | 948 | if (IS_ERR(reg)) |
|---|
| 929 | 949 | return PTR_ERR(reg); |
|---|
| 930 | 950 | |
|---|
| 931 | | - /* Force the PLL-Audio-1x divider to 4 */ |
|---|
| 951 | + /* Force the PLL-Audio-1x divider to 1 */ |
|---|
| 932 | 952 | val = readl(reg + SUN50I_A64_PLL_AUDIO_REG); |
|---|
| 933 | 953 | val &= ~GENMASK(19, 16); |
|---|
| 934 | | - writel(val | (3 << 16), reg + SUN50I_A64_PLL_AUDIO_REG); |
|---|
| 954 | + writel(val | (0 << 16), reg + SUN50I_A64_PLL_AUDIO_REG); |
|---|
| 935 | 955 | |
|---|
| 936 | 956 | writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); |
|---|
| 937 | 957 | |
|---|