mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
Merge branches 'clk-airoha', 'clk-rockchip', 'clk-stm', 'clk-thead' and 'clk-bcm' into clk-next
* clk-airoha: clk: en7523: Add clock for eMMC for EN7581 dt-bindings: clock: add ID for eMMC for EN7581 dt-bindings: clock: drop NUM_CLOCKS define for EN7581 clk: en7523: Rework clock handling for different clock numbers clk: en7523: Initialize num before accessing hws in en7523_register_clocks() clk: en7523: Fix wrong BUS clock for EN7581 clk: amlogic: axg-audio: revert reset implementation Revert "clk: Fix invalid execution of clk_set_rate" * clk-rockchip: clk: rockchip: rk3588: make refclko25m_ethX critical clk: rockchip: rk3588: drop RK3588_LINKED_CLK clk: rockchip: implement linked gate clock support clk: rockchip: expose rockchip_clk_set_lookup clk: rockchip: rk3588: register GATE_LINK later clk: rockchip: support clocks registered late * clk-stm: clk: stm32f4: support spread spectrum clock generation clk: stm32f4: use FIELD helpers to access the PLLCFGR fields dt-bindings: clock: st,stm32-rcc: support spread spectrum clocking dt-bindings: clock: convert stm32 rcc bindings to json-schema * clk-thead: clk: thead: Fix cpu2vp_clk for TH1520 AP_SUBSYS clocks clk: thead: Add CLK_IGNORE_UNUSED to fix TH1520 boot clk: thead: Fix clk gate registration to pass flags * clk-bcm: clk: bcm: rpi: Add disp clock clk: bcm: rpi: Create helper to retrieve private data clk: bcm: rpi: Enable minimize for all firmware clocks clk: bcm: rpi: Allow cpufreq driver to also adjust gpu clocks clk: bcm: rpi: Add ISP to exported clocks
This commit is contained in:
commit
1d2da923fb
|
@ -1,138 +0,0 @@
|
|||
STMicroelectronics STM32 Reset and Clock Controller
|
||||
===================================================
|
||||
|
||||
The RCC IP is both a reset and a clock controller.
|
||||
|
||||
Please refer to clock-bindings.txt for common clock controller binding usage.
|
||||
Please also refer to reset.txt for common reset controller binding usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be:
|
||||
"st,stm32f42xx-rcc"
|
||||
"st,stm32f469-rcc"
|
||||
"st,stm32f746-rcc"
|
||||
"st,stm32f769-rcc"
|
||||
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- #reset-cells: 1, see below
|
||||
- #clock-cells: 2, device nodes should specify the clock in their "clocks"
|
||||
property, containing a phandle to the clock device node, an index selecting
|
||||
between gated clocks and other clocks and an index specifying the clock to
|
||||
use.
|
||||
- clocks: External oscillator clock phandle
|
||||
- high speed external clock signal (HSE)
|
||||
- external I2S clock (I2S_CKIN)
|
||||
|
||||
Example:
|
||||
|
||||
rcc: rcc@40023800 {
|
||||
#reset-cells = <1>;
|
||||
#clock-cells = <2>
|
||||
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
|
||||
reg = <0x40023800 0x400>;
|
||||
clocks = <&clk_hse>, <&clk_i2s_ckin>;
|
||||
};
|
||||
|
||||
Specifying gated clocks
|
||||
=======================
|
||||
|
||||
The primary index must be set to 0.
|
||||
|
||||
The secondary index is the bit number within the RCC register bank, starting
|
||||
from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
|
||||
|
||||
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
|
||||
Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
|
||||
|
||||
To simplify the usage and to share bit definition with the reset and clock
|
||||
drivers of the RCC IP, macros are available to generate the index in
|
||||
human-readble format.
|
||||
|
||||
For STM32F4 series, the macro are available here:
|
||||
- include/dt-bindings/mfd/stm32f4-rcc.h
|
||||
|
||||
Example:
|
||||
|
||||
/* Gated clock, AHB1 bit 0 (GPIOA) */
|
||||
... {
|
||||
clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>
|
||||
};
|
||||
|
||||
/* Gated clock, AHB2 bit 4 (CRYP) */
|
||||
... {
|
||||
clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)>
|
||||
};
|
||||
|
||||
Specifying other clocks
|
||||
=======================
|
||||
|
||||
The primary index must be set to 1.
|
||||
|
||||
The secondary index is bound with the following magic numbers:
|
||||
|
||||
0 SYSTICK
|
||||
1 FCLK
|
||||
2 CLK_LSI (low-power clock source)
|
||||
3 CLK_LSE (generated from a 32.768 kHz low-speed external
|
||||
crystal or ceramic resonator)
|
||||
4 CLK_HSE_RTC (HSE division factor for RTC clock)
|
||||
5 CLK_RTC (real-time clock)
|
||||
6 PLL_VCO_I2S (vco frequency of I2S pll)
|
||||
7 PLL_VCO_SAI (vco frequency of SAI pll)
|
||||
8 CLK_LCD (LCD-TFT)
|
||||
9 CLK_I2S (I2S clocks)
|
||||
10 CLK_SAI1 (audio clocks)
|
||||
11 CLK_SAI2
|
||||
12 CLK_I2SQ_PDIV (post divisor of pll i2s q divisor)
|
||||
13 CLK_SAIQ_PDIV (post divisor of pll sai q divisor)
|
||||
|
||||
14 CLK_HSI (Internal ocscillator clock)
|
||||
15 CLK_SYSCLK (System Clock)
|
||||
16 CLK_HDMI_CEC (HDMI-CEC clock)
|
||||
17 CLK_SPDIF (SPDIF-Rx clock)
|
||||
18 CLK_USART1 (U(s)arts clocks)
|
||||
19 CLK_USART2
|
||||
20 CLK_USART3
|
||||
21 CLK_UART4
|
||||
22 CLK_UART5
|
||||
23 CLK_USART6
|
||||
24 CLK_UART7
|
||||
25 CLK_UART8
|
||||
26 CLK_I2C1 (I2S clocks)
|
||||
27 CLK_I2C2
|
||||
28 CLK_I2C3
|
||||
29 CLK_I2C4
|
||||
30 CLK_LPTIMER (LPTimer1 clock)
|
||||
31 CLK_PLL_SRC
|
||||
32 CLK_DFSDM1
|
||||
33 CLK_ADFSDM1
|
||||
34 CLK_F769_DSI
|
||||
)
|
||||
|
||||
Example:
|
||||
|
||||
/* Misc clock, FCLK */
|
||||
... {
|
||||
clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)>
|
||||
};
|
||||
|
||||
|
||||
Specifying softreset control of devices
|
||||
=======================================
|
||||
|
||||
Device nodes should specify the reset channel required in their "resets"
|
||||
property, containing a phandle to the reset device node and an index specifying
|
||||
which channel to use.
|
||||
The index is the bit number within the RCC registers bank, starting from RCC
|
||||
base address.
|
||||
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
|
||||
Where bit_offset is the bit offset within the register.
|
||||
For example, for CRC reset:
|
||||
crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140
|
||||
|
||||
example:
|
||||
|
||||
timer2 {
|
||||
resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
|
||||
};
|
144
Documentation/devicetree/bindings/clock/st,stm32-rcc.yaml
Normal file
144
Documentation/devicetree/bindings/clock/st,stm32-rcc.yaml
Normal file
|
@ -0,0 +1,144 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/st,stm32-rcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STM32 Reset Clock Controller
|
||||
|
||||
maintainers:
|
||||
- Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
||||
|
||||
description: |
|
||||
The RCC IP is both a reset and a clock controller.
|
||||
The reset phandle argument is the bit number within the RCC registers bank,
|
||||
starting from RCC base address.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- st,stm32f42xx-rcc
|
||||
- st,stm32f746-rcc
|
||||
- st,stm32h743-rcc
|
||||
- const: st,stm32-rcc
|
||||
- items:
|
||||
- enum:
|
||||
- st,stm32f469-rcc
|
||||
- const: st,stm32f42xx-rcc
|
||||
- const: st,stm32-rcc
|
||||
- items:
|
||||
- enum:
|
||||
- st,stm32f769-rcc
|
||||
- const: st,stm32f746-rcc
|
||||
- const: st,stm32-rcc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#clock-cells':
|
||||
enum: [1, 2]
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
st,syscfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to system configuration controller. It can be used to control the
|
||||
power domain circuitry.
|
||||
|
||||
st,ssc-modfreq-hz:
|
||||
description:
|
||||
The modulation frequency for main PLL (in Hz)
|
||||
|
||||
st,ssc-moddepth-permyriad:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
The modulation rate for main PLL (in permyriad, i.e. 0.01%)
|
||||
minimum: 25
|
||||
maximum: 200
|
||||
|
||||
st,ssc-modmethod:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
The modulation techniques for main PLL.
|
||||
items:
|
||||
enum:
|
||||
- center-spread
|
||||
- down-spread
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#reset-cells'
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
- st,syscfg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: st,stm32h743-rcc
|
||||
then:
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
description: |
|
||||
The clock index for the specified type.
|
||||
clocks:
|
||||
items:
|
||||
- description: high speed external (HSE) clock input
|
||||
- description: low speed external (LSE) clock input
|
||||
- description: Inter-IC sound (I2S) clock input
|
||||
st,ssc-modfreq-hz: false
|
||||
st,ssc-moddepth-permyriad: false
|
||||
st,ssc-modmethod: false
|
||||
|
||||
else:
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 2
|
||||
description: |
|
||||
- The first cell is the clock type, possible values are 0 for
|
||||
gated clocks and 1 otherwise.
|
||||
- The second cell is the clock index for the specified type.
|
||||
clocks:
|
||||
items:
|
||||
- description: high speed external (HSE) clock input
|
||||
- description: Inter-IC sound (I2S) clock input
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Reset and Clock Control Module node:
|
||||
- |
|
||||
clock-controller@40023800 {
|
||||
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
|
||||
reg = <0x40023800 0x400>;
|
||||
#clock-cells = <2>;
|
||||
#reset-cells = <1>;
|
||||
clocks = <&clk_hse>, <&clk_i2s_ckin>;
|
||||
st,syscfg = <&pwrcfg>;
|
||||
st,ssc-modfreq-hz = <10000>;
|
||||
st,ssc-moddepth-permyriad = <200>;
|
||||
st,ssc-modmethod = "center-spread";
|
||||
};
|
||||
- |
|
||||
clock-controller@58024400 {
|
||||
compatible = "st,stm32h743-rcc", "st,stm32-rcc";
|
||||
reg = <0x58024400 0x400>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s>;
|
||||
st,syscfg = <&pwrcfg>;
|
||||
};
|
||||
|
||||
...
|
|
@ -3,4 +3,4 @@ STMicroelectronics STM32 Peripheral Reset Controller
|
|||
|
||||
The RCC IP is both a reset and a clock controller.
|
||||
|
||||
Please see Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
|
||||
Please see Documentation/devicetree/bindings/clock/st,stm32-rcc.yaml
|
||||
|
|
|
@ -34,6 +34,7 @@ static char *rpi_firmware_clk_names[] = {
|
|||
[RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc",
|
||||
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb",
|
||||
[RPI_FIRMWARE_VEC_CLK_ID] = "vec",
|
||||
[RPI_FIRMWARE_DISP_CLK_ID] = "disp",
|
||||
};
|
||||
|
||||
#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
|
||||
|
@ -56,6 +57,12 @@ struct raspberrypi_clk_data {
|
|||
struct raspberrypi_clk *rpi;
|
||||
};
|
||||
|
||||
static inline
|
||||
const struct raspberrypi_clk_data *clk_hw_to_data(const struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct raspberrypi_clk_data, hw);
|
||||
}
|
||||
|
||||
struct raspberrypi_clk_variant {
|
||||
bool export;
|
||||
char *clkdev;
|
||||
|
@ -111,18 +118,31 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
|
|||
},
|
||||
[RPI_FIRMWARE_V3D_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_PIXEL_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_HEVC_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_ISP_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_VEC_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_DISP_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -153,7 +173,6 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware,
|
|||
struct raspberrypi_firmware_prop msg = {
|
||||
.id = cpu_to_le32(data->id),
|
||||
.val = cpu_to_le32(*val),
|
||||
.disable_turbo = cpu_to_le32(1),
|
||||
};
|
||||
int ret;
|
||||
|
||||
|
@ -168,8 +187,7 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware,
|
|||
|
||||
static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct raspberrypi_clk_data *data =
|
||||
container_of(hw, struct raspberrypi_clk_data, hw);
|
||||
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
|
||||
struct raspberrypi_clk *rpi = data->rpi;
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
@ -186,8 +204,7 @@ static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
|
|||
static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct raspberrypi_clk_data *data =
|
||||
container_of(hw, struct raspberrypi_clk_data, hw);
|
||||
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
|
||||
struct raspberrypi_clk *rpi = data->rpi;
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
@ -203,8 +220,7 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
|
|||
static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct raspberrypi_clk_data *data =
|
||||
container_of(hw, struct raspberrypi_clk_data, hw);
|
||||
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
|
||||
struct raspberrypi_clk *rpi = data->rpi;
|
||||
u32 _rate = rate;
|
||||
int ret;
|
||||
|
@ -221,8 +237,7 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct raspberrypi_clk_data *data =
|
||||
container_of(hw, struct raspberrypi_clk_data, hw);
|
||||
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
|
||||
struct raspberrypi_clk_variant *variant = data->variant;
|
||||
|
||||
/*
|
||||
|
|
|
@ -75,6 +75,7 @@ struct en_rst_data {
|
|||
};
|
||||
|
||||
struct en_clk_soc_data {
|
||||
u32 num_clocks;
|
||||
const struct clk_ops pcie_ops;
|
||||
int (*hw_init)(struct platform_device *pdev,
|
||||
struct clk_hw_onecell_data *clk_data);
|
||||
|
@ -87,8 +88,10 @@ static const u32 slic_base[] = { 100000000, 3125000 };
|
|||
static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
|
||||
/* EN7581 */
|
||||
static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
|
||||
static const u32 bus7581_base[] = { 600000000, 540000000 };
|
||||
static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
|
||||
static const u32 crypto_base[] = { 540000000, 480000000 };
|
||||
static const u32 emmc7581_base[] = { 200000000, 150000000 };
|
||||
|
||||
static const struct en_clk_desc en7523_base_clks[] = {
|
||||
{
|
||||
|
@ -222,8 +225,8 @@ static const struct en_clk_desc en7581_base_clks[] = {
|
|||
.base_reg = REG_BUS_CLK_DIV_SEL,
|
||||
.base_bits = 1,
|
||||
.base_shift = 8,
|
||||
.base_values = bus_base,
|
||||
.n_base_values = ARRAY_SIZE(bus_base),
|
||||
.base_values = bus7581_base,
|
||||
.n_base_values = ARRAY_SIZE(bus7581_base),
|
||||
|
||||
.div_bits = 3,
|
||||
.div_shift = 0,
|
||||
|
@ -279,6 +282,15 @@ static const struct en_clk_desc en7581_base_clks[] = {
|
|||
.base_shift = 0,
|
||||
.base_values = crypto_base,
|
||||
.n_base_values = ARRAY_SIZE(crypto_base),
|
||||
}, {
|
||||
.id = EN7581_CLK_EMMC,
|
||||
.name = "emmc",
|
||||
|
||||
.base_reg = REG_CRYPTO_CLKSRC2,
|
||||
.base_bits = 1,
|
||||
.base_shift = 12,
|
||||
.base_values = emmc7581_base,
|
||||
.n_base_values = ARRAY_SIZE(emmc7581_base),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -524,8 +536,6 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
|||
|
||||
hw = en7523_register_pcie_clk(dev, np_base);
|
||||
clk_data->hws[EN7523_CLK_PCIE] = hw;
|
||||
|
||||
clk_data->num = EN7523_NUM_CLOCKS;
|
||||
}
|
||||
|
||||
static int en7523_clk_hw_init(struct platform_device *pdev,
|
||||
|
@ -586,8 +596,6 @@ static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
|||
|
||||
hw = en7523_register_pcie_clk(dev, base);
|
||||
clk_data->hws[EN7523_CLK_PCIE] = hw;
|
||||
|
||||
clk_data->num = EN7523_NUM_CLOCKS;
|
||||
}
|
||||
|
||||
static int en7523_reset_update(struct reset_controller_dev *rcdev,
|
||||
|
@ -701,13 +709,15 @@ static int en7523_clk_probe(struct platform_device *pdev)
|
|||
struct clk_hw_onecell_data *clk_data;
|
||||
int r;
|
||||
|
||||
soc_data = device_get_match_data(&pdev->dev);
|
||||
|
||||
clk_data = devm_kzalloc(&pdev->dev,
|
||||
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
|
||||
struct_size(clk_data, hws, soc_data->num_clocks),
|
||||
GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
soc_data = device_get_match_data(&pdev->dev);
|
||||
clk_data->num = soc_data->num_clocks;
|
||||
r = soc_data->hw_init(pdev, clk_data);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -716,6 +726,7 @@ static int en7523_clk_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct en_clk_soc_data en7523_data = {
|
||||
.num_clocks = ARRAY_SIZE(en7523_base_clks) + 1,
|
||||
.pcie_ops = {
|
||||
.is_enabled = en7523_pci_is_enabled,
|
||||
.prepare = en7523_pci_prepare,
|
||||
|
@ -725,6 +736,8 @@ static const struct en_clk_soc_data en7523_data = {
|
|||
};
|
||||
|
||||
static const struct en_clk_soc_data en7581_data = {
|
||||
/* We increment num_clocks by 1 to account for additional PCIe clock */
|
||||
.num_clocks = ARRAY_SIZE(en7581_base_clks) + 1,
|
||||
.pcie_ops = {
|
||||
.is_enabled = en7581_pci_is_enabled,
|
||||
.enable = en7581_pci_enable,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Inspired by clk-asm9260.c .
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -34,11 +35,20 @@
|
|||
#define STM32F4_RCC_APB2ENR 0x44
|
||||
#define STM32F4_RCC_BDCR 0x70
|
||||
#define STM32F4_RCC_CSR 0x74
|
||||
#define STM32F4_RCC_SSCGR 0x80
|
||||
#define STM32F4_RCC_PLLI2SCFGR 0x84
|
||||
#define STM32F4_RCC_PLLSAICFGR 0x88
|
||||
#define STM32F4_RCC_DCKCFGR 0x8c
|
||||
#define STM32F7_RCC_DCKCFGR2 0x90
|
||||
|
||||
#define STM32F4_RCC_PLLCFGR_N_MASK GENMASK(14, 6)
|
||||
|
||||
#define STM32F4_RCC_SSCGR_SSCGEN BIT(31)
|
||||
#define STM32F4_RCC_SSCGR_SPREADSEL BIT(30)
|
||||
#define STM32F4_RCC_SSCGR_RESERVED_MASK GENMASK(29, 28)
|
||||
#define STM32F4_RCC_SSCGR_INCSTEP_MASK GENMASK(27, 13)
|
||||
#define STM32F4_RCC_SSCGR_MODPER_MASK GENMASK(12, 0)
|
||||
|
||||
#define NONE -1
|
||||
#define NO_IDX NONE
|
||||
#define NO_MUX NONE
|
||||
|
@ -364,6 +374,16 @@ static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
|
|||
{ STM32F4_RCC_APB2ENR, 30, "mdio", "apb2_div" },
|
||||
};
|
||||
|
||||
enum stm32f4_pll_ssc_mod_type {
|
||||
STM32F4_PLL_SSC_CENTER_SPREAD,
|
||||
STM32F4_PLL_SSC_DOWN_SPREAD,
|
||||
};
|
||||
|
||||
static const char * const stm32f4_ssc_mod_methods[] __initconst = {
|
||||
[STM32F4_PLL_SSC_DOWN_SPREAD] = "down-spread",
|
||||
[STM32F4_PLL_SSC_CENTER_SPREAD] = "center-spread",
|
||||
};
|
||||
|
||||
/*
|
||||
* This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
|
||||
* have gate bits associated with them. Its combined hweight is 71.
|
||||
|
@ -509,6 +529,12 @@ static const struct clk_div_table pll_divr_table[] = {
|
|||
{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
|
||||
};
|
||||
|
||||
struct stm32f4_pll_ssc {
|
||||
unsigned int mod_freq;
|
||||
unsigned int mod_depth;
|
||||
enum stm32f4_pll_ssc_mod_type mod_type;
|
||||
};
|
||||
|
||||
struct stm32f4_pll {
|
||||
spinlock_t *lock;
|
||||
struct clk_gate gate;
|
||||
|
@ -516,6 +542,8 @@ struct stm32f4_pll {
|
|||
u8 bit_rdy_idx;
|
||||
u8 status;
|
||||
u8 n_start;
|
||||
bool ssc_enable;
|
||||
struct stm32f4_pll_ssc ssc_conf;
|
||||
};
|
||||
|
||||
#define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
|
||||
|
@ -538,6 +566,7 @@ struct stm32f4_vco_data {
|
|||
u8 offset;
|
||||
u8 bit_idx;
|
||||
u8 bit_rdy_idx;
|
||||
bool sscg;
|
||||
};
|
||||
|
||||
static const struct stm32f4_vco_data vco_data[] = {
|
||||
|
@ -632,9 +661,11 @@ static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
|
|||
{
|
||||
struct clk_gate *gate = to_clk_gate(hw);
|
||||
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
|
||||
unsigned long val;
|
||||
unsigned long n;
|
||||
|
||||
n = (readl(base + pll->offset) >> 6) & 0x1ff;
|
||||
val = readl(base + pll->offset);
|
||||
n = FIELD_GET(STM32F4_RCC_PLLCFGR_N_MASK, val);
|
||||
|
||||
return parent_rate * n;
|
||||
}
|
||||
|
@ -656,6 +687,32 @@ static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return *prate * n;
|
||||
}
|
||||
|
||||
static void stm32f4_pll_set_ssc(struct clk_hw *hw, unsigned long parent_rate,
|
||||
unsigned int ndiv)
|
||||
{
|
||||
struct clk_gate *gate = to_clk_gate(hw);
|
||||
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
|
||||
struct stm32f4_pll_ssc *ssc = &pll->ssc_conf;
|
||||
u32 modeper, incstep;
|
||||
u32 sscgr;
|
||||
|
||||
sscgr = readl(base + STM32F4_RCC_SSCGR);
|
||||
/* reserved field must be kept at reset value */
|
||||
sscgr &= STM32F4_RCC_SSCGR_RESERVED_MASK;
|
||||
|
||||
modeper = DIV_ROUND_CLOSEST(parent_rate, 4 * ssc->mod_freq);
|
||||
incstep = DIV_ROUND_CLOSEST(((1 << 15) - 1) * ssc->mod_depth * ndiv,
|
||||
5 * 10000 * modeper);
|
||||
sscgr |= STM32F4_RCC_SSCGR_SSCGEN |
|
||||
FIELD_PREP(STM32F4_RCC_SSCGR_INCSTEP_MASK, incstep) |
|
||||
FIELD_PREP(STM32F4_RCC_SSCGR_MODPER_MASK, modeper);
|
||||
|
||||
if (ssc->mod_type)
|
||||
sscgr |= STM32F4_RCC_SSCGR_SPREADSEL;
|
||||
|
||||
writel(sscgr, base + STM32F4_RCC_SSCGR);
|
||||
}
|
||||
|
||||
static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
|
@ -673,9 +730,13 @@ static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
n = rate / parent_rate;
|
||||
|
||||
val = readl(base + pll->offset) & ~(0x1ff << 6);
|
||||
val = readl(base + pll->offset) & ~STM32F4_RCC_PLLCFGR_N_MASK;
|
||||
val |= FIELD_PREP(STM32F4_RCC_PLLCFGR_N_MASK, n);
|
||||
|
||||
writel(val | ((n & 0x1ff) << 6), base + pll->offset);
|
||||
writel(val, base + pll->offset);
|
||||
|
||||
if (pll->ssc_enable)
|
||||
stm32f4_pll_set_ssc(hw, parent_rate, n);
|
||||
|
||||
if (pll_state)
|
||||
stm32f4_pll_enable(hw);
|
||||
|
@ -782,6 +843,84 @@ static struct clk_hw *clk_register_pll_div(const char *name,
|
|||
return hw;
|
||||
}
|
||||
|
||||
static int __init stm32f4_pll_init_ssc(struct clk_hw *hw,
|
||||
const struct stm32f4_pll_ssc *conf)
|
||||
{
|
||||
struct clk_gate *gate = to_clk_gate(hw);
|
||||
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate;
|
||||
int pll_state;
|
||||
unsigned long n, val;
|
||||
|
||||
parent = clk_hw_get_parent(hw);
|
||||
if (!parent) {
|
||||
pr_err("%s: failed to get clock parent\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
|
||||
pll->ssc_enable = true;
|
||||
memcpy(&pll->ssc_conf, conf, sizeof(pll->ssc_conf));
|
||||
|
||||
pll_state = stm32f4_pll_is_enabled(hw);
|
||||
|
||||
if (pll_state)
|
||||
stm32f4_pll_disable(hw);
|
||||
|
||||
val = readl(base + pll->offset);
|
||||
n = FIELD_GET(STM32F4_RCC_PLLCFGR_N_MASK, val);
|
||||
|
||||
pr_debug("%s: pll: %s, parent: %s, parent-rate: %lu, n: %lu\n",
|
||||
__func__, clk_hw_get_name(hw), clk_hw_get_name(parent),
|
||||
parent_rate, n);
|
||||
|
||||
stm32f4_pll_set_ssc(hw, parent_rate, n);
|
||||
|
||||
if (pll_state)
|
||||
stm32f4_pll_enable(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init stm32f4_pll_ssc_parse_dt(struct device_node *np,
|
||||
struct stm32f4_pll_ssc *conf)
|
||||
{
|
||||
int ret;
|
||||
const char *s;
|
||||
|
||||
if (!conf)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_property_read_u32(np, "st,ssc-modfreq-hz", &conf->mod_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_property_read_u32(np, "st,ssc-moddepth-permyriad",
|
||||
&conf->mod_depth);
|
||||
if (ret) {
|
||||
pr_err("%pOF: missing st,ssc-moddepth-permyriad\n", np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fwnode_property_match_property_string(of_fwnode_handle(np),
|
||||
"st,ssc-modmethod",
|
||||
stm32f4_ssc_mod_methods,
|
||||
ARRAY_SIZE(stm32f4_ssc_mod_methods));
|
||||
if (ret < 0) {
|
||||
pr_err("%pOF: failed to get st,ssc-modmethod\n", np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
conf->mod_type = ret;
|
||||
|
||||
pr_debug("%pOF: SSCG settings: mod_freq: %d, mod_depth: %d mod_method: %s [%d]\n",
|
||||
np, conf->mod_freq, conf->mod_depth, s, conf->mod_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc,
|
||||
const struct stm32f4_pll_data *data, spinlock_t *lock)
|
||||
{
|
||||
|
@ -1689,7 +1828,8 @@ static void __init stm32f4_rcc_init(struct device_node *np)
|
|||
const struct of_device_id *match;
|
||||
const struct stm32f4_clk_data *data;
|
||||
unsigned long pllm;
|
||||
struct clk_hw *pll_src_hw;
|
||||
struct clk_hw *pll_src_hw, *pll_vco_hw;
|
||||
struct stm32f4_pll_ssc ssc_conf;
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
|
@ -1748,8 +1888,8 @@ static void __init stm32f4_rcc_init(struct device_node *np)
|
|||
clk_hw_register_fixed_factor(NULL, "vco_in", pll_src,
|
||||
0, 1, pllm);
|
||||
|
||||
stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
|
||||
&stm32f4_clk_lock);
|
||||
pll_vco_hw = stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
|
||||
&stm32f4_clk_lock);
|
||||
|
||||
clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
|
||||
&data->pll_data[1], &stm32f4_clk_lock);
|
||||
|
@ -1894,6 +2034,9 @@ static void __init stm32f4_rcc_init(struct device_node *np)
|
|||
|
||||
of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
|
||||
|
||||
if (!stm32f4_pll_ssc_parse_dt(np, &ssc_conf))
|
||||
stm32f4_pll_init_ssc(pll_vco_hw, &ssc_conf);
|
||||
|
||||
return;
|
||||
fail:
|
||||
kfree(clks);
|
||||
|
|
|
@ -2530,7 +2530,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
|||
rate = clk_core_req_round_rate_nolock(core, req_rate);
|
||||
|
||||
/* bail early if nothing to do */
|
||||
if (rate == clk_core_get_rate_recalc(core))
|
||||
if (rate == clk_core_get_rate_nolock(core))
|
||||
return 0;
|
||||
|
||||
/* fail on a direct rate set of a protected provider */
|
||||
|
|
|
@ -106,7 +106,7 @@ config COMMON_CLK_AXG_AUDIO
|
|||
select COMMON_CLK_MESON_SCLK_DIV
|
||||
select COMMON_CLK_MESON_CLKC_UTILS
|
||||
select REGMAP_MMIO
|
||||
depends on RESET_MESON_AUX
|
||||
select RESET_CONTROLLER
|
||||
help
|
||||
Support for the audio clock controller on AmLogic A113D devices,
|
||||
aka axg, Say Y if you want audio subsystem to work.
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <soc/amlogic/reset-meson-aux.h>
|
||||
|
||||
#include "meson-clkc-utils.h"
|
||||
#include "axg-audio.h"
|
||||
#include "clk-regmap.h"
|
||||
|
@ -1680,6 +1678,84 @@ static struct clk_regmap *const sm1_clk_regmaps[] = {
|
|||
&sm1_earcrx_dmac_clk,
|
||||
};
|
||||
|
||||
struct axg_audio_reset_data {
|
||||
struct reset_controller_dev rstc;
|
||||
struct regmap *map;
|
||||
unsigned int offset;
|
||||
};
|
||||
|
||||
static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst,
|
||||
unsigned long id,
|
||||
unsigned int *reg,
|
||||
unsigned int *bit)
|
||||
{
|
||||
unsigned int stride = regmap_get_reg_stride(rst->map);
|
||||
|
||||
*reg = (id / (stride * BITS_PER_BYTE)) * stride;
|
||||
*reg += rst->offset;
|
||||
*bit = id % (stride * BITS_PER_BYTE);
|
||||
}
|
||||
|
||||
static int axg_audio_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
struct axg_audio_reset_data *rst =
|
||||
container_of(rcdev, struct axg_audio_reset_data, rstc);
|
||||
unsigned int offset, bit;
|
||||
|
||||
axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
|
||||
|
||||
regmap_update_bits(rst->map, offset, BIT(bit),
|
||||
assert ? BIT(bit) : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axg_audio_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct axg_audio_reset_data *rst =
|
||||
container_of(rcdev, struct axg_audio_reset_data, rstc);
|
||||
unsigned int val, offset, bit;
|
||||
|
||||
axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
|
||||
|
||||
regmap_read(rst->map, offset, &val);
|
||||
|
||||
return !!(val & BIT(bit));
|
||||
}
|
||||
|
||||
static int axg_audio_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return axg_audio_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return axg_audio_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = axg_audio_reset_assert(rcdev, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return axg_audio_reset_deassert(rcdev, id);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops axg_audio_rstc_ops = {
|
||||
.assert = axg_audio_reset_assert,
|
||||
.deassert = axg_audio_reset_deassert,
|
||||
.reset = axg_audio_reset_toggle,
|
||||
.status = axg_audio_reset_status,
|
||||
};
|
||||
|
||||
static struct regmap_config axg_audio_regmap_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
|
@ -1690,14 +1766,16 @@ struct audioclk_data {
|
|||
struct clk_regmap *const *regmap_clks;
|
||||
unsigned int regmap_clk_num;
|
||||
struct meson_clk_hw_data hw_clks;
|
||||
unsigned int reset_offset;
|
||||
unsigned int reset_num;
|
||||
unsigned int max_register;
|
||||
const char *rst_drvname;
|
||||
};
|
||||
|
||||
static int axg_audio_clkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct audioclk_data *data;
|
||||
struct axg_audio_reset_data *rst;
|
||||
struct regmap *map;
|
||||
void __iomem *regs;
|
||||
struct clk_hw *hw;
|
||||
|
@ -1756,11 +1834,22 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Register auxiliary reset driver when applicable */
|
||||
if (data->rst_drvname)
|
||||
ret = devm_meson_rst_aux_register(dev, map, data->rst_drvname);
|
||||
/* Stop here if there is no reset */
|
||||
if (!data->reset_num)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
|
||||
if (!rst)
|
||||
return -ENOMEM;
|
||||
|
||||
rst->map = map;
|
||||
rst->offset = data->reset_offset;
|
||||
rst->rstc.nr_resets = data->reset_num;
|
||||
rst->rstc.ops = &axg_audio_rstc_ops;
|
||||
rst->rstc.of_node = dev->of_node;
|
||||
rst->rstc.owner = THIS_MODULE;
|
||||
|
||||
return devm_reset_controller_register(dev, &rst->rstc);
|
||||
}
|
||||
|
||||
static const struct audioclk_data axg_audioclk_data = {
|
||||
|
@ -1780,8 +1869,9 @@ static const struct audioclk_data g12a_audioclk_data = {
|
|||
.hws = g12a_audio_hw_clks,
|
||||
.num = ARRAY_SIZE(g12a_audio_hw_clks),
|
||||
},
|
||||
.reset_offset = AUDIO_SW_RESET,
|
||||
.reset_num = 26,
|
||||
.max_register = AUDIO_CLK_SPDIFOUT_B_CTRL,
|
||||
.rst_drvname = "rst-g12a",
|
||||
};
|
||||
|
||||
static const struct audioclk_data sm1_audioclk_data = {
|
||||
|
@ -1791,8 +1881,9 @@ static const struct audioclk_data sm1_audioclk_data = {
|
|||
.hws = sm1_audio_hw_clks,
|
||||
.num = ARRAY_SIZE(sm1_audio_hw_clks),
|
||||
},
|
||||
.reset_offset = AUDIO_SM1_SW_RESET0,
|
||||
.reset_num = 39,
|
||||
.max_register = AUDIO_EARCRX_DMAC_CLK_CTRL,
|
||||
.rst_drvname = "rst-sm1",
|
||||
};
|
||||
|
||||
static const struct of_device_id clkc_match_table[] = {
|
||||
|
|
|
@ -13,6 +13,7 @@ clk-rockchip-y += clk-inverter.o
|
|||
clk-rockchip-y += clk-mmc-phase.o
|
||||
clk-rockchip-y += clk-muxgrf.o
|
||||
clk-rockchip-y += clk-ddr.o
|
||||
clk-rockchip-y += gate-link.o
|
||||
clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o
|
||||
|
||||
obj-$(CONFIG_CLK_PX30) += clk-px30.o
|
||||
|
|
|
@ -12,28 +12,6 @@
|
|||
#include <dt-bindings/clock/rockchip,rk3588-cru.h>
|
||||
#include "clk.h"
|
||||
|
||||
/*
|
||||
* Recent Rockchip SoCs have a new hardware block called Native Interface
|
||||
* Unit (NIU), which gates clocks to devices behind them. These effectively
|
||||
* need two parent clocks.
|
||||
*
|
||||
* Downstream enables the linked clock via runtime PM whenever the gate is
|
||||
* enabled. This implementation uses separate clock nodes for each of the
|
||||
* linked gate clocks, which leaks parts of the clock tree into DT.
|
||||
*
|
||||
* The GATE_LINK macro instead takes the second parent via 'linkname', but
|
||||
* ignores the information. Once the clock framework is ready to handle it, the
|
||||
* information should be passed on here. But since these clocks are required to
|
||||
* access multiple relevant IP blocks, such as PCIe or USB, we mark all linked
|
||||
* clocks critical until a better solution is available. This will waste some
|
||||
* power, but avoids leaking implementation details into DT or hanging the
|
||||
* system.
|
||||
*/
|
||||
#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \
|
||||
GATE(_id, cname, pname, f, o, b, gf)
|
||||
#define RK3588_LINKED_CLK CLK_IS_CRITICAL
|
||||
|
||||
|
||||
#define RK3588_GRF_SOC_STATUS0 0x600
|
||||
#define RK3588_PHYREF_ALT_GATE 0xc38
|
||||
|
||||
|
@ -266,6 +244,8 @@ static struct rockchip_pll_rate_table rk3588_pll_rates[] = {
|
|||
}, \
|
||||
}
|
||||
|
||||
static struct rockchip_clk_provider *early_ctx;
|
||||
|
||||
static struct rockchip_cpuclk_rate_table rk3588_cpub0clk_rates[] __initdata = {
|
||||
RK3588_CPUB01CLK_RATE(2496000000, 1),
|
||||
RK3588_CPUB01CLK_RATE(2400000000, 1),
|
||||
|
@ -694,7 +674,7 @@ static struct rockchip_pll_clock rk3588_pll_clks[] __initdata = {
|
|||
RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates),
|
||||
};
|
||||
|
||||
static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
||||
static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
|
||||
/*
|
||||
* CRU Clock-Architecture
|
||||
*/
|
||||
|
@ -792,10 +772,10 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
COMPOSITE(MCLK_GMAC0_OUT, "mclk_gmac0_out", gpll_cpll_p, 0,
|
||||
RK3588_CLKSEL_CON(15), 7, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RK3588_CLKGATE_CON(5), 3, GFLAGS),
|
||||
COMPOSITE(REFCLKO25M_ETH0_OUT, "refclko25m_eth0_out", gpll_cpll_p, 0,
|
||||
COMPOSITE(REFCLKO25M_ETH0_OUT, "refclko25m_eth0_out", gpll_cpll_p, CLK_IS_CRITICAL,
|
||||
RK3588_CLKSEL_CON(15), 15, 1, MFLAGS, 8, 7, DFLAGS,
|
||||
RK3588_CLKGATE_CON(5), 4, GFLAGS),
|
||||
COMPOSITE(REFCLKO25M_ETH1_OUT, "refclko25m_eth1_out", gpll_cpll_p, 0,
|
||||
COMPOSITE(REFCLKO25M_ETH1_OUT, "refclko25m_eth1_out", gpll_cpll_p, CLK_IS_CRITICAL,
|
||||
RK3588_CLKSEL_CON(16), 7, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RK3588_CLKGATE_CON(5), 5, GFLAGS),
|
||||
COMPOSITE(CLK_CIFOUT_OUT, "clk_cifout_out", gpll_cpll_24m_spll_p, 0,
|
||||
|
@ -1456,7 +1436,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
COMPOSITE_NODIV(HCLK_NVM_ROOT, "hclk_nvm_root", mux_200m_100m_50m_24m_p, 0,
|
||||
RK3588_CLKSEL_CON(77), 0, 2, MFLAGS,
|
||||
RK3588_CLKGATE_CON(31), 0, GFLAGS),
|
||||
COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, 0,
|
||||
RK3588_CLKSEL_CON(77), 7, 1, MFLAGS, 2, 5, DFLAGS,
|
||||
RK3588_CLKGATE_CON(31), 1, GFLAGS),
|
||||
GATE(ACLK_EMMC, "aclk_emmc", "aclk_nvm_root", 0,
|
||||
|
@ -1685,13 +1665,13 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
RK3588_CLKGATE_CON(42), 9, GFLAGS),
|
||||
|
||||
/* vdpu */
|
||||
COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, 0,
|
||||
RK3588_CLKSEL_CON(98), 5, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RK3588_CLKGATE_CON(44), 0, GFLAGS),
|
||||
COMPOSITE_NODIV(ACLK_VDPU_LOW_ROOT, "aclk_vdpu_low_root", mux_400m_200m_100m_24m_p, 0,
|
||||
RK3588_CLKSEL_CON(98), 7, 2, MFLAGS,
|
||||
RK3588_CLKGATE_CON(44), 1, GFLAGS),
|
||||
COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, 0,
|
||||
RK3588_CLKSEL_CON(98), 9, 2, MFLAGS,
|
||||
RK3588_CLKGATE_CON(44), 2, GFLAGS),
|
||||
COMPOSITE(ACLK_JPEG_DECODER_ROOT, "aclk_jpeg_decoder_root", gpll_cpll_aupll_spll_p, 0,
|
||||
|
@ -1742,9 +1722,9 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
COMPOSITE(ACLK_RKVENC0_ROOT, "aclk_rkvenc0_root", gpll_cpll_npll_p, 0,
|
||||
RK3588_CLKSEL_CON(102), 7, 2, MFLAGS, 2, 5, DFLAGS,
|
||||
RK3588_CLKGATE_CON(47), 1, GFLAGS),
|
||||
GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", RK3588_LINKED_CLK,
|
||||
GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", 0,
|
||||
RK3588_CLKGATE_CON(47), 4, GFLAGS),
|
||||
GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", RK3588_LINKED_CLK,
|
||||
GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", 0,
|
||||
RK3588_CLKGATE_CON(47), 5, GFLAGS),
|
||||
COMPOSITE(CLK_RKVENC0_CORE, "clk_rkvenc0_core", gpll_cpll_aupll_npll_p, 0,
|
||||
RK3588_CLKSEL_CON(102), 14, 2, MFLAGS, 9, 5, DFLAGS,
|
||||
|
@ -1754,10 +1734,10 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
RK3588_CLKGATE_CON(48), 6, GFLAGS),
|
||||
|
||||
/* vi */
|
||||
COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, 0,
|
||||
RK3588_CLKSEL_CON(106), 5, 3, MFLAGS, 0, 5, DFLAGS,
|
||||
RK3588_CLKGATE_CON(49), 0, GFLAGS),
|
||||
COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, 0,
|
||||
RK3588_CLKSEL_CON(106), 8, 2, MFLAGS,
|
||||
RK3588_CLKGATE_CON(49), 1, GFLAGS),
|
||||
COMPOSITE_NODIV(PCLK_VI_ROOT, "pclk_vi_root", mux_100m_50m_24m_p, 0,
|
||||
|
@ -1927,10 +1907,10 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0,
|
||||
RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS,
|
||||
RK3588_CLKGATE_CON(52), 0, GFLAGS),
|
||||
COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0,
|
||||
RK3588_CLKSEL_CON(110), 8, 2, MFLAGS,
|
||||
RK3588_CLKGATE_CON(52), 1, GFLAGS),
|
||||
COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK,
|
||||
COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, 0,
|
||||
RK3588_CLKSEL_CON(110), 10, 2, MFLAGS,
|
||||
RK3588_CLKGATE_CON(52), 2, GFLAGS),
|
||||
COMPOSITE_NODIV(PCLK_VOP_ROOT, "pclk_vop_root", mux_100m_50m_24m_p, 0,
|
||||
|
@ -2428,10 +2408,12 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
RK3588_CLKGATE_CON(68), 5, GFLAGS),
|
||||
GATE(ACLK_AV1, "aclk_av1", "aclk_av1_pre", 0,
|
||||
RK3588_CLKGATE_CON(68), 2, GFLAGS),
|
||||
};
|
||||
|
||||
static struct rockchip_clk_branch rk3588_clk_branches[] = {
|
||||
GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", ACLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 6, GFLAGS),
|
||||
GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", HCLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 8, GFLAGS),
|
||||
GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS),
|
||||
GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, 0, RK3588_CLKGATE_CON(31), 2, GFLAGS),
|
||||
GATE_LINK(ACLK_USB, "aclk_usb", "aclk_usb_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 2, GFLAGS),
|
||||
GATE_LINK(HCLK_USB, "hclk_usb", "hclk_usb_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 3, GFLAGS),
|
||||
GATE_LINK(ACLK_JPEG_DECODER_PRE, "aclk_jpeg_decoder_pre", "aclk_jpeg_decoder_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(44), 7, GFLAGS),
|
||||
|
@ -2443,9 +2425,9 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
GATE_LINK(HCLK_RKVDEC1_PRE, "hclk_rkvdec1_pre", "hclk_rkvdec1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 4, GFLAGS),
|
||||
GATE_LINK(ACLK_RKVDEC1_PRE, "aclk_rkvdec1_pre", "aclk_rkvdec1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 5, GFLAGS),
|
||||
GATE_LINK(ACLK_HDCP0_PRE, "aclk_hdcp0_pre", "aclk_vo0_root", ACLK_VOP_LOW_ROOT, 0, RK3588_CLKGATE_CON(55), 9, GFLAGS),
|
||||
GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(55), 5, GFLAGS),
|
||||
GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, 0, RK3588_CLKGATE_CON(55), 5, GFLAGS),
|
||||
GATE_LINK(ACLK_HDCP1_PRE, "aclk_hdcp1_pre", "aclk_hdcp1_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 6, GFLAGS),
|
||||
GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(59), 9, GFLAGS),
|
||||
GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 9, GFLAGS),
|
||||
GATE_LINK(ACLK_AV1_PRE, "aclk_av1_pre", "aclk_av1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 1, GFLAGS),
|
||||
GATE_LINK(PCLK_AV1_PRE, "pclk_av1_pre", "pclk_av1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 4, GFLAGS),
|
||||
GATE_LINK(HCLK_SDIO_PRE, "hclk_sdio_pre", "hclk_sdio_root", HCLK_NVM, 0, RK3588_CLKGATE_CON(75), 1, GFLAGS),
|
||||
|
@ -2453,26 +2435,31 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
|
|||
GATE_LINK(PCLK_VO1GRF, "pclk_vo1grf", "pclk_vo1_root", HCLK_VO1, CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(59), 12, GFLAGS),
|
||||
};
|
||||
|
||||
static void __init rk3588_clk_init(struct device_node *np)
|
||||
static void __init rk3588_clk_early_init(struct device_node *np)
|
||||
{
|
||||
struct rockchip_clk_provider *ctx;
|
||||
unsigned long clk_nr_clks;
|
||||
unsigned long clk_nr_clks, max_clk_id1, max_clk_id2;
|
||||
void __iomem *reg_base;
|
||||
|
||||
clk_nr_clks = rockchip_clk_find_max_clk_id(rk3588_clk_branches,
|
||||
ARRAY_SIZE(rk3588_clk_branches)) + 1;
|
||||
max_clk_id1 = rockchip_clk_find_max_clk_id(rk3588_clk_branches,
|
||||
ARRAY_SIZE(rk3588_clk_branches));
|
||||
max_clk_id2 = rockchip_clk_find_max_clk_id(rk3588_early_clk_branches,
|
||||
ARRAY_SIZE(rk3588_early_clk_branches));
|
||||
clk_nr_clks = max(max_clk_id1, max_clk_id2) + 1;
|
||||
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base) {
|
||||
pr_err("%s: could not map cru region\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = rockchip_clk_init(np, reg_base, clk_nr_clks);
|
||||
ctx = rockchip_clk_init_early(np, reg_base, clk_nr_clks);
|
||||
if (IS_ERR(ctx)) {
|
||||
pr_err("%s: rockchip clk init failed\n", __func__);
|
||||
iounmap(reg_base);
|
||||
return;
|
||||
}
|
||||
early_ctx = ctx;
|
||||
|
||||
rockchip_clk_register_plls(ctx, rk3588_pll_clks,
|
||||
ARRAY_SIZE(rk3588_pll_clks),
|
||||
|
@ -2491,14 +2478,55 @@ static void __init rk3588_clk_init(struct device_node *np)
|
|||
&rk3588_cpub1clk_data, rk3588_cpub1clk_rates,
|
||||
ARRAY_SIZE(rk3588_cpub1clk_rates));
|
||||
|
||||
rockchip_clk_register_branches(ctx, rk3588_clk_branches,
|
||||
ARRAY_SIZE(rk3588_clk_branches));
|
||||
|
||||
rk3588_rst_init(np, reg_base);
|
||||
|
||||
rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL);
|
||||
rockchip_clk_register_branches(ctx, rk3588_early_clk_branches,
|
||||
ARRAY_SIZE(rk3588_early_clk_branches));
|
||||
|
||||
rockchip_clk_of_add_provider(np, ctx);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_early_init);
|
||||
|
||||
CLK_OF_DECLARE(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_init);
|
||||
static int clk_rk3588_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_clk_provider *ctx = early_ctx;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
rockchip_clk_register_late_branches(dev, ctx, rk3588_clk_branches,
|
||||
ARRAY_SIZE(rk3588_clk_branches));
|
||||
|
||||
rockchip_clk_finalize(ctx);
|
||||
|
||||
rk3588_rst_init(np, ctx->reg_base);
|
||||
rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL);
|
||||
|
||||
/*
|
||||
* Re-add clock provider, so that the newly added clocks are also
|
||||
* re-parented and get their defaults configured.
|
||||
*/
|
||||
of_clk_del_provider(np);
|
||||
rockchip_clk_of_add_provider(np, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id clk_rk3588_match_table[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3588-cru",
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver clk_rk3588_driver = {
|
||||
.probe = clk_rk3588_probe,
|
||||
.driver = {
|
||||
.name = "clk-rk3588",
|
||||
.of_match_table = clk_rk3588_match_table,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rockchip_clk_rk3588_drv_register(void)
|
||||
{
|
||||
return platform_driver_register(&clk_rk3588_driver);
|
||||
}
|
||||
core_initcall(rockchip_clk_rk3588_drv_register);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
|
@ -197,12 +198,6 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
|
|||
clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n);
|
||||
}
|
||||
|
||||
static void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
|
||||
struct clk *clk, unsigned int id)
|
||||
{
|
||||
ctx->clk_data.clks[id] = clk;
|
||||
}
|
||||
|
||||
static struct clk *rockchip_clk_register_frac_branch(
|
||||
struct rockchip_clk_provider *ctx, const char *name,
|
||||
const char *const *parent_names, u8 num_parents,
|
||||
|
@ -292,7 +287,7 @@ static struct clk *rockchip_clk_register_frac_branch(
|
|||
return mux_clk;
|
||||
}
|
||||
|
||||
rockchip_clk_add_lookup(ctx, mux_clk, child->id);
|
||||
rockchip_clk_set_lookup(ctx, mux_clk, child->id);
|
||||
|
||||
/* notifier on the fraction divider to catch rate changes */
|
||||
if (frac->mux_frac_idx >= 0) {
|
||||
|
@ -359,14 +354,17 @@ static struct clk *rockchip_clk_register_factor_branch(const char *name,
|
|||
return hw->clk;
|
||||
}
|
||||
|
||||
struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
|
||||
void __iomem *base,
|
||||
unsigned long nr_clks)
|
||||
static struct rockchip_clk_provider *rockchip_clk_init_base(
|
||||
struct device_node *np, void __iomem *base,
|
||||
unsigned long nr_clks, bool has_late_clocks)
|
||||
{
|
||||
struct rockchip_clk_provider *ctx;
|
||||
struct clk **clk_table;
|
||||
struct clk *default_clk_val;
|
||||
int i;
|
||||
|
||||
default_clk_val = ERR_PTR(has_late_clocks ? -EPROBE_DEFER : -ENOENT);
|
||||
|
||||
ctx = kzalloc(sizeof(struct rockchip_clk_provider), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -376,7 +374,7 @@ struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
|
|||
goto err_free;
|
||||
|
||||
for (i = 0; i < nr_clks; ++i)
|
||||
clk_table[i] = ERR_PTR(-ENOENT);
|
||||
clk_table[i] = default_clk_val;
|
||||
|
||||
ctx->reg_base = base;
|
||||
ctx->clk_data.clks = clk_table;
|
||||
|
@ -393,8 +391,33 @@ err_free:
|
|||
kfree(ctx);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
|
||||
void __iomem *base,
|
||||
unsigned long nr_clks)
|
||||
{
|
||||
return rockchip_clk_init_base(np, base, nr_clks, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_init);
|
||||
|
||||
struct rockchip_clk_provider *rockchip_clk_init_early(struct device_node *np,
|
||||
void __iomem *base,
|
||||
unsigned long nr_clks)
|
||||
{
|
||||
return rockchip_clk_init_base(np, base, nr_clks, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_init_early);
|
||||
|
||||
void rockchip_clk_finalize(struct rockchip_clk_provider *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ctx->clk_data.clk_num; ++i)
|
||||
if (ctx->clk_data.clks[i] == ERR_PTR(-EPROBE_DEFER))
|
||||
ctx->clk_data.clks[i] = ERR_PTR(-ENOENT);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_finalize);
|
||||
|
||||
void rockchip_clk_of_add_provider(struct device_node *np,
|
||||
struct rockchip_clk_provider *ctx)
|
||||
{
|
||||
|
@ -424,7 +447,7 @@ void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
|
|||
continue;
|
||||
}
|
||||
|
||||
rockchip_clk_add_lookup(ctx, clk, list->id);
|
||||
rockchip_clk_set_lookup(ctx, clk, list->id);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_register_plls);
|
||||
|
@ -446,6 +469,29 @@ unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id);
|
||||
|
||||
static struct platform_device *rockchip_clk_register_gate_link(
|
||||
struct device *parent_dev,
|
||||
struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_clk_branch *clkbr)
|
||||
{
|
||||
struct rockchip_gate_link_platdata gate_link_pdata = {
|
||||
.ctx = ctx,
|
||||
.clkbr = clkbr,
|
||||
};
|
||||
|
||||
struct platform_device_info pdevinfo = {
|
||||
.parent = parent_dev,
|
||||
.name = "rockchip-gate-link-clk",
|
||||
.id = clkbr->id,
|
||||
.fwnode = dev_fwnode(parent_dev),
|
||||
.of_node_reused = true,
|
||||
.data = &gate_link_pdata,
|
||||
.size_data = sizeof(gate_link_pdata),
|
||||
};
|
||||
|
||||
return platform_device_register_full(&pdevinfo);
|
||||
}
|
||||
|
||||
void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_clk_branch *list,
|
||||
unsigned int nr_clk)
|
||||
|
@ -571,6 +617,9 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
|
|||
list->div_width, list->div_flags,
|
||||
ctx->reg_base, &ctx->lock);
|
||||
break;
|
||||
case branch_linked_gate:
|
||||
/* must be registered late, fall-through for error message */
|
||||
break;
|
||||
}
|
||||
|
||||
/* none of the cases above matched */
|
||||
|
@ -586,11 +635,36 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
|
|||
continue;
|
||||
}
|
||||
|
||||
rockchip_clk_add_lookup(ctx, clk, list->id);
|
||||
rockchip_clk_set_lookup(ctx, clk, list->id);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_register_branches);
|
||||
|
||||
void rockchip_clk_register_late_branches(struct device *dev,
|
||||
struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_clk_branch *list,
|
||||
unsigned int nr_clk)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||
struct platform_device *pdev = NULL;
|
||||
|
||||
switch (list->branch_type) {
|
||||
case branch_linked_gate:
|
||||
pdev = rockchip_clk_register_gate_link(dev, ctx, list);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unknown clock type %d\n", list->branch_type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pdev)
|
||||
dev_err(dev, "failed to register device for clock %s\n", list->name);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_register_late_branches);
|
||||
|
||||
void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
|
||||
unsigned int lookup_id,
|
||||
const char *name, const char *const *parent_names,
|
||||
|
@ -610,7 +684,7 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
|
|||
return;
|
||||
}
|
||||
|
||||
rockchip_clk_add_lookup(ctx, clk, lookup_id);
|
||||
rockchip_clk_set_lookup(ctx, clk, lookup_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk);
|
||||
|
||||
|
|
|
@ -570,6 +570,7 @@ enum rockchip_clk_branch_type {
|
|||
branch_divider,
|
||||
branch_fraction_divider,
|
||||
branch_gate,
|
||||
branch_linked_gate,
|
||||
branch_mmc,
|
||||
branch_inverter,
|
||||
branch_factor,
|
||||
|
@ -597,6 +598,7 @@ struct rockchip_clk_branch {
|
|||
int gate_offset;
|
||||
u8 gate_shift;
|
||||
u8 gate_flags;
|
||||
unsigned int linked_clk_id;
|
||||
struct rockchip_clk_branch *child;
|
||||
};
|
||||
|
||||
|
@ -895,6 +897,20 @@ struct rockchip_clk_branch {
|
|||
.gate_flags = gf, \
|
||||
}
|
||||
|
||||
#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.branch_type = branch_linked_gate, \
|
||||
.name = cname, \
|
||||
.parent_names = (const char *[]){ pname }, \
|
||||
.linked_clk_id = linkedclk, \
|
||||
.num_parents = 1, \
|
||||
.flags = f, \
|
||||
.gate_offset = o, \
|
||||
.gate_shift = b, \
|
||||
.gate_flags = gf, \
|
||||
}
|
||||
|
||||
#define MMC(_id, cname, pname, offset, shift) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
|
@ -1022,8 +1038,28 @@ struct rockchip_clk_branch {
|
|||
#define SGRF_GATE(_id, cname, pname) \
|
||||
FACTOR(_id, cname, pname, 0, 1, 1)
|
||||
|
||||
static inline struct clk *rockchip_clk_get_lookup(struct rockchip_clk_provider *ctx,
|
||||
unsigned int id)
|
||||
{
|
||||
return ctx->clk_data.clks[id];
|
||||
}
|
||||
|
||||
static inline void rockchip_clk_set_lookup(struct rockchip_clk_provider *ctx,
|
||||
struct clk *clk, unsigned int id)
|
||||
{
|
||||
ctx->clk_data.clks[id] = clk;
|
||||
}
|
||||
|
||||
struct rockchip_gate_link_platdata {
|
||||
struct rockchip_clk_provider *ctx;
|
||||
struct rockchip_clk_branch *clkbr;
|
||||
};
|
||||
|
||||
struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
|
||||
void __iomem *base, unsigned long nr_clks);
|
||||
struct rockchip_clk_provider *rockchip_clk_init_early(struct device_node *np,
|
||||
void __iomem *base, unsigned long nr_clks);
|
||||
void rockchip_clk_finalize(struct rockchip_clk_provider *ctx);
|
||||
void rockchip_clk_of_add_provider(struct device_node *np,
|
||||
struct rockchip_clk_provider *ctx);
|
||||
unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list,
|
||||
|
@ -1031,6 +1067,10 @@ unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list,
|
|||
void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_clk_branch *list,
|
||||
unsigned int nr_clk);
|
||||
void rockchip_clk_register_late_branches(struct device *dev,
|
||||
struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_clk_branch *list,
|
||||
unsigned int nr_clk);
|
||||
void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_pll_clock *pll_list,
|
||||
unsigned int nr_pll, int grf_lock_offset);
|
||||
|
|
85
drivers/clk/rockchip/gate-link.c
Normal file
85
drivers/clk/rockchip/gate-link.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2024 Collabora Ltd.
|
||||
* Author: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include "clk.h"
|
||||
|
||||
static int rk_clk_gate_link_register(struct device *dev,
|
||||
struct rockchip_clk_provider *ctx,
|
||||
struct rockchip_clk_branch *clkbr)
|
||||
{
|
||||
unsigned long flags = clkbr->flags | CLK_SET_RATE_PARENT;
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_register_gate(dev, clkbr->name, clkbr->parent_names[0],
|
||||
flags, ctx->reg_base + clkbr->gate_offset,
|
||||
clkbr->gate_shift, clkbr->gate_flags,
|
||||
&ctx->lock);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
rockchip_clk_set_lookup(ctx, clk, clkbr->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_clk_gate_link_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_gate_link_platdata *pdata;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *linked_clk;
|
||||
int ret;
|
||||
|
||||
pdata = dev_get_platdata(dev);
|
||||
if (!pdata)
|
||||
return dev_err_probe(dev, -ENODEV, "missing platform data");
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_pm_clk_create(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
linked_clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->linked_clk_id);
|
||||
ret = pm_clk_add_clk(dev, linked_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rk_clk_gate_link_register(dev, pdata->ctx, pdata->clkbr);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pm_clk_remove_clk(dev, linked_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rk_clk_gate_link_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver rk_clk_gate_link_driver = {
|
||||
.probe = rk_clk_gate_link_probe,
|
||||
.driver = {
|
||||
.name = "rockchip-gate-link-clk",
|
||||
.pm = &rk_clk_gate_link_pm_ops,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rk_clk_gate_link_drv_register(void)
|
||||
{
|
||||
return platform_driver_register(&rk_clk_gate_link_driver);
|
||||
}
|
||||
core_initcall(rk_clk_gate_link_drv_register);
|
|
@ -657,7 +657,7 @@ static struct ccu_div apb_pclk = {
|
|||
.hw.init = CLK_HW_INIT_PARENTS_DATA("apb-pclk",
|
||||
apb_parents,
|
||||
&ccu_div_ops,
|
||||
0),
|
||||
CLK_IGNORE_UNUSED),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -787,13 +787,13 @@ static CCU_GATE(CLK_X2X_CPUSYS, x2x_cpusys_clk, "x2x-cpusys", axi4_cpusys2_aclk_
|
|||
0x134, BIT(7), 0);
|
||||
static CCU_GATE(CLK_CPU2AON_X2H, cpu2aon_x2h_clk, "cpu2aon-x2h", axi_aclk_pd, 0x138, BIT(8), 0);
|
||||
static CCU_GATE(CLK_CPU2PERI_X2H, cpu2peri_x2h_clk, "cpu2peri-x2h", axi4_cpusys2_aclk_pd,
|
||||
0x140, BIT(9), 0);
|
||||
0x140, BIT(9), CLK_IGNORE_UNUSED);
|
||||
static CCU_GATE(CLK_PERISYS_APB1_HCLK, perisys_apb1_hclk, "perisys-apb1-hclk", perisys_ahb_hclk_pd,
|
||||
0x150, BIT(9), 0);
|
||||
static CCU_GATE(CLK_PERISYS_APB2_HCLK, perisys_apb2_hclk, "perisys-apb2-hclk", perisys_ahb_hclk_pd,
|
||||
0x150, BIT(10), 0);
|
||||
0x150, BIT(10), CLK_IGNORE_UNUSED);
|
||||
static CCU_GATE(CLK_PERISYS_APB3_HCLK, perisys_apb3_hclk, "perisys-apb3-hclk", perisys_ahb_hclk_pd,
|
||||
0x150, BIT(11), 0);
|
||||
0x150, BIT(11), CLK_IGNORE_UNUSED);
|
||||
static CCU_GATE(CLK_PERISYS_APB4_HCLK, perisys_apb4_hclk, "perisys-apb4-hclk", perisys_ahb_hclk_pd,
|
||||
0x150, BIT(12), 0);
|
||||
static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, BIT(5), 0);
|
||||
|
@ -889,7 +889,6 @@ static struct ccu_common *th1520_div_clks[] = {
|
|||
&vo_axi_clk.common,
|
||||
&vp_apb_clk.common,
|
||||
&vp_axi_clk.common,
|
||||
&cpu2vp_clk.common,
|
||||
&venc_clk.common,
|
||||
&dpu0_clk.common,
|
||||
&dpu1_clk.common,
|
||||
|
@ -909,6 +908,7 @@ static struct ccu_common *th1520_gate_clks[] = {
|
|||
&bmu_clk.common,
|
||||
&cpu2aon_x2h_clk.common,
|
||||
&cpu2peri_x2h_clk.common,
|
||||
&cpu2vp_clk.common,
|
||||
&perisys_apb1_hclk.common,
|
||||
&perisys_apb2_hclk.common,
|
||||
&perisys_apb3_hclk.common,
|
||||
|
@ -1041,7 +1041,8 @@ static int th1520_clk_probe(struct platform_device *pdev)
|
|||
hw = devm_clk_hw_register_gate_parent_data(dev,
|
||||
cg->common.hw.init->name,
|
||||
cg->common.hw.init->parent_data,
|
||||
0, base + cg->common.cfg0,
|
||||
cg->common.hw.init->flags,
|
||||
base + cg->common.cfg0,
|
||||
ffs(cg->enable) - 1, 0, NULL);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
#define EN7523_CLK_CRYPTO 6
|
||||
#define EN7523_CLK_PCIE 7
|
||||
|
||||
#define EN7523_NUM_CLOCKS 8
|
||||
#define EN7581_CLK_EMMC 8
|
||||
|
||||
#endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* List of clocks which are not derived from system clock (SYSCLOCK)
|
||||
*
|
||||
* The index of these clocks is the secondary index of DT bindings
|
||||
* (see Documentation/devicetree/bindings/clock/st,stm32-rcc.txt)
|
||||
* (see Documentation/devicetree/bindings/clock/st,stm32-rcc.yaml)
|
||||
*
|
||||
* e.g:
|
||||
<assigned-clocks = <&rcc 1 CLK_LSE>;
|
||||
|
|
|
@ -152,6 +152,7 @@ enum rpi_firmware_clk_id {
|
|||
RPI_FIRMWARE_M2MC_CLK_ID,
|
||||
RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
|
||||
RPI_FIRMWARE_VEC_CLK_ID,
|
||||
RPI_FIRMWARE_DISP_CLK_ID,
|
||||
RPI_FIRMWARE_NUM_CLK_ID,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user