I'm actually surprised this time. There aren't any new Qualcomm SoC clk
drivers. And there's zero diff in the core clk framework. Instead we have new clk drivers for STM and Sophgo, with Samsung^WGoogle in third for the diffstat because they introduced HSI0 and HSI2 clk drivers for Google's GS101 SoC (high speed interface things like PCIe, UFS, and MMC). Beyond those big diffs there's the usual updates to various clk drivers for incorrect parent descriptions or mising MODULE_DEVICE_TABLE()s, etc. Nothing in particular stands out as super interesting here. New Drivers: - STM32MP257 SoC clk driver - Airoha EN7581 SoC clk driver - Sophgo CV1800B, CV1812H and SG2000 SoC clk driver - Loongson-2k0500 and Loongson-2k2000 SoC clk driver - Add HSI0 and HSI2 clock controllers for Google GS101 - Add i.MX95 BLK CTL clock driver Updates: - Allocate clk_ops dynamically for SCMI clk driver - Add support in qcom RCG and RCG2 for multiple configurations for the same frequency - Use above support for IPQ8074 NSS port 5 and 6 clocks to resolve issues - Fix the Qualcomm APSS IPQ5018 PLL to fix boot failures of some boards - Cleanups and fixes for Qualcomm Stromer PLLs - Reduce max CPU frequency on Qualcomm APSS IPQ5018 - Fix Kconfig dependencies of Qualcomm SM8650 GPU and SC8280XP camera clk drivers - Make Qualcomm MSM8998 Venus clocks functional - Cleanup downstream remnants related to DisplayPort across Qualcomm SM8450, SM6350, SM8550, and SM8650 - Reuse the Huayra APSS register map on Qualcomm MSM8996 CBF PLL - Use a specific Qualcomm QCS404 compatible for the otherwise generic HFPLL - Remove Qualcomm SM8150 CPUSS AHB clk as it is unused - Remove an unused field in the Qualcomm RPM clk driver - Add missing MODULE_DEVICE_TABLE to Qualcomm MSM8917 and MSM8953 global clock controller drivers - Allow choice of manual or firmware-driven control over PLLs, needed to fully implement CPU clock controllers on Exynos850 - Correct PLL clock IDs on ExynosAutov9 - Propagate certain clock rates to allow setting proper SPI clock rates on Google GS101 - Mark certain Google GS101 clocks critical - Convert old S3C64xx clock controller bindings to DT schema - Add new PLL rate and missing mux on Rockchip rk3568 - Add missing reset line on Rockchip rk3588 - Removal of an unused field in struct rockchip_mmc_clock - Amlogic s4/a1: add regmap maximum register for proper debugfs dump - Amlogic s4: add MODULE_DEVICE_TABLE() on pll and periph controllers - Amlogic pll driver: print clock name on lock error to help debug - Amlogic vclk: finish dsi clock path support - Amlogic license: fix occurence "GPL v2" as reported by checkpatch - Add PM runtime support to i.MX8MP Audiomix - Add DT schema for i.MX95 Display Master Block Control - Convert to platform remove callback returning void for i.MX8MP Audiomix - Add SPI (MSIOF) and external interrupt (INTC-EX) clocks on Renesas R-Car V4M - Add interrupt controller (PLIC) clock and reset on Renesas RZ/Five - Prepare power domain support for Renesas RZ/G2L family members, and add actual support on Renesas RZ/G3S SoC - Add thermal, serial (SCIF), and timer (CMT/TMU) clocks on Renesas R-Car V4M - Add additional constraints to Allwinner A64 PLL MIPI clock - Fix autoloading sunxi-ng clocks when build as a module -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAmZGs1MRHHNib3lkQGtl cm5lbC5vcmcACgkQrQKIl8bklSW2Pw/+OciG7jQzlWQD09M9qTSzygVu/0+NF8ez ecvLnWzz3b05GSWqfeG3mm09RmaTtggwPcWx4ad5NBDxGfhn+rT72WWJt6EjA1ln i/eNUQIlFZmiDM7Xwx6S841hcRbPz9/RRIeXtmiDkMWjsysr6MHlTkWWVMNfGkiE 9jxM5BH6N04A4664k3a4qlcZkj2KNkOLeCyzMLtm5aIwBoL3fZ+Q3sqVTgp5imt1 rzJgpGfN1QhAnd8kV2oIPtJEs9woZtRjCtTtLrTnoGf518uq25ZJx7Mz3Dx+ubUv dtOLjjXdM+Q/ou7DM3h7HRjiZC8Mp8CprwwoxEbckBL4gBWYPyu8e6eZNBsF+3Ol 7WP3TZknDrWsUDxAcX37Euidd+hc8xtbXCQwm+QcugEee7ZXK4ElTgXwyH3FUqn2 GBI5D0+/3WyoBLqVQ7nTkMV0ps5dHrpBj6J1u/7ZfvC23/E7/5CzIxULXt1hTOcI F1cqS78HLAc8BK3gw/63e5TtTMA4cItJD7InBB0jemfeoy03nuWzFbRUqtAStkHd BKxmGSV3XXMdGtiN5SFy3tk7NlKeFMiVBiTzD++Vx9IL3mCdArtULu93OfUIOzXW B/ekJKi9OHkJx3mBrbio6k4rugQDZovzWN9U2pDJtGCIaAXgYgwKuP8S9UwKLIcx R6QarNE5Rsc= =YoVJ -----END PGP SIGNATURE----- Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk updates from Stephen Boyd: "I'm actually surprised this time. There aren't any new Qualcomm SoC clk drivers. And there's zero diff in the core clk framework. Instead we have new clk drivers for STM and Sophgo, with Samsung^WGoogle in third for the diffstat because they introduced HSI0 and HSI2 clk drivers for Google's GS101 SoC (high speed interface things like PCIe, UFS, and MMC). Beyond those big diffs there's the usual updates to various clk drivers for incorrect parent descriptions or mising MODULE_DEVICE_TABLE()s, etc. Nothing in particular stands out as super interesting here. New Drivers: - STM32MP257 SoC clk driver - Airoha EN7581 SoC clk driver - Sophgo CV1800B, CV1812H and SG2000 SoC clk driver - Loongson-2k0500 and Loongson-2k2000 SoC clk driver - Add HSI0 and HSI2 clock controllers for Google GS101 - Add i.MX95 BLK CTL clock driver Updates: - Allocate clk_ops dynamically for SCMI clk driver - Add support in qcom RCG and RCG2 for multiple configurations for the same frequency - Use above support for IPQ8074 NSS port 5 and 6 clocks to resolve issues - Fix the Qualcomm APSS IPQ5018 PLL to fix boot failures of some boards - Cleanups and fixes for Qualcomm Stromer PLLs - Reduce max CPU frequency on Qualcomm APSS IPQ5018 - Fix Kconfig dependencies of Qualcomm SM8650 GPU and SC8280XP camera clk drivers - Make Qualcomm MSM8998 Venus clocks functional - Cleanup downstream remnants related to DisplayPort across Qualcomm SM8450, SM6350, SM8550, and SM8650 - Reuse the Huayra APSS register map on Qualcomm MSM8996 CBF PLL - Use a specific Qualcomm QCS404 compatible for the otherwise generic HFPLL - Remove Qualcomm SM8150 CPUSS AHB clk as it is unused - Remove an unused field in the Qualcomm RPM clk driver - Add missing MODULE_DEVICE_TABLE to Qualcomm MSM8917 and MSM8953 global clock controller drivers - Allow choice of manual or firmware-driven control over PLLs, needed to fully implement CPU clock controllers on Exynos850 - Correct PLL clock IDs on ExynosAutov9 - Propagate certain clock rates to allow setting proper SPI clock rates on Google GS101 - Mark certain Google GS101 clocks critical - Convert old S3C64xx clock controller bindings to DT schema - Add new PLL rate and missing mux on Rockchip rk3568 - Add missing reset line on Rockchip rk3588 - Removal of an unused field in struct rockchip_mmc_clock - Amlogic s4/a1: add regmap maximum register for proper debugfs dump - Amlogic s4: add MODULE_DEVICE_TABLE() on pll and periph controllers - Amlogic pll driver: print clock name on lock error to help debug - Amlogic vclk: finish dsi clock path support - Amlogic license: fix occurence "GPL v2" as reported by checkpatch - Add PM runtime support to i.MX8MP Audiomix - Add DT schema for i.MX95 Display Master Block Control - Convert to platform remove callback returning void for i.MX8MP Audiomix - Add SPI (MSIOF) and external interrupt (INTC-EX) clocks on Renesas R-Car V4M - Add interrupt controller (PLIC) clock and reset on Renesas RZ/Five - Prepare power domain support for Renesas RZ/G2L family members, and add actual support on Renesas RZ/G3S SoC - Add thermal, serial (SCIF), and timer (CMT/TMU) clocks on Renesas R-Car V4M - Add additional constraints to Allwinner A64 PLL MIPI clock - Fix autoloading sunxi-ng clocks when build as a module" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (118 commits) clk: samsung: Don't register clkdev lookup for the fixed rate clocks clk, reset: microchip: mpfs: fix incorrect preprocessor conditions clk: qcom: clk-alpha-pll: fix rate setting for Stromer PLLs clk: qcom: apss-ipq-pll: fix PLL rate for IPQ5018 clk: qcom: Fix SM_GPUCC_8650 dependencies clk: qcom: Fix SC_CAMCC_8280XP dependencies dt-bindings: clocks: stm32mp25: add access-controllers description clock, reset: microchip: move all mpfs reset code to the reset subsystem clk: samsung: gs101: drop unused HSI2 clock parent data clk: rockchip: rk3568: Add PLL rate for 724 MHz clk: rockchip: Remove an unused field in struct rockchip_mmc_clock dt-bindings: clock: fixed: Define a preferred node name clk: meson: s4: fix module autoloading clk: samsung: gs101: mark some apm UASC and XIU clocks critical clk: imx: imx8mp: Convert to platform remove callback returning void clk: imx: imx8mp: Switch to RUNTIME_PM_OPS() clk: bcm: rpi: Assign ->num before accessing ->hws clk: bcm: dvp: Assign ->num before accessing ->hws clk: samsung: gs101: add support for cmu_hsi2 clk: samsung: gs101: add support for cmu_hsi0 ...
This commit is contained in:
commit
619b92b9c8
@ -29,10 +29,13 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: airoha,en7523-scu
|
||||
- enum:
|
||||
- airoha,en7523-scu
|
||||
- airoha,en7581-scu
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
"#clock-cells":
|
||||
description:
|
||||
@ -45,6 +48,30 @@ required:
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
const: airoha,en7523-scu
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: scu base address
|
||||
- description: misc scu base address
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
const: airoha,en7581-scu
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: scu base address
|
||||
- description: misc scu base address
|
||||
- description: pb scu base address
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -11,6 +11,15 @@ maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
anyOf:
|
||||
- description:
|
||||
Preferred name is 'clock-<freq>' with <freq> being the output
|
||||
frequency as defined in the 'clock-frequency' property.
|
||||
pattern: "^clock-([0-9]+|[a-z0-9-]+)$"
|
||||
- description: Any name allowed
|
||||
deprecated: true
|
||||
|
||||
compatible:
|
||||
const: fixed-clock
|
||||
|
||||
|
@ -11,6 +11,15 @@ maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
anyOf:
|
||||
- description:
|
||||
If the frequency is fixed, the preferred name is 'clock-<freq>' with
|
||||
<freq> being the output frequency.
|
||||
pattern: "^clock-([0-9]+|[0-9a-z-]+)$"
|
||||
- description: Any name allowed
|
||||
deprecated: true
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- fixed-factor-clock
|
||||
|
@ -16,7 +16,9 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- loongson,ls2k-clk
|
||||
- loongson,ls2k0500-clk
|
||||
- loongson,ls2k-clk # This is for Loongson-2K1000
|
||||
- loongson,ls2k2000-clk
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/nxp,imx95-blk-ctl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP i.MX95 Block Control
|
||||
|
||||
maintainers:
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- nxp,imx95-lvds-csr
|
||||
- nxp,imx95-display-csr
|
||||
- nxp,imx95-camera-csr
|
||||
- nxp,imx95-vpu-csr
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
description:
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell. See
|
||||
include/dt-bindings/clock/nxp,imx95-clock.h
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- power-domains
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
syscon@4c410000 {
|
||||
compatible = "nxp,imx95-vpu-csr", "syscon";
|
||||
reg = <0x4c410000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&scmi_clk 114>;
|
||||
power-domains = <&scmi_devpd 21>;
|
||||
};
|
||||
...
|
@ -0,0 +1,64 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/nxp,imx95-display-master-csr.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP i.MX95 Display Master Block Control
|
||||
|
||||
maintainers:
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: nxp,imx95-display-master-csr
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
description:
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell. See
|
||||
include/dt-bindings/clock/nxp,imx95-clock.h
|
||||
|
||||
mux-controller:
|
||||
type: object
|
||||
$ref: /schemas/mux/reg-mux.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- mux-controller
|
||||
- power-domains
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
syscon@4c410000 {
|
||||
compatible = "nxp,imx95-display-master-csr", "syscon";
|
||||
reg = <0x4c410000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&scmi_clk 62>;
|
||||
power-domains = <&scmi_devpd 3>;
|
||||
|
||||
mux: mux-controller {
|
||||
compatible = "mmio-mux";
|
||||
#mux-control-cells = <1>;
|
||||
mux-reg-masks = <0x4 0x00000001>; /* Pixel_link_sel */
|
||||
idle-states = <0>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,63 +0,0 @@
|
||||
High-Frequency PLL (HFPLL)
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>:
|
||||
shall contain only one of the following. The generic
|
||||
compatible "qcom,hfpll" should be also included.
|
||||
|
||||
"qcom,hfpll-ipq8064", "qcom,hfpll"
|
||||
"qcom,hfpll-apq8064", "qcom,hfpll"
|
||||
"qcom,hfpll-msm8974", "qcom,hfpll"
|
||||
"qcom,hfpll-msm8960", "qcom,hfpll"
|
||||
"qcom,msm8976-hfpll-a53", "qcom,hfpll"
|
||||
"qcom,msm8976-hfpll-a72", "qcom,hfpll"
|
||||
"qcom,msm8976-hfpll-cci", "qcom,hfpll"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: address and size of HPLL registers. An optional second
|
||||
element specifies the address and size of the alias
|
||||
register region.
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: reference to the xo clock.
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "xo".
|
||||
|
||||
- clock-output-names:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Name of the PLL. Typically hfpllX where X is a CPU number
|
||||
starting at 0. Otherwise hfpll_Y where Y is more specific
|
||||
such as "l2".
|
||||
|
||||
Example:
|
||||
|
||||
1) An HFPLL for the L2 cache.
|
||||
|
||||
clock-controller@f9016000 {
|
||||
compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
|
||||
reg = <0xf9016000 0x30>;
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "xo";
|
||||
clock-output-names = "hfpll_l2";
|
||||
};
|
||||
|
||||
2) An HFPLL for CPU0. This HFPLL has the alias register region.
|
||||
|
||||
clock-controller@f908a000 {
|
||||
compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
|
||||
reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "xo";
|
||||
clock-output-names = "hfpll0";
|
||||
};
|
69
Documentation/devicetree/bindings/clock/qcom,hfpll.yaml
Normal file
69
Documentation/devicetree/bindings/clock/qcom,hfpll.yaml
Normal file
@ -0,0 +1,69 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,hfpll.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm High-Frequency PLL
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
|
||||
description:
|
||||
The HFPLL is used as CPU PLL on various Qualcomm SoCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- qcom,msm8974-hfpll
|
||||
- qcom,msm8976-hfpll-a53
|
||||
- qcom,msm8976-hfpll-a72
|
||||
- qcom,msm8976-hfpll-cci
|
||||
- qcom,qcs404-hfpll
|
||||
- const: qcom,hfpll
|
||||
deprecated: true
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: HFPLL registers
|
||||
- description: Alias register region
|
||||
minItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: board XO clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
|
||||
clock-output-names:
|
||||
description:
|
||||
Name of the PLL. Typically hfpllX where X is a CPU number starting at 0.
|
||||
Otherwise hfpll_Y where Y is more specific such as "l2".
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
- clock-names
|
||||
- clock-output-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@f908a000 {
|
||||
compatible = "qcom,msm8974-hfpll";
|
||||
reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "hfpll0";
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "xo";
|
||||
};
|
@ -57,7 +57,8 @@ properties:
|
||||
can be power-managed through Module Standby should refer to the CPG device
|
||||
node in their "power-domains" property, as documented by the generic PM
|
||||
Domain bindings in Documentation/devicetree/bindings/power/power-domain.yaml.
|
||||
const: 0
|
||||
The power domain specifiers defined in <dt-bindings/clock/r9a0*-cpg.h> could
|
||||
be used to reference individual CPG power domains.
|
||||
|
||||
'#reset-cells':
|
||||
description:
|
||||
@ -76,6 +77,21 @@ required:
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a08g045-cpg
|
||||
then:
|
||||
properties:
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
else:
|
||||
properties:
|
||||
'#power-domain-cells':
|
||||
const: 0
|
||||
|
||||
examples:
|
||||
- |
|
||||
cpg: clock-controller@11010000 {
|
||||
|
@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/samsung,s3c6400-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung S3C6400 SoC clock controller
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzk@kernel.org>
|
||||
|
||||
description: |
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names and/or provided as clock inputs to this clock controller:
|
||||
- "fin_pll" - PLL input clock (xtal/extclk) - required,
|
||||
- "xusbxti" - USB xtal - required,
|
||||
- "iiscdclk0" - I2S0 codec clock - optional,
|
||||
- "iiscdclk1" - I2S1 codec clock - optional,
|
||||
- "iiscdclk2" - I2S2 codec clock - optional,
|
||||
- "pcmcdclk0" - PCM0 codec clock - optional,
|
||||
- "pcmcdclk1" - PCM1 codec clock - optional, only S3C6410.
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
include/dt-bindings/clock/samsung,s3c64xx-clock.h header.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,s3c6400-clock
|
||||
- samsung,s3c6410-clock
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@7e00f000 {
|
||||
compatible = "samsung,s3c6410-clock";
|
||||
reg = <0x7e00f000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&fin_pll>;
|
||||
};
|
@ -1,76 +0,0 @@
|
||||
* Samsung S3C64xx Clock Controller
|
||||
|
||||
The S3C64xx clock controller generates and supplies clock to various controllers
|
||||
within the SoC. The clock binding described here is applicable to all SoCs in
|
||||
the S3C64xx family.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
- "samsung,s3c6400-clock" - controller compatible with S3C6400 SoC.
|
||||
- "samsung,s3c6410-clock" - controller compatible with S3C6410 SoC.
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. Some of the clocks are available only
|
||||
on a particular S3C64xx SoC and this is specified where applicable.
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/samsung,s3c64xx-clock.h header and can be used in device
|
||||
tree sources.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names:
|
||||
- "fin_pll" - PLL input clock (xtal/extclk) - required,
|
||||
- "xusbxti" - USB xtal - required,
|
||||
- "iiscdclk0" - I2S0 codec clock - optional,
|
||||
- "iiscdclk1" - I2S1 codec clock - optional,
|
||||
- "iiscdclk2" - I2S2 codec clock - optional,
|
||||
- "pcmcdclk0" - PCM0 codec clock - optional,
|
||||
- "pcmcdclk1" - PCM1 codec clock - optional, only S3C6410.
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
clock: clock-controller@7e00f000 {
|
||||
compatible = "samsung,s3c6410-clock";
|
||||
reg = <0x7e00f000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
Example: Required external clocks:
|
||||
|
||||
fin_pll: clock-fin-pll {
|
||||
compatible = "fixed-clock";
|
||||
clock-output-names = "fin_pll";
|
||||
clock-frequency = <12000000>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
xusbxti: clock-xusbxti {
|
||||
compatible = "fixed-clock";
|
||||
clock-output-names = "xusbxti";
|
||||
clock-frequency = <48000000>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock generated by the clock
|
||||
controller (refer to the standard clock bindings for information about
|
||||
"clocks" and "clock-names" properties):
|
||||
|
||||
uart0: serial@7f005000 {
|
||||
compatible = "samsung,s3c6400-uart";
|
||||
reg = <0x7f005000 0x100>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <5>;
|
||||
clock-names = "uart", "clk_uart_baud2",
|
||||
"clk_uart_baud3";
|
||||
clocks = <&clock PCLK_UART0>, <&clocks PCLK_UART0>,
|
||||
<&clock SCLK_UART>;
|
||||
};
|
@ -4,7 +4,7 @@
|
||||
$id: http://devicetree.org/schemas/clock/sophgo,cv1800-clk.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sophgo CV1800 Series Clock Controller
|
||||
title: Sophgo CV1800/SG2000 Series Clock Controller
|
||||
|
||||
maintainers:
|
||||
- Inochi Amaoto <inochiama@outlook.com>
|
||||
@ -14,6 +14,7 @@ properties:
|
||||
enum:
|
||||
- sophgo,cv1800-clk
|
||||
- sophgo,cv1810-clk
|
||||
- sophgo,sg2000-clk
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -38,14 +38,85 @@ properties:
|
||||
- description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz)
|
||||
- description: CK_SCMI_LSE Low Speed External oscillator (32 KHz)
|
||||
- description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz)
|
||||
- description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (coud be gated)
|
||||
- description: CK_SCMI_ICN_HS_MCU High Speed interconnect bus clock
|
||||
- description: CK_SCMI_ICN_LS_MCU Low Speed interconnect bus clock
|
||||
- description: CK_SCMI_ICN_SDMMC SDMMC interconnect bus clock
|
||||
- description: CK_SCMI_ICN_DDR DDR interconnect bus clock
|
||||
- description: CK_SCMI_ICN_DISPLAY Display interconnect bus clock
|
||||
- description: CK_SCMI_ICN_HSL HSL interconnect bus clock
|
||||
- description: CK_SCMI_ICN_NIC NIC interconnect bus clock
|
||||
- description: CK_SCMI_ICN_VID Video interconnect bus clock
|
||||
- description: CK_SCMI_FLEXGEN_07 flexgen clock 7
|
||||
- description: CK_SCMI_FLEXGEN_08 flexgen clock 8
|
||||
- description: CK_SCMI_FLEXGEN_09 flexgen clock 9
|
||||
- description: CK_SCMI_FLEXGEN_10 flexgen clock 10
|
||||
- description: CK_SCMI_FLEXGEN_11 flexgen clock 11
|
||||
- description: CK_SCMI_FLEXGEN_12 flexgen clock 12
|
||||
- description: CK_SCMI_FLEXGEN_13 flexgen clock 13
|
||||
- description: CK_SCMI_FLEXGEN_14 flexgen clock 14
|
||||
- description: CK_SCMI_FLEXGEN_15 flexgen clock 15
|
||||
- description: CK_SCMI_FLEXGEN_16 flexgen clock 16
|
||||
- description: CK_SCMI_FLEXGEN_17 flexgen clock 17
|
||||
- description: CK_SCMI_FLEXGEN_18 flexgen clock 18
|
||||
- description: CK_SCMI_FLEXGEN_19 flexgen clock 19
|
||||
- description: CK_SCMI_FLEXGEN_20 flexgen clock 20
|
||||
- description: CK_SCMI_FLEXGEN_21 flexgen clock 21
|
||||
- description: CK_SCMI_FLEXGEN_22 flexgen clock 22
|
||||
- description: CK_SCMI_FLEXGEN_23 flexgen clock 23
|
||||
- description: CK_SCMI_FLEXGEN_24 flexgen clock 24
|
||||
- description: CK_SCMI_FLEXGEN_25 flexgen clock 25
|
||||
- description: CK_SCMI_FLEXGEN_26 flexgen clock 26
|
||||
- description: CK_SCMI_FLEXGEN_27 flexgen clock 27
|
||||
- description: CK_SCMI_FLEXGEN_28 flexgen clock 28
|
||||
- description: CK_SCMI_FLEXGEN_29 flexgen clock 29
|
||||
- description: CK_SCMI_FLEXGEN_30 flexgen clock 30
|
||||
- description: CK_SCMI_FLEXGEN_31 flexgen clock 31
|
||||
- description: CK_SCMI_FLEXGEN_32 flexgen clock 32
|
||||
- description: CK_SCMI_FLEXGEN_33 flexgen clock 33
|
||||
- description: CK_SCMI_FLEXGEN_34 flexgen clock 34
|
||||
- description: CK_SCMI_FLEXGEN_35 flexgen clock 35
|
||||
- description: CK_SCMI_FLEXGEN_36 flexgen clock 36
|
||||
- description: CK_SCMI_FLEXGEN_37 flexgen clock 37
|
||||
- description: CK_SCMI_FLEXGEN_38 flexgen clock 38
|
||||
- description: CK_SCMI_FLEXGEN_39 flexgen clock 39
|
||||
- description: CK_SCMI_FLEXGEN_40 flexgen clock 40
|
||||
- description: CK_SCMI_FLEXGEN_41 flexgen clock 41
|
||||
- description: CK_SCMI_FLEXGEN_42 flexgen clock 42
|
||||
- description: CK_SCMI_FLEXGEN_43 flexgen clock 43
|
||||
- description: CK_SCMI_FLEXGEN_44 flexgen clock 44
|
||||
- description: CK_SCMI_FLEXGEN_45 flexgen clock 45
|
||||
- description: CK_SCMI_FLEXGEN_46 flexgen clock 46
|
||||
- description: CK_SCMI_FLEXGEN_47 flexgen clock 47
|
||||
- description: CK_SCMI_FLEXGEN_48 flexgen clock 48
|
||||
- description: CK_SCMI_FLEXGEN_49 flexgen clock 49
|
||||
- description: CK_SCMI_FLEXGEN_50 flexgen clock 50
|
||||
- description: CK_SCMI_FLEXGEN_51 flexgen clock 51
|
||||
- description: CK_SCMI_FLEXGEN_52 flexgen clock 52
|
||||
- description: CK_SCMI_FLEXGEN_53 flexgen clock 53
|
||||
- description: CK_SCMI_FLEXGEN_54 flexgen clock 54
|
||||
- description: CK_SCMI_FLEXGEN_55 flexgen clock 55
|
||||
- description: CK_SCMI_FLEXGEN_56 flexgen clock 56
|
||||
- description: CK_SCMI_FLEXGEN_57 flexgen clock 57
|
||||
- description: CK_SCMI_FLEXGEN_58 flexgen clock 58
|
||||
- description: CK_SCMI_FLEXGEN_59 flexgen clock 59
|
||||
- description: CK_SCMI_FLEXGEN_60 flexgen clock 60
|
||||
- description: CK_SCMI_FLEXGEN_61 flexgen clock 61
|
||||
- description: CK_SCMI_FLEXGEN_62 flexgen clock 62
|
||||
- description: CK_SCMI_FLEXGEN_63 flexgen clock 63
|
||||
- description: CK_SCMI_ICN_APB1 Peripheral bridge 1
|
||||
- description: CK_SCMI_ICN_APB2 Peripheral bridge 2
|
||||
- description: CK_SCMI_ICN_APB3 Peripheral bridge 3
|
||||
- description: CK_SCMI_ICN_APB4 Peripheral bridge 4
|
||||
- description: CK_SCMI_ICN_APBDBG Peripheral bridge for degub
|
||||
- description: CK_SCMI_TIMG1 Peripheral bridge for timer1
|
||||
- description: CK_SCMI_TIMG2 Peripheral bridge for timer2
|
||||
- description: CK_SCMI_PLL3 PLL3 clock
|
||||
- description: clk_dsi_txbyte DSI byte clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: hse
|
||||
- const: hsi
|
||||
- const: msi
|
||||
- const: lse
|
||||
- const: lsi
|
||||
access-controllers:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -53,7 +124,6 @@ required:
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -66,11 +136,85 @@ examples:
|
||||
reg = <0x44200000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
clock-names = "hse", "hsi", "msi", "lse", "lsi";
|
||||
clocks = <&scmi_clk CK_SCMI_HSE>,
|
||||
<&scmi_clk CK_SCMI_HSI>,
|
||||
<&scmi_clk CK_SCMI_MSI>,
|
||||
<&scmi_clk CK_SCMI_LSE>,
|
||||
<&scmi_clk CK_SCMI_LSI>;
|
||||
clocks = <&scmi_clk CK_SCMI_HSE>,
|
||||
<&scmi_clk CK_SCMI_HSI>,
|
||||
<&scmi_clk CK_SCMI_MSI>,
|
||||
<&scmi_clk CK_SCMI_LSE>,
|
||||
<&scmi_clk CK_SCMI_LSI>,
|
||||
<&scmi_clk CK_SCMI_HSE_DIV2>,
|
||||
<&scmi_clk CK_SCMI_ICN_HS_MCU>,
|
||||
<&scmi_clk CK_SCMI_ICN_LS_MCU>,
|
||||
<&scmi_clk CK_SCMI_ICN_SDMMC>,
|
||||
<&scmi_clk CK_SCMI_ICN_DDR>,
|
||||
<&scmi_clk CK_SCMI_ICN_DISPLAY>,
|
||||
<&scmi_clk CK_SCMI_ICN_HSL>,
|
||||
<&scmi_clk CK_SCMI_ICN_NIC>,
|
||||
<&scmi_clk CK_SCMI_ICN_VID>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_07>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_08>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_09>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_10>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_11>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_12>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_13>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_14>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_15>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_16>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_17>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_18>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_19>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_20>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_21>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_22>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_23>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_24>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_25>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_26>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_27>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_28>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_29>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_30>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_31>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_32>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_33>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_34>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_35>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_36>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_37>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_38>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_39>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_40>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_41>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_42>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_43>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_44>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_45>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_46>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_47>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_48>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_49>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_50>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_51>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_52>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_53>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_54>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_55>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_56>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_57>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_58>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_59>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_60>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_61>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_62>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_63>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB1>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB2>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB3>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB4>,
|
||||
<&scmi_clk CK_SCMI_ICN_APBDBG>,
|
||||
<&scmi_clk CK_SCMI_TIMG1>,
|
||||
<&scmi_clk CK_SCMI_TIMG2>,
|
||||
<&scmi_clk CK_SCMI_PLL3>,
|
||||
<&clk_dsi_txbyte>;
|
||||
};
|
||||
...
|
||||
|
@ -489,6 +489,7 @@ source "drivers/clk/rockchip/Kconfig"
|
||||
source "drivers/clk/samsung/Kconfig"
|
||||
source "drivers/clk/sifive/Kconfig"
|
||||
source "drivers/clk/socfpga/Kconfig"
|
||||
source "drivers/clk/sophgo/Kconfig"
|
||||
source "drivers/clk/sprd/Kconfig"
|
||||
source "drivers/clk/starfive/Kconfig"
|
||||
source "drivers/clk/sunxi/Kconfig"
|
||||
|
@ -118,6 +118,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
|
||||
obj-$(CONFIG_CLK_SIFIVE) += sifive/
|
||||
obj-y += socfpga/
|
||||
obj-y += sophgo/
|
||||
obj-$(CONFIG_PLAT_SPEAR) += spear/
|
||||
obj-y += sprd/
|
||||
obj-$(CONFIG_ARCH_STI) += st/
|
||||
|
@ -56,6 +56,8 @@ static int clk_dvp_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->num = NR_CLOCKS;
|
||||
|
||||
data->hws[0] = clk_hw_register_gate_parent_data(&pdev->dev,
|
||||
"hdmi0-108MHz",
|
||||
&clk_dvp_parent, 0,
|
||||
@ -76,7 +78,6 @@ static int clk_dvp_probe(struct platform_device *pdev)
|
||||
goto unregister_clk0;
|
||||
}
|
||||
|
||||
data->num = NR_CLOCKS;
|
||||
ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
|
||||
data);
|
||||
if (ret)
|
||||
|
@ -371,8 +371,8 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
data->hws[clks->id] = hw;
|
||||
data->num = clks->id + 1;
|
||||
data->hws[clks->id] = hw;
|
||||
}
|
||||
|
||||
clks++;
|
||||
|
@ -3,14 +3,16 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <dt-bindings/clock/en7523-clk.h>
|
||||
|
||||
#define REG_PCI_CONTROL 0x88
|
||||
#define REG_PCI_CONTROL_PERSTOUT BIT(29)
|
||||
#define REG_PCI_CONTROL_PERSTOUT1 BIT(26)
|
||||
#define REG_PCI_CONTROL_REFCLK_EN0 BIT(23)
|
||||
#define REG_PCI_CONTROL_REFCLK_EN1 BIT(22)
|
||||
#define REG_PCI_CONTROL_PERSTOUT2 BIT(16)
|
||||
#define REG_GSW_CLK_DIV_SEL 0x1b4
|
||||
#define REG_EMI_CLK_DIV_SEL 0x1b8
|
||||
#define REG_BUS_CLK_DIV_SEL 0x1bc
|
||||
@ -18,10 +20,25 @@
|
||||
#define REG_SPI_CLK_FREQ_SEL 0x1c8
|
||||
#define REG_NPU_CLK_DIV_SEL 0x1fc
|
||||
#define REG_CRYPTO_CLKSRC 0x200
|
||||
#define REG_RESET_CONTROL 0x834
|
||||
#define REG_RESET_CONTROL2 0x830
|
||||
#define REG_RESET2_CONTROL_PCIE2 BIT(27)
|
||||
#define REG_RESET_CONTROL1 0x834
|
||||
#define REG_RESET_CONTROL_PCIEHB BIT(29)
|
||||
#define REG_RESET_CONTROL_PCIE1 BIT(27)
|
||||
#define REG_RESET_CONTROL_PCIE2 BIT(26)
|
||||
/* EN7581 */
|
||||
#define REG_PCIE0_MEM 0x00
|
||||
#define REG_PCIE0_MEM_MASK 0x04
|
||||
#define REG_PCIE1_MEM 0x08
|
||||
#define REG_PCIE1_MEM_MASK 0x0c
|
||||
#define REG_PCIE2_MEM 0x10
|
||||
#define REG_PCIE2_MEM_MASK 0x14
|
||||
#define REG_PCIE_RESET_OPEN_DRAIN 0x018c
|
||||
#define REG_PCIE_RESET_OPEN_DRAIN_MASK GENMASK(2, 0)
|
||||
#define REG_NP_SCU_PCIC 0x88
|
||||
#define REG_NP_SCU_SSTR 0x9c
|
||||
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
|
||||
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
|
||||
|
||||
struct en_clk_desc {
|
||||
int id;
|
||||
@ -47,6 +64,12 @@ struct en_clk_gate {
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
struct en_clk_soc_data {
|
||||
const struct clk_ops pcie_ops;
|
||||
int (*hw_init)(struct platform_device *pdev, void __iomem *base,
|
||||
void __iomem *np_base);
|
||||
};
|
||||
|
||||
static const u32 gsw_base[] = { 400000000, 500000000 };
|
||||
static const u32 emi_base[] = { 333000000, 400000000 };
|
||||
static const u32 bus_base[] = { 500000000, 540000000 };
|
||||
@ -145,11 +168,6 @@ static const struct en_clk_desc en7523_base_clks[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_clk_en7523[] = {
|
||||
{ .compatible = "airoha,en7523-scu", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
|
||||
{
|
||||
const struct en_clk_desc *desc = &en7523_base_clks[i];
|
||||
@ -212,14 +230,14 @@ static int en7523_pci_prepare(struct clk_hw *hw)
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
/* Reset to default */
|
||||
val = readl(np_base + REG_RESET_CONTROL);
|
||||
val = readl(np_base + REG_RESET_CONTROL1);
|
||||
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
|
||||
REG_RESET_CONTROL_PCIEHB;
|
||||
writel(val & ~mask, np_base + REG_RESET_CONTROL);
|
||||
writel(val & ~mask, np_base + REG_RESET_CONTROL1);
|
||||
usleep_range(1000, 2000);
|
||||
writel(val | mask, np_base + REG_RESET_CONTROL);
|
||||
writel(val | mask, np_base + REG_RESET_CONTROL1);
|
||||
msleep(100);
|
||||
writel(val & ~mask, np_base + REG_RESET_CONTROL);
|
||||
writel(val & ~mask, np_base + REG_RESET_CONTROL1);
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
/* Release device */
|
||||
@ -247,14 +265,10 @@ static void en7523_pci_unprepare(struct clk_hw *hw)
|
||||
static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
|
||||
void __iomem *np_base)
|
||||
{
|
||||
static const struct clk_ops pcie_gate_ops = {
|
||||
.is_enabled = en7523_pci_is_enabled,
|
||||
.prepare = en7523_pci_prepare,
|
||||
.unprepare = en7523_pci_unprepare,
|
||||
};
|
||||
const struct en_clk_soc_data *soc_data = device_get_match_data(dev);
|
||||
struct clk_init_data init = {
|
||||
.name = "pcie",
|
||||
.ops = &pcie_gate_ops,
|
||||
.ops = &soc_data->pcie_ops,
|
||||
};
|
||||
struct en_clk_gate *cg;
|
||||
|
||||
@ -264,7 +278,10 @@ static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
|
||||
|
||||
cg->base = np_base;
|
||||
cg->hw.init = &init;
|
||||
en7523_pci_unprepare(&cg->hw);
|
||||
|
||||
if (init.ops->disable)
|
||||
init.ops->disable(&cg->hw);
|
||||
init.ops->unprepare(&cg->hw);
|
||||
|
||||
if (clk_hw_register(dev, &cg->hw))
|
||||
return NULL;
|
||||
@ -272,6 +289,111 @@ static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
|
||||
return &cg->hw;
|
||||
}
|
||||
|
||||
static int en7581_pci_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
|
||||
u32 val, mask;
|
||||
|
||||
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
|
||||
val = readl(cg->base + REG_PCI_CONTROL);
|
||||
return (val & mask) == mask;
|
||||
}
|
||||
|
||||
static int en7581_pci_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
|
||||
void __iomem *np_base = cg->base;
|
||||
u32 val, mask;
|
||||
|
||||
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
|
||||
REG_RESET_CONTROL_PCIEHB;
|
||||
val = readl(np_base + REG_RESET_CONTROL1);
|
||||
writel(val & ~mask, np_base + REG_RESET_CONTROL1);
|
||||
val = readl(np_base + REG_RESET_CONTROL2);
|
||||
writel(val & ~REG_RESET2_CONTROL_PCIE2, np_base + REG_RESET_CONTROL2);
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en7581_pci_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
|
||||
void __iomem *np_base = cg->base;
|
||||
u32 val, mask;
|
||||
|
||||
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
|
||||
REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
|
||||
REG_PCI_CONTROL_PERSTOUT;
|
||||
val = readl(np_base + REG_PCI_CONTROL);
|
||||
writel(val | mask, np_base + REG_PCI_CONTROL);
|
||||
msleep(250);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void en7581_pci_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
|
||||
void __iomem *np_base = cg->base;
|
||||
u32 val, mask;
|
||||
|
||||
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
|
||||
REG_RESET_CONTROL_PCIEHB;
|
||||
val = readl(np_base + REG_RESET_CONTROL1);
|
||||
writel(val | mask, np_base + REG_RESET_CONTROL1);
|
||||
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2;
|
||||
writel(val | mask, np_base + REG_RESET_CONTROL1);
|
||||
val = readl(np_base + REG_RESET_CONTROL2);
|
||||
writel(val | REG_RESET_CONTROL_PCIE2, np_base + REG_RESET_CONTROL2);
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static void en7581_pci_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
|
||||
void __iomem *np_base = cg->base;
|
||||
u32 val, mask;
|
||||
|
||||
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
|
||||
REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
|
||||
REG_PCI_CONTROL_PERSTOUT;
|
||||
val = readl(np_base + REG_PCI_CONTROL);
|
||||
writel(val & ~mask, np_base + REG_PCI_CONTROL);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
static int en7581_clk_hw_init(struct platform_device *pdev,
|
||||
void __iomem *base,
|
||||
void __iomem *np_base)
|
||||
{
|
||||
void __iomem *pb_base;
|
||||
u32 val;
|
||||
|
||||
pb_base = devm_platform_ioremap_resource(pdev, 2);
|
||||
if (IS_ERR(pb_base))
|
||||
return PTR_ERR(pb_base);
|
||||
|
||||
val = readl(np_base + REG_NP_SCU_SSTR);
|
||||
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
|
||||
writel(val, np_base + REG_NP_SCU_SSTR);
|
||||
val = readl(np_base + REG_NP_SCU_PCIC);
|
||||
writel(val | 3, np_base + REG_NP_SCU_PCIC);
|
||||
|
||||
writel(0x20000000, pb_base + REG_PCIE0_MEM);
|
||||
writel(0xfc000000, pb_base + REG_PCIE0_MEM_MASK);
|
||||
writel(0x24000000, pb_base + REG_PCIE1_MEM);
|
||||
writel(0xfc000000, pb_base + REG_PCIE1_MEM_MASK);
|
||||
writel(0x28000000, pb_base + REG_PCIE2_MEM);
|
||||
writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK);
|
||||
|
||||
val = readl(base + REG_PCIE_RESET_OPEN_DRAIN);
|
||||
writel(val | REG_PCIE_RESET_OPEN_DRAIN_MASK,
|
||||
base + REG_PCIE_RESET_OPEN_DRAIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
|
||||
void __iomem *base, void __iomem *np_base)
|
||||
{
|
||||
@ -304,6 +426,7 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
||||
static int en7523_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct en_clk_soc_data *soc_data;
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
void __iomem *base, *np_base;
|
||||
int r;
|
||||
@ -316,6 +439,13 @@ static int en7523_clk_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(np_base))
|
||||
return PTR_ERR(np_base);
|
||||
|
||||
soc_data = device_get_match_data(&pdev->dev);
|
||||
if (soc_data->hw_init) {
|
||||
r = soc_data->hw_init(pdev, base, np_base);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
clk_data = devm_kzalloc(&pdev->dev,
|
||||
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
|
||||
GFP_KERNEL);
|
||||
@ -333,6 +463,31 @@ static int en7523_clk_probe(struct platform_device *pdev)
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct en_clk_soc_data en7523_data = {
|
||||
.pcie_ops = {
|
||||
.is_enabled = en7523_pci_is_enabled,
|
||||
.prepare = en7523_pci_prepare,
|
||||
.unprepare = en7523_pci_unprepare,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct en_clk_soc_data en7581_data = {
|
||||
.pcie_ops = {
|
||||
.is_enabled = en7581_pci_is_enabled,
|
||||
.prepare = en7581_pci_prepare,
|
||||
.enable = en7581_pci_enable,
|
||||
.unprepare = en7581_pci_unprepare,
|
||||
.disable = en7581_pci_disable,
|
||||
},
|
||||
.hw_init = en7581_clk_hw_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_clk_en7523[] = {
|
||||
{ .compatible = "airoha,en7523-scu", .data = &en7523_data },
|
||||
{ .compatible = "airoha,en7581-scu", .data = &en7581_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver clk_en7523_drv = {
|
||||
.probe = en7523_clk_probe,
|
||||
.driver = {
|
||||
|
@ -67,12 +67,10 @@ struct gemini_gate_data {
|
||||
* struct clk_gemini_pci - Gemini PCI clock
|
||||
* @hw: corresponding clock hardware entry
|
||||
* @map: regmap to access the registers
|
||||
* @rate: current rate
|
||||
*/
|
||||
struct clk_gemini_pci {
|
||||
struct clk_hw hw;
|
||||
struct regmap *map;
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,6 @@
|
||||
struct hb_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
char *parent_name;
|
||||
};
|
||||
#define to_hb_clk(p) container_of(p, struct hb_clk, hw)
|
||||
|
||||
|
@ -13,317 +13,348 @@
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <dt-bindings/clock/loongson,ls2k-clk.h>
|
||||
|
||||
#define LOONGSON2_PLL_MULT_SHIFT 32
|
||||
#define LOONGSON2_PLL_MULT_WIDTH 10
|
||||
#define LOONGSON2_PLL_DIV_SHIFT 26
|
||||
#define LOONGSON2_PLL_DIV_WIDTH 6
|
||||
#define LOONGSON2_APB_FREQSCALE_SHIFT 20
|
||||
#define LOONGSON2_APB_FREQSCALE_WIDTH 3
|
||||
#define LOONGSON2_USB_FREQSCALE_SHIFT 16
|
||||
#define LOONGSON2_USB_FREQSCALE_WIDTH 3
|
||||
#define LOONGSON2_SATA_FREQSCALE_SHIFT 12
|
||||
#define LOONGSON2_SATA_FREQSCALE_WIDTH 3
|
||||
#define LOONGSON2_BOOT_FREQSCALE_SHIFT 8
|
||||
#define LOONGSON2_BOOT_FREQSCALE_WIDTH 3
|
||||
|
||||
static void __iomem *loongson2_pll_base;
|
||||
|
||||
static const struct clk_parent_data pdata[] = {
|
||||
{ .fw_name = "ref_100m",},
|
||||
{ .fw_name = "ref_100m", },
|
||||
};
|
||||
|
||||
static struct clk_hw *loongson2_clk_register(struct device *dev,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
const struct clk_ops *ops,
|
||||
unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init = { };
|
||||
|
||||
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
|
||||
if (!hw)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
init.flags = flags;
|
||||
init.num_parents = 1;
|
||||
|
||||
if (!parent_name)
|
||||
init.parent_data = pdata;
|
||||
else
|
||||
init.parent_names = &parent_name;
|
||||
|
||||
hw->init = &init;
|
||||
|
||||
ret = devm_clk_hw_register(dev, hw);
|
||||
if (ret)
|
||||
hw = ERR_PTR(ret);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static unsigned long loongson2_calc_pll_rate(int offset, unsigned long rate)
|
||||
{
|
||||
u64 val;
|
||||
u32 mult, div;
|
||||
|
||||
val = readq(loongson2_pll_base + offset);
|
||||
|
||||
mult = (val >> LOONGSON2_PLL_MULT_SHIFT) &
|
||||
clk_div_mask(LOONGSON2_PLL_MULT_WIDTH);
|
||||
div = (val >> LOONGSON2_PLL_DIV_SHIFT) &
|
||||
clk_div_mask(LOONGSON2_PLL_DIV_WIDTH);
|
||||
|
||||
return div_u64((u64)rate * mult, div);
|
||||
}
|
||||
|
||||
static unsigned long loongson2_node_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_pll_rate(0x0, parent_rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_node_clk_ops = {
|
||||
.recalc_rate = loongson2_node_recalc_rate,
|
||||
enum loongson2_clk_type {
|
||||
CLK_TYPE_PLL,
|
||||
CLK_TYPE_SCALE,
|
||||
CLK_TYPE_DIVIDER,
|
||||
CLK_TYPE_GATE,
|
||||
CLK_TYPE_FIXED,
|
||||
CLK_TYPE_NONE,
|
||||
};
|
||||
|
||||
static unsigned long loongson2_ddr_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_pll_rate(0x10, parent_rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_ddr_clk_ops = {
|
||||
.recalc_rate = loongson2_ddr_recalc_rate,
|
||||
struct loongson2_clk_provider {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
spinlock_t clk_lock; /* protect access to DIV registers */
|
||||
};
|
||||
|
||||
static unsigned long loongson2_dc_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_pll_rate(0x20, parent_rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_dc_clk_ops = {
|
||||
.recalc_rate = loongson2_dc_recalc_rate,
|
||||
struct loongson2_clk_data {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 div_shift;
|
||||
u8 div_width;
|
||||
u8 mult_shift;
|
||||
u8 mult_width;
|
||||
};
|
||||
|
||||
static unsigned long loongson2_pix0_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_pll_rate(0x30, parent_rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_pix0_clk_ops = {
|
||||
.recalc_rate = loongson2_pix0_recalc_rate,
|
||||
struct loongson2_clk_board_info {
|
||||
u8 id;
|
||||
enum loongson2_clk_type type;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
unsigned long fixed_rate;
|
||||
u8 reg_offset;
|
||||
u8 div_shift;
|
||||
u8 div_width;
|
||||
u8 mult_shift;
|
||||
u8 mult_width;
|
||||
u8 bit_idx;
|
||||
};
|
||||
|
||||
static unsigned long loongson2_pix1_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_pll_rate(0x40, parent_rate);
|
||||
}
|
||||
#define CLK_DIV(_id, _name, _pname, _offset, _dshift, _dwidth) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_DIVIDER, \
|
||||
.name = _name, \
|
||||
.parent_name = _pname, \
|
||||
.reg_offset = _offset, \
|
||||
.div_shift = _dshift, \
|
||||
.div_width = _dwidth, \
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_pix1_clk_ops = {
|
||||
.recalc_rate = loongson2_pix1_recalc_rate,
|
||||
#define CLK_PLL(_id, _name, _offset, _mshift, _mwidth, \
|
||||
_dshift, _dwidth) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_PLL, \
|
||||
.name = _name, \
|
||||
.parent_name = NULL, \
|
||||
.reg_offset = _offset, \
|
||||
.mult_shift = _mshift, \
|
||||
.mult_width = _mwidth, \
|
||||
.div_shift = _dshift, \
|
||||
.div_width = _dwidth, \
|
||||
}
|
||||
|
||||
#define CLK_SCALE(_id, _name, _pname, _offset, \
|
||||
_dshift, _dwidth) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_SCALE, \
|
||||
.name = _name, \
|
||||
.parent_name = _pname, \
|
||||
.reg_offset = _offset, \
|
||||
.div_shift = _dshift, \
|
||||
.div_width = _dwidth, \
|
||||
}
|
||||
|
||||
#define CLK_GATE(_id, _name, _pname, _offset, _bidx) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_GATE, \
|
||||
.name = _name, \
|
||||
.parent_name = _pname, \
|
||||
.reg_offset = _offset, \
|
||||
.bit_idx = _bidx, \
|
||||
}
|
||||
|
||||
#define CLK_FIXED(_id, _name, _pname, _rate) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_FIXED, \
|
||||
.name = _name, \
|
||||
.parent_name = _pname, \
|
||||
.fixed_rate = _rate, \
|
||||
}
|
||||
|
||||
static const struct loongson2_clk_board_info ls2k0500_clks[] = {
|
||||
CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 16, 8, 8, 6),
|
||||
CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x8, 16, 8, 8, 6),
|
||||
CLK_PLL(LOONGSON2_DC_PLL, "pll_soc", 0x10, 16, 8, 8, 6),
|
||||
CLK_PLL(LOONGSON2_PIX0_PLL, "pll_pix0", 0x18, 16, 8, 8, 6),
|
||||
CLK_PLL(LOONGSON2_PIX1_PLL, "pll_pix1", 0x20, 16, 8, 8, 6),
|
||||
CLK_DIV(LOONGSON2_NODE_CLK, "clk_node", "pll_node", 0, 24, 6),
|
||||
CLK_DIV(LOONGSON2_DDR_CLK, "clk_ddr", "pll_ddr", 0x8, 24, 6),
|
||||
CLK_DIV(LOONGSON2_HDA_CLK, "clk_hda", "pll_ddr", 0xc, 8, 6),
|
||||
CLK_DIV(LOONGSON2_GPU_CLK, "clk_gpu", "pll_soc", 0x10, 24, 6),
|
||||
CLK_DIV(LOONGSON2_DC_CLK, "clk_sb", "pll_soc", 0x14, 0, 6),
|
||||
CLK_DIV(LOONGSON2_GMAC_CLK, "clk_gmac", "pll_soc", 0x14, 8, 6),
|
||||
CLK_DIV(LOONGSON2_PIX0_CLK, "clk_pix0", "pll_pix0", 0x18, 24, 6),
|
||||
CLK_DIV(LOONGSON2_PIX1_CLK, "clk_pix1", "pll_pix1", 0x20, 24, 6),
|
||||
CLK_SCALE(LOONGSON2_BOOT_CLK, "clk_boot", "clk_sb", 0x28, 8, 3),
|
||||
CLK_SCALE(LOONGSON2_SATA_CLK, "clk_sata", "clk_sb", 0x28, 12, 3),
|
||||
CLK_SCALE(LOONGSON2_USB_CLK, "clk_usb", "clk_sb", 0x28, 16, 3),
|
||||
CLK_SCALE(LOONGSON2_APB_CLK, "clk_apb", "clk_sb", 0x28, 20, 3),
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
static unsigned long loongson2_calc_rate(unsigned long rate,
|
||||
int shift, int width)
|
||||
{
|
||||
u64 val;
|
||||
u32 mult;
|
||||
|
||||
val = readq(loongson2_pll_base + 0x50);
|
||||
|
||||
mult = (val >> shift) & clk_div_mask(width);
|
||||
|
||||
return div_u64((u64)rate * (mult + 1), 8);
|
||||
}
|
||||
|
||||
static unsigned long loongson2_boot_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_rate(parent_rate,
|
||||
LOONGSON2_BOOT_FREQSCALE_SHIFT,
|
||||
LOONGSON2_BOOT_FREQSCALE_WIDTH);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_boot_clk_ops = {
|
||||
.recalc_rate = loongson2_boot_recalc_rate,
|
||||
};
|
||||
|
||||
static unsigned long loongson2_apb_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_rate(parent_rate,
|
||||
LOONGSON2_APB_FREQSCALE_SHIFT,
|
||||
LOONGSON2_APB_FREQSCALE_WIDTH);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_apb_clk_ops = {
|
||||
.recalc_rate = loongson2_apb_recalc_rate,
|
||||
};
|
||||
|
||||
static unsigned long loongson2_usb_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_rate(parent_rate,
|
||||
LOONGSON2_USB_FREQSCALE_SHIFT,
|
||||
LOONGSON2_USB_FREQSCALE_WIDTH);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_usb_clk_ops = {
|
||||
.recalc_rate = loongson2_usb_recalc_rate,
|
||||
};
|
||||
|
||||
static unsigned long loongson2_sata_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return loongson2_calc_rate(parent_rate,
|
||||
LOONGSON2_SATA_FREQSCALE_SHIFT,
|
||||
LOONGSON2_SATA_FREQSCALE_WIDTH);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_sata_clk_ops = {
|
||||
.recalc_rate = loongson2_sata_recalc_rate,
|
||||
};
|
||||
|
||||
static inline int loongson2_check_clk_hws(struct clk_hw *clks[], unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (IS_ERR(clks[i])) {
|
||||
pr_err("Loongson2 clk %u: register failed with %ld\n",
|
||||
i, PTR_ERR(clks[i]));
|
||||
return PTR_ERR(clks[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson2_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct clk_hw **hws;
|
||||
struct clk_hw_onecell_data *clk_hw_data;
|
||||
spinlock_t loongson2_clk_lock;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
loongson2_pll_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(loongson2_pll_base))
|
||||
return PTR_ERR(loongson2_pll_base);
|
||||
|
||||
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, LOONGSON2_CLK_END),
|
||||
GFP_KERNEL);
|
||||
if (WARN_ON(!clk_hw_data))
|
||||
return -ENOMEM;
|
||||
|
||||
clk_hw_data->num = LOONGSON2_CLK_END;
|
||||
hws = clk_hw_data->hws;
|
||||
|
||||
hws[LOONGSON2_NODE_PLL] = loongson2_clk_register(dev, "node_pll",
|
||||
NULL,
|
||||
&loongson2_node_clk_ops, 0);
|
||||
|
||||
hws[LOONGSON2_DDR_PLL] = loongson2_clk_register(dev, "ddr_pll",
|
||||
NULL,
|
||||
&loongson2_ddr_clk_ops, 0);
|
||||
|
||||
hws[LOONGSON2_DC_PLL] = loongson2_clk_register(dev, "dc_pll",
|
||||
NULL,
|
||||
&loongson2_dc_clk_ops, 0);
|
||||
|
||||
hws[LOONGSON2_PIX0_PLL] = loongson2_clk_register(dev, "pix0_pll",
|
||||
NULL,
|
||||
&loongson2_pix0_clk_ops, 0);
|
||||
|
||||
hws[LOONGSON2_PIX1_PLL] = loongson2_clk_register(dev, "pix1_pll",
|
||||
NULL,
|
||||
&loongson2_pix1_clk_ops, 0);
|
||||
|
||||
hws[LOONGSON2_BOOT_CLK] = loongson2_clk_register(dev, "boot",
|
||||
NULL,
|
||||
&loongson2_boot_clk_ops, 0);
|
||||
|
||||
hws[LOONGSON2_NODE_CLK] = devm_clk_hw_register_divider(dev, "node",
|
||||
"node_pll", 0,
|
||||
loongson2_pll_base + 0x8, 0,
|
||||
6, CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
|
||||
static const struct loongson2_clk_board_info ls2k1000_clks[] = {
|
||||
CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 32, 10, 26, 6),
|
||||
CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x10, 32, 10, 26, 6),
|
||||
CLK_PLL(LOONGSON2_DC_PLL, "pll_dc", 0x20, 32, 10, 26, 6),
|
||||
CLK_PLL(LOONGSON2_PIX0_PLL, "pll_pix0", 0x30, 32, 10, 26, 6),
|
||||
CLK_PLL(LOONGSON2_PIX1_PLL, "pll_pix1", 0x40, 32, 10, 26, 6),
|
||||
CLK_DIV(LOONGSON2_NODE_CLK, "clk_node", "pll_node", 0x8, 0, 6),
|
||||
CLK_DIV(LOONGSON2_DDR_CLK, "clk_ddr", "pll_ddr", 0x18, 0, 6),
|
||||
CLK_DIV(LOONGSON2_GPU_CLK, "clk_gpu", "pll_ddr", 0x18, 22, 6),
|
||||
/*
|
||||
* The hda clk divisor in the upper 32bits and the clk-prodiver
|
||||
* layer code doesn't support 64bit io operation thus a conversion
|
||||
* is required that subtract shift by 32 and add 4byte to the hda
|
||||
* address
|
||||
*/
|
||||
hws[LOONGSON2_HDA_CLK] = devm_clk_hw_register_divider(dev, "hda",
|
||||
"ddr_pll", 0,
|
||||
loongson2_pll_base + 0x22, 12,
|
||||
7, CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
CLK_DIV(LOONGSON2_HDA_CLK, "clk_hda", "pll_ddr", 0x22, 12, 7),
|
||||
CLK_DIV(LOONGSON2_DC_CLK, "clk_dc", "pll_dc", 0x28, 0, 6),
|
||||
CLK_DIV(LOONGSON2_GMAC_CLK, "clk_gmac", "pll_dc", 0x28, 22, 6),
|
||||
CLK_DIV(LOONGSON2_PIX0_CLK, "clk_pix0", "pll_pix0", 0x38, 0, 6),
|
||||
CLK_DIV(LOONGSON2_PIX1_CLK, "clk_pix1", "pll_pix1", 0x38, 0, 6),
|
||||
CLK_SCALE(LOONGSON2_BOOT_CLK, "clk_boot", NULL, 0x50, 8, 3),
|
||||
CLK_SCALE(LOONGSON2_SATA_CLK, "clk_sata", "clk_gmac", 0x50, 12, 3),
|
||||
CLK_SCALE(LOONGSON2_USB_CLK, "clk_usb", "clk_gmac", 0x50, 16, 3),
|
||||
CLK_SCALE(LOONGSON2_APB_CLK, "clk_apb", "clk_gmac", 0x50, 20, 3),
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
hws[LOONGSON2_GPU_CLK] = devm_clk_hw_register_divider(dev, "gpu",
|
||||
"ddr_pll", 0,
|
||||
loongson2_pll_base + 0x18, 22,
|
||||
6, CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
static const struct loongson2_clk_board_info ls2k2000_clks[] = {
|
||||
CLK_PLL(LOONGSON2_DC_PLL, "pll_0", 0, 21, 9, 32, 6),
|
||||
CLK_PLL(LOONGSON2_DDR_PLL, "pll_1", 0x10, 21, 9, 32, 6),
|
||||
CLK_PLL(LOONGSON2_NODE_PLL, "pll_2", 0x20, 21, 9, 32, 6),
|
||||
CLK_PLL(LOONGSON2_PIX0_PLL, "pll_pix0", 0x30, 21, 9, 32, 6),
|
||||
CLK_PLL(LOONGSON2_PIX1_PLL, "pll_pix1", 0x40, 21, 9, 32, 6),
|
||||
CLK_GATE(LOONGSON2_OUT0_GATE, "out0_gate", "pll_0", 0, 40),
|
||||
CLK_GATE(LOONGSON2_GMAC_GATE, "gmac_gate", "pll_0", 0, 41),
|
||||
CLK_GATE(LOONGSON2_RIO_GATE, "rio_gate", "pll_0", 0, 42),
|
||||
CLK_GATE(LOONGSON2_DC_GATE, "dc_gate", "pll_1", 0x10, 40),
|
||||
CLK_GATE(LOONGSON2_DDR_GATE, "ddr_gate", "pll_1", 0x10, 41),
|
||||
CLK_GATE(LOONGSON2_GPU_GATE, "gpu_gate", "pll_1", 0x10, 42),
|
||||
CLK_GATE(LOONGSON2_HDA_GATE, "hda_gate", "pll_2", 0x20, 40),
|
||||
CLK_GATE(LOONGSON2_NODE_GATE, "node_gate", "pll_2", 0x20, 41),
|
||||
CLK_GATE(LOONGSON2_EMMC_GATE, "emmc_gate", "pll_2", 0x20, 42),
|
||||
CLK_GATE(LOONGSON2_PIX0_GATE, "pix0_gate", "pll_pix0", 0x30, 40),
|
||||
CLK_GATE(LOONGSON2_PIX1_GATE, "pix1_gate", "pll_pix1", 0x40, 40),
|
||||
CLK_DIV(LOONGSON2_OUT0_CLK, "clk_out0", "out0_gate", 0, 0, 6),
|
||||
CLK_DIV(LOONGSON2_GMAC_CLK, "clk_gmac", "gmac_gate", 0, 7, 6),
|
||||
CLK_DIV(LOONGSON2_RIO_CLK, "clk_rio", "rio_gate", 0, 14, 6),
|
||||
CLK_DIV(LOONGSON2_DC_CLK, "clk_dc", "dc_gate", 0x10, 0, 6),
|
||||
CLK_DIV(LOONGSON2_GPU_CLK, "clk_gpu", "gpu_gate", 0x10, 7, 6),
|
||||
CLK_DIV(LOONGSON2_DDR_CLK, "clk_ddr", "ddr_gate", 0x10, 14, 6),
|
||||
CLK_DIV(LOONGSON2_HDA_CLK, "clk_hda", "hda_gate", 0x20, 0, 6),
|
||||
CLK_DIV(LOONGSON2_NODE_CLK, "clk_node", "node_gate", 0x20, 7, 6),
|
||||
CLK_DIV(LOONGSON2_EMMC_CLK, "clk_emmc", "emmc_gate", 0x20, 14, 6),
|
||||
CLK_DIV(LOONGSON2_PIX0_CLK, "clk_pix0", "pll_pix0", 0x30, 0, 6),
|
||||
CLK_DIV(LOONGSON2_PIX1_CLK, "clk_pix1", "pll_pix1", 0x40, 0, 6),
|
||||
CLK_SCALE(LOONGSON2_SATA_CLK, "clk_sata", "clk_out0", 0x50, 12, 3),
|
||||
CLK_SCALE(LOONGSON2_USB_CLK, "clk_usb", "clk_out0", 0x50, 16, 3),
|
||||
CLK_SCALE(LOONGSON2_APB_CLK, "clk_apb", "clk_node", 0x50, 20, 3),
|
||||
CLK_SCALE(LOONGSON2_BOOT_CLK, "clk_boot", NULL, 0x50, 23, 3),
|
||||
CLK_SCALE(LOONGSON2_DES_CLK, "clk_des", "clk_node", 0x50, 40, 3),
|
||||
CLK_SCALE(LOONGSON2_I2S_CLK, "clk_i2s", "clk_node", 0x50, 44, 3),
|
||||
CLK_FIXED(LOONGSON2_MISC_CLK, "clk_misc", NULL, 50000000),
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
hws[LOONGSON2_DDR_CLK] = devm_clk_hw_register_divider(dev, "ddr",
|
||||
"ddr_pll", 0,
|
||||
loongson2_pll_base + 0x18, 0,
|
||||
6, CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
static inline struct loongson2_clk_data *to_loongson2_clk(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct loongson2_clk_data, hw);
|
||||
}
|
||||
|
||||
hws[LOONGSON2_GMAC_CLK] = devm_clk_hw_register_divider(dev, "gmac",
|
||||
"dc_pll", 0,
|
||||
loongson2_pll_base + 0x28, 22,
|
||||
6, CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
static inline unsigned long loongson2_rate_part(u64 val, u8 shift, u8 width)
|
||||
{
|
||||
return (val & GENMASK(shift + width - 1, shift)) >> shift;
|
||||
}
|
||||
|
||||
hws[LOONGSON2_DC_CLK] = devm_clk_hw_register_divider(dev, "dc",
|
||||
"dc_pll", 0,
|
||||
loongson2_pll_base + 0x28, 0,
|
||||
6, CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
static unsigned long loongson2_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u64 val, mult, div;
|
||||
struct loongson2_clk_data *clk = to_loongson2_clk(hw);
|
||||
|
||||
hws[LOONGSON2_APB_CLK] = loongson2_clk_register(dev, "apb",
|
||||
"gmac",
|
||||
&loongson2_apb_clk_ops, 0);
|
||||
val = readq(clk->reg);
|
||||
mult = loongson2_rate_part(val, clk->mult_shift, clk->mult_width);
|
||||
div = loongson2_rate_part(val, clk->div_shift, clk->div_width);
|
||||
|
||||
hws[LOONGSON2_USB_CLK] = loongson2_clk_register(dev, "usb",
|
||||
"gmac",
|
||||
&loongson2_usb_clk_ops, 0);
|
||||
return div_u64((u64)parent_rate * mult, div);
|
||||
}
|
||||
|
||||
hws[LOONGSON2_SATA_CLK] = loongson2_clk_register(dev, "sata",
|
||||
"gmac",
|
||||
&loongson2_sata_clk_ops, 0);
|
||||
static const struct clk_ops loongson2_pll_recalc_ops = {
|
||||
.recalc_rate = loongson2_pll_recalc_rate,
|
||||
};
|
||||
|
||||
hws[LOONGSON2_PIX0_CLK] = clk_hw_register_divider(NULL, "pix0",
|
||||
"pix0_pll", 0,
|
||||
loongson2_pll_base + 0x38, 0, 6,
|
||||
CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
static unsigned long loongson2_freqscale_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u64 val, mult;
|
||||
struct loongson2_clk_data *clk = to_loongson2_clk(hw);
|
||||
|
||||
hws[LOONGSON2_PIX1_CLK] = clk_hw_register_divider(NULL, "pix1",
|
||||
"pix1_pll", 0,
|
||||
loongson2_pll_base + 0x48, 0, 6,
|
||||
CLK_DIVIDER_ONE_BASED,
|
||||
&loongson2_clk_lock);
|
||||
val = readq(clk->reg);
|
||||
mult = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1;
|
||||
|
||||
ret = loongson2_check_clk_hws(hws, LOONGSON2_CLK_END);
|
||||
return div_u64((u64)parent_rate * mult, 8);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_freqscale_recalc_ops = {
|
||||
.recalc_rate = loongson2_freqscale_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp,
|
||||
const struct loongson2_clk_board_info *cld,
|
||||
const struct clk_ops *ops)
|
||||
{
|
||||
int ret;
|
||||
struct clk_hw *hw;
|
||||
struct loongson2_clk_data *clk;
|
||||
struct clk_init_data init = { };
|
||||
|
||||
clk = devm_kzalloc(clp->dev, sizeof(*clk), GFP_KERNEL);
|
||||
if (!clk)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = cld->name;
|
||||
init.ops = ops;
|
||||
init.flags = 0;
|
||||
init.num_parents = 1;
|
||||
|
||||
if (!cld->parent_name)
|
||||
init.parent_data = pdata;
|
||||
else
|
||||
init.parent_names = &cld->parent_name;
|
||||
|
||||
clk->reg = clp->base + cld->reg_offset;
|
||||
clk->div_shift = cld->div_shift;
|
||||
clk->div_width = cld->div_width;
|
||||
clk->mult_shift = cld->mult_shift;
|
||||
clk->mult_width = cld->mult_width;
|
||||
clk->hw.init = &init;
|
||||
|
||||
hw = &clk->hw;
|
||||
ret = devm_clk_hw_register(clp->dev, hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
clk = ERR_PTR(ret);
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data);
|
||||
return hw;
|
||||
}
|
||||
|
||||
static int loongson2_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i, clks_num = 0;
|
||||
struct clk_hw *hw;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct loongson2_clk_provider *clp;
|
||||
const struct loongson2_clk_board_info *p, *data;
|
||||
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
for (p = data; p->name; p++)
|
||||
clks_num++;
|
||||
|
||||
clp = devm_kzalloc(dev, struct_size(clp, clk_data.hws, clks_num),
|
||||
GFP_KERNEL);
|
||||
if (!clp)
|
||||
return -ENOMEM;
|
||||
|
||||
clp->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(clp->base))
|
||||
return PTR_ERR(clp->base);
|
||||
|
||||
spin_lock_init(&clp->clk_lock);
|
||||
clp->clk_data.num = clks_num + 1;
|
||||
clp->dev = dev;
|
||||
|
||||
for (i = 0; i < clks_num; i++) {
|
||||
p = &data[i];
|
||||
switch (p->type) {
|
||||
case CLK_TYPE_PLL:
|
||||
hw = loongson2_clk_register(clp, p,
|
||||
&loongson2_pll_recalc_ops);
|
||||
break;
|
||||
case CLK_TYPE_SCALE:
|
||||
hw = loongson2_clk_register(clp, p,
|
||||
&loongson2_freqscale_recalc_ops);
|
||||
break;
|
||||
case CLK_TYPE_DIVIDER:
|
||||
hw = devm_clk_hw_register_divider(dev, p->name,
|
||||
p->parent_name, 0,
|
||||
clp->base + p->reg_offset,
|
||||
p->div_shift, p->div_width,
|
||||
CLK_DIVIDER_ONE_BASED,
|
||||
&clp->clk_lock);
|
||||
break;
|
||||
case CLK_TYPE_GATE:
|
||||
hw = devm_clk_hw_register_gate(dev, p->name, p->parent_name, 0,
|
||||
clp->base + p->reg_offset,
|
||||
p->bit_idx, 0,
|
||||
&clp->clk_lock);
|
||||
break;
|
||||
case CLK_TYPE_FIXED:
|
||||
hw = clk_hw_register_fixed_rate_parent_data(dev, p->name, pdata,
|
||||
0, p->fixed_rate);
|
||||
break;
|
||||
default:
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid clk type\n");
|
||||
}
|
||||
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw),
|
||||
"Register clk: %s, type: %u failed!\n",
|
||||
p->name, p->type);
|
||||
|
||||
clp->clk_data.hws[p->id] = hw;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clp->clk_data);
|
||||
}
|
||||
|
||||
static const struct of_device_id loongson2_clk_match_table[] = {
|
||||
{ .compatible = "loongson,ls2k-clk" },
|
||||
{ .compatible = "loongson,ls2k0500-clk", .data = &ls2k0500_clks },
|
||||
{ .compatible = "loongson,ls2k-clk", .data = &ls2k1000_clks },
|
||||
{ .compatible = "loongson,ls2k2000-clk", .data = &ls2k2000_clks },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, loongson2_clk_match_table);
|
||||
@ -338,4 +369,5 @@ static struct platform_driver loongson2_clk_driver = {
|
||||
module_platform_driver(loongson2_clk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Loongson2 clock driver");
|
||||
MODULE_AUTHOR("Loongson Technology Corporation Limited");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -25,10 +25,12 @@
|
||||
#define RS9_REG_SS_AMP_0V7 0x1
|
||||
#define RS9_REG_SS_AMP_0V8 0x2
|
||||
#define RS9_REG_SS_AMP_0V9 0x3
|
||||
#define RS9_REG_SS_AMP_DEFAULT RS9_REG_SS_AMP_0V8
|
||||
#define RS9_REG_SS_AMP_MASK 0x3
|
||||
#define RS9_REG_SS_SSC_100 0
|
||||
#define RS9_REG_SS_SSC_M025 (1 << 3)
|
||||
#define RS9_REG_SS_SSC_M050 (3 << 3)
|
||||
#define RS9_REG_SS_SSC_DEFAULT RS9_REG_SS_SSC_100
|
||||
#define RS9_REG_SS_SSC_MASK (3 << 3)
|
||||
#define RS9_REG_SS_SSC_LOCK BIT(5)
|
||||
#define RS9_REG_SR 0x2
|
||||
@ -205,8 +207,8 @@ static int rs9_get_common_config(struct rs9_driver_data *rs9)
|
||||
int ret;
|
||||
|
||||
/* Set defaults */
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
|
||||
rs9->pll_ssc = RS9_REG_SS_SSC_100;
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_DEFAULT;
|
||||
rs9->pll_ssc = RS9_REG_SS_SSC_DEFAULT;
|
||||
|
||||
/* Output clock amplitude */
|
||||
ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt",
|
||||
@ -247,13 +249,13 @@ static void rs9_update_config(struct rs9_driver_data *rs9)
|
||||
int i;
|
||||
|
||||
/* If amplitude is non-default, update it. */
|
||||
if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) {
|
||||
if (rs9->pll_amplitude != RS9_REG_SS_AMP_DEFAULT) {
|
||||
regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK,
|
||||
rs9->pll_amplitude);
|
||||
}
|
||||
|
||||
/* If SSC is non-default, update it. */
|
||||
if (rs9->pll_ssc != RS9_REG_SS_SSC_100) {
|
||||
if (rs9->pll_ssc != RS9_REG_SS_SSC_DEFAULT) {
|
||||
regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK,
|
||||
rs9->pll_ssc);
|
||||
}
|
||||
|
@ -2,9 +2,10 @@
|
||||
/*
|
||||
* System Control and Power Interface (SCMI) Protocol based clock driver
|
||||
*
|
||||
* Copyright (C) 2018-2022 ARM Ltd.
|
||||
* Copyright (C) 2018-2024 ARM Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
@ -16,6 +17,17 @@
|
||||
#define NOT_ATOMIC false
|
||||
#define ATOMIC true
|
||||
|
||||
enum scmi_clk_feats {
|
||||
SCMI_CLK_ATOMIC_SUPPORTED,
|
||||
SCMI_CLK_STATE_CTRL_SUPPORTED,
|
||||
SCMI_CLK_RATE_CTRL_SUPPORTED,
|
||||
SCMI_CLK_PARENT_CTRL_SUPPORTED,
|
||||
SCMI_CLK_DUTY_CYCLE_SUPPORTED,
|
||||
SCMI_CLK_FEATS_COUNT
|
||||
};
|
||||
|
||||
#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
|
||||
|
||||
static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
|
||||
|
||||
struct scmi_clk {
|
||||
@ -158,41 +170,44 @@ static int scmi_clk_atomic_is_enabled(struct clk_hw *hw)
|
||||
return !!enabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can provide enable/disable/is_enabled atomic callbacks only if the
|
||||
* underlying SCMI transport for an SCMI instance is configured to handle
|
||||
* SCMI commands in an atomic manner.
|
||||
*
|
||||
* When no SCMI atomic transport support is available we instead provide only
|
||||
* the prepare/unprepare API, as allowed by the clock framework when atomic
|
||||
* calls are not available.
|
||||
*
|
||||
* Two distinct sets of clk_ops are provided since we could have multiple SCMI
|
||||
* instances with different underlying transport quality, so they cannot be
|
||||
* shared.
|
||||
*/
|
||||
static const struct clk_ops scmi_clk_ops = {
|
||||
.recalc_rate = scmi_clk_recalc_rate,
|
||||
.round_rate = scmi_clk_round_rate,
|
||||
.set_rate = scmi_clk_set_rate,
|
||||
.prepare = scmi_clk_enable,
|
||||
.unprepare = scmi_clk_disable,
|
||||
.set_parent = scmi_clk_set_parent,
|
||||
.get_parent = scmi_clk_get_parent,
|
||||
.determine_rate = scmi_clk_determine_rate,
|
||||
};
|
||||
static int scmi_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
struct scmi_clk *clk = to_scmi_clk(hw);
|
||||
|
||||
static const struct clk_ops scmi_atomic_clk_ops = {
|
||||
.recalc_rate = scmi_clk_recalc_rate,
|
||||
.round_rate = scmi_clk_round_rate,
|
||||
.set_rate = scmi_clk_set_rate,
|
||||
.enable = scmi_clk_atomic_enable,
|
||||
.disable = scmi_clk_atomic_disable,
|
||||
.is_enabled = scmi_clk_atomic_is_enabled,
|
||||
.set_parent = scmi_clk_set_parent,
|
||||
.get_parent = scmi_clk_get_parent,
|
||||
.determine_rate = scmi_clk_determine_rate,
|
||||
};
|
||||
ret = scmi_proto_clk_ops->config_oem_get(clk->ph, clk->id,
|
||||
SCMI_CLOCK_CFG_DUTY_CYCLE,
|
||||
&val, NULL, false);
|
||||
if (!ret) {
|
||||
duty->num = val;
|
||||
duty->den = 100;
|
||||
} else {
|
||||
dev_warn(clk->dev,
|
||||
"Failed to get duty cycle for clock ID %d\n", clk->id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_clk_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
struct scmi_clk *clk = to_scmi_clk(hw);
|
||||
|
||||
/* SCMI OEM Duty Cycle is expressed as a percentage */
|
||||
val = (duty->num * 100) / duty->den;
|
||||
ret = scmi_proto_clk_ops->config_oem_set(clk->ph, clk->id,
|
||||
SCMI_CLOCK_CFG_DUTY_CYCLE,
|
||||
val, false);
|
||||
if (ret)
|
||||
dev_warn(clk->dev,
|
||||
"Failed to set duty cycle(%u/%u) for clock ID %d\n",
|
||||
duty->num, duty->den, clk->id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
|
||||
const struct clk_ops *scmi_ops)
|
||||
@ -230,17 +245,153 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_clk_ops_alloc() - Alloc and configure clock operations
|
||||
* @dev: A device reference for devres
|
||||
* @feats_key: A bitmap representing the desired clk_ops capabilities
|
||||
*
|
||||
* Allocate and configure a proper set of clock operations depending on the
|
||||
* specifically required SCMI clock features.
|
||||
*
|
||||
* Return: A pointer to the allocated and configured clk_ops on success,
|
||||
* or NULL on allocation failure.
|
||||
*/
|
||||
static const struct clk_ops *
|
||||
scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
|
||||
{
|
||||
struct clk_ops *ops;
|
||||
|
||||
ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
|
||||
if (!ops)
|
||||
return NULL;
|
||||
/*
|
||||
* We can provide enable/disable/is_enabled atomic callbacks only if the
|
||||
* underlying SCMI transport for an SCMI instance is configured to
|
||||
* handle SCMI commands in an atomic manner.
|
||||
*
|
||||
* When no SCMI atomic transport support is available we instead provide
|
||||
* only the prepare/unprepare API, as allowed by the clock framework
|
||||
* when atomic calls are not available.
|
||||
*/
|
||||
if (feats_key & BIT(SCMI_CLK_STATE_CTRL_SUPPORTED)) {
|
||||
if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED)) {
|
||||
ops->enable = scmi_clk_atomic_enable;
|
||||
ops->disable = scmi_clk_atomic_disable;
|
||||
} else {
|
||||
ops->prepare = scmi_clk_enable;
|
||||
ops->unprepare = scmi_clk_disable;
|
||||
}
|
||||
}
|
||||
|
||||
if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED))
|
||||
ops->is_enabled = scmi_clk_atomic_is_enabled;
|
||||
|
||||
/* Rate ops */
|
||||
ops->recalc_rate = scmi_clk_recalc_rate;
|
||||
ops->round_rate = scmi_clk_round_rate;
|
||||
ops->determine_rate = scmi_clk_determine_rate;
|
||||
if (feats_key & BIT(SCMI_CLK_RATE_CTRL_SUPPORTED))
|
||||
ops->set_rate = scmi_clk_set_rate;
|
||||
|
||||
/* Parent ops */
|
||||
ops->get_parent = scmi_clk_get_parent;
|
||||
if (feats_key & BIT(SCMI_CLK_PARENT_CTRL_SUPPORTED))
|
||||
ops->set_parent = scmi_clk_set_parent;
|
||||
|
||||
/* Duty cycle */
|
||||
if (feats_key & BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED)) {
|
||||
ops->get_duty_cycle = scmi_clk_get_duty_cycle;
|
||||
ops->set_duty_cycle = scmi_clk_set_duty_cycle;
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_clk_ops_select() - Select a proper set of clock operations
|
||||
* @sclk: A reference to an SCMI clock descriptor
|
||||
* @atomic_capable: A flag to indicate if atomic mode is supported by the
|
||||
* transport
|
||||
* @atomic_threshold_us: Platform atomic threshold value in microseconds:
|
||||
* clk_ops are atomic when clock enable latency is less
|
||||
* than this threshold
|
||||
* @clk_ops_db: A reference to the array used as a database to store all the
|
||||
* created clock operations combinations.
|
||||
* @db_size: Maximum number of entries held by @clk_ops_db
|
||||
*
|
||||
* After having built a bitmap descriptor to represent the set of features
|
||||
* needed by this SCMI clock, at first use it to lookup into the set of
|
||||
* previously allocated clk_ops to check if a suitable combination of clock
|
||||
* operations was already created; when no match is found allocate a brand new
|
||||
* set of clk_ops satisfying the required combination of features and save it
|
||||
* for future references.
|
||||
*
|
||||
* In this way only one set of clk_ops is ever created for each different
|
||||
* combination that is effectively needed by a driver instance.
|
||||
*
|
||||
* Return: A pointer to the allocated and configured clk_ops on success, or
|
||||
* NULL otherwise.
|
||||
*/
|
||||
static const struct clk_ops *
|
||||
scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
|
||||
unsigned int atomic_threshold_us,
|
||||
const struct clk_ops **clk_ops_db, size_t db_size)
|
||||
{
|
||||
const struct scmi_clock_info *ci = sclk->info;
|
||||
unsigned int feats_key = 0;
|
||||
const struct clk_ops *ops;
|
||||
|
||||
/*
|
||||
* Note that when transport is atomic but SCMI protocol did not
|
||||
* specify (or support) an enable_latency associated with a
|
||||
* clock, we default to use atomic operations mode.
|
||||
*/
|
||||
if (atomic_capable && ci->enable_latency <= atomic_threshold_us)
|
||||
feats_key |= BIT(SCMI_CLK_ATOMIC_SUPPORTED);
|
||||
|
||||
if (!ci->state_ctrl_forbidden)
|
||||
feats_key |= BIT(SCMI_CLK_STATE_CTRL_SUPPORTED);
|
||||
|
||||
if (!ci->rate_ctrl_forbidden)
|
||||
feats_key |= BIT(SCMI_CLK_RATE_CTRL_SUPPORTED);
|
||||
|
||||
if (!ci->parent_ctrl_forbidden)
|
||||
feats_key |= BIT(SCMI_CLK_PARENT_CTRL_SUPPORTED);
|
||||
|
||||
if (ci->extended_config)
|
||||
feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
|
||||
|
||||
if (WARN_ON(feats_key >= db_size))
|
||||
return NULL;
|
||||
|
||||
/* Lookup previously allocated ops */
|
||||
ops = clk_ops_db[feats_key];
|
||||
if (ops)
|
||||
return ops;
|
||||
|
||||
/* Did not find a pre-allocated clock_ops */
|
||||
ops = scmi_clk_ops_alloc(sclk->dev, feats_key);
|
||||
if (!ops)
|
||||
return NULL;
|
||||
|
||||
/* Store new ops combinations */
|
||||
clk_ops_db[feats_key] = ops;
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
static int scmi_clocks_probe(struct scmi_device *sdev)
|
||||
{
|
||||
int idx, count, err;
|
||||
unsigned int atomic_threshold;
|
||||
bool is_atomic;
|
||||
unsigned int atomic_threshold_us;
|
||||
bool transport_is_atomic;
|
||||
struct clk_hw **hws;
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct device *dev = &sdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct scmi_handle *handle = sdev->handle;
|
||||
struct scmi_protocol_handle *ph;
|
||||
const struct clk_ops *scmi_clk_ops_db[SCMI_MAX_CLK_OPS] = {};
|
||||
|
||||
if (!handle)
|
||||
return -ENODEV;
|
||||
@ -264,7 +415,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
|
||||
clk_data->num = count;
|
||||
hws = clk_data->hws;
|
||||
|
||||
is_atomic = handle->is_transport_atomic(handle, &atomic_threshold);
|
||||
transport_is_atomic = handle->is_transport_atomic(handle,
|
||||
&atomic_threshold_us);
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
struct scmi_clk *sclk;
|
||||
@ -286,15 +438,17 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
|
||||
sclk->dev = dev;
|
||||
|
||||
/*
|
||||
* Note that when transport is atomic but SCMI protocol did not
|
||||
* specify (or support) an enable_latency associated with a
|
||||
* clock, we default to use atomic operations mode.
|
||||
* Note that the scmi_clk_ops_db is on the stack, not global,
|
||||
* because it cannot be shared between mulitple probe-sequences
|
||||
* to avoid sharing the devm_ allocated clk_ops between multiple
|
||||
* SCMI clk driver instances.
|
||||
*/
|
||||
if (is_atomic &&
|
||||
sclk->info->enable_latency <= atomic_threshold)
|
||||
scmi_ops = &scmi_atomic_clk_ops;
|
||||
else
|
||||
scmi_ops = &scmi_clk_ops;
|
||||
scmi_ops = scmi_clk_ops_select(sclk, transport_is_atomic,
|
||||
atomic_threshold_us,
|
||||
scmi_clk_ops_db,
|
||||
ARRAY_SIZE(scmi_clk_ops_db));
|
||||
if (!scmi_ops)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize clock parent data. */
|
||||
if (sclk->info->num_parents > 0) {
|
||||
@ -318,8 +472,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
|
||||
} else {
|
||||
dev_dbg(dev, "Registered clock:%s%s\n",
|
||||
sclk->info->name,
|
||||
scmi_ops == &scmi_atomic_clk_ops ?
|
||||
" (atomic ops)" : "");
|
||||
scmi_ops->enable ? " (atomic ops)" : "");
|
||||
hws[idx] = &sclk->hw;
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,13 @@ config CLK_IMX93
|
||||
help
|
||||
Build the driver for i.MX93 CCM Clock Driver
|
||||
|
||||
config CLK_IMX95_BLK_CTL
|
||||
tristate "IMX95 Clock Driver for BLK CTL"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
select MXC_CLK
|
||||
help
|
||||
Build the clock driver for i.MX95 BLK CTL
|
||||
|
||||
config CLK_IMXRT1050
|
||||
tristate "IMXRT1050 CCM Clock Driver"
|
||||
depends on SOC_IMXRT || COMPILE_TEST
|
||||
|
@ -31,6 +31,7 @@ obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-imx8mp-audiomix.o
|
||||
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
|
||||
|
||||
obj-$(CONFIG_CLK_IMX93) += clk-imx93.o
|
||||
obj-$(CONFIG_CLK_IMX95_BLK_CTL) += clk-imx95-blk-ctl.o
|
||||
|
||||
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o clk-imx-acm.o
|
||||
clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
|
||||
|
@ -7,10 +7,12 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <dt-bindings/clock/imx8mp-clock.h>
|
||||
|
||||
@ -18,6 +20,7 @@
|
||||
|
||||
#define CLKEN0 0x000
|
||||
#define CLKEN1 0x004
|
||||
#define EARC 0x200
|
||||
#define SAI1_MCLK_SEL 0x300
|
||||
#define SAI2_MCLK_SEL 0x304
|
||||
#define SAI3_MCLK_SEL 0x308
|
||||
@ -26,6 +29,11 @@
|
||||
#define SAI7_MCLK_SEL 0x314
|
||||
#define PDM_SEL 0x318
|
||||
#define SAI_PLL_GNRL_CTL 0x400
|
||||
#define SAI_PLL_FDIVL_CTL0 0x404
|
||||
#define SAI_PLL_FDIVL_CTL1 0x408
|
||||
#define SAI_PLL_SSCG_CTL 0x40C
|
||||
#define SAI_PLL_MNIT_CTL 0x410
|
||||
#define IPG_LP_CTRL 0x504
|
||||
|
||||
#define SAIn_MCLK1_PARENT(n) \
|
||||
static const struct clk_parent_data \
|
||||
@ -182,26 +190,82 @@ static struct clk_imx8mp_audiomix_sel sels[] = {
|
||||
CLK_SAIn(7)
|
||||
};
|
||||
|
||||
static const u16 audiomix_regs[] = {
|
||||
CLKEN0,
|
||||
CLKEN1,
|
||||
EARC,
|
||||
SAI1_MCLK_SEL,
|
||||
SAI2_MCLK_SEL,
|
||||
SAI3_MCLK_SEL,
|
||||
SAI5_MCLK_SEL,
|
||||
SAI6_MCLK_SEL,
|
||||
SAI7_MCLK_SEL,
|
||||
PDM_SEL,
|
||||
SAI_PLL_GNRL_CTL,
|
||||
SAI_PLL_FDIVL_CTL0,
|
||||
SAI_PLL_FDIVL_CTL1,
|
||||
SAI_PLL_SSCG_CTL,
|
||||
SAI_PLL_MNIT_CTL,
|
||||
IPG_LP_CTRL,
|
||||
};
|
||||
|
||||
struct clk_imx8mp_audiomix_priv {
|
||||
void __iomem *base;
|
||||
u32 regs_save[ARRAY_SIZE(audiomix_regs)];
|
||||
|
||||
/* Must be last */
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
};
|
||||
|
||||
static void clk_imx8mp_audiomix_save_restore(struct device *dev, bool save)
|
||||
{
|
||||
struct clk_imx8mp_audiomix_priv *priv = dev_get_drvdata(dev);
|
||||
void __iomem *base = priv->base;
|
||||
int i;
|
||||
|
||||
if (save) {
|
||||
for (i = 0; i < ARRAY_SIZE(audiomix_regs); i++)
|
||||
priv->regs_save[i] = readl(base + audiomix_regs[i]);
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(audiomix_regs); i++)
|
||||
writel(priv->regs_save[i], base + audiomix_regs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw_onecell_data *priv;
|
||||
struct clk_imx8mp_audiomix_priv *priv;
|
||||
struct clk_hw_onecell_data *clk_hw_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *base;
|
||||
struct clk_hw *hw;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
priv = devm_kzalloc(dev,
|
||||
struct_size(priv, hws, IMX8MP_CLK_AUDIOMIX_END),
|
||||
struct_size(priv, clk_data.hws, IMX8MP_CLK_AUDIOMIX_END),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->num = IMX8MP_CLK_AUDIOMIX_END;
|
||||
clk_hw_data = &priv->clk_data;
|
||||
clk_hw_data->num = IMX8MP_CLK_AUDIOMIX_END;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
priv->base = base;
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
/*
|
||||
* pm_runtime_enable needs to be called before clk register.
|
||||
* That is to make core->rpm_enabled to be true for clock
|
||||
* usage.
|
||||
*/
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sels); i++) {
|
||||
if (sels[i].num_parents == 1) {
|
||||
hw = devm_clk_hw_register_gate_parent_data(dev,
|
||||
@ -216,10 +280,12 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
|
||||
0, NULL, NULL);
|
||||
}
|
||||
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
if (IS_ERR(hw)) {
|
||||
ret = PTR_ERR(hw);
|
||||
goto err_clk_register;
|
||||
}
|
||||
|
||||
priv->hws[sels[i].clkid] = hw;
|
||||
clk_hw_data->hws[sels[i].clkid] = hw;
|
||||
}
|
||||
|
||||
/* SAI PLL */
|
||||
@ -228,39 +294,84 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
|
||||
ARRAY_SIZE(clk_imx8mp_audiomix_pll_parents),
|
||||
CLK_SET_RATE_NO_REPARENT, base + SAI_PLL_GNRL_CTL,
|
||||
0, 2, 0, NULL, NULL);
|
||||
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = hw;
|
||||
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = hw;
|
||||
|
||||
hw = imx_dev_clk_hw_pll14xx(dev, "sai_pll", "sai_pll_ref_sel",
|
||||
base + 0x400, &imx_1443x_pll);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
ret = PTR_ERR(hw);
|
||||
goto err_clk_register;
|
||||
}
|
||||
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_mux_parent_data_table(dev,
|
||||
"sai_pll_bypass", clk_imx8mp_audiomix_pll_bypass_sels,
|
||||
ARRAY_SIZE(clk_imx8mp_audiomix_pll_bypass_sels),
|
||||
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||
base + SAI_PLL_GNRL_CTL, 16, 1, 0, NULL, NULL);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
ret = PTR_ERR(hw);
|
||||
goto err_clk_register;
|
||||
}
|
||||
|
||||
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_gate(dev, "sai_pll_out", "sai_pll_bypass",
|
||||
0, base + SAI_PLL_GNRL_CTL, 13,
|
||||
0, NULL);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
ret = PTR_ERR(hw);
|
||||
goto err_clk_register;
|
||||
}
|
||||
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "sai_pll_out_div2",
|
||||
"sai_pll_out", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
if (IS_ERR(hw)) {
|
||||
ret = PTR_ERR(hw);
|
||||
goto err_clk_register;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
|
||||
priv);
|
||||
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
|
||||
clk_hw_data);
|
||||
if (ret)
|
||||
goto err_clk_register;
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
return 0;
|
||||
|
||||
err_clk_register:
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_imx8mp_audiomix_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
static int clk_imx8mp_audiomix_runtime_suspend(struct device *dev)
|
||||
{
|
||||
clk_imx8mp_audiomix_save_restore(dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_imx8mp_audiomix_runtime_resume(struct device *dev)
|
||||
{
|
||||
clk_imx8mp_audiomix_save_restore(dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops clk_imx8mp_audiomix_pm_ops = {
|
||||
RUNTIME_PM_OPS(clk_imx8mp_audiomix_runtime_suspend,
|
||||
clk_imx8mp_audiomix_runtime_resume, NULL)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id clk_imx8mp_audiomix_of_match[] = {
|
||||
{ .compatible = "fsl,imx8mp-audio-blk-ctrl" },
|
||||
{ /* sentinel */ }
|
||||
@ -269,9 +380,11 @@ MODULE_DEVICE_TABLE(of, clk_imx8mp_audiomix_of_match);
|
||||
|
||||
static struct platform_driver clk_imx8mp_audiomix_driver = {
|
||||
.probe = clk_imx8mp_audiomix_probe,
|
||||
.remove_new = clk_imx8mp_audiomix_remove,
|
||||
.driver = {
|
||||
.name = "imx8mp-audio-blk-ctrl",
|
||||
.of_match_table = clk_imx8mp_audiomix_of_match,
|
||||
.pm = pm_ptr(&clk_imx8mp_audiomix_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
438
drivers/clk/imx/clk-imx95-blk-ctl.c
Normal file
438
drivers/clk/imx/clk-imx95-blk-ctl.c
Normal file
@ -0,0 +1,438 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2024 NXP
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/nxp,imx95-clock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
CLK_GATE,
|
||||
CLK_DIVIDER,
|
||||
CLK_MUX,
|
||||
};
|
||||
|
||||
struct imx95_blk_ctl {
|
||||
struct device *dev;
|
||||
spinlock_t lock;
|
||||
struct clk *clk_apb;
|
||||
|
||||
void __iomem *base;
|
||||
/* clock gate register */
|
||||
u32 clk_reg_restore;
|
||||
};
|
||||
|
||||
struct imx95_blk_ctl_clk_dev_data {
|
||||
const char *name;
|
||||
const char * const *parent_names;
|
||||
u32 num_parents;
|
||||
u32 reg;
|
||||
u32 bit_idx;
|
||||
u32 bit_width;
|
||||
u32 clk_type;
|
||||
u32 flags;
|
||||
u32 flags2;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
struct imx95_blk_ctl_dev_data {
|
||||
const struct imx95_blk_ctl_clk_dev_data *clk_dev_data;
|
||||
u32 num_clks;
|
||||
bool rpm_enabled;
|
||||
u32 clk_reg_offset;
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_clk_dev_data vpublk_clk_dev_data[] = {
|
||||
[IMX95_CLK_VPUBLK_WAVE] = {
|
||||
.name = "vpublk_wave_vpu",
|
||||
.parent_names = (const char *[]){ "vpu", },
|
||||
.num_parents = 1,
|
||||
.reg = 8,
|
||||
.bit_idx = 0,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_VPUBLK_JPEG_ENC] = {
|
||||
.name = "vpublk_jpeg_enc",
|
||||
.parent_names = (const char *[]){ "vpujpeg", },
|
||||
.num_parents = 1,
|
||||
.reg = 8,
|
||||
.bit_idx = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_VPUBLK_JPEG_DEC] = {
|
||||
.name = "vpublk_jpeg_dec",
|
||||
.parent_names = (const char *[]){ "vpujpeg", },
|
||||
.num_parents = 1,
|
||||
.reg = 8,
|
||||
.bit_idx = 2,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_dev_data vpublk_dev_data = {
|
||||
.num_clks = ARRAY_SIZE(vpublk_clk_dev_data),
|
||||
.clk_dev_data = vpublk_clk_dev_data,
|
||||
.rpm_enabled = true,
|
||||
.clk_reg_offset = 8,
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_clk_dev_data camblk_clk_dev_data[] = {
|
||||
[IMX95_CLK_CAMBLK_CSI2_FOR0] = {
|
||||
.name = "camblk_csi2_for0",
|
||||
.parent_names = (const char *[]){ "camisi", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 0,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_CAMBLK_CSI2_FOR1] = {
|
||||
.name = "camblk_csi2_for1",
|
||||
.parent_names = (const char *[]){ "camisi", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_CAMBLK_ISP_AXI] = {
|
||||
.name = "camblk_isp_axi",
|
||||
.parent_names = (const char *[]){ "camaxi", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 4,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_CAMBLK_ISP_PIXEL] = {
|
||||
.name = "camblk_isp_pixel",
|
||||
.parent_names = (const char *[]){ "camisi", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 5,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_CAMBLK_ISP] = {
|
||||
.name = "camblk_isp",
|
||||
.parent_names = (const char *[]){ "camisi", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 6,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_dev_data camblk_dev_data = {
|
||||
.num_clks = ARRAY_SIZE(camblk_clk_dev_data),
|
||||
.clk_dev_data = camblk_clk_dev_data,
|
||||
.clk_reg_offset = 0,
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_clk_dev_data lvds_clk_dev_data[] = {
|
||||
[IMX95_CLK_DISPMIX_LVDS_PHY_DIV] = {
|
||||
.name = "ldb_phy_div",
|
||||
.parent_names = (const char *[]){ "ldbpll", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 0,
|
||||
.bit_width = 1,
|
||||
.type = CLK_DIVIDER,
|
||||
.flags2 = CLK_DIVIDER_POWER_OF_TWO,
|
||||
},
|
||||
[IMX95_CLK_DISPMIX_LVDS_CH0_GATE] = {
|
||||
.name = "lvds_ch0_gate",
|
||||
.parent_names = (const char *[]){ "ldb_phy_div", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 1,
|
||||
.bit_width = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_DISPMIX_LVDS_CH1_GATE] = {
|
||||
.name = "lvds_ch1_gate",
|
||||
.parent_names = (const char *[]){ "ldb_phy_div", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 2,
|
||||
.bit_width = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_DISPMIX_PIX_DI0_GATE] = {
|
||||
.name = "lvds_di0_gate",
|
||||
.parent_names = (const char *[]){ "ldb_pll_div7", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 3,
|
||||
.bit_width = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
[IMX95_CLK_DISPMIX_PIX_DI1_GATE] = {
|
||||
.name = "lvds_di1_gate",
|
||||
.parent_names = (const char *[]){ "ldb_pll_div7", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 4,
|
||||
.bit_width = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.flags2 = CLK_GATE_SET_TO_DISABLE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_dev_data lvds_csr_dev_data = {
|
||||
.num_clks = ARRAY_SIZE(lvds_clk_dev_data),
|
||||
.clk_dev_data = lvds_clk_dev_data,
|
||||
.clk_reg_offset = 0,
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_clk_dev_data dispmix_csr_clk_dev_data[] = {
|
||||
[IMX95_CLK_DISPMIX_ENG0_SEL] = {
|
||||
.name = "disp_engine0_sel",
|
||||
.parent_names = (const char *[]){"videopll1", "dsi_pll", "ldb_pll_div7", },
|
||||
.num_parents = 4,
|
||||
.reg = 0,
|
||||
.bit_idx = 0,
|
||||
.bit_width = 2,
|
||||
.type = CLK_MUX,
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||
},
|
||||
[IMX95_CLK_DISPMIX_ENG1_SEL] = {
|
||||
.name = "disp_engine1_sel",
|
||||
.parent_names = (const char *[]){"videopll1", "dsi_pll", "ldb_pll_div7", },
|
||||
.num_parents = 4,
|
||||
.reg = 0,
|
||||
.bit_idx = 2,
|
||||
.bit_width = 2,
|
||||
.type = CLK_MUX,
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_dev_data dispmix_csr_dev_data = {
|
||||
.num_clks = ARRAY_SIZE(dispmix_csr_clk_dev_data),
|
||||
.clk_dev_data = dispmix_csr_clk_dev_data,
|
||||
.clk_reg_offset = 0,
|
||||
};
|
||||
|
||||
static int imx95_bc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct imx95_blk_ctl_dev_data *bc_data;
|
||||
struct imx95_blk_ctl *bc;
|
||||
struct clk_hw_onecell_data *clk_hw_data;
|
||||
struct clk_hw **hws;
|
||||
void __iomem *base;
|
||||
int i, ret;
|
||||
|
||||
bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
|
||||
if (!bc)
|
||||
return -ENOMEM;
|
||||
bc->dev = dev;
|
||||
dev_set_drvdata(&pdev->dev, bc);
|
||||
|
||||
spin_lock_init(&bc->lock);
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
bc->base = base;
|
||||
bc->clk_apb = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(bc->clk_apb))
|
||||
return dev_err_probe(dev, PTR_ERR(bc->clk_apb), "failed to get APB clock\n");
|
||||
|
||||
ret = clk_prepare_enable(bc->clk_apb);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable apb clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
if (!bc_data)
|
||||
return devm_of_platform_populate(dev);
|
||||
|
||||
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, bc_data->num_clks),
|
||||
GFP_KERNEL);
|
||||
if (!clk_hw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (bc_data->rpm_enabled)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
clk_hw_data->num = bc_data->num_clks;
|
||||
hws = clk_hw_data->hws;
|
||||
|
||||
for (i = 0; i < bc_data->num_clks; i++) {
|
||||
const struct imx95_blk_ctl_clk_dev_data *data = &bc_data->clk_dev_data[i];
|
||||
void __iomem *reg = base + data->reg;
|
||||
|
||||
if (data->type == CLK_MUX) {
|
||||
hws[i] = clk_hw_register_mux(dev, data->name, data->parent_names,
|
||||
data->num_parents, data->flags, reg,
|
||||
data->bit_idx, data->bit_width,
|
||||
data->flags2, &bc->lock);
|
||||
} else if (data->type == CLK_DIVIDER) {
|
||||
hws[i] = clk_hw_register_divider(dev, data->name, data->parent_names[0],
|
||||
data->flags, reg, data->bit_idx,
|
||||
data->bit_width, data->flags2, &bc->lock);
|
||||
} else {
|
||||
hws[i] = clk_hw_register_gate(dev, data->name, data->parent_names[0],
|
||||
data->flags, reg, data->bit_idx,
|
||||
data->flags2, &bc->lock);
|
||||
}
|
||||
if (IS_ERR(hws[i])) {
|
||||
ret = PTR_ERR(hws[i]);
|
||||
dev_err(dev, "failed to register: %s:%d\n", data->name, ret);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, clk_hw_data);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
ret = devm_of_platform_populate(dev);
|
||||
if (ret) {
|
||||
of_clk_del_provider(dev->of_node);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pm_runtime_enabled(bc->dev))
|
||||
clk_disable_unprepare(bc->clk_apb);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < bc_data->num_clks; i++) {
|
||||
if (IS_ERR_OR_NULL(hws[i]))
|
||||
continue;
|
||||
clk_hw_unregister(hws[i]);
|
||||
}
|
||||
|
||||
if (bc_data->rpm_enabled)
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int imx95_bc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(bc->clk_apb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx95_bc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
|
||||
return clk_prepare_enable(bc->clk_apb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int imx95_bc_suspend(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
const struct imx95_blk_ctl_dev_data *bc_data;
|
||||
int ret;
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
if (!bc_data)
|
||||
return 0;
|
||||
|
||||
if (bc_data->rpm_enabled) {
|
||||
ret = pm_runtime_get_sync(bc->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bc->dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bc->clk_reg_restore = readl(bc->base + bc_data->clk_reg_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx95_bc_resume(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
const struct imx95_blk_ctl_dev_data *bc_data;
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
if (!bc_data)
|
||||
return 0;
|
||||
|
||||
writel(bc->clk_reg_restore, bc->base + bc_data->clk_reg_offset);
|
||||
|
||||
if (bc_data->rpm_enabled)
|
||||
pm_runtime_put(bc->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops imx95_bc_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(imx95_bc_runtime_suspend, imx95_bc_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(imx95_bc_suspend, imx95_bc_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id imx95_bc_of_match[] = {
|
||||
{ .compatible = "nxp,imx95-camera-csr", .data = &camblk_dev_data },
|
||||
{ .compatible = "nxp,imx95-display-master-csr", },
|
||||
{ .compatible = "nxp,imx95-lvds-csr", .data = &lvds_csr_dev_data },
|
||||
{ .compatible = "nxp,imx95-display-csr", .data = &dispmix_csr_dev_data },
|
||||
{ .compatible = "nxp,imx95-vpu-csr", .data = &vpublk_dev_data },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx95_bc_of_match);
|
||||
|
||||
static struct platform_driver imx95_bc_driver = {
|
||||
.probe = imx95_bc_probe,
|
||||
.driver = {
|
||||
.name = "imx95-blk-ctl",
|
||||
.of_match_table = imx95_bc_of_match,
|
||||
.pm = &imx95_bc_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx95_bc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NXP i.MX95 blk ctl driver");
|
||||
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -53,7 +53,7 @@ static const struct mtk_gate mm_clks[] = {
|
||||
GATE_MM0(CLK_MM_MM_DSI0, "mm_dsi0", "mm_sel", 17),
|
||||
GATE_MM0(CLK_MM_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 18),
|
||||
GATE_MM0(CLK_MM_MM_MDP_RDMA1, "mm_mdp_rdma1", "mm_sel", 19),
|
||||
GATE_MM0(CLK_MM_DPI0_DPI0, "mm_dpi0_dpi0", "vpll_dpix", 20),
|
||||
GATE_MM0(CLK_MM_DPI0_DPI0, "mm_dpi0_dpi0", "dpi0_sel", 20),
|
||||
GATE_MM0(CLK_MM_MM_FAKE, "mm_fake", "mm_sel", 21),
|
||||
GATE_MM0(CLK_MM_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 22),
|
||||
GATE_MM0(CLK_MM_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 23),
|
||||
|
@ -68,7 +68,7 @@ void fhctl_parse_dt(const u8 *compatible_node, struct mtk_pllfh_data *pllfhs,
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, compatible_node);
|
||||
if (!node) {
|
||||
pr_err("cannot find \"%s\"\n", compatible_node);
|
||||
pr_warn("cannot find \"%s\"\n", compatible_node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,10 @@ config COMMON_CLK_MESON_VID_PLL_DIV
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_VCLK
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_CLKC_UTILS
|
||||
tristate
|
||||
|
||||
@ -140,6 +144,7 @@ config COMMON_CLK_G12A
|
||||
select COMMON_CLK_MESON_EE_CLKC
|
||||
select COMMON_CLK_MESON_CPU_DYNDIV
|
||||
select COMMON_CLK_MESON_VID_PLL_DIV
|
||||
select COMMON_CLK_MESON_VCLK
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_VCLK) += vclk.o
|
||||
|
||||
# Amlogic Clock controllers
|
||||
|
||||
|
@ -2187,6 +2187,7 @@ static struct regmap_config a1_periphs_regmap_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = DMC_CLK_CTRL,
|
||||
};
|
||||
|
||||
static struct meson_clk_hw_data a1_periphs_clks = {
|
||||
|
@ -299,6 +299,7 @@ static struct regmap_config a1_pll_regmap_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = ANACTRL_HIFIPLL_STS,
|
||||
};
|
||||
|
||||
static struct meson_clk_hw_data a1_pll_clks = {
|
||||
|
@ -340,4 +340,4 @@ static struct platform_driver axg_aoclkc_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(axg_aoclkc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1877,4 +1877,4 @@ module_platform_driver(axg_audio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic AXG/G12A/SM1 Audio Clock driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -2185,4 +2185,4 @@ static struct platform_driver axg_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(axg_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -69,4 +69,4 @@ EXPORT_SYMBOL_GPL(meson_clk_cpu_dyndiv_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic CPU Dynamic Clock divider");
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -140,4 +140,4 @@ EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops);
|
||||
MODULE_DESCRIPTION("Amlogic dual divider driver");
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -177,4 +177,4 @@ EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic MPLL driver");
|
||||
MODULE_AUTHOR("Michael Turquette <mturquette@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -183,4 +183,4 @@ EXPORT_SYMBOL_GPL(meson_sclk_ws_inv_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic phase driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -436,8 +436,8 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
ret = meson_clk_pll_enable(hw);
|
||||
if (ret) {
|
||||
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
|
||||
__func__, old_rate);
|
||||
pr_warn("%s: pll %s didn't lock, trying to set old rate %lu\n",
|
||||
__func__, clk_hw_get_name(hw), old_rate);
|
||||
/*
|
||||
* FIXME: Do we really need/want this HACK ?
|
||||
* It looks unsafe. what happens if the clock gets into a
|
||||
@ -486,4 +486,4 @@ EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops);
|
||||
MODULE_DESCRIPTION("Amlogic PLL driver");
|
||||
MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -183,4 +183,4 @@ EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -475,4 +475,4 @@ static struct platform_driver g12a_aoclkc_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(g12a_aoclkc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-cpu-dyndiv.h"
|
||||
#include "vid-pll-div.h"
|
||||
#include "vclk.h"
|
||||
#include "meson-eeclk.h"
|
||||
#include "g12a.h"
|
||||
|
||||
@ -3165,7 +3166,7 @@ static struct clk_regmap g12a_vclk2_sel = {
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = g12a_vclk_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(g12a_vclk_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3193,7 +3194,6 @@ static struct clk_regmap g12a_vclk2_input = {
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3215,19 +3215,32 @@ static struct clk_regmap g12a_vclk_div = {
|
||||
};
|
||||
|
||||
static struct clk_regmap g12a_vclk2_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VIID_CLK_DIV,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
.data = &(struct meson_vclk_div_data){
|
||||
.div = {
|
||||
.reg_off = HHI_VIID_CLK_DIV,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.enable = {
|
||||
.reg_off = HHI_VIID_CLK_DIV,
|
||||
.shift = 16,
|
||||
.width = 1,
|
||||
},
|
||||
.reset = {
|
||||
.reg_off = HHI_VIID_CLK_DIV,
|
||||
.shift = 17,
|
||||
.width = 1,
|
||||
},
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.ops = &meson_vclk_div_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&g12a_vclk2_input.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3246,16 +3259,24 @@ static struct clk_regmap g12a_vclk = {
|
||||
};
|
||||
|
||||
static struct clk_regmap g12a_vclk2 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 19,
|
||||
.data = &(struct meson_vclk_gate_data){
|
||||
.enable = {
|
||||
.reg_off = HHI_VIID_CLK_CNTL,
|
||||
.shift = 19,
|
||||
.width = 1,
|
||||
},
|
||||
.reset = {
|
||||
.reg_off = HHI_VIID_CLK_CNTL,
|
||||
.shift = 15,
|
||||
.width = 1,
|
||||
},
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.ops = &meson_vclk_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3339,7 +3360,7 @@ static struct clk_regmap g12a_vclk2_div1 = {
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3353,7 +3374,7 @@ static struct clk_regmap g12a_vclk2_div2_en = {
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3367,7 +3388,7 @@ static struct clk_regmap g12a_vclk2_div4_en = {
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3381,7 +3402,7 @@ static struct clk_regmap g12a_vclk2_div6_en = {
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3395,7 +3416,7 @@ static struct clk_regmap g12a_vclk2_div12_en = {
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3461,6 +3482,7 @@ static struct clk_fixed_factor g12a_vclk2_div2 = {
|
||||
&g12a_vclk2_div2_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3474,6 +3496,7 @@ static struct clk_fixed_factor g12a_vclk2_div4 = {
|
||||
&g12a_vclk2_div4_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3487,6 +3510,7 @@ static struct clk_fixed_factor g12a_vclk2_div6 = {
|
||||
&g12a_vclk2_div6_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3500,6 +3524,7 @@ static struct clk_fixed_factor g12a_vclk2_div12 = {
|
||||
&g12a_vclk2_div12_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3561,7 +3586,7 @@ static struct clk_regmap g12a_cts_encl_sel = {
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = g12a_cts_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(g12a_cts_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@ -3717,15 +3742,26 @@ static struct clk_regmap g12a_mipi_dsi_pxclk_sel = {
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = g12a_mipi_dsi_pxclk_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* FIXME: Force as bypass by forcing a single /1 table entry, and doensn't on boot value
|
||||
* when setting a clock whith this node in the clock path, but doesn't garantee the divider
|
||||
* is at /1 at boot until a rate is set.
|
||||
*/
|
||||
static const struct clk_div_table g12a_mipi_dsi_pxclk_div_table[] = {
|
||||
{ .val = 0, .div = 1 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct clk_regmap g12a_mipi_dsi_pxclk_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_MIPIDSI_PHY_CLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
.table = g12a_mipi_dsi_pxclk_div_table,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mipi_dsi_pxclk_div",
|
||||
@ -5578,4 +5614,4 @@ static struct platform_driver g12a_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(g12a_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -300,4 +300,4 @@ static struct platform_driver gxbb_aoclkc_driver = {
|
||||
},
|
||||
};
|
||||
module_platform_driver(gxbb_aoclkc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -3569,4 +3569,4 @@ static struct platform_driver gxbb_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(gxbb_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -89,4 +89,4 @@ int meson_aoclkc_probe(struct platform_device *pdev)
|
||||
return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_aoclkc_probe);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -58,4 +58,4 @@ int meson_eeclkc_probe(struct platform_device *pdev)
|
||||
return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_eeclkc_probe);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -3751,6 +3751,7 @@ static struct regmap_config clkc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = CLKCTRL_DEMOD_CLK_CTRL,
|
||||
};
|
||||
|
||||
static struct meson_clk_hw_data s4_periphs_clks = {
|
||||
@ -3799,6 +3800,7 @@ static const struct of_device_id clkc_match_table[] = {
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clkc_match_table);
|
||||
|
||||
static struct platform_driver s4_driver = {
|
||||
.probe = meson_s4_periphs_probe,
|
||||
|
@ -798,6 +798,7 @@ static struct regmap_config clkc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = ANACTRL_HDMIPLL_CTRL0,
|
||||
};
|
||||
|
||||
static struct meson_clk_hw_data s4_pll_clks = {
|
||||
@ -853,6 +854,7 @@ static const struct of_device_id clkc_match_table[] = {
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clkc_match_table);
|
||||
|
||||
static struct platform_driver s4_driver = {
|
||||
.probe = meson_s4_pll_probe,
|
||||
|
@ -251,4 +251,4 @@ EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic Sample divider driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
141
drivers/clk/meson/vclk.c
Normal file
141
drivers/clk/meson/vclk.c
Normal file
@ -0,0 +1,141 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 Neil Armstrong <neil.armstrong@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include "vclk.h"
|
||||
|
||||
/* The VCLK gate has a supplementary reset bit to pulse after ungating */
|
||||
|
||||
static inline struct meson_vclk_gate_data *
|
||||
clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
|
||||
{
|
||||
return (struct meson_vclk_gate_data *)clk->data;
|
||||
}
|
||||
|
||||
static int meson_vclk_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
|
||||
|
||||
meson_parm_write(clk->map, &vclk->enable, 1);
|
||||
|
||||
/* Do a reset pulse */
|
||||
meson_parm_write(clk->map, &vclk->reset, 1);
|
||||
meson_parm_write(clk->map, &vclk->reset, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_vclk_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
|
||||
|
||||
meson_parm_write(clk->map, &vclk->enable, 0);
|
||||
}
|
||||
|
||||
static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
|
||||
|
||||
return meson_parm_read(clk->map, &vclk->enable);
|
||||
}
|
||||
|
||||
const struct clk_ops meson_vclk_gate_ops = {
|
||||
.enable = meson_vclk_gate_enable,
|
||||
.disable = meson_vclk_gate_disable,
|
||||
.is_enabled = meson_vclk_gate_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_vclk_gate_ops);
|
||||
|
||||
/* The VCLK Divider has supplementary reset & enable bits */
|
||||
|
||||
static inline struct meson_vclk_div_data *
|
||||
clk_get_meson_vclk_div_data(struct clk_regmap *clk)
|
||||
{
|
||||
return (struct meson_vclk_div_data *)clk->data;
|
||||
}
|
||||
|
||||
static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
|
||||
|
||||
return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, &vclk->div),
|
||||
vclk->table, vclk->flags, vclk->div.width);
|
||||
}
|
||||
|
||||
static int meson_vclk_div_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
|
||||
|
||||
return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
|
||||
vclk->flags);
|
||||
}
|
||||
|
||||
static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
|
||||
int ret;
|
||||
|
||||
ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width,
|
||||
vclk->flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
meson_parm_write(clk->map, &vclk->div, ret);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int meson_vclk_div_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
|
||||
|
||||
/* Unreset the divider when ungating */
|
||||
meson_parm_write(clk->map, &vclk->reset, 0);
|
||||
meson_parm_write(clk->map, &vclk->enable, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_vclk_div_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
|
||||
|
||||
/* Reset the divider when gating */
|
||||
meson_parm_write(clk->map, &vclk->enable, 0);
|
||||
meson_parm_write(clk->map, &vclk->reset, 1);
|
||||
}
|
||||
|
||||
static int meson_vclk_div_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
|
||||
|
||||
return meson_parm_read(clk->map, &vclk->enable);
|
||||
}
|
||||
|
||||
const struct clk_ops meson_vclk_div_ops = {
|
||||
.recalc_rate = meson_vclk_div_recalc_rate,
|
||||
.determine_rate = meson_vclk_div_determine_rate,
|
||||
.set_rate = meson_vclk_div_set_rate,
|
||||
.enable = meson_vclk_div_enable,
|
||||
.disable = meson_vclk_div_disable,
|
||||
.is_enabled = meson_vclk_div_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_vclk_div_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic vclk clock driver");
|
||||
MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
|
||||
MODULE_LICENSE("GPL");
|
51
drivers/clk/meson/vclk.h
Normal file
51
drivers/clk/meson/vclk.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Neil Armstrong <neil.armstrong@linaro.org>
|
||||
*/
|
||||
|
||||
#ifndef __VCLK_H
|
||||
#define __VCLK_H
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "parm.h"
|
||||
|
||||
/**
|
||||
* struct meson_vclk_gate_data - vclk_gate regmap backed specific data
|
||||
*
|
||||
* @enable: vclk enable field
|
||||
* @reset: vclk reset field
|
||||
* @flags: hardware-specific flags
|
||||
*
|
||||
* Flags:
|
||||
* Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored
|
||||
*/
|
||||
struct meson_vclk_gate_data {
|
||||
struct parm enable;
|
||||
struct parm reset;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_vclk_gate_ops;
|
||||
|
||||
/**
|
||||
* struct meson_vclk_div_data - vclk_div regmap back specific data
|
||||
*
|
||||
* @div: divider field
|
||||
* @enable: vclk divider enable field
|
||||
* @reset: vclk divider reset field
|
||||
* @table: array of value/divider pairs, last entry should have div = 0
|
||||
*
|
||||
* Flags:
|
||||
* Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored
|
||||
*/
|
||||
struct meson_vclk_div_data {
|
||||
struct parm div;
|
||||
struct parm enable;
|
||||
struct parm reset;
|
||||
const struct clk_div_table *table;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_vclk_div_ops;
|
||||
|
||||
#endif /* __VCLK_H */
|
@ -96,4 +96,4 @@ EXPORT_SYMBOL_GPL(meson_vid_pll_div_ro_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic video pll divider driver");
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -4,12 +4,10 @@
|
||||
*
|
||||
* Copyright (C) 2020-2022 Microchip Technology Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <dt-bindings/clock/microchip,mpfs-clock.h>
|
||||
#include <soc/microchip/mpfs.h>
|
||||
|
||||
@ -361,93 +359,6 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Peripheral clock resets
|
||||
*/
|
||||
|
||||
#if IS_ENABLED(CONFIG_RESET_CONTROLLER)
|
||||
|
||||
u32 mpfs_reset_read(struct device *dev)
|
||||
{
|
||||
struct mpfs_clock_data *clock_data = dev_get_drvdata(dev->parent);
|
||||
|
||||
return readl_relaxed(clock_data->base + REG_SUBBLK_RESET_CR);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mpfs_reset_read, MCHP_CLK_MPFS);
|
||||
|
||||
void mpfs_reset_write(struct device *dev, u32 val)
|
||||
{
|
||||
struct mpfs_clock_data *clock_data = dev_get_drvdata(dev->parent);
|
||||
|
||||
writel_relaxed(val, clock_data->base + REG_SUBBLK_RESET_CR);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mpfs_reset_write, MCHP_CLK_MPFS);
|
||||
|
||||
static void mpfs_reset_unregister_adev(void *_adev)
|
||||
{
|
||||
struct auxiliary_device *adev = _adev;
|
||||
|
||||
auxiliary_device_delete(adev);
|
||||
auxiliary_device_uninit(adev);
|
||||
}
|
||||
|
||||
static void mpfs_reset_adev_release(struct device *dev)
|
||||
{
|
||||
struct auxiliary_device *adev = to_auxiliary_dev(dev);
|
||||
|
||||
kfree(adev);
|
||||
}
|
||||
|
||||
static struct auxiliary_device *mpfs_reset_adev_alloc(struct mpfs_clock_data *clk_data)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
|
||||
if (!adev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
adev->name = "reset-mpfs";
|
||||
adev->dev.parent = clk_data->dev;
|
||||
adev->dev.release = mpfs_reset_adev_release;
|
||||
adev->id = 666u;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret) {
|
||||
kfree(adev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return adev;
|
||||
}
|
||||
|
||||
static int mpfs_reset_controller_register(struct mpfs_clock_data *clk_data)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = mpfs_reset_adev_alloc(clk_data);
|
||||
if (IS_ERR(adev))
|
||||
return PTR_ERR(adev);
|
||||
|
||||
ret = auxiliary_device_add(adev);
|
||||
if (ret) {
|
||||
auxiliary_device_uninit(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(clk_data->dev, mpfs_reset_unregister_adev, adev);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_RESET_CONTROLLER */
|
||||
|
||||
static int mpfs_reset_controller_register(struct mpfs_clock_data *clk_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_RESET_CONTROLLER */
|
||||
|
||||
static int mpfs_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -499,7 +410,7 @@ static int mpfs_clk_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mpfs_reset_controller_register(clk_data);
|
||||
return mpfs_reset_controller_register(dev, clk_data->base + REG_SUBBLK_RESET_CR);
|
||||
}
|
||||
|
||||
static const struct of_device_id mpfs_clk_of_match_table[] = {
|
||||
@ -532,3 +443,4 @@ MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver");
|
||||
MODULE_AUTHOR("Padmarao Begari <padmarao.begari@microchip.com>");
|
||||
MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
|
||||
MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
|
||||
MODULE_IMPORT_NS(MCHP_CLK_MPFS);
|
||||
|
@ -250,7 +250,6 @@ static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = {
|
||||
struct lpc18xx_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
spinlock_t *lock;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
|
@ -474,6 +474,7 @@ config SC_CAMCC_7280
|
||||
|
||||
config SC_CAMCC_8280XP
|
||||
tristate "SC8280XP Camera Clock Controller"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
select SC_GCC_8280XP
|
||||
help
|
||||
Support for the camera clock controller on Qualcomm Technologies, Inc
|
||||
@ -1094,6 +1095,7 @@ config SM_GPUCC_8550
|
||||
|
||||
config SM_GPUCC_8650
|
||||
tristate "SM8650 Graphics Clock Controller"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
select SM_GCC_8650
|
||||
help
|
||||
Support for the graphics clock controller on SM8650 devices.
|
||||
|
@ -8,43 +8,14 @@
|
||||
|
||||
#include "clk-alpha-pll.h"
|
||||
|
||||
/*
|
||||
* Even though APSS PLL type is of existing one (like Huayra), its offsets
|
||||
* are different from the one mentioned in the clk-alpha-pll.c, since the
|
||||
* PLL is specific to APSS, so lets the define the same.
|
||||
*/
|
||||
static const u8 ipq_pll_offsets[][PLL_OFF_MAX_REGS] = {
|
||||
[CLK_ALPHA_PLL_TYPE_HUAYRA] = {
|
||||
[PLL_OFF_L_VAL] = 0x08,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x10,
|
||||
[PLL_OFF_USER_CTL] = 0x18,
|
||||
[PLL_OFF_CONFIG_CTL] = 0x20,
|
||||
[PLL_OFF_CONFIG_CTL_U] = 0x24,
|
||||
[PLL_OFF_STATUS] = 0x28,
|
||||
[PLL_OFF_TEST_CTL] = 0x30,
|
||||
[PLL_OFF_TEST_CTL_U] = 0x34,
|
||||
},
|
||||
[CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = {
|
||||
[PLL_OFF_L_VAL] = 0x08,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x10,
|
||||
[PLL_OFF_ALPHA_VAL_U] = 0x14,
|
||||
[PLL_OFF_USER_CTL] = 0x18,
|
||||
[PLL_OFF_USER_CTL_U] = 0x1c,
|
||||
[PLL_OFF_CONFIG_CTL] = 0x20,
|
||||
[PLL_OFF_STATUS] = 0x28,
|
||||
[PLL_OFF_TEST_CTL] = 0x30,
|
||||
[PLL_OFF_TEST_CTL_U] = 0x34,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_alpha_pll ipq_pll_huayra = {
|
||||
.offset = 0x0,
|
||||
.regs = ipq_pll_offsets[CLK_ALPHA_PLL_TYPE_HUAYRA],
|
||||
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_APSS],
|
||||
.flags = SUPPORTS_DYNAMIC_UPDATE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x0,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.hw.init = &(const struct clk_init_data) {
|
||||
.name = "a53pll",
|
||||
.parent_data = &(const struct clk_parent_data) {
|
||||
.fw_name = "xo",
|
||||
@ -55,14 +26,36 @@ static struct clk_alpha_pll ipq_pll_huayra = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_alpha_pll ipq_pll_stromer_plus = {
|
||||
static struct clk_alpha_pll ipq_pll_stromer = {
|
||||
.offset = 0x0,
|
||||
.regs = ipq_pll_offsets[CLK_ALPHA_PLL_TYPE_STROMER_PLUS],
|
||||
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER],
|
||||
.flags = SUPPORTS_DYNAMIC_UPDATE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x0,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.hw.init = &(const struct clk_init_data) {
|
||||
.name = "a53pll",
|
||||
.parent_data = &(const struct clk_parent_data) {
|
||||
.fw_name = "xo",
|
||||
},
|
||||
.num_parents = 1,
|
||||
.ops = &clk_alpha_pll_stromer_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_alpha_pll ipq_pll_stromer_plus = {
|
||||
.offset = 0x0,
|
||||
/*
|
||||
* The register offsets of the Stromer Plus PLL used in IPQ5332
|
||||
* are the same as the Stromer PLL's offsets.
|
||||
*/
|
||||
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER],
|
||||
.flags = SUPPORTS_DYNAMIC_UPDATE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x0,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(const struct clk_init_data) {
|
||||
.name = "a53pll",
|
||||
.parent_data = &(const struct clk_parent_data) {
|
||||
.fw_name = "xo",
|
||||
@ -73,8 +66,9 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = {
|
||||
},
|
||||
};
|
||||
|
||||
/* 1.008 GHz configuration */
|
||||
static const struct alpha_pll_config ipq5018_pll_config = {
|
||||
.l = 0x32,
|
||||
.l = 0x2a,
|
||||
.config_ctl_val = 0x4001075b,
|
||||
.config_ctl_hi_val = 0x304,
|
||||
.main_output_mask = BIT(0),
|
||||
@ -144,30 +138,30 @@ struct apss_pll_data {
|
||||
};
|
||||
|
||||
static const struct apss_pll_data ipq5018_pll_data = {
|
||||
.pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS,
|
||||
.pll = &ipq_pll_stromer_plus,
|
||||
.pll_type = CLK_ALPHA_PLL_TYPE_STROMER,
|
||||
.pll = &ipq_pll_stromer,
|
||||
.pll_config = &ipq5018_pll_config,
|
||||
};
|
||||
|
||||
static struct apss_pll_data ipq5332_pll_data = {
|
||||
static const struct apss_pll_data ipq5332_pll_data = {
|
||||
.pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS,
|
||||
.pll = &ipq_pll_stromer_plus,
|
||||
.pll_config = &ipq5332_pll_config,
|
||||
};
|
||||
|
||||
static struct apss_pll_data ipq8074_pll_data = {
|
||||
static const struct apss_pll_data ipq8074_pll_data = {
|
||||
.pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA,
|
||||
.pll = &ipq_pll_huayra,
|
||||
.pll_config = &ipq8074_pll_config,
|
||||
};
|
||||
|
||||
static struct apss_pll_data ipq6018_pll_data = {
|
||||
static const struct apss_pll_data ipq6018_pll_data = {
|
||||
.pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA,
|
||||
.pll = &ipq_pll_huayra,
|
||||
.pll_config = &ipq6018_pll_config,
|
||||
};
|
||||
|
||||
static struct apss_pll_data ipq9574_pll_data = {
|
||||
static const struct apss_pll_data ipq9574_pll_data = {
|
||||
.pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA,
|
||||
.pll = &ipq_pll_huayra,
|
||||
.pll_config = &ipq9574_pll_config,
|
||||
@ -203,7 +197,8 @@ static int apss_ipq_pll_probe(struct platform_device *pdev)
|
||||
|
||||
if (data->pll_type == CLK_ALPHA_PLL_TYPE_HUAYRA)
|
||||
clk_alpha_pll_configure(data->pll, regmap, data->pll_config);
|
||||
else if (data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER_PLUS)
|
||||
else if (data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER ||
|
||||
data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER_PLUS)
|
||||
clk_stromer_pll_configure(data->pll, regmap, data->pll_config);
|
||||
|
||||
ret = devm_clk_register_regmap(dev, &data->pll->clkr);
|
||||
|
@ -83,6 +83,16 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
|
||||
[PLL_OFF_TEST_CTL_U] = 0x20,
|
||||
[PLL_OFF_STATUS] = 0x24,
|
||||
},
|
||||
[CLK_ALPHA_PLL_TYPE_HUAYRA_APSS] = {
|
||||
[PLL_OFF_L_VAL] = 0x08,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x10,
|
||||
[PLL_OFF_USER_CTL] = 0x18,
|
||||
[PLL_OFF_CONFIG_CTL] = 0x20,
|
||||
[PLL_OFF_CONFIG_CTL_U] = 0x24,
|
||||
[PLL_OFF_STATUS] = 0x28,
|
||||
[PLL_OFF_TEST_CTL] = 0x30,
|
||||
[PLL_OFF_TEST_CTL_U] = 0x34,
|
||||
},
|
||||
[CLK_ALPHA_PLL_TYPE_BRAMMO] = {
|
||||
[PLL_OFF_L_VAL] = 0x04,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x08,
|
||||
@ -213,10 +223,9 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
|
||||
[PLL_OFF_USER_CTL] = 0x18,
|
||||
[PLL_OFF_USER_CTL_U] = 0x1c,
|
||||
[PLL_OFF_CONFIG_CTL] = 0x20,
|
||||
[PLL_OFF_CONFIG_CTL_U] = 0xff,
|
||||
[PLL_OFF_STATUS] = 0x28,
|
||||
[PLL_OFF_TEST_CTL] = 0x30,
|
||||
[PLL_OFF_TEST_CTL_U] = 0x34,
|
||||
[PLL_OFF_STATUS] = 0x28,
|
||||
},
|
||||
[CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = {
|
||||
[PLL_OFF_L_VAL] = 0x04,
|
||||
@ -2114,6 +2123,15 @@ void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma
|
||||
{
|
||||
u32 lval = config->l;
|
||||
|
||||
/*
|
||||
* If the bootloader left the PLL enabled it's likely that there are
|
||||
* RCGs that will lock up if we disable the PLL below.
|
||||
*/
|
||||
if (trion_pll_is_enabled(pll, regmap)) {
|
||||
pr_debug("Lucid Evo PLL is already enabled, skipping configuration\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lval |= TRION_PLL_CAL_VAL << LUCID_EVO_PLL_CAL_L_VAL_SHIFT;
|
||||
clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), lval);
|
||||
clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
|
||||
@ -2490,6 +2508,8 @@ static int clk_alpha_pll_stromer_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
rate = alpha_pll_round_rate(rate, prate, &l, &a, ALPHA_REG_BITWIDTH);
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
|
||||
|
||||
a <<= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH;
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
|
||||
a >> ALPHA_BITWIDTH);
|
||||
|
@ -15,6 +15,7 @@
|
||||
enum {
|
||||
CLK_ALPHA_PLL_TYPE_DEFAULT,
|
||||
CLK_ALPHA_PLL_TYPE_HUAYRA,
|
||||
CLK_ALPHA_PLL_TYPE_HUAYRA_APSS,
|
||||
CLK_ALPHA_PLL_TYPE_BRAMMO,
|
||||
CLK_ALPHA_PLL_TYPE_FABIA,
|
||||
CLK_ALPHA_PLL_TYPE_TRION,
|
||||
@ -73,8 +74,10 @@ struct pll_vco {
|
||||
/**
|
||||
* struct clk_alpha_pll - phase locked loop (PLL)
|
||||
* @offset: base address of registers
|
||||
* @vco_table: array of VCO settings
|
||||
* @regs: alpha pll register map (see @clk_alpha_pll_regs)
|
||||
* @vco_table: array of VCO settings
|
||||
* @num_vco: number of VCO settings in @vco_table
|
||||
* @flags: bitmask to indicate features supported by the hardware
|
||||
* @clkr: regmap clock handle
|
||||
*/
|
||||
struct clk_alpha_pll {
|
||||
|
@ -41,17 +41,6 @@ enum {
|
||||
|
||||
#define CBF_PLL_OFFSET 0xf000
|
||||
|
||||
static const u8 cbf_pll_regs[PLL_OFF_MAX_REGS] = {
|
||||
[PLL_OFF_L_VAL] = 0x08,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x10,
|
||||
[PLL_OFF_USER_CTL] = 0x18,
|
||||
[PLL_OFF_CONFIG_CTL] = 0x20,
|
||||
[PLL_OFF_CONFIG_CTL_U] = 0x24,
|
||||
[PLL_OFF_TEST_CTL] = 0x30,
|
||||
[PLL_OFF_TEST_CTL_U] = 0x34,
|
||||
[PLL_OFF_STATUS] = 0x28,
|
||||
};
|
||||
|
||||
static struct alpha_pll_config cbfpll_config = {
|
||||
.l = 72,
|
||||
.config_ctl_val = 0x200d4828,
|
||||
@ -67,7 +56,7 @@ static struct alpha_pll_config cbfpll_config = {
|
||||
|
||||
static struct clk_alpha_pll cbf_pll = {
|
||||
.offset = CBF_PLL_OFFSET,
|
||||
.regs = cbf_pll_regs,
|
||||
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_APSS],
|
||||
.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "cbf_pll",
|
||||
|
@ -17,6 +17,23 @@ struct freq_tbl {
|
||||
u16 n;
|
||||
};
|
||||
|
||||
#define C(s, h, m, n) { (s), (2 * (h) - 1), (m), (n) }
|
||||
#define FM(f, confs) { (f), ARRAY_SIZE(confs), (confs) }
|
||||
#define FMS(f, s, h, m, n) { (f), 1, (const struct freq_conf []){ C(s, h, m, n) } }
|
||||
|
||||
struct freq_conf {
|
||||
u8 src;
|
||||
u8 pre_div;
|
||||
u16 m;
|
||||
u16 n;
|
||||
};
|
||||
|
||||
struct freq_multi_tbl {
|
||||
unsigned long freq;
|
||||
size_t num_confs;
|
||||
const struct freq_conf *confs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mn - M/N:D counter
|
||||
* @mnctr_en_bit: bit to enable mn counter
|
||||
@ -138,6 +155,7 @@ extern const struct clk_ops clk_dyn_rcg_ops;
|
||||
* @safe_src_index: safe src index value
|
||||
* @parent_map: map from software's parent index to hardware's src_sel field
|
||||
* @freq_tbl: frequency table
|
||||
* @freq_multi_tbl: frequency table for clocks reachable with multiple RCGs conf
|
||||
* @clkr: regmap clock handle
|
||||
* @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG
|
||||
* @parked_cfg: cached value of the CFG register for parked RCGs
|
||||
@ -149,7 +167,10 @@ struct clk_rcg2 {
|
||||
u8 hid_width;
|
||||
u8 safe_src_index;
|
||||
const struct parent_map *parent_map;
|
||||
const struct freq_tbl *freq_tbl;
|
||||
union {
|
||||
const struct freq_tbl *freq_tbl;
|
||||
const struct freq_multi_tbl *freq_multi_tbl;
|
||||
};
|
||||
struct clk_regmap clkr;
|
||||
u8 cfg_off;
|
||||
u32 parked_cfg;
|
||||
@ -169,6 +190,7 @@ struct clk_rcg2_gfx3d {
|
||||
|
||||
extern const struct clk_ops clk_rcg2_ops;
|
||||
extern const struct clk_ops clk_rcg2_floor_ops;
|
||||
extern const struct clk_ops clk_rcg2_fm_ops;
|
||||
extern const struct clk_ops clk_rcg2_mux_closest_ops;
|
||||
extern const struct clk_ops clk_edp_pixel_ops;
|
||||
extern const struct clk_ops clk_byte_ops;
|
||||
|
@ -260,6 +260,115 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct freq_conf *
|
||||
__clk_rcg2_select_conf(struct clk_hw *hw, const struct freq_multi_tbl *f,
|
||||
unsigned long req_rate)
|
||||
{
|
||||
unsigned long rate_diff, best_rate_diff = ULONG_MAX;
|
||||
const struct freq_conf *conf, *best_conf = NULL;
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const char *name = clk_hw_get_name(hw);
|
||||
unsigned long parent_rate, rate;
|
||||
struct clk_hw *p;
|
||||
int index, i;
|
||||
|
||||
/* Exit early if only one config is defined */
|
||||
if (f->num_confs == 1) {
|
||||
best_conf = f->confs;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Search in each provided config the one that is near the wanted rate */
|
||||
for (i = 0, conf = f->confs; i < f->num_confs; i++, conf++) {
|
||||
index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
|
||||
if (index < 0)
|
||||
continue;
|
||||
|
||||
p = clk_hw_get_parent_by_index(hw, index);
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
parent_rate = clk_hw_get_rate(p);
|
||||
rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div);
|
||||
|
||||
if (rate == req_rate) {
|
||||
best_conf = conf;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rate_diff = abs_diff(req_rate, rate);
|
||||
if (rate_diff < best_rate_diff) {
|
||||
best_rate_diff = rate_diff;
|
||||
best_conf = conf;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Very unlikely. Warn if we couldn't find a correct config
|
||||
* due to parent not found in every config.
|
||||
*/
|
||||
if (unlikely(!best_conf)) {
|
||||
WARN(1, "%s: can't find a configuration for rate %lu\n",
|
||||
name, req_rate);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
exit:
|
||||
return best_conf;
|
||||
}
|
||||
|
||||
static int _freq_tbl_fm_determine_rate(struct clk_hw *hw, const struct freq_multi_tbl *f,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long clk_flags, rate = req->rate;
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_conf *conf;
|
||||
struct clk_hw *p;
|
||||
int index;
|
||||
|
||||
f = qcom_find_freq_multi(f, rate);
|
||||
if (!f || !f->confs)
|
||||
return -EINVAL;
|
||||
|
||||
conf = __clk_rcg2_select_conf(hw, f, rate);
|
||||
if (IS_ERR(conf))
|
||||
return PTR_ERR(conf);
|
||||
index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
|
||||
if (index < 0)
|
||||
return index;
|
||||
|
||||
clk_flags = clk_hw_get_flags(hw);
|
||||
p = clk_hw_get_parent_by_index(hw, index);
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
if (clk_flags & CLK_SET_RATE_PARENT) {
|
||||
rate = f->freq;
|
||||
if (conf->pre_div) {
|
||||
if (!rate)
|
||||
rate = req->rate;
|
||||
rate /= 2;
|
||||
rate *= conf->pre_div + 1;
|
||||
}
|
||||
|
||||
if (conf->n) {
|
||||
u64 tmp = rate;
|
||||
|
||||
tmp = tmp * conf->n;
|
||||
do_div(tmp, conf->m);
|
||||
rate = tmp;
|
||||
}
|
||||
} else {
|
||||
rate = clk_hw_get_rate(p);
|
||||
}
|
||||
|
||||
req->best_parent_hw = p;
|
||||
req->best_parent_rate = rate;
|
||||
req->rate = f->freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_rcg2_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
@ -276,6 +385,14 @@ static int clk_rcg2_determine_floor_rate(struct clk_hw *hw,
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, FLOOR);
|
||||
}
|
||||
|
||||
static int clk_rcg2_fm_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
|
||||
return _freq_tbl_fm_determine_rate(hw, rcg->freq_multi_tbl, req);
|
||||
}
|
||||
|
||||
static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f,
|
||||
u32 *_cfg)
|
||||
{
|
||||
@ -371,6 +488,30 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return clk_rcg2_configure(rcg, f);
|
||||
}
|
||||
|
||||
static int __clk_rcg2_fm_set_rate(struct clk_hw *hw, unsigned long rate)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_multi_tbl *f;
|
||||
const struct freq_conf *conf;
|
||||
struct freq_tbl f_tbl = {};
|
||||
|
||||
f = qcom_find_freq_multi(rcg->freq_multi_tbl, rate);
|
||||
if (!f || !f->confs)
|
||||
return -EINVAL;
|
||||
|
||||
conf = __clk_rcg2_select_conf(hw, f, rate);
|
||||
if (IS_ERR(conf))
|
||||
return PTR_ERR(conf);
|
||||
|
||||
f_tbl.freq = f->freq;
|
||||
f_tbl.src = conf->src;
|
||||
f_tbl.pre_div = conf->pre_div;
|
||||
f_tbl.m = conf->m;
|
||||
f_tbl.n = conf->n;
|
||||
|
||||
return clk_rcg2_configure(rcg, &f_tbl);
|
||||
}
|
||||
|
||||
static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
@ -383,6 +524,12 @@ static int clk_rcg2_set_floor_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return __clk_rcg2_set_rate(hw, rate, FLOOR);
|
||||
}
|
||||
|
||||
static int clk_rcg2_fm_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return __clk_rcg2_fm_set_rate(hw, rate);
|
||||
}
|
||||
|
||||
static int clk_rcg2_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate, u8 index)
|
||||
{
|
||||
@ -395,6 +542,12 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw,
|
||||
return __clk_rcg2_set_rate(hw, rate, FLOOR);
|
||||
}
|
||||
|
||||
static int clk_rcg2_fm_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate, u8 index)
|
||||
{
|
||||
return __clk_rcg2_fm_set_rate(hw, rate);
|
||||
}
|
||||
|
||||
static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
@ -505,6 +658,19 @@ const struct clk_ops clk_rcg2_floor_ops = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
|
||||
|
||||
const struct clk_ops clk_rcg2_fm_ops = {
|
||||
.is_enabled = clk_rcg2_is_enabled,
|
||||
.get_parent = clk_rcg2_get_parent,
|
||||
.set_parent = clk_rcg2_set_parent,
|
||||
.recalc_rate = clk_rcg2_recalc_rate,
|
||||
.determine_rate = clk_rcg2_fm_determine_rate,
|
||||
.set_rate = clk_rcg2_fm_set_rate,
|
||||
.set_rate_and_parent = clk_rcg2_fm_set_rate_and_parent,
|
||||
.get_duty_cycle = clk_rcg2_get_duty_cycle,
|
||||
.set_duty_cycle = clk_rcg2_set_duty_cycle,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_fm_ops);
|
||||
|
||||
const struct clk_ops clk_rcg2_mux_closest_ops = {
|
||||
.determine_rate = __clk_mux_determine_rate_closest,
|
||||
.get_parent = clk_rcg2_get_parent,
|
||||
|
@ -98,7 +98,6 @@ struct clk_rpm {
|
||||
};
|
||||
|
||||
struct rpm_cc {
|
||||
struct qcom_rpm *rpm;
|
||||
struct clk_rpm **clks;
|
||||
size_t num_clks;
|
||||
u32 xo_buffer_value;
|
||||
|
@ -41,6 +41,24 @@ struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_find_freq);
|
||||
|
||||
const struct freq_multi_tbl *qcom_find_freq_multi(const struct freq_multi_tbl *f,
|
||||
unsigned long rate)
|
||||
{
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
if (!f->freq)
|
||||
return f;
|
||||
|
||||
for (; f->freq; f++)
|
||||
if (rate <= f->freq)
|
||||
return f;
|
||||
|
||||
/* Default to our fastest rate */
|
||||
return f - 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_find_freq_multi);
|
||||
|
||||
const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
|
||||
unsigned long rate)
|
||||
{
|
||||
|
@ -45,6 +45,8 @@ extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
|
||||
unsigned long rate);
|
||||
extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
|
||||
unsigned long rate);
|
||||
extern const struct freq_multi_tbl *qcom_find_freq_multi(const struct freq_multi_tbl *f,
|
||||
unsigned long rate);
|
||||
extern void
|
||||
qcom_pll_set_fsm_mode(struct regmap *m, u32 reg, u8 bias_count, u8 lock_count);
|
||||
extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
|
||||
|
@ -221,26 +221,17 @@ static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = {
|
||||
F(162000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(270000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = {
|
||||
.cmd_rcgr = 0x10f8,
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_0,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dp_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "disp_cc_mdss_dp_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_0,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -309,26 +309,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = {
|
||||
F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = {
|
||||
.cmd_rcgr = 0x819c,
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx0_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -382,13 +373,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx1_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -442,13 +432,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx2_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -502,13 +491,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx3_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -345,26 +345,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = {
|
||||
F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = {
|
||||
.cmd_rcgr = 0x8170,
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_7,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx0_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_7,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_7),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -418,13 +409,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx1_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -478,13 +468,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx2_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -538,13 +527,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx3_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -343,26 +343,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = {
|
||||
F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = {
|
||||
.cmd_rcgr = 0x8170,
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_7,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(const struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx0_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_7,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_7),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -416,13 +407,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(const struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx1_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -476,13 +466,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(const struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx2_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -536,13 +525,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = {
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = disp_cc_parent_map_3,
|
||||
.freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
|
||||
.clkr.hw.init = &(const struct clk_init_data) {
|
||||
.name = "disp_cc_mdss_dptx3_link_clk_src",
|
||||
.parent_data = disp_cc_parent_data_3,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_byte2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1677,15 +1677,23 @@ static struct clk_regmap_div nss_port4_tx_div_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = {
|
||||
F(19200000, P_XO, 1, 0, 0),
|
||||
F(25000000, P_UNIPHY1_RX, 12.5, 0, 0),
|
||||
F(25000000, P_UNIPHY0_RX, 5, 0, 0),
|
||||
F(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
||||
F(125000000, P_UNIPHY1_RX, 2.5, 0, 0),
|
||||
F(125000000, P_UNIPHY0_RX, 1, 0, 0),
|
||||
F(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
||||
F(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
||||
static const struct freq_conf ftbl_nss_port5_rx_clk_src_25[] = {
|
||||
C(P_UNIPHY1_RX, 12.5, 0, 0),
|
||||
C(P_UNIPHY0_RX, 5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_conf ftbl_nss_port5_rx_clk_src_125[] = {
|
||||
C(P_UNIPHY1_RX, 2.5, 0, 0),
|
||||
C(P_UNIPHY0_RX, 1, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_multi_tbl ftbl_nss_port5_rx_clk_src[] = {
|
||||
FMS(19200000, P_XO, 1, 0, 0),
|
||||
FM(25000000, ftbl_nss_port5_rx_clk_src_25),
|
||||
FMS(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
||||
FM(125000000, ftbl_nss_port5_rx_clk_src_125),
|
||||
FMS(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
||||
FMS(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -1712,14 +1720,14 @@ gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = {
|
||||
|
||||
static struct clk_rcg2 nss_port5_rx_clk_src = {
|
||||
.cmd_rcgr = 0x68060,
|
||||
.freq_tbl = ftbl_nss_port5_rx_clk_src,
|
||||
.freq_multi_tbl = ftbl_nss_port5_rx_clk_src,
|
||||
.hid_width = 5,
|
||||
.parent_map = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "nss_port5_rx_clk_src",
|
||||
.parent_data = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias,
|
||||
.num_parents = ARRAY_SIZE(gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias),
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_rcg2_fm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1739,15 +1747,23 @@ static struct clk_regmap_div nss_port5_rx_div_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = {
|
||||
F(19200000, P_XO, 1, 0, 0),
|
||||
F(25000000, P_UNIPHY1_TX, 12.5, 0, 0),
|
||||
F(25000000, P_UNIPHY0_TX, 5, 0, 0),
|
||||
F(78125000, P_UNIPHY1_TX, 4, 0, 0),
|
||||
F(125000000, P_UNIPHY1_TX, 2.5, 0, 0),
|
||||
F(125000000, P_UNIPHY0_TX, 1, 0, 0),
|
||||
F(156250000, P_UNIPHY1_TX, 2, 0, 0),
|
||||
F(312500000, P_UNIPHY1_TX, 1, 0, 0),
|
||||
static const struct freq_conf ftbl_nss_port5_tx_clk_src_25[] = {
|
||||
C(P_UNIPHY1_TX, 12.5, 0, 0),
|
||||
C(P_UNIPHY0_TX, 5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_conf ftbl_nss_port5_tx_clk_src_125[] = {
|
||||
C(P_UNIPHY1_TX, 2.5, 0, 0),
|
||||
C(P_UNIPHY0_TX, 1, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_multi_tbl ftbl_nss_port5_tx_clk_src[] = {
|
||||
FMS(19200000, P_XO, 1, 0, 0),
|
||||
FM(25000000, ftbl_nss_port5_tx_clk_src_25),
|
||||
FMS(78125000, P_UNIPHY1_TX, 4, 0, 0),
|
||||
FM(125000000, ftbl_nss_port5_tx_clk_src_125),
|
||||
FMS(156250000, P_UNIPHY1_TX, 2, 0, 0),
|
||||
FMS(312500000, P_UNIPHY1_TX, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -1774,14 +1790,14 @@ gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = {
|
||||
|
||||
static struct clk_rcg2 nss_port5_tx_clk_src = {
|
||||
.cmd_rcgr = 0x68068,
|
||||
.freq_tbl = ftbl_nss_port5_tx_clk_src,
|
||||
.freq_multi_tbl = ftbl_nss_port5_tx_clk_src,
|
||||
.hid_width = 5,
|
||||
.parent_map = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "nss_port5_tx_clk_src",
|
||||
.parent_data = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias,
|
||||
.num_parents = ARRAY_SIZE(gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias),
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_rcg2_fm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1801,15 +1817,23 @@ static struct clk_regmap_div nss_port5_tx_div_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = {
|
||||
F(19200000, P_XO, 1, 0, 0),
|
||||
F(25000000, P_UNIPHY2_RX, 5, 0, 0),
|
||||
F(25000000, P_UNIPHY2_RX, 12.5, 0, 0),
|
||||
F(78125000, P_UNIPHY2_RX, 4, 0, 0),
|
||||
F(125000000, P_UNIPHY2_RX, 1, 0, 0),
|
||||
F(125000000, P_UNIPHY2_RX, 2.5, 0, 0),
|
||||
F(156250000, P_UNIPHY2_RX, 2, 0, 0),
|
||||
F(312500000, P_UNIPHY2_RX, 1, 0, 0),
|
||||
static const struct freq_conf ftbl_nss_port6_rx_clk_src_25[] = {
|
||||
C(P_UNIPHY2_RX, 5, 0, 0),
|
||||
C(P_UNIPHY2_RX, 12.5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_conf ftbl_nss_port6_rx_clk_src_125[] = {
|
||||
C(P_UNIPHY2_RX, 1, 0, 0),
|
||||
C(P_UNIPHY2_RX, 2.5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_multi_tbl ftbl_nss_port6_rx_clk_src[] = {
|
||||
FMS(19200000, P_XO, 1, 0, 0),
|
||||
FM(25000000, ftbl_nss_port6_rx_clk_src_25),
|
||||
FMS(78125000, P_UNIPHY2_RX, 4, 0, 0),
|
||||
FM(125000000, ftbl_nss_port6_rx_clk_src_125),
|
||||
FMS(156250000, P_UNIPHY2_RX, 2, 0, 0),
|
||||
FMS(312500000, P_UNIPHY2_RX, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -1831,14 +1855,14 @@ static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = {
|
||||
|
||||
static struct clk_rcg2 nss_port6_rx_clk_src = {
|
||||
.cmd_rcgr = 0x68070,
|
||||
.freq_tbl = ftbl_nss_port6_rx_clk_src,
|
||||
.freq_multi_tbl = ftbl_nss_port6_rx_clk_src,
|
||||
.hid_width = 5,
|
||||
.parent_map = gcc_xo_uniphy2_rx_tx_ubi32_bias_map,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "nss_port6_rx_clk_src",
|
||||
.parent_data = gcc_xo_uniphy2_rx_tx_ubi32_bias,
|
||||
.num_parents = ARRAY_SIZE(gcc_xo_uniphy2_rx_tx_ubi32_bias),
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_rcg2_fm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1858,15 +1882,23 @@ static struct clk_regmap_div nss_port6_rx_div_clk_src = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = {
|
||||
F(19200000, P_XO, 1, 0, 0),
|
||||
F(25000000, P_UNIPHY2_TX, 5, 0, 0),
|
||||
F(25000000, P_UNIPHY2_TX, 12.5, 0, 0),
|
||||
F(78125000, P_UNIPHY2_TX, 4, 0, 0),
|
||||
F(125000000, P_UNIPHY2_TX, 1, 0, 0),
|
||||
F(125000000, P_UNIPHY2_TX, 2.5, 0, 0),
|
||||
F(156250000, P_UNIPHY2_TX, 2, 0, 0),
|
||||
F(312500000, P_UNIPHY2_TX, 1, 0, 0),
|
||||
static const struct freq_conf ftbl_nss_port6_tx_clk_src_25[] = {
|
||||
C(P_UNIPHY2_TX, 5, 0, 0),
|
||||
C(P_UNIPHY2_TX, 12.5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_conf ftbl_nss_port6_tx_clk_src_125[] = {
|
||||
C(P_UNIPHY2_TX, 1, 0, 0),
|
||||
C(P_UNIPHY2_TX, 2.5, 0, 0),
|
||||
};
|
||||
|
||||
static const struct freq_multi_tbl ftbl_nss_port6_tx_clk_src[] = {
|
||||
FMS(19200000, P_XO, 1, 0, 0),
|
||||
FM(25000000, ftbl_nss_port6_tx_clk_src_25),
|
||||
FMS(78125000, P_UNIPHY1_RX, 4, 0, 0),
|
||||
FM(125000000, ftbl_nss_port6_tx_clk_src_125),
|
||||
FMS(156250000, P_UNIPHY1_RX, 2, 0, 0),
|
||||
FMS(312500000, P_UNIPHY1_RX, 1, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -1888,14 +1920,14 @@ static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = {
|
||||
|
||||
static struct clk_rcg2 nss_port6_tx_clk_src = {
|
||||
.cmd_rcgr = 0x68078,
|
||||
.freq_tbl = ftbl_nss_port6_tx_clk_src,
|
||||
.freq_multi_tbl = ftbl_nss_port6_tx_clk_src,
|
||||
.hid_width = 5,
|
||||
.parent_map = gcc_xo_uniphy2_tx_rx_ubi32_bias_map,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "nss_port6_tx_clk_src",
|
||||
.parent_data = gcc_xo_uniphy2_tx_rx_ubi32_bias,
|
||||
.num_parents = ARRAY_SIZE(gcc_xo_uniphy2_tx_rx_ubi32_bias),
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_rcg2_fm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -3278,6 +3278,7 @@ static const struct of_device_id gcc_msm8917_match_table[] = {
|
||||
{ .compatible = "qcom,gcc-qm215", .data = &gcc_qm215_desc },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gcc_msm8917_match_table);
|
||||
|
||||
static struct platform_driver gcc_msm8917_driver = {
|
||||
.probe = gcc_msm8917_probe,
|
||||
|
@ -4227,6 +4227,7 @@ static const struct of_device_id gcc_msm8953_match_table[] = {
|
||||
{ .compatible = "qcom,gcc-msm8953" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gcc_msm8953_match_table);
|
||||
|
||||
static struct platform_driver gcc_msm8953_driver = {
|
||||
.probe = gcc_msm8953_probe,
|
||||
|
@ -207,28 +207,6 @@ static const struct clk_parent_data gcc_parents_7[] = {
|
||||
{ .hw = &gpll0_out_even.clkr.hw },
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
|
||||
F(19200000, P_BI_TCXO, 1, 0, 0),
|
||||
F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
|
||||
F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg2 gcc_cpuss_ahb_clk_src = {
|
||||
.cmd_rcgr = 0x48014,
|
||||
.mnd_width = 0,
|
||||
.hid_width = 5,
|
||||
.parent_map = gcc_parent_map_0,
|
||||
.freq_tbl = ftbl_gcc_cpuss_ahb_clk_src,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_cpuss_ahb_clk_src",
|
||||
.parent_data = gcc_parents_0,
|
||||
.num_parents = ARRAY_SIZE(gcc_parents_0),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src[] = {
|
||||
F(19200000, P_BI_TCXO, 1, 0, 0),
|
||||
F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
|
||||
@ -1361,24 +1339,6 @@ static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_cpuss_ahb_clk = {
|
||||
.halt_reg = 0x48000,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52004,
|
||||
.enable_mask = BIT(21),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_cpuss_ahb_clk",
|
||||
.parent_hws = (const struct clk_hw *[]){
|
||||
&gcc_cpuss_ahb_clk_src.clkr.hw },
|
||||
.num_parents = 1,
|
||||
/* required for cpuss */
|
||||
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_cpuss_dvm_bus_clk = {
|
||||
.halt_reg = 0x48190,
|
||||
.halt_check = BRANCH_HALT,
|
||||
@ -2685,24 +2645,6 @@ static struct clk_branch gcc_sdcc4_apps_clk = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = {
|
||||
.halt_reg = 0x4819c,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.clkr = {
|
||||
.enable_reg = 0x52004,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_sys_noc_cpuss_ahb_clk",
|
||||
.parent_hws = (const struct clk_hw *[]){
|
||||
&gcc_cpuss_ahb_clk_src.clkr.hw },
|
||||
.num_parents = 1,
|
||||
/* required for cpuss */
|
||||
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_tsif_ahb_clk = {
|
||||
.halt_reg = 0x36004,
|
||||
.halt_check = BRANCH_HALT,
|
||||
@ -3550,8 +3492,6 @@ static struct clk_regmap *gcc_sm8150_clocks[] = {
|
||||
[GCC_CAMERA_XO_CLK] = &gcc_camera_xo_clk.clkr,
|
||||
[GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
|
||||
[GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr,
|
||||
[GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr,
|
||||
[GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr,
|
||||
[GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr,
|
||||
[GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
|
||||
[GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr,
|
||||
@ -3669,7 +3609,6 @@ static struct clk_regmap *gcc_sm8150_clocks[] = {
|
||||
[GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr,
|
||||
[GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr,
|
||||
[GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr,
|
||||
[GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr,
|
||||
[GCC_TSIF_AHB_CLK] = &gcc_tsif_ahb_clk.clkr,
|
||||
[GCC_TSIF_INACTIVITY_TIMERS_CLK] = &gcc_tsif_inactivity_timers_clk.clkr,
|
||||
[GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr,
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-hfpll.h"
|
||||
|
||||
static const struct hfpll_data hdata = {
|
||||
static const struct hfpll_data qcs404 = {
|
||||
.mode_reg = 0x00,
|
||||
.l_reg = 0x04,
|
||||
.m_reg = 0x08,
|
||||
@ -84,10 +84,12 @@ static const struct hfpll_data msm8976_cci = {
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_hfpll_match_table[] = {
|
||||
{ .compatible = "qcom,hfpll", .data = &hdata },
|
||||
{ .compatible = "qcom,msm8976-hfpll-a53", .data = &msm8976_a53 },
|
||||
{ .compatible = "qcom,msm8976-hfpll-a72", .data = &msm8976_a72 },
|
||||
{ .compatible = "qcom,msm8976-hfpll-cci", .data = &msm8976_cci },
|
||||
{ .compatible = "qcom,qcs404-hfpll", .data = &qcs404 },
|
||||
/* Deprecated in bindings */
|
||||
{ .compatible = "qcom,hfpll", .data = &qcs404 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
|
||||
|
@ -2535,6 +2535,8 @@ static struct clk_branch vmem_ahb_clk = {
|
||||
|
||||
static struct gdsc video_top_gdsc = {
|
||||
.gdscr = 0x1024,
|
||||
.cxcs = (unsigned int []){ 0x1028, 0x1034, 0x1038 },
|
||||
.cxc_count = 3,
|
||||
.pd = {
|
||||
.name = "video_top",
|
||||
},
|
||||
@ -2543,20 +2545,26 @@ static struct gdsc video_top_gdsc = {
|
||||
|
||||
static struct gdsc video_subcore0_gdsc = {
|
||||
.gdscr = 0x1040,
|
||||
.cxcs = (unsigned int []){ 0x1048 },
|
||||
.cxc_count = 1,
|
||||
.pd = {
|
||||
.name = "video_subcore0",
|
||||
},
|
||||
.parent = &video_top_gdsc.pd,
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.flags = HW_CTRL,
|
||||
};
|
||||
|
||||
static struct gdsc video_subcore1_gdsc = {
|
||||
.gdscr = 0x1044,
|
||||
.cxcs = (unsigned int []){ 0x104c },
|
||||
.cxc_count = 1,
|
||||
.pd = {
|
||||
.name = "video_subcore1",
|
||||
},
|
||||
.parent = &video_top_gdsc.pd,
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.flags = HW_CTRL,
|
||||
};
|
||||
|
||||
static struct gdsc mdss_gdsc = {
|
||||
|
@ -30,8 +30,6 @@ struct r8a73a4_cpg {
|
||||
#define CPG_PLL2HCR 0xe4
|
||||
#define CPG_PLL2SCR 0xf4
|
||||
|
||||
#define CLK_ENABLE_ON_INIT BIT(0)
|
||||
|
||||
struct div4_clk {
|
||||
const char *name;
|
||||
unsigned int reg;
|
||||
|
@ -26,28 +26,25 @@ struct r8a7740_cpg {
|
||||
#define CPG_USBCKCR 0x8c
|
||||
#define CPG_FRQCRC 0xe0
|
||||
|
||||
#define CLK_ENABLE_ON_INIT BIT(0)
|
||||
|
||||
struct div4_clk {
|
||||
const char *name;
|
||||
unsigned int reg;
|
||||
unsigned int shift;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static struct div4_clk div4_clks[] = {
|
||||
{ "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT },
|
||||
{ "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT },
|
||||
{ "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT },
|
||||
{ "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT },
|
||||
{ "hp", CPG_FRQCRB, 4, 0 },
|
||||
{ "hpp", CPG_FRQCRC, 20, 0 },
|
||||
{ "usbp", CPG_FRQCRC, 16, 0 },
|
||||
{ "s", CPG_FRQCRC, 12, 0 },
|
||||
{ "zb", CPG_FRQCRC, 8, 0 },
|
||||
{ "m3", CPG_FRQCRC, 4, 0 },
|
||||
{ "cp", CPG_FRQCRC, 0, 0 },
|
||||
{ NULL, 0, 0, 0 },
|
||||
{ "i", CPG_FRQCRA, 20 },
|
||||
{ "zg", CPG_FRQCRA, 16 },
|
||||
{ "b", CPG_FRQCRA, 8 },
|
||||
{ "m1", CPG_FRQCRA, 4 },
|
||||
{ "hp", CPG_FRQCRB, 4 },
|
||||
{ "hpp", CPG_FRQCRC, 20 },
|
||||
{ "usbp", CPG_FRQCRC, 16 },
|
||||
{ "s", CPG_FRQCRC, 12 },
|
||||
{ "zb", CPG_FRQCRC, 8 },
|
||||
{ "m3", CPG_FRQCRC, 4 },
|
||||
{ "cp", CPG_FRQCRC, 0 },
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
static const struct clk_div_table div4_div_table[] = {
|
||||
|
@ -34,8 +34,6 @@ struct sh73a0_cpg {
|
||||
#define CPG_DSI0PHYCR 0x6c
|
||||
#define CPG_DSI1PHYCR 0x70
|
||||
|
||||
#define CLK_ENABLE_ON_INIT BIT(0)
|
||||
|
||||
struct div4_clk {
|
||||
const char *name;
|
||||
const char *parent;
|
||||
|
@ -139,7 +139,7 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
|
||||
DEF_MOD("avb3", 214, R8A779A0_CLK_S3D2),
|
||||
DEF_MOD("avb4", 215, R8A779A0_CLK_S3D2),
|
||||
DEF_MOD("avb5", 216, R8A779A0_CLK_S3D2),
|
||||
DEF_MOD("canfd0", 328, R8A779A0_CLK_CANFD),
|
||||
DEF_MOD("canfd0", 328, R8A779A0_CLK_S3D2),
|
||||
DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0),
|
||||
DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0),
|
||||
DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0),
|
||||
|
@ -184,14 +184,35 @@ static const struct mssr_mod_clk r8a779h0_mod_clks[] = {
|
||||
DEF_MOD("i2c1", 519, R8A779H0_CLK_S0D6_PER),
|
||||
DEF_MOD("i2c2", 520, R8A779H0_CLK_S0D6_PER),
|
||||
DEF_MOD("i2c3", 521, R8A779H0_CLK_S0D6_PER),
|
||||
DEF_MOD("irqc", 611, R8A779H0_CLK_CL16M),
|
||||
DEF_MOD("msi0", 618, R8A779H0_CLK_MSO),
|
||||
DEF_MOD("msi1", 619, R8A779H0_CLK_MSO),
|
||||
DEF_MOD("msi2", 620, R8A779H0_CLK_MSO),
|
||||
DEF_MOD("msi3", 621, R8A779H0_CLK_MSO),
|
||||
DEF_MOD("msi4", 622, R8A779H0_CLK_MSO),
|
||||
DEF_MOD("msi5", 623, R8A779H0_CLK_MSO),
|
||||
DEF_MOD("rpc-if", 629, R8A779H0_CLK_RPCD2),
|
||||
DEF_MOD("scif0", 702, R8A779H0_CLK_SASYNCPERD4),
|
||||
DEF_MOD("scif1", 703, R8A779H0_CLK_SASYNCPERD4),
|
||||
DEF_MOD("scif3", 704, R8A779H0_CLK_SASYNCPERD4),
|
||||
DEF_MOD("scif4", 705, R8A779H0_CLK_SASYNCPERD4),
|
||||
DEF_MOD("sdhi0", 706, R8A779H0_CLK_SD0),
|
||||
DEF_MOD("sydm1", 709, R8A779H0_CLK_S0D6_PER),
|
||||
DEF_MOD("sydm2", 710, R8A779H0_CLK_S0D6_PER),
|
||||
DEF_MOD("tmu0", 713, R8A779H0_CLK_SASYNCRT),
|
||||
DEF_MOD("tmu1", 714, R8A779H0_CLK_SASYNCPERD2),
|
||||
DEF_MOD("tmu2", 715, R8A779H0_CLK_SASYNCPERD2),
|
||||
DEF_MOD("tmu3", 716, R8A779H0_CLK_SASYNCPERD2),
|
||||
DEF_MOD("tmu4", 717, R8A779H0_CLK_SASYNCPERD2),
|
||||
DEF_MOD("wdt1:wdt0", 907, R8A779H0_CLK_R),
|
||||
DEF_MOD("cmt0", 910, R8A779H0_CLK_R),
|
||||
DEF_MOD("cmt1", 911, R8A779H0_CLK_R),
|
||||
DEF_MOD("cmt2", 912, R8A779H0_CLK_R),
|
||||
DEF_MOD("cmt3", 913, R8A779H0_CLK_R),
|
||||
DEF_MOD("pfc0", 915, R8A779H0_CLK_CP),
|
||||
DEF_MOD("pfc1", 916, R8A779H0_CLK_CP),
|
||||
DEF_MOD("pfc2", 917, R8A779H0_CLK_CP),
|
||||
DEF_MOD("tsc2:tsc1", 919, R8A779H0_CLK_CL16M),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -149,7 +149,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct rzg2l_mod_clk r9a07g043_mod_clks[] = {
|
||||
static const struct rzg2l_mod_clk r9a07g043_mod_clks[] = {
|
||||
#ifdef CONFIG_ARM64
|
||||
DEF_MOD("gic", R9A07G043_GIC600_GICCLK, R9A07G043_CLK_P1,
|
||||
0x514, 0),
|
||||
@ -280,9 +280,13 @@ static struct rzg2l_mod_clk r9a07g043_mod_clks[] = {
|
||||
0x5a8, 1),
|
||||
DEF_MOD("tsu_pclk", R9A07G043_TSU_PCLK, R9A07G043_CLK_TSU,
|
||||
0x5ac, 0),
|
||||
#ifdef CONFIG_RISCV
|
||||
DEF_MOD("nceplic_aclk", R9A07G043_NCEPLIC_ACLK, R9A07G043_CLK_P1,
|
||||
0x608, 0),
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct rzg2l_reset r9a07g043_resets[] = {
|
||||
static const struct rzg2l_reset r9a07g043_resets[] = {
|
||||
#ifdef CONFIG_ARM64
|
||||
DEF_RST(R9A07G043_GIC600_GICRESET_N, 0x814, 0),
|
||||
DEF_RST(R9A07G043_GIC600_DBG_GICRESET_N, 0x814, 1),
|
||||
@ -338,6 +342,10 @@ static struct rzg2l_reset r9a07g043_resets[] = {
|
||||
DEF_RST(R9A07G043_ADC_PRESETN, 0x8a8, 0),
|
||||
DEF_RST(R9A07G043_ADC_ADRST_N, 0x8a8, 1),
|
||||
DEF_RST(R9A07G043_TSU_PRESETN, 0x8ac, 0),
|
||||
#ifdef CONFIG_RISCV
|
||||
DEF_RST(R9A07G043_NCEPLIC_ARESETN, 0x908, 0),
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static const unsigned int r9a07g043_crit_mod_clks[] __initconst = {
|
||||
@ -347,6 +355,7 @@ static const unsigned int r9a07g043_crit_mod_clks[] __initconst = {
|
||||
#endif
|
||||
#ifdef CONFIG_RISCV
|
||||
MOD_CLK_BASE + R9A07G043_IAX45_CLK,
|
||||
MOD_CLK_BASE + R9A07G043_NCEPLIC_ACLK,
|
||||
#endif
|
||||
MOD_CLK_BASE + R9A07G043_DMAC_ACLK,
|
||||
};
|
||||
|
@ -368,7 +368,7 @@ static const struct {
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct rzg2l_reset r9a07g044_resets[] = {
|
||||
static const struct rzg2l_reset r9a07g044_resets[] = {
|
||||
DEF_RST(R9A07G044_GIC600_GICRESET_N, 0x814, 0),
|
||||
DEF_RST(R9A07G044_GIC600_DBG_GICRESET_N, 0x814, 1),
|
||||
DEF_RST(R9A07G044_IA55_RESETN, 0x818, 0),
|
||||
|
@ -240,6 +240,43 @@ static const unsigned int r9a08g045_crit_mod_clks[] __initconst = {
|
||||
MOD_CLK_BASE + R9A08G045_DMAC_ACLK,
|
||||
};
|
||||
|
||||
static const struct rzg2l_cpg_pm_domain_init_data r9a08g045_pm_domains[] = {
|
||||
/* Keep always-on domain on the first position for proper domains registration. */
|
||||
DEF_PD("always-on", R9A08G045_PD_ALWAYS_ON,
|
||||
DEF_REG_CONF(0, 0),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
DEF_PD("gic", R9A08G045_PD_GIC,
|
||||
DEF_REG_CONF(CPG_BUS_ACPU_MSTOP, BIT(3)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
DEF_PD("ia55", R9A08G045_PD_IA55,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_CPU_MSTOP, BIT(13)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
DEF_PD("dmac", R9A08G045_PD_DMAC,
|
||||
DEF_REG_CONF(CPG_BUS_REG1_MSTOP, GENMASK(3, 0)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
DEF_PD("wdt0", R9A08G045_PD_WDT0,
|
||||
DEF_REG_CONF(CPG_BUS_REG0_MSTOP, BIT(0)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_PD("sdhi0", R9A08G045_PD_SDHI0,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(0)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_PD("sdhi1", R9A08G045_PD_SDHI1,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(1)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_PD("sdhi2", R9A08G045_PD_SDHI2,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(11)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_PD("eth0", R9A08G045_PD_ETHER0,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(2)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_PD("eth1", R9A08G045_PD_ETHER1,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(3)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_PD("scif0", R9A08G045_PD_SCIF0,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(1)),
|
||||
RZG2L_PD_F_NONE),
|
||||
};
|
||||
|
||||
const struct rzg2l_cpg_info r9a08g045_cpg_info = {
|
||||
/* Core Clocks */
|
||||
.core_clks = r9a08g045_core_clks,
|
||||
@ -260,5 +297,9 @@ const struct rzg2l_cpg_info r9a08g045_cpg_info = {
|
||||
.resets = r9a08g045_resets,
|
||||
.num_resets = R9A08G045_VBAT_BRESETN + 1, /* Last reset ID + 1 */
|
||||
|
||||
/* Power domains */
|
||||
.pm_domains = r9a08g045_pm_domains,
|
||||
.num_pm_domains = ARRAY_SIZE(r9a08g045_pm_domains),
|
||||
|
||||
.has_clk_mon_regs = true,
|
||||
};
|
||||
|
@ -139,7 +139,6 @@ struct rzg2l_pll5_mux_dsi_div_param {
|
||||
* @num_resets: Number of Module Resets in info->resets[]
|
||||
* @last_dt_core_clk: ID of the last Core Clock exported to DT
|
||||
* @info: Pointer to platform data
|
||||
* @genpd: PM domain
|
||||
* @mux_dsi_div_params: pll5 mux and dsi div parameters
|
||||
*/
|
||||
struct rzg2l_cpg_priv {
|
||||
@ -156,8 +155,6 @@ struct rzg2l_cpg_priv {
|
||||
|
||||
const struct rzg2l_cpg_info *info;
|
||||
|
||||
struct generic_pm_domain genpd;
|
||||
|
||||
struct rzg2l_pll5_mux_dsi_div_param mux_dsi_div_params;
|
||||
};
|
||||
|
||||
@ -1559,9 +1556,34 @@ static bool rzg2l_cpg_is_pm_clk(struct rzg2l_cpg_priv *priv,
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_pm_domains - RZ/G2L PM domains data structure
|
||||
* @onecell_data: cell data
|
||||
* @domains: generic PM domains
|
||||
*/
|
||||
struct rzg2l_cpg_pm_domains {
|
||||
struct genpd_onecell_data onecell_data;
|
||||
struct generic_pm_domain *domains[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_pd - RZ/G2L power domain data structure
|
||||
* @genpd: generic PM domain
|
||||
* @priv: pointer to CPG private data structure
|
||||
* @conf: CPG PM domain configuration info
|
||||
* @id: RZ/G2L power domain ID
|
||||
*/
|
||||
struct rzg2l_cpg_pd {
|
||||
struct generic_pm_domain genpd;
|
||||
struct rzg2l_cpg_priv *priv;
|
||||
struct rzg2l_cpg_pm_domain_conf conf;
|
||||
u16 id;
|
||||
};
|
||||
|
||||
static int rzg2l_cpg_attach_dev(struct generic_pm_domain *domain, struct device *dev)
|
||||
{
|
||||
struct rzg2l_cpg_priv *priv = container_of(domain, struct rzg2l_cpg_priv, genpd);
|
||||
struct rzg2l_cpg_pd *pd = container_of(domain, struct rzg2l_cpg_pd, genpd);
|
||||
struct rzg2l_cpg_priv *priv = pd->priv;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_phandle_args clkspec;
|
||||
bool once = true;
|
||||
@ -1617,31 +1639,180 @@ static void rzg2l_cpg_detach_dev(struct generic_pm_domain *unused, struct device
|
||||
}
|
||||
|
||||
static void rzg2l_cpg_genpd_remove(void *data)
|
||||
{
|
||||
struct genpd_onecell_data *celldata = data;
|
||||
|
||||
for (unsigned int i = 0; i < celldata->num_domains; i++)
|
||||
pm_genpd_remove(celldata->domains[i]);
|
||||
}
|
||||
|
||||
static void rzg2l_cpg_genpd_remove_simple(void *data)
|
||||
{
|
||||
pm_genpd_remove(data);
|
||||
}
|
||||
|
||||
static int rzg2l_cpg_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rzg2l_cpg_pd *pd = container_of(domain, struct rzg2l_cpg_pd, genpd);
|
||||
struct rzg2l_cpg_reg_conf mstop = pd->conf.mstop;
|
||||
struct rzg2l_cpg_priv *priv = pd->priv;
|
||||
|
||||
/* Set MSTOP. */
|
||||
if (mstop.mask)
|
||||
writel(mstop.mask << 16, priv->base + mstop.off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_cpg_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rzg2l_cpg_pd *pd = container_of(domain, struct rzg2l_cpg_pd, genpd);
|
||||
struct rzg2l_cpg_reg_conf mstop = pd->conf.mstop;
|
||||
struct rzg2l_cpg_priv *priv = pd->priv;
|
||||
|
||||
/* Set MSTOP. */
|
||||
if (mstop.mask)
|
||||
writel(mstop.mask | (mstop.mask << 16), priv->base + mstop.off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init rzg2l_cpg_pd_setup(struct rzg2l_cpg_pd *pd, bool always_on)
|
||||
{
|
||||
struct dev_power_governor *governor;
|
||||
|
||||
pd->genpd.flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
pd->genpd.attach_dev = rzg2l_cpg_attach_dev;
|
||||
pd->genpd.detach_dev = rzg2l_cpg_detach_dev;
|
||||
if (always_on) {
|
||||
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
governor = &pm_domain_always_on_gov;
|
||||
} else {
|
||||
pd->genpd.power_on = rzg2l_cpg_power_on;
|
||||
pd->genpd.power_off = rzg2l_cpg_power_off;
|
||||
governor = &simple_qos_governor;
|
||||
}
|
||||
|
||||
return pm_genpd_init(&pd->genpd, governor, !always_on);
|
||||
}
|
||||
|
||||
static int __init rzg2l_cpg_add_clk_domain(struct rzg2l_cpg_priv *priv)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct generic_pm_domain *genpd = &priv->genpd;
|
||||
struct rzg2l_cpg_pd *pd;
|
||||
int ret;
|
||||
|
||||
genpd->name = np->name;
|
||||
genpd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ALWAYS_ON |
|
||||
GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
genpd->attach_dev = rzg2l_cpg_attach_dev;
|
||||
genpd->detach_dev = rzg2l_cpg_detach_dev;
|
||||
ret = pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->genpd.name = np->name;
|
||||
pd->priv = priv;
|
||||
ret = rzg2l_cpg_pd_setup(pd, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, rzg2l_cpg_genpd_remove, genpd);
|
||||
ret = devm_add_action_or_reset(dev, rzg2l_cpg_genpd_remove_simple, &pd->genpd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_genpd_add_provider_simple(np, genpd);
|
||||
return of_genpd_add_provider_simple(np, &pd->genpd);
|
||||
}
|
||||
|
||||
static struct generic_pm_domain *
|
||||
rzg2l_cpg_pm_domain_xlate(const struct of_phandle_args *spec, void *data)
|
||||
{
|
||||
struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
|
||||
struct genpd_onecell_data *genpd = data;
|
||||
|
||||
if (spec->args_count != 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
for (unsigned int i = 0; i < genpd->num_domains; i++) {
|
||||
struct rzg2l_cpg_pd *pd = container_of(genpd->domains[i], struct rzg2l_cpg_pd,
|
||||
genpd);
|
||||
|
||||
if (pd->id == spec->args[0]) {
|
||||
domain = &pd->genpd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static int __init rzg2l_cpg_add_pm_domains(struct rzg2l_cpg_priv *priv)
|
||||
{
|
||||
const struct rzg2l_cpg_info *info = priv->info;
|
||||
struct device *dev = priv->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct rzg2l_cpg_pm_domains *domains;
|
||||
struct generic_pm_domain *parent;
|
||||
u32 ncells;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "#power-domain-cells", &ncells);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* For backward compatibility. */
|
||||
if (!ncells)
|
||||
return rzg2l_cpg_add_clk_domain(priv);
|
||||
|
||||
domains = devm_kzalloc(dev, struct_size(domains, domains, info->num_pm_domains),
|
||||
GFP_KERNEL);
|
||||
if (!domains)
|
||||
return -ENOMEM;
|
||||
|
||||
domains->onecell_data.domains = domains->domains;
|
||||
domains->onecell_data.num_domains = info->num_pm_domains;
|
||||
domains->onecell_data.xlate = rzg2l_cpg_pm_domain_xlate;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, rzg2l_cpg_genpd_remove, &domains->onecell_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (unsigned int i = 0; i < info->num_pm_domains; i++) {
|
||||
bool always_on = !!(info->pm_domains[i].flags & RZG2L_PD_F_ALWAYS_ON);
|
||||
struct rzg2l_cpg_pd *pd;
|
||||
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->genpd.name = info->pm_domains[i].name;
|
||||
pd->conf = info->pm_domains[i].conf;
|
||||
pd->id = info->pm_domains[i].id;
|
||||
pd->priv = priv;
|
||||
|
||||
ret = rzg2l_cpg_pd_setup(pd, always_on);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (always_on) {
|
||||
ret = rzg2l_cpg_power_on(&pd->genpd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
domains->domains[i] = &pd->genpd;
|
||||
/* Parent should be on the very first entry of info->pm_domains[]. */
|
||||
if (!i) {
|
||||
parent = &pd->genpd;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = pm_genpd_add_subdomain(parent, &pd->genpd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_genpd_add_provider_onecell(np, &domains->onecell_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init rzg2l_cpg_probe(struct platform_device *pdev)
|
||||
@ -1697,7 +1868,7 @@ static int __init rzg2l_cpg_probe(struct platform_device *pdev)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = rzg2l_cpg_add_clk_domain(priv);
|
||||
error = rzg2l_cpg_add_pm_domains(priv);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -27,6 +27,18 @@
|
||||
#define CPG_PL6_ETH_SSEL (0x418)
|
||||
#define CPG_PL5_SDIV (0x420)
|
||||
#define CPG_RST_MON (0x680)
|
||||
#define CPG_BUS_ACPU_MSTOP (0xB60)
|
||||
#define CPG_BUS_MCPU1_MSTOP (0xB64)
|
||||
#define CPG_BUS_MCPU2_MSTOP (0xB68)
|
||||
#define CPG_BUS_PERI_COM_MSTOP (0xB6C)
|
||||
#define CPG_BUS_PERI_CPU_MSTOP (0xB70)
|
||||
#define CPG_BUS_PERI_DDR_MSTOP (0xB74)
|
||||
#define CPG_BUS_REG0_MSTOP (0xB7C)
|
||||
#define CPG_BUS_REG1_MSTOP (0xB80)
|
||||
#define CPG_BUS_TZCDDR_MSTOP (0xB84)
|
||||
#define CPG_MHU_MSTOP (0xB88)
|
||||
#define CPG_BUS_MCPU3_MSTOP (0xB90)
|
||||
#define CPG_BUS_PERI_CPU2_MSTOP (0xB94)
|
||||
#define CPG_OTHERFUNC1_REG (0xBE8)
|
||||
|
||||
#define CPG_SIPLL5_STBY_RESETB BIT(0)
|
||||
@ -234,6 +246,55 @@ struct rzg2l_reset {
|
||||
#define DEF_RST(_id, _off, _bit) \
|
||||
DEF_RST_MON(_id, _off, _bit, -1)
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_reg_conf - RZ/G2L register configuration data structure
|
||||
* @off: register offset
|
||||
* @mask: register mask
|
||||
*/
|
||||
struct rzg2l_cpg_reg_conf {
|
||||
u16 off;
|
||||
u16 mask;
|
||||
};
|
||||
|
||||
#define DEF_REG_CONF(_off, _mask) ((struct rzg2l_cpg_reg_conf) { .off = (_off), .mask = (_mask) })
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_pm_domain_conf - PM domain configuration data structure
|
||||
* @mstop: MSTOP register configuration
|
||||
*/
|
||||
struct rzg2l_cpg_pm_domain_conf {
|
||||
struct rzg2l_cpg_reg_conf mstop;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_pm_domain_init_data - PM domain init data
|
||||
* @name: PM domain name
|
||||
* @conf: PM domain configuration
|
||||
* @flags: RZG2L PM domain flags (see RZG2L_PD_F_*)
|
||||
* @id: PM domain ID (similar to the ones defined in
|
||||
* include/dt-bindings/clock/<soc-id>-cpg.h)
|
||||
*/
|
||||
struct rzg2l_cpg_pm_domain_init_data {
|
||||
const char * const name;
|
||||
struct rzg2l_cpg_pm_domain_conf conf;
|
||||
u32 flags;
|
||||
u16 id;
|
||||
};
|
||||
|
||||
#define DEF_PD(_name, _id, _mstop_conf, _flags) \
|
||||
{ \
|
||||
.name = (_name), \
|
||||
.id = (_id), \
|
||||
.conf = { \
|
||||
.mstop = (_mstop_conf), \
|
||||
}, \
|
||||
.flags = (_flags), \
|
||||
}
|
||||
|
||||
/* Power domain flags. */
|
||||
#define RZG2L_PD_F_ALWAYS_ON BIT(0)
|
||||
#define RZG2L_PD_F_NONE (0)
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_info - SoC-specific CPG Description
|
||||
*
|
||||
@ -252,6 +313,8 @@ struct rzg2l_reset {
|
||||
* @crit_mod_clks: Array with Module Clock IDs of critical clocks that
|
||||
* should not be disabled without a knowledgeable driver
|
||||
* @num_crit_mod_clks: Number of entries in crit_mod_clks[]
|
||||
* @pm_domains: PM domains init data array
|
||||
* @num_pm_domains: Number of PM domains
|
||||
* @has_clk_mon_regs: Flag indicating whether the SoC has CLK_MON registers
|
||||
*/
|
||||
struct rzg2l_cpg_info {
|
||||
@ -278,6 +341,10 @@ struct rzg2l_cpg_info {
|
||||
const unsigned int *crit_mod_clks;
|
||||
unsigned int num_crit_mod_clks;
|
||||
|
||||
/* Power domain. */
|
||||
const struct rzg2l_cpg_pm_domain_init_data *pm_domains;
|
||||
unsigned int num_pm_domains;
|
||||
|
||||
bool has_clk_mon_regs;
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
struct rockchip_mmc_clock {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
int id;
|
||||
int shift;
|
||||
int cached_phase;
|
||||
struct notifier_block clk_rate_change_nb;
|
||||
|
@ -64,6 +64,7 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = {
|
||||
RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
|
||||
RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
|
||||
RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0),
|
||||
RK3036_PLL_RATE(724000000, 3, 181, 2, 1, 1, 0),
|
||||
RK3036_PLL_RATE(700000000, 3, 350, 4, 1, 1, 0),
|
||||
RK3036_PLL_RATE(696000000, 1, 116, 4, 1, 1, 0),
|
||||
RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0),
|
||||
@ -215,6 +216,7 @@ static const struct rockchip_cpuclk_reg_data rk3568_cpuclk_data = {
|
||||
|
||||
PNAME(mux_pll_p) = { "xin24m" };
|
||||
PNAME(mux_usb480m_p) = { "xin24m", "usb480m_phy", "clk_rtc_32k" };
|
||||
PNAME(mux_usb480m_phy_p) = { "clk_usbphy0_480m", "clk_usbphy1_480m"};
|
||||
PNAME(mux_armclk_p) = { "apll", "gpll" };
|
||||
PNAME(clk_i2s0_8ch_tx_p) = { "clk_i2s0_8ch_tx_src", "clk_i2s0_8ch_tx_frac", "i2s0_mclkin", "xin_osc0_half" };
|
||||
PNAME(clk_i2s0_8ch_rx_p) = { "clk_i2s0_8ch_rx_src", "clk_i2s0_8ch_rx_frac", "i2s0_mclkin", "xin_osc0_half" };
|
||||
@ -485,6 +487,9 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
|
||||
MUX(USB480M, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
|
||||
RK3568_MODE_CON0, 14, 2, MFLAGS),
|
||||
|
||||
MUX(USB480M_PHY, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
|
||||
RK3568_MISC_CON2, 15, 1, MFLAGS),
|
||||
|
||||
/* PD_CORE */
|
||||
COMPOSITE(0, "sclk_core_src", apll_gpll_npll_p, CLK_IGNORE_UNUSED,
|
||||
RK3568_CLKSEL_CON(2), 8, 2, MFLAGS, 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
|
||||
|
@ -577,6 +577,7 @@ static const int rk3588_register_offset[] = {
|
||||
|
||||
/* SOFTRST_CON59 */
|
||||
RK3588_CRU_RESET_OFFSET(SRST_A_HDCP1_BIU, 59, 6),
|
||||
RK3588_CRU_RESET_OFFSET(SRST_A_HDMIRX_BIU, 59, 7),
|
||||
RK3588_CRU_RESET_OFFSET(SRST_A_VO1_BIU, 59, 8),
|
||||
RK3588_CRU_RESET_OFFSET(SRST_H_VOP1_BIU, 59, 9),
|
||||
RK3588_CRU_RESET_OFFSET(SRST_H_VOP1_S_BIU, 59, 10),
|
||||
|
@ -17,10 +17,17 @@
|
||||
|
||||
#include "clk-exynos-arm64.h"
|
||||
|
||||
/* PLL register bits */
|
||||
#define PLL_CON1_MANUAL BIT(1)
|
||||
|
||||
/* Gate register bits */
|
||||
#define GATE_MANUAL BIT(20)
|
||||
#define GATE_ENABLE_HWACG BIT(28)
|
||||
|
||||
/* PLL_CONx_PLL register offsets range */
|
||||
#define PLL_CON_OFF_START 0x100
|
||||
#define PLL_CON_OFF_END 0x600
|
||||
|
||||
/* Gate register offsets range */
|
||||
#define GATE_OFF_START 0x2000
|
||||
#define GATE_OFF_END 0x2fff
|
||||
@ -38,17 +45,36 @@ struct exynos_arm64_cmu_data {
|
||||
struct samsung_clk_provider *ctx;
|
||||
};
|
||||
|
||||
/* Check if the register offset is a GATE register */
|
||||
static bool is_gate_reg(unsigned long off)
|
||||
{
|
||||
return off >= GATE_OFF_START && off <= GATE_OFF_END;
|
||||
}
|
||||
|
||||
/* Check if the register offset is a PLL_CONx register */
|
||||
static bool is_pll_conx_reg(unsigned long off)
|
||||
{
|
||||
return off >= PLL_CON_OFF_START && off <= PLL_CON_OFF_END;
|
||||
}
|
||||
|
||||
/* Check if the register offset is a PLL_CON1 register */
|
||||
static bool is_pll_con1_reg(unsigned long off)
|
||||
{
|
||||
return is_pll_conx_reg(off) && (off & 0xf) == 0x4 && !(off & 0x10);
|
||||
}
|
||||
|
||||
/**
|
||||
* exynos_arm64_init_clocks - Set clocks initial configuration
|
||||
* @np: CMU device tree node with "reg" property (CMU addr)
|
||||
* @reg_offs: Register offsets array for clocks to init
|
||||
* @reg_offs_len: Number of register offsets in reg_offs array
|
||||
* @np: CMU device tree node with "reg" property (CMU addr)
|
||||
* @cmu: CMU data
|
||||
*
|
||||
* Set manual control mode for all gate clocks.
|
||||
* Set manual control mode for all gate and PLL clocks.
|
||||
*/
|
||||
static void __init exynos_arm64_init_clocks(struct device_node *np,
|
||||
const unsigned long *reg_offs, size_t reg_offs_len)
|
||||
const struct samsung_cmu_info *cmu)
|
||||
{
|
||||
const unsigned long *reg_offs = cmu->clk_regs;
|
||||
size_t reg_offs_len = cmu->nr_clk_regs;
|
||||
void __iomem *reg_base;
|
||||
size_t i;
|
||||
|
||||
@ -60,14 +86,14 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
|
||||
void __iomem *reg = reg_base + reg_offs[i];
|
||||
u32 val;
|
||||
|
||||
/* Modify only gate clock registers */
|
||||
if (reg_offs[i] < GATE_OFF_START || reg_offs[i] > GATE_OFF_END)
|
||||
continue;
|
||||
|
||||
val = readl(reg);
|
||||
val |= GATE_MANUAL;
|
||||
val &= ~GATE_ENABLE_HWACG;
|
||||
writel(val, reg);
|
||||
if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
|
||||
writel(PLL_CON1_MANUAL, reg);
|
||||
} else if (is_gate_reg(reg_offs[i])) {
|
||||
val = readl(reg);
|
||||
val |= GATE_MANUAL;
|
||||
val &= ~GATE_ENABLE_HWACG;
|
||||
writel(val, reg);
|
||||
}
|
||||
}
|
||||
|
||||
iounmap(reg_base);
|
||||
@ -177,7 +203,7 @@ void __init exynos_arm64_register_cmu(struct device *dev,
|
||||
pr_err("%s: could not enable bus clock %s; err = %d\n",
|
||||
__func__, cmu->clk_name, err);
|
||||
|
||||
exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
|
||||
exynos_arm64_init_clocks(np, cmu);
|
||||
samsung_cmu_register_one(np, cmu);
|
||||
}
|
||||
|
||||
@ -224,7 +250,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
|
||||
__func__, cmu->clk_name, ret);
|
||||
|
||||
if (set_manual)
|
||||
exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
|
||||
exynos_arm64_init_clocks(np, cmu);
|
||||
|
||||
reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg_base))
|
||||
|
@ -14,13 +14,16 @@
|
||||
#include <dt-bindings/clock/exynos850.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "clk-cpu.h"
|
||||
#include "clk-exynos-arm64.h"
|
||||
|
||||
/* NOTE: Must be equal to the last clock ID increased by one */
|
||||
#define CLKS_NR_TOP (CLK_DOUT_G3D_SWITCH + 1)
|
||||
#define CLKS_NR_TOP (CLK_DOUT_CPUCL1_SWITCH + 1)
|
||||
#define CLKS_NR_APM (CLK_GOUT_SYSREG_APM_PCLK + 1)
|
||||
#define CLKS_NR_AUD (CLK_GOUT_AUD_CMU_AUD_PCLK + 1)
|
||||
#define CLKS_NR_CMGP (CLK_GOUT_SYSREG_CMGP_PCLK + 1)
|
||||
#define CLKS_NR_CPUCL0 (CLK_CLUSTER0_SCLK + 1)
|
||||
#define CLKS_NR_CPUCL1 (CLK_CLUSTER1_SCLK + 1)
|
||||
#define CLKS_NR_G3D (CLK_GOUT_G3D_SYSREG_PCLK + 1)
|
||||
#define CLKS_NR_HSI (CLK_GOUT_HSI_CMU_HSI_PCLK + 1)
|
||||
#define CLKS_NR_IS (CLK_GOUT_IS_SYSREG_PCLK + 1)
|
||||
@ -47,6 +50,10 @@
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CORE_CCI 0x1018
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD 0x101c
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CORE_SSS 0x1020
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG 0x1024
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH 0x1028
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CPUCL1_DBG 0x102c
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH 0x1030
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_DPU 0x1034
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH 0x1038
|
||||
#define CLK_CON_MUX_MUX_CLKCMU_HSI_BUS 0x103c
|
||||
@ -69,6 +76,10 @@
|
||||
#define CLK_CON_DIV_CLKCMU_CORE_CCI 0x1824
|
||||
#define CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD 0x1828
|
||||
#define CLK_CON_DIV_CLKCMU_CORE_SSS 0x182c
|
||||
#define CLK_CON_DIV_CLKCMU_CPUCL0_DBG 0x1830
|
||||
#define CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH 0x1834
|
||||
#define CLK_CON_DIV_CLKCMU_CPUCL1_DBG 0x1838
|
||||
#define CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH 0x183c
|
||||
#define CLK_CON_DIV_CLKCMU_DPU 0x1840
|
||||
#define CLK_CON_DIV_CLKCMU_G3D_SWITCH 0x1844
|
||||
#define CLK_CON_DIV_CLKCMU_HSI_BUS 0x1848
|
||||
@ -97,6 +108,10 @@
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CORE_CCI 0x2020
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD 0x2024
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CORE_SSS 0x2028
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG 0x202c
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH 0x2030
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CPUCL1_DBG 0x2034
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH 0x2038
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_DPU 0x203c
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH 0x2040
|
||||
#define CLK_CON_GAT_GATE_CLKCMU_HSI_BUS 0x2044
|
||||
@ -130,6 +145,10 @@ static const unsigned long top_clk_regs[] __initconst = {
|
||||
CLK_CON_MUX_MUX_CLKCMU_CORE_CCI,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CORE_SSS,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL1_DBG,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH,
|
||||
CLK_CON_MUX_MUX_CLKCMU_DPU,
|
||||
CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH,
|
||||
CLK_CON_MUX_MUX_CLKCMU_HSI_BUS,
|
||||
@ -152,6 +171,10 @@ static const unsigned long top_clk_regs[] __initconst = {
|
||||
CLK_CON_DIV_CLKCMU_CORE_CCI,
|
||||
CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD,
|
||||
CLK_CON_DIV_CLKCMU_CORE_SSS,
|
||||
CLK_CON_DIV_CLKCMU_CPUCL0_DBG,
|
||||
CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH,
|
||||
CLK_CON_DIV_CLKCMU_CPUCL1_DBG,
|
||||
CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH,
|
||||
CLK_CON_DIV_CLKCMU_DPU,
|
||||
CLK_CON_DIV_CLKCMU_G3D_SWITCH,
|
||||
CLK_CON_DIV_CLKCMU_HSI_BUS,
|
||||
@ -180,6 +203,10 @@ static const unsigned long top_clk_regs[] __initconst = {
|
||||
CLK_CON_GAT_GATE_CLKCMU_CORE_CCI,
|
||||
CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD,
|
||||
CLK_CON_GAT_GATE_CLKCMU_CORE_SSS,
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG,
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH,
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL1_DBG,
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH,
|
||||
CLK_CON_GAT_GATE_CLKCMU_DPU,
|
||||
CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH,
|
||||
CLK_CON_GAT_GATE_CLKCMU_HSI_BUS,
|
||||
@ -234,6 +261,14 @@ PNAME(mout_core_mmc_embd_p) = { "oscclk", "dout_shared0_div2",
|
||||
"oscclk", "oscclk" };
|
||||
PNAME(mout_core_sss_p) = { "dout_shared0_div3", "dout_shared1_div3",
|
||||
"dout_shared0_div4", "dout_shared1_div4" };
|
||||
/* List of parent clocks for Muxes in CMU_TOP: for CMU_CPUCL0 */
|
||||
PNAME(mout_cpucl0_switch_p) = { "fout_shared0_pll", "fout_shared1_pll",
|
||||
"dout_shared0_div2", "dout_shared1_div2" };
|
||||
PNAME(mout_cpucl0_dbg_p) = { "dout_shared0_div4", "dout_shared1_div4" };
|
||||
/* List of parent clocks for Muxes in CMU_TOP: for CMU_CPUCL1 */
|
||||
PNAME(mout_cpucl1_switch_p) = { "fout_shared0_pll", "fout_shared1_pll",
|
||||
"dout_shared0_div2", "dout_shared1_div2" };
|
||||
PNAME(mout_cpucl1_dbg_p) = { "dout_shared0_div4", "dout_shared1_div4" };
|
||||
/* List of parent clocks for Muxes in CMU_TOP: for CMU_G3D */
|
||||
PNAME(mout_g3d_switch_p) = { "dout_shared0_div2", "dout_shared1_div2",
|
||||
"dout_shared0_div3", "dout_shared1_div3" };
|
||||
@ -300,6 +335,18 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = {
|
||||
MUX(CLK_MOUT_CORE_SSS, "mout_core_sss", mout_core_sss_p,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CORE_SSS, 0, 2),
|
||||
|
||||
/* CPUCL0 */
|
||||
MUX(CLK_MOUT_CPUCL0_DBG, "mout_cpucl0_dbg", mout_cpucl0_dbg_p,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG, 0, 1),
|
||||
MUX(CLK_MOUT_CPUCL0_SWITCH, "mout_cpucl0_switch", mout_cpucl0_switch_p,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH, 0, 2),
|
||||
|
||||
/* CPUCL1 */
|
||||
MUX(CLK_MOUT_CPUCL1_DBG, "mout_cpucl1_dbg", mout_cpucl1_dbg_p,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL1_DBG, 0, 1),
|
||||
MUX(CLK_MOUT_CPUCL1_SWITCH, "mout_cpucl1_switch", mout_cpucl1_switch_p,
|
||||
CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH, 0, 2),
|
||||
|
||||
/* DPU */
|
||||
MUX(CLK_MOUT_DPU, "mout_dpu", mout_dpu_p,
|
||||
CLK_CON_MUX_MUX_CLKCMU_DPU, 0, 2),
|
||||
@ -378,6 +425,18 @@ static const struct samsung_div_clock top_div_clks[] __initconst = {
|
||||
DIV(CLK_DOUT_CORE_SSS, "dout_core_sss", "gout_core_sss",
|
||||
CLK_CON_DIV_CLKCMU_CORE_SSS, 0, 4),
|
||||
|
||||
/* CPUCL0 */
|
||||
DIV(CLK_DOUT_CPUCL0_DBG, "dout_cpucl0_dbg", "gout_cpucl0_dbg",
|
||||
CLK_CON_DIV_CLKCMU_CPUCL0_DBG, 0, 3),
|
||||
DIV(CLK_DOUT_CPUCL0_SWITCH, "dout_cpucl0_switch", "gout_cpucl0_switch",
|
||||
CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH, 0, 3),
|
||||
|
||||
/* CPUCL1 */
|
||||
DIV(CLK_DOUT_CPUCL1_DBG, "dout_cpucl1_dbg", "gout_cpucl1_dbg",
|
||||
CLK_CON_DIV_CLKCMU_CPUCL1_DBG, 0, 3),
|
||||
DIV(CLK_DOUT_CPUCL1_SWITCH, "dout_cpucl1_switch", "gout_cpucl1_switch",
|
||||
CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH, 0, 3),
|
||||
|
||||
/* DPU */
|
||||
DIV(CLK_DOUT_DPU, "dout_dpu", "gout_dpu",
|
||||
CLK_CON_DIV_CLKCMU_DPU, 0, 4),
|
||||
@ -442,6 +501,18 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = {
|
||||
GATE(CLK_GOUT_AUD, "gout_aud", "mout_aud",
|
||||
CLK_CON_GAT_GATE_CLKCMU_AUD, 21, 0, 0),
|
||||
|
||||
/* CPUCL0 */
|
||||
GATE(CLK_GOUT_CPUCL0_DBG, "gout_cpucl0_dbg", "mout_cpucl0_dbg",
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG, 21, 0, 0),
|
||||
GATE(CLK_GOUT_CPUCL0_SWITCH, "gout_cpucl0_switch", "mout_cpucl0_switch",
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH, 21, 0, 0),
|
||||
|
||||
/* CPUCL1 */
|
||||
GATE(CLK_GOUT_CPUCL1_DBG, "gout_cpucl1_dbg", "mout_cpucl1_dbg",
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL1_DBG, 21, 0, 0),
|
||||
GATE(CLK_GOUT_CPUCL1_SWITCH, "gout_cpucl1_switch", "mout_cpucl1_switch",
|
||||
CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH, 21, 0, 0),
|
||||
|
||||
/* DPU */
|
||||
GATE(CLK_GOUT_DPU, "gout_dpu", "mout_dpu",
|
||||
CLK_CON_GAT_GATE_CLKCMU_DPU, 21, 0, 0),
|
||||
@ -1030,6 +1101,373 @@ static const struct samsung_cmu_info cmgp_cmu_info __initconst = {
|
||||
.clk_name = "gout_clkcmu_cmgp_bus",
|
||||
};
|
||||
|
||||
/* ---- CMU_CPUCL0 ---------------------------------------------------------- */
|
||||
|
||||
/* Register Offset definitions for CMU_CPUCL0 (0x10900000) */
|
||||
#define PLL_LOCKTIME_PLL_CPUCL0 0x0000
|
||||
#define PLL_CON0_PLL_CPUCL0 0x0100
|
||||
#define PLL_CON1_PLL_CPUCL0 0x0104
|
||||
#define PLL_CON3_PLL_CPUCL0 0x010c
|
||||
#define PLL_CON0_MUX_CLKCMU_CPUCL0_DBG_USER 0x0600
|
||||
#define PLL_CON0_MUX_CLKCMU_CPUCL0_SWITCH_USER 0x0610
|
||||
#define CLK_CON_MUX_MUX_CLK_CPUCL0_PLL 0x100c
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER0_ACLK 0x1800
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER0_ATCLK 0x1808
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER0_PCLKDBG 0x180c
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER0_PERIPHCLK 0x1810
|
||||
#define CLK_CON_DIV_DIV_CLK_CPUCL0_CMUREF 0x1814
|
||||
#define CLK_CON_DIV_DIV_CLK_CPUCL0_CPU 0x1818
|
||||
#define CLK_CON_DIV_DIV_CLK_CPUCL0_PCLK 0x181c
|
||||
#define CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_ATCLK 0x2000
|
||||
#define CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_PCLK 0x2004
|
||||
#define CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_PERIPHCLK 0x2008
|
||||
#define CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_SCLK 0x200c
|
||||
#define CLK_CON_GAT_CLK_CPUCL0_CMU_CPUCL0_PCLK 0x2010
|
||||
#define CLK_CON_GAT_GATE_CLK_CPUCL0_CPU 0x2020
|
||||
|
||||
static const unsigned long cpucl0_clk_regs[] __initconst = {
|
||||
PLL_LOCKTIME_PLL_CPUCL0,
|
||||
PLL_CON0_PLL_CPUCL0,
|
||||
PLL_CON1_PLL_CPUCL0,
|
||||
PLL_CON3_PLL_CPUCL0,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL0_DBG_USER,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL0_SWITCH_USER,
|
||||
CLK_CON_MUX_MUX_CLK_CPUCL0_PLL,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER0_ACLK,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER0_ATCLK,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER0_PCLKDBG,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER0_PERIPHCLK,
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL0_CMUREF,
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL0_CPU,
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL0_PCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_ATCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_PCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_PERIPHCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_SCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL0_CMU_CPUCL0_PCLK,
|
||||
CLK_CON_GAT_GATE_CLK_CPUCL0_CPU,
|
||||
};
|
||||
|
||||
/* List of parent clocks for Muxes in CMU_CPUCL0 */
|
||||
PNAME(mout_pll_cpucl0_p) = { "oscclk", "fout_cpucl0_pll" };
|
||||
PNAME(mout_cpucl0_switch_user_p) = { "oscclk", "dout_cpucl0_switch" };
|
||||
PNAME(mout_cpucl0_dbg_user_p) = { "oscclk", "dout_cpucl0_dbg" };
|
||||
PNAME(mout_cpucl0_pll_p) = { "mout_pll_cpucl0",
|
||||
"mout_cpucl0_switch_user" };
|
||||
|
||||
static const struct samsung_pll_rate_table cpu_pll_rates[] __initconst = {
|
||||
PLL_35XX_RATE(26 * MHZ, 2210000000U, 255, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 2106000000U, 243, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 2002000000U, 231, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 1846000000U, 213, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 1742000000U, 201, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 1586000000U, 183, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 1456000000U, 168, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 1300000000U, 150, 3, 0),
|
||||
PLL_35XX_RATE(26 * MHZ, 1157000000U, 267, 3, 1),
|
||||
PLL_35XX_RATE(26 * MHZ, 1053000000U, 243, 3, 1),
|
||||
PLL_35XX_RATE(26 * MHZ, 949000000U, 219, 3, 1),
|
||||
PLL_35XX_RATE(26 * MHZ, 806000000U, 186, 3, 1),
|
||||
PLL_35XX_RATE(26 * MHZ, 650000000U, 150, 3, 1),
|
||||
PLL_35XX_RATE(26 * MHZ, 546000000U, 252, 3, 2),
|
||||
PLL_35XX_RATE(26 * MHZ, 442000000U, 204, 3, 2),
|
||||
PLL_35XX_RATE(26 * MHZ, 351000000U, 162, 3, 2),
|
||||
PLL_35XX_RATE(26 * MHZ, 247000000U, 114, 3, 2),
|
||||
PLL_35XX_RATE(26 * MHZ, 182000000U, 168, 3, 3),
|
||||
PLL_35XX_RATE(26 * MHZ, 130000000U, 120, 3, 3),
|
||||
};
|
||||
|
||||
static const struct samsung_pll_clock cpucl0_pll_clks[] __initconst = {
|
||||
PLL(pll_0822x, CLK_FOUT_CPUCL0_PLL, "fout_cpucl0_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_CPUCL0, PLL_CON3_PLL_CPUCL0, cpu_pll_rates),
|
||||
};
|
||||
|
||||
static const struct samsung_mux_clock cpucl0_mux_clks[] __initconst = {
|
||||
MUX_F(CLK_MOUT_PLL_CPUCL0, "mout_pll_cpucl0", mout_pll_cpucl0_p,
|
||||
PLL_CON0_PLL_CPUCL0, 4, 1,
|
||||
CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
|
||||
MUX_F(CLK_MOUT_CPUCL0_SWITCH_USER, "mout_cpucl0_switch_user",
|
||||
mout_cpucl0_switch_user_p,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL0_SWITCH_USER, 4, 1,
|
||||
CLK_SET_RATE_PARENT, 0),
|
||||
MUX(CLK_MOUT_CPUCL0_DBG_USER, "mout_cpucl0_dbg_user",
|
||||
mout_cpucl0_dbg_user_p,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL0_DBG_USER, 4, 1),
|
||||
MUX_F(CLK_MOUT_CPUCL0_PLL, "mout_cpucl0_pll", mout_cpucl0_pll_p,
|
||||
CLK_CON_MUX_MUX_CLK_CPUCL0_PLL, 0, 1, CLK_SET_RATE_PARENT, 0),
|
||||
};
|
||||
|
||||
static const struct samsung_div_clock cpucl0_div_clks[] __initconst = {
|
||||
DIV_F(CLK_DOUT_CPUCL0_CPU, "dout_cpucl0_cpu", "mout_cpucl0_pll",
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL0_CPU, 0, 1,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CPUCL0_CMUREF, "dout_cpucl0_cmuref", "dout_cpucl0_cpu",
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL0_CMUREF, 0, 3,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CPUCL0_PCLK, "dout_cpucl0_pclk", "dout_cpucl0_cpu",
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL0_PCLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
|
||||
/* EMBEDDED_CMU_CPUCL0 */
|
||||
DIV_F(CLK_DOUT_CLUSTER0_ACLK, "dout_cluster0_aclk", "gout_cluster0_cpu",
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER0_ACLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CLUSTER0_ATCLK, "dout_cluster0_atclk",
|
||||
"gout_cluster0_cpu", CLK_CON_DIV_DIV_CLK_CLUSTER0_ATCLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CLUSTER0_PCLKDBG, "dout_cluster0_pclkdbg",
|
||||
"gout_cluster0_cpu", CLK_CON_DIV_DIV_CLK_CLUSTER0_PCLKDBG, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CLUSTER0_PERIPHCLK, "dout_cluster0_periphclk",
|
||||
"gout_cluster0_cpu", CLK_CON_DIV_DIV_CLK_CLUSTER0_PERIPHCLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
};
|
||||
|
||||
static const struct samsung_gate_clock cpucl0_gate_clks[] __initconst = {
|
||||
GATE(CLK_GOUT_CPUCL0_CMU_CPUCL0_PCLK, "gout_cpucl0_cmu_cpucl0_pclk",
|
||||
"dout_cpucl0_pclk",
|
||||
CLK_CON_GAT_CLK_CPUCL0_CMU_CPUCL0_PCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
|
||||
/* EMBEDDED_CMU_CPUCL0 */
|
||||
GATE(CLK_GOUT_CLUSTER0_CPU, "gout_cluster0_cpu", "dout_cpucl0_cpu",
|
||||
CLK_CON_GAT_GATE_CLK_CPUCL0_CPU, 21, CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER0_SCLK, "gout_cluster0_sclk", "gout_cluster0_cpu",
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_SCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER0_ATCLK, "gout_cluster0_atclk",
|
||||
"dout_cluster0_atclk",
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_ATCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER0_PERIPHCLK, "gout_cluster0_periphclk",
|
||||
"dout_cluster0_periphclk",
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_PERIPHCLK, 21,
|
||||
CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER0_PCLK, "gout_cluster0_pclk",
|
||||
"dout_cluster0_pclkdbg",
|
||||
CLK_CON_GAT_CLK_CPUCL0_CLUSTER0_PCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
};
|
||||
|
||||
/*
|
||||
* Each parameter is going to be written into the corresponding DIV register. So
|
||||
* the actual divider value for each parameter will be 1/(param+1). All these
|
||||
* parameters must be in the range of 0..15, as the divider range for all of
|
||||
* these DIV clocks is 1..16. The default values for these dividers is
|
||||
* (1, 3, 3, 1).
|
||||
*/
|
||||
#define E850_CPU_DIV0(aclk, atclk, pclkdbg, periphclk) \
|
||||
(((aclk) << 16) | ((atclk) << 12) | ((pclkdbg) << 8) | \
|
||||
((periphclk) << 4))
|
||||
|
||||
static const struct exynos_cpuclk_cfg_data exynos850_cluster_clk_d[] __initconst
|
||||
= {
|
||||
{ 2210000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 2106000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 2002000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1846000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1742000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1586000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1456000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1300000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1157000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 1053000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 949000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 806000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 650000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 546000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 442000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 351000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 247000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 182000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 130000, E850_CPU_DIV0(1, 3, 3, 1) },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct samsung_cpu_clock cpucl0_cpu_clks[] __initconst = {
|
||||
CPU_CLK(CLK_CLUSTER0_SCLK, "cluster0_clk", CLK_MOUT_PLL_CPUCL0,
|
||||
CLK_MOUT_CPUCL0_SWITCH_USER, 0, 0x0, CPUCLK_LAYOUT_E850_CL0,
|
||||
exynos850_cluster_clk_d),
|
||||
};
|
||||
|
||||
static const struct samsung_cmu_info cpucl0_cmu_info __initconst = {
|
||||
.pll_clks = cpucl0_pll_clks,
|
||||
.nr_pll_clks = ARRAY_SIZE(cpucl0_pll_clks),
|
||||
.mux_clks = cpucl0_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(cpucl0_mux_clks),
|
||||
.div_clks = cpucl0_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(cpucl0_div_clks),
|
||||
.gate_clks = cpucl0_gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(cpucl0_gate_clks),
|
||||
.cpu_clks = cpucl0_cpu_clks,
|
||||
.nr_cpu_clks = ARRAY_SIZE(cpucl0_cpu_clks),
|
||||
.nr_clk_ids = CLKS_NR_CPUCL0,
|
||||
.clk_regs = cpucl0_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(cpucl0_clk_regs),
|
||||
.clk_name = "dout_cpucl0_switch",
|
||||
.manual_plls = true,
|
||||
};
|
||||
|
||||
static void __init exynos850_cmu_cpucl0_init(struct device_node *np)
|
||||
{
|
||||
exynos_arm64_register_cmu(NULL, np, &cpucl0_cmu_info);
|
||||
}
|
||||
|
||||
/* Register CMU_CPUCL0 early, as CPU clocks should be available ASAP */
|
||||
CLK_OF_DECLARE(exynos850_cmu_cpucl0, "samsung,exynos850-cmu-cpucl0",
|
||||
exynos850_cmu_cpucl0_init);
|
||||
|
||||
/* ---- CMU_CPUCL1 ---------------------------------------------------------- */
|
||||
|
||||
/* Register Offset definitions for CMU_CPUCL1 (0x10800000) */
|
||||
#define PLL_LOCKTIME_PLL_CPUCL1 0x0000
|
||||
#define PLL_CON0_PLL_CPUCL1 0x0100
|
||||
#define PLL_CON1_PLL_CPUCL1 0x0104
|
||||
#define PLL_CON3_PLL_CPUCL1 0x010c
|
||||
#define PLL_CON0_MUX_CLKCMU_CPUCL1_DBG_USER 0x0600
|
||||
#define PLL_CON0_MUX_CLKCMU_CPUCL1_SWITCH_USER 0x0610
|
||||
#define CLK_CON_MUX_MUX_CLK_CPUCL1_PLL 0x1000
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER1_ACLK 0x1800
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER1_ATCLK 0x1808
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER1_PCLKDBG 0x180c
|
||||
#define CLK_CON_DIV_DIV_CLK_CLUSTER1_PERIPHCLK 0x1810
|
||||
#define CLK_CON_DIV_DIV_CLK_CPUCL1_CMUREF 0x1814
|
||||
#define CLK_CON_DIV_DIV_CLK_CPUCL1_CPU 0x1818
|
||||
#define CLK_CON_DIV_DIV_CLK_CPUCL1_PCLK 0x181c
|
||||
#define CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_ATCLK 0x2000
|
||||
#define CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_PCLK 0x2004
|
||||
#define CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_PERIPHCLK 0x2008
|
||||
#define CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_SCLK 0x200c
|
||||
#define CLK_CON_GAT_CLK_CPUCL1_CMU_CPUCL1_PCLK 0x2010
|
||||
#define CLK_CON_GAT_GATE_CLK_CPUCL1_CPU 0x2020
|
||||
|
||||
static const unsigned long cpucl1_clk_regs[] __initconst = {
|
||||
PLL_LOCKTIME_PLL_CPUCL1,
|
||||
PLL_CON0_PLL_CPUCL1,
|
||||
PLL_CON1_PLL_CPUCL1,
|
||||
PLL_CON3_PLL_CPUCL1,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL1_DBG_USER,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL1_SWITCH_USER,
|
||||
CLK_CON_MUX_MUX_CLK_CPUCL1_PLL,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER1_ACLK,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER1_ATCLK,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER1_PCLKDBG,
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER1_PERIPHCLK,
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL1_CMUREF,
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL1_CPU,
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL1_PCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_ATCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_PCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_PERIPHCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_SCLK,
|
||||
CLK_CON_GAT_CLK_CPUCL1_CMU_CPUCL1_PCLK,
|
||||
CLK_CON_GAT_GATE_CLK_CPUCL1_CPU,
|
||||
};
|
||||
|
||||
/* List of parent clocks for Muxes in CMU_CPUCL0 */
|
||||
PNAME(mout_pll_cpucl1_p) = { "oscclk", "fout_cpucl1_pll" };
|
||||
PNAME(mout_cpucl1_switch_user_p) = { "oscclk", "dout_cpucl1_switch" };
|
||||
PNAME(mout_cpucl1_dbg_user_p) = { "oscclk", "dout_cpucl1_dbg" };
|
||||
PNAME(mout_cpucl1_pll_p) = { "mout_pll_cpucl1",
|
||||
"mout_cpucl1_switch_user" };
|
||||
|
||||
static const struct samsung_pll_clock cpucl1_pll_clks[] __initconst = {
|
||||
PLL(pll_0822x, CLK_FOUT_CPUCL1_PLL, "fout_cpucl1_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_CPUCL1, PLL_CON3_PLL_CPUCL1, cpu_pll_rates),
|
||||
};
|
||||
|
||||
static const struct samsung_mux_clock cpucl1_mux_clks[] __initconst = {
|
||||
MUX_F(CLK_MOUT_PLL_CPUCL1, "mout_pll_cpucl1", mout_pll_cpucl1_p,
|
||||
PLL_CON0_PLL_CPUCL1, 4, 1,
|
||||
CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
|
||||
MUX_F(CLK_MOUT_CPUCL1_SWITCH_USER, "mout_cpucl1_switch_user",
|
||||
mout_cpucl1_switch_user_p,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL1_SWITCH_USER, 4, 1,
|
||||
CLK_SET_RATE_PARENT, 0),
|
||||
MUX(CLK_MOUT_CPUCL1_DBG_USER, "mout_cpucl1_dbg_user",
|
||||
mout_cpucl1_dbg_user_p,
|
||||
PLL_CON0_MUX_CLKCMU_CPUCL1_DBG_USER, 4, 1),
|
||||
MUX_F(CLK_MOUT_CPUCL1_PLL, "mout_cpucl1_pll", mout_cpucl1_pll_p,
|
||||
CLK_CON_MUX_MUX_CLK_CPUCL1_PLL, 0, 1, CLK_SET_RATE_PARENT, 0),
|
||||
};
|
||||
|
||||
static const struct samsung_div_clock cpucl1_div_clks[] __initconst = {
|
||||
DIV_F(CLK_DOUT_CPUCL1_CPU, "dout_cpucl1_cpu", "mout_cpucl1_pll",
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL1_CPU, 0, 1,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CPUCL1_CMUREF, "dout_cpucl1_cmuref", "dout_cpucl1_cpu",
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL1_CMUREF, 0, 3,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CPUCL1_PCLK, "dout_cpucl1_pclk", "dout_cpucl1_cpu",
|
||||
CLK_CON_DIV_DIV_CLK_CPUCL1_PCLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
|
||||
/* EMBEDDED_CMU_CPUCL1 */
|
||||
DIV_F(CLK_DOUT_CLUSTER1_ACLK, "dout_cluster1_aclk", "gout_cluster1_cpu",
|
||||
CLK_CON_DIV_DIV_CLK_CLUSTER1_ACLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CLUSTER1_ATCLK, "dout_cluster1_atclk",
|
||||
"gout_cluster1_cpu", CLK_CON_DIV_DIV_CLK_CLUSTER1_ATCLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CLUSTER1_PCLKDBG, "dout_cluster1_pclkdbg",
|
||||
"gout_cluster1_cpu", CLK_CON_DIV_DIV_CLK_CLUSTER1_PCLKDBG, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
DIV_F(CLK_DOUT_CLUSTER1_PERIPHCLK, "dout_cluster1_periphclk",
|
||||
"gout_cluster1_cpu", CLK_CON_DIV_DIV_CLK_CLUSTER1_PERIPHCLK, 0, 4,
|
||||
CLK_GET_RATE_NOCACHE, CLK_DIVIDER_READ_ONLY),
|
||||
};
|
||||
|
||||
static const struct samsung_gate_clock cpucl1_gate_clks[] __initconst = {
|
||||
GATE(CLK_GOUT_CPUCL1_CMU_CPUCL1_PCLK, "gout_cpucl1_cmu_cpucl1_pclk",
|
||||
"dout_cpucl1_pclk",
|
||||
CLK_CON_GAT_CLK_CPUCL1_CMU_CPUCL1_PCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
|
||||
/* EMBEDDED_CMU_CPUCL1 */
|
||||
GATE(CLK_GOUT_CLUSTER1_CPU, "gout_cluster1_cpu", "dout_cpucl1_cpu",
|
||||
CLK_CON_GAT_GATE_CLK_CPUCL1_CPU, 21, CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER1_SCLK, "gout_cluster1_sclk", "gout_cluster1_cpu",
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_SCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER1_ATCLK, "gout_cluster1_atclk",
|
||||
"dout_cluster1_atclk",
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_ATCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER1_PERIPHCLK, "gout_cluster1_periphclk",
|
||||
"dout_cluster1_periphclk",
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_PERIPHCLK, 21,
|
||||
CLK_IGNORE_UNUSED, 0),
|
||||
GATE(CLK_GOUT_CLUSTER1_PCLK, "gout_cluster1_pclk",
|
||||
"dout_cluster1_pclkdbg",
|
||||
CLK_CON_GAT_CLK_CPUCL1_CLUSTER1_PCLK, 21, CLK_IGNORE_UNUSED, 0),
|
||||
};
|
||||
|
||||
static const struct samsung_cpu_clock cpucl1_cpu_clks[] __initconst = {
|
||||
CPU_CLK(CLK_CLUSTER1_SCLK, "cluster1_clk", CLK_MOUT_PLL_CPUCL1,
|
||||
CLK_MOUT_CPUCL1_SWITCH_USER, 0, 0x0, CPUCLK_LAYOUT_E850_CL1,
|
||||
exynos850_cluster_clk_d),
|
||||
};
|
||||
|
||||
static const struct samsung_cmu_info cpucl1_cmu_info __initconst = {
|
||||
.pll_clks = cpucl1_pll_clks,
|
||||
.nr_pll_clks = ARRAY_SIZE(cpucl1_pll_clks),
|
||||
.mux_clks = cpucl1_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(cpucl1_mux_clks),
|
||||
.div_clks = cpucl1_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(cpucl1_div_clks),
|
||||
.gate_clks = cpucl1_gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(cpucl1_gate_clks),
|
||||
.cpu_clks = cpucl1_cpu_clks,
|
||||
.nr_cpu_clks = ARRAY_SIZE(cpucl1_cpu_clks),
|
||||
.nr_clk_ids = CLKS_NR_CPUCL1,
|
||||
.clk_regs = cpucl1_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(cpucl1_clk_regs),
|
||||
.clk_name = "dout_cpucl1_switch",
|
||||
.manual_plls = true,
|
||||
};
|
||||
|
||||
static void __init exynos850_cmu_cpucl1_init(struct device_node *np)
|
||||
{
|
||||
exynos_arm64_register_cmu(NULL, np, &cpucl1_cmu_info);
|
||||
}
|
||||
|
||||
/* Register CMU_CPUCL1 early, as CPU clocks should be available ASAP */
|
||||
CLK_OF_DECLARE(exynos850_cmu_cpucl1, "samsung,exynos850-cmu-cpucl1",
|
||||
exynos850_cmu_cpucl1_init);
|
||||
|
||||
/* ---- CMU_G3D ------------------------------------------------------------- */
|
||||
|
||||
/* Register Offset definitions for CMU_G3D (0x11400000) */
|
||||
|
@ -352,13 +352,13 @@ static const struct samsung_pll_clock top_pll_clks[] __initconst = {
|
||||
/* CMU_TOP_PURECLKCOMP */
|
||||
PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, NULL),
|
||||
PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared1_pll", "oscclk",
|
||||
PLL(pll_0822x, FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_SHARED1, PLL_CON3_PLL_SHARED1, NULL),
|
||||
PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared2_pll", "oscclk",
|
||||
PLL(pll_0822x, FOUT_SHARED2_PLL, "fout_shared2_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_SHARED2, PLL_CON3_PLL_SHARED2, NULL),
|
||||
PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared3_pll", "oscclk",
|
||||
PLL(pll_0822x, FOUT_SHARED3_PLL, "fout_shared3_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_SHARED3, PLL_CON3_PLL_SHARED3, NULL),
|
||||
PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared4_pll", "oscclk",
|
||||
PLL(pll_0822x, FOUT_SHARED4_PLL, "fout_shared4_pll", "oscclk",
|
||||
PLL_LOCKTIME_PLL_SHARED4, PLL_CON3_PLL_SHARED4, NULL),
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -139,7 +139,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
|
||||
unsigned int nr_clk)
|
||||
{
|
||||
struct clk_hw *clk_hw;
|
||||
unsigned int idx, ret;
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < nr_clk; idx++, list++) {
|
||||
clk_hw = clk_hw_register_fixed_rate(ctx->dev, list->name,
|
||||
@ -151,15 +151,6 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
|
||||
}
|
||||
|
||||
samsung_clk_add_lookup(ctx, clk_hw, list->id);
|
||||
|
||||
/*
|
||||
* Unconditionally add a clock lookup for the fixed rate clocks.
|
||||
* There are not many of these on any of Samsung platforms.
|
||||
*/
|
||||
ret = clk_hw_register_clkdev(clk_hw, list->name, NULL);
|
||||
if (ret)
|
||||
pr_err("%s: failed to register clock lookup for %s",
|
||||
__func__, list->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ struct samsung_mux_clock {
|
||||
.name = cname, \
|
||||
.parent_names = pnames, \
|
||||
.num_parents = ARRAY_SIZE(pnames), \
|
||||
.flags = (f) | CLK_SET_RATE_NO_REPARENT, \
|
||||
.flags = f, \
|
||||
.offset = o, \
|
||||
.shift = s, \
|
||||
.width = w, \
|
||||
@ -141,9 +141,16 @@ struct samsung_mux_clock {
|
||||
}
|
||||
|
||||
#define MUX(_id, cname, pnames, o, s, w) \
|
||||
__MUX(_id, cname, pnames, o, s, w, 0, 0)
|
||||
__MUX(_id, cname, pnames, o, s, w, CLK_SET_RATE_NO_REPARENT, 0)
|
||||
|
||||
#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \
|
||||
__MUX(_id, cname, pnames, o, s, w, (f) | CLK_SET_RATE_NO_REPARENT, mf)
|
||||
|
||||
/* Used by MUX clocks where reparenting on clock rate change is allowed. */
|
||||
#define nMUX(_id, cname, pnames, o, s, w) \
|
||||
__MUX(_id, cname, pnames, o, s, w, 0, 0)
|
||||
|
||||
#define nMUX_F(_id, cname, pnames, o, s, w, f, mf) \
|
||||
__MUX(_id, cname, pnames, o, s, w, f, mf)
|
||||
|
||||
/**
|
||||
@ -330,6 +337,7 @@ struct samsung_clock_reg_cache {
|
||||
* @suspend_regs: list of clock registers to set before suspend
|
||||
* @nr_suspend_regs: count of clock registers in @suspend_regs
|
||||
* @clk_name: name of the parent clock needed for CMU register access
|
||||
* @manual_plls: Enable manual control for PLL clocks
|
||||
*/
|
||||
struct samsung_cmu_info {
|
||||
const struct samsung_pll_clock *pll_clks;
|
||||
@ -354,6 +362,9 @@ struct samsung_cmu_info {
|
||||
const struct samsung_clk_reg_dump *suspend_regs;
|
||||
unsigned int nr_suspend_regs;
|
||||
const char *clk_name;
|
||||
|
||||
/* ARM64 Exynos CMUs */
|
||||
bool manual_plls;
|
||||
};
|
||||
|
||||
struct samsung_clk_provider *samsung_clk_init(struct device *dev,
|
||||
|
11
drivers/clk/sophgo/Kconfig
Normal file
11
drivers/clk/sophgo/Kconfig
Normal file
@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# common clock support for SOPHGO SoC family.
|
||||
|
||||
config CLK_SOPHGO_CV1800
|
||||
tristate "Support for the Sophgo CV1800 series SoCs clock controller"
|
||||
depends on ARCH_SOPHGO || COMPILE_TEST
|
||||
help
|
||||
This driver supports clock controller of Sophgo CV18XX series SoC.
|
||||
The driver require a 25MHz Oscillator to function generate clock.
|
||||
It includes PLLs, common clock function and some vendor clock for
|
||||
IPs of CV18XX series SoC
|
7
drivers/clk/sophgo/Makefile
Normal file
7
drivers/clk/sophgo/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_CLK_SOPHGO_CV1800) += clk-sophgo-cv1800.o
|
||||
|
||||
clk-sophgo-cv1800-y += clk-cv1800.o
|
||||
clk-sophgo-cv1800-y += clk-cv18xx-common.o
|
||||
clk-sophgo-cv1800-y += clk-cv18xx-ip.o
|
||||
clk-sophgo-cv1800-y += clk-cv18xx-pll.o
|
1537
drivers/clk/sophgo/clk-cv1800.c
Normal file
1537
drivers/clk/sophgo/clk-cv1800.c
Normal file
File diff suppressed because it is too large
Load Diff
123
drivers/clk/sophgo/clk-cv1800.h
Normal file
123
drivers/clk/sophgo/clk-cv1800.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
|
||||
*/
|
||||
|
||||
#ifndef _CLK_SOPHGO_CV1800_H_
|
||||
#define _CLK_SOPHGO_CV1800_H_
|
||||
|
||||
#include <dt-bindings/clock/sophgo,cv1800.h>
|
||||
|
||||
#define CV1800_CLK_MAX (CLK_XTAL_AP + 1)
|
||||
#define CV1810_CLK_MAX (CLK_DISP_SRC_VIP + 1)
|
||||
|
||||
#define REG_PLL_G2_CTRL 0x800
|
||||
#define REG_PLL_G2_STATUS 0x804
|
||||
#define REG_MIPIMPLL_CSR 0x808
|
||||
#define REG_A0PLL_CSR 0x80C
|
||||
#define REG_DISPPLL_CSR 0x810
|
||||
#define REG_CAM0PLL_CSR 0x814
|
||||
#define REG_CAM1PLL_CSR 0x818
|
||||
#define REG_PLL_G2_SSC_SYN_CTRL 0x840
|
||||
#define REG_A0PLL_SSC_SYN_CTRL 0x850
|
||||
#define REG_A0PLL_SSC_SYN_SET 0x854
|
||||
#define REG_A0PLL_SSC_SYN_SPAN 0x858
|
||||
#define REG_A0PLL_SSC_SYN_STEP 0x85C
|
||||
#define REG_DISPPLL_SSC_SYN_CTRL 0x860
|
||||
#define REG_DISPPLL_SSC_SYN_SET 0x864
|
||||
#define REG_DISPPLL_SSC_SYN_SPAN 0x868
|
||||
#define REG_DISPPLL_SSC_SYN_STEP 0x86C
|
||||
#define REG_CAM0PLL_SSC_SYN_CTRL 0x870
|
||||
#define REG_CAM0PLL_SSC_SYN_SET 0x874
|
||||
#define REG_CAM0PLL_SSC_SYN_SPAN 0x878
|
||||
#define REG_CAM0PLL_SSC_SYN_STEP 0x87C
|
||||
#define REG_CAM1PLL_SSC_SYN_CTRL 0x880
|
||||
#define REG_CAM1PLL_SSC_SYN_SET 0x884
|
||||
#define REG_CAM1PLL_SSC_SYN_SPAN 0x888
|
||||
#define REG_CAM1PLL_SSC_SYN_STEP 0x88C
|
||||
#define REG_APLL_FRAC_DIV_CTRL 0x890
|
||||
#define REG_APLL_FRAC_DIV_M 0x894
|
||||
#define REG_APLL_FRAC_DIV_N 0x898
|
||||
#define REG_MIPIMPLL_CLK_CSR 0x8A0
|
||||
#define REG_A0PLL_CLK_CSR 0x8A4
|
||||
#define REG_DISPPLL_CLK_CSR 0x8A8
|
||||
#define REG_CAM0PLL_CLK_CSR 0x8AC
|
||||
#define REG_CAM1PLL_CLK_CSR 0x8B0
|
||||
#define REG_CLK_CAM0_SRC_DIV 0x8C0
|
||||
#define REG_CLK_CAM1_SRC_DIV 0x8C4
|
||||
|
||||
/* top_pll_g6 */
|
||||
#define REG_PLL_G6_CTRL 0x900
|
||||
#define REG_PLL_G6_STATUS 0x904
|
||||
#define REG_MPLL_CSR 0x908
|
||||
#define REG_TPLL_CSR 0x90C
|
||||
#define REG_FPLL_CSR 0x910
|
||||
#define REG_PLL_G6_SSC_SYN_CTRL 0x940
|
||||
#define REG_DPLL_SSC_SYN_CTRL 0x950
|
||||
#define REG_DPLL_SSC_SYN_SET 0x954
|
||||
#define REG_DPLL_SSC_SYN_SPAN 0x958
|
||||
#define REG_DPLL_SSC_SYN_STEP 0x95C
|
||||
#define REG_MPLL_SSC_SYN_CTRL 0x960
|
||||
#define REG_MPLL_SSC_SYN_SET 0x964
|
||||
#define REG_MPLL_SSC_SYN_SPAN 0x968
|
||||
#define REG_MPLL_SSC_SYN_STEP 0x96C
|
||||
#define REG_TPLL_SSC_SYN_CTRL 0x970
|
||||
#define REG_TPLL_SSC_SYN_SET 0x974
|
||||
#define REG_TPLL_SSC_SYN_SPAN 0x978
|
||||
#define REG_TPLL_SSC_SYN_STEP 0x97C
|
||||
|
||||
/* clkgen */
|
||||
#define REG_CLK_EN_0 0x000
|
||||
#define REG_CLK_EN_1 0x004
|
||||
#define REG_CLK_EN_2 0x008
|
||||
#define REG_CLK_EN_3 0x00C
|
||||
#define REG_CLK_EN_4 0x010
|
||||
#define REG_CLK_SEL_0 0x020
|
||||
#define REG_CLK_BYP_0 0x030
|
||||
#define REG_CLK_BYP_1 0x034
|
||||
|
||||
#define REG_DIV_CLK_A53_0 0x040
|
||||
#define REG_DIV_CLK_A53_1 0x044
|
||||
#define REG_DIV_CLK_CPU_AXI0 0x048
|
||||
#define REG_DIV_CLK_CPU_GIC 0x050
|
||||
#define REG_DIV_CLK_TPU 0x054
|
||||
#define REG_DIV_CLK_EMMC 0x064
|
||||
#define REG_DIV_CLK_EMMC_100K 0x06C
|
||||
#define REG_DIV_CLK_SD0 0x070
|
||||
#define REG_DIV_CLK_SD0_100K 0x078
|
||||
#define REG_DIV_CLK_SD1 0x07C
|
||||
#define REG_DIV_CLK_SD1_100K 0x084
|
||||
#define REG_DIV_CLK_SPI_NAND 0x088
|
||||
#define REG_DIV_CLK_ETH0_500M 0x08C
|
||||
#define REG_DIV_CLK_ETH1_500M 0x090
|
||||
#define REG_DIV_CLK_GPIO_DB 0x094
|
||||
#define REG_DIV_CLK_SDMA_AUD0 0x098
|
||||
#define REG_DIV_CLK_SDMA_AUD1 0x09C
|
||||
#define REG_DIV_CLK_SDMA_AUD2 0x0A0
|
||||
#define REG_DIV_CLK_SDMA_AUD3 0x0A4
|
||||
#define REG_DIV_CLK_CAM0_200 0x0A8
|
||||
#define REG_DIV_CLK_AXI4 0x0B8
|
||||
#define REG_DIV_CLK_AXI6 0x0BC
|
||||
#define REG_DIV_CLK_DSI_ESC 0x0C4
|
||||
#define REG_DIV_CLK_AXI_VIP 0x0C8
|
||||
#define REG_DIV_CLK_SRC_VIP_SYS_0 0x0D0
|
||||
#define REG_DIV_CLK_SRC_VIP_SYS_1 0x0D8
|
||||
#define REG_DIV_CLK_DISP_SRC_VIP 0x0E0
|
||||
#define REG_DIV_CLK_AXI_VIDEO_CODEC 0x0E4
|
||||
#define REG_DIV_CLK_VC_SRC0 0x0EC
|
||||
#define REG_DIV_CLK_1M 0x0FC
|
||||
#define REG_DIV_CLK_SPI 0x100
|
||||
#define REG_DIV_CLK_I2C 0x104
|
||||
#define REG_DIV_CLK_SRC_VIP_SYS_2 0x110
|
||||
#define REG_DIV_CLK_AUDSRC 0x118
|
||||
#define REG_DIV_CLK_PWM_SRC_0 0x120
|
||||
#define REG_DIV_CLK_AP_DEBUG 0x128
|
||||
#define REG_DIV_CLK_RTCSYS_SRC_0 0x12C
|
||||
#define REG_DIV_CLK_C906_0_0 0x130
|
||||
#define REG_DIV_CLK_C906_0_1 0x134
|
||||
#define REG_DIV_CLK_C906_1_0 0x138
|
||||
#define REG_DIV_CLK_C906_1_1 0x13C
|
||||
#define REG_DIV_CLK_SRC_VIP_SYS_3 0x140
|
||||
#define REG_DIV_CLK_SRC_VIP_SYS_4 0x144
|
||||
|
||||
#endif /* _CLK_SOPHGO_CV1800_H_ */
|
66
drivers/clk/sophgo/clk-cv18xx-common.c
Normal file
66
drivers/clk/sophgo/clk-cv18xx-common.c
Normal file
@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#include "clk-cv18xx-common.h"
|
||||
|
||||
int cv1800_clk_setbit(struct cv1800_clk_common *common,
|
||||
struct cv1800_clk_regbit *field)
|
||||
{
|
||||
u32 mask = BIT(field->shift);
|
||||
u32 value;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(common->lock, flags);
|
||||
|
||||
value = readl(common->base + field->reg);
|
||||
writel(value | mask, common->base + field->reg);
|
||||
|
||||
spin_unlock_irqrestore(common->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cv1800_clk_clearbit(struct cv1800_clk_common *common,
|
||||
struct cv1800_clk_regbit *field)
|
||||
{
|
||||
u32 mask = BIT(field->shift);
|
||||
u32 value;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(common->lock, flags);
|
||||
|
||||
value = readl(common->base + field->reg);
|
||||
writel(value & ~mask, common->base + field->reg);
|
||||
|
||||
spin_unlock_irqrestore(common->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cv1800_clk_checkbit(struct cv1800_clk_common *common,
|
||||
struct cv1800_clk_regbit *field)
|
||||
{
|
||||
return readl(common->base + field->reg) & BIT(field->shift);
|
||||
}
|
||||
|
||||
#define PLL_LOCK_TIMEOUT_US (200 * 1000)
|
||||
|
||||
void cv1800_clk_wait_for_lock(struct cv1800_clk_common *common,
|
||||
u32 reg, u32 lock)
|
||||
{
|
||||
void __iomem *addr = common->base + reg;
|
||||
u32 regval;
|
||||
|
||||
if (!lock)
|
||||
return;
|
||||
|
||||
WARN_ON(readl_relaxed_poll_timeout(addr, regval, regval & lock,
|
||||
100, PLL_LOCK_TIMEOUT_US));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user