Merge branches 'clk-socfpga', 'clk-doc', 'clk-qcom', 'clk-vc5' and 'clk-bcm' into clk-next

- Enable CPU clks on Qualcomm IPQ6018 SoCs
 - Enable CPU clks on Qualcomm MSM8996 SoCs
 - GPU clk support for Qualcomm SM8150 and SM8250 SoCs
 - Audio clks on Qualcomm SC7180 SoCs
 - Make defines for bcm63xx-gate clks to use in DT
 - Support gate clks on BCM6318 SoCs
 - Add HDMI clks for BCM2711 SoCs
 - Support BCM2711 SoC firmware clks

* clk-socfpga:
  clk: socfpga: agilex: mpu_l2ram_clk should be mpu_ccu_clk
  clk: socfpga: agilex: add nand_x_clk and nand_ecc_clk
  dt-bindings: agilex: add NAND_X_CLK and NAND_ECC_CLK

* clk-doc:
  clk: Clean up kernel-doc errors
  clk: <linux/clk-provider.h>: drop a duplicated word
  clk: add function documentation for clk_hw_round_rate()

* clk-qcom: (38 commits)
  dt-bindings: clock: Fix YAML schemas for LPASS clocks on SC7180
  clk: qcom: gcc-sdm660: Fix up gcc_mss_mnoc_bimc_axi_clk
  clk: qcom: gcc-sdm660: Add missing modem reset
  clk: qcom: lpass: Add support for LPASS clock controller for SC7180
  clk: qcom: gcc: Add support for GCC LPASS clock for SC7180
  dt-bindings: clock: Add YAML schemas for LPASS clocks on SC7180
  clk: qcom: gdsc: Add support to enable retention of GSDCR
  clk: qcom: Export gdsc_gx_do_nothing_enable() to modules
  clk: qcom: Add graphics clock controller driver for SM8250
  clk: qcom: Add graphics clock controller driver for SM8150
  clk: qcom: add common gdsc_gx_do_nothing_enable for gpucc drivers
  dt-bindings: clock: add SM8250 QCOM Graphics clock bindings
  dt-bindings: clock: add SM8150 QCOM Graphics clock bindings
  dt-bindings: clock: combine qcom,sdm845-gpucc and qcom,sc7180-gpucc
  clk: qcom: gcc: remove unnecessary vco_table from SM8150
  clk: qcom: clk-alpha-pll: use the right PCAL_DONE value for lucid pll
  clk: qcom: clk-alpha-pll: same regs and ops for trion and lucid
  clk: qcom: clk-alpha-pll: remove unused/incorrect PLL_CAL_VAL
  clk: qcom: gcc: fix sm8150 GPU and NPU clocks
  dt-bindings: clock: Fix qcom,msm8996-apcc yaml syntax
  ...

* clk-vc5:
  clk: vc5: use a dedicated struct to describe the output drivers
  dt-bindings: clk: versaclock5: convert to yaml
  MAINTAINERS: take over IDT VersaClock 5 clock driver
  dt-bindings: clk: versaclock5: fix 'idt' prefix typos
  clk: vc5: Add memory check to prevent oops
  clk: vc5: fix use of memory after it has been kfree'd
  clk: vc5: Enable addition output configurations of the Versaclock
  dt: Add additional option bindings for IDT VersaClock
  clk: vc5: Allow Versaclock driver to support multiple instances

* clk-bcm: (44 commits)
  clk: bcm2835: Do not use prediv with bcm2711's PLLs
  dt-bindings: arm: bcm: Add a select to the RPI Firmware binding
  clk: bcm: dvp: Add missing module informations
  clk: bcm: rpi: Remove the quirks for the CPU clock
  clk: bcm2835: Don't cache the PLLB rate
  clk: bcm2835: Allow custom CCF flags for the PLLs
  Revert "clk: bcm2835: remove pllb"
  clk: bcm: rpi: Give firmware clocks a name
  clk: bcm: rpi: Discover the firmware clocks
  clk: bcm: rpi: Add an enum for the firmware clocks
  clk: bcm: rpi: Add DT provider for the clocks
  clk: bcm: rpi: Make the PLLB registration function return a clk_hw
  clk: bcm: rpi: Split pllb clock hooks
  clk: bcm: rpi: Rename is_prepared function
  clk: bcm: rpi: Pass the clocks data to the firmware function
  clk: bcm: rpi: Add clock id to data
  clk: bcm: rpi: Create a data structure for the clocks
  clk: bcm: rpi: Use CCF boundaries instead of rolling our own
  clk: bcm: rpi: Make sure the clkdev lookup is removed
  clk: bcm: rpi: Switch to clk_hw_register_clkdev
  ...
This commit is contained in:
Stephen Boyd 2020-08-03 15:06:16 -07:00
71 changed files with 4435 additions and 702 deletions

View File

@ -1,14 +0,0 @@
Raspberry Pi VideoCore firmware driver
Required properties:
- compatible: Should be "raspberrypi,bcm2835-firmware"
- mboxes: Phandle to the firmware device's Mailbox.
(See: ../mailbox/mailbox.txt for more information)
Example:
firmware {
compatible = "raspberrypi,bcm2835-firmware";
mboxes = <&mailbox>;
};

View File

@ -0,0 +1,68 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/arm/bcm/raspberrypi,bcm2835-firmware.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Raspberry Pi VideoCore firmware driver
maintainers:
- Eric Anholt <eric@anholt.net>
- Stefan Wahren <wahrenst@gmx.net>
select:
properties:
compatible:
contains:
const: raspberrypi,bcm2835-firmware
required:
- compatible
properties:
compatible:
items:
- const: raspberrypi,bcm2835-firmware
- const: simple-bus
mboxes:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: |
Phandle to the firmware device's Mailbox.
(See: ../mailbox/mailbox.txt for more information)
clocks:
type: object
properties:
compatible:
const: raspberrypi,firmware-clocks
"#clock-cells":
const: 1
description: >
The argument is the ID of the clocks contained by the
firmware messages.
required:
- compatible
- "#clock-cells"
additionalProperties: false
required:
- compatible
- mboxes
examples:
- |
firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
mboxes = <&mailbox>;
firmware_clocks: clocks {
compatible = "raspberrypi,firmware-clocks";
#clock-cells = <1>;
};
};
...

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/brcm,bcm2711-dvp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom BCM2711 HDMI DVP Device Tree Bindings
maintainers:
- Maxime Ripard <mripard@kernel.org>
properties:
"#clock-cells":
const: 1
"#reset-cells":
const: 1
compatible:
const: brcm,brcm2711-dvp
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- "#clock-cells"
- "#reset-cells"
- compatible
- reg
- clocks
additionalProperties: false
examples:
- |
dvp: clock@7ef00000 {
compatible = "brcm,brcm2711-dvp";
reg = <0x7ef00000 0x10>;
clocks = <&clk_108MHz>;
#clock-cells = <1>;
#reset-cells = <1>;
};
...

View File

@ -3,6 +3,8 @@ Gated Clock Controller Bindings for MIPS based BCM63XX SoCs
Required properties: Required properties:
- compatible: must be one of: - compatible: must be one of:
"brcm,bcm3368-clocks" "brcm,bcm3368-clocks"
"brcm,bcm6318-clocks"
"brcm,bcm6318-ubus-clocks"
"brcm,bcm6328-clocks" "brcm,bcm6328-clocks"
"brcm,bcm6358-clocks" "brcm,bcm6358-clocks"
"brcm,bcm6362-clocks" "brcm,bcm6362-clocks"

View File

@ -1,92 +0,0 @@
Binding for IDT VersaClock 5,6 programmable i2c clock generators.
The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock
generators providing from 3 to 12 output clocks.
==I2C device node==
Required properties:
- compatible: shall be one of
"idt,5p49v5923"
"idt,5p49v5925"
"idt,5p49v5933"
"idt,5p49v5935"
"idt,5p49v6901"
"idt,5p49v6965"
- reg: i2c device address, shall be 0x68 or 0x6a.
- #clock-cells: from common clock binding; shall be set to 1.
- clocks: from common clock binding; list of parent clock handles,
- 5p49v5923 and
5p49v5925 and
5p49v6901: (required) either or both of XTAL or CLKIN
reference clock.
- 5p49v5933 and
- 5p49v5935: (optional) property not present (internal
Xtal used) or CLKIN reference
clock.
- clock-names: from common clock binding; clock input names, can be
- 5p49v5923 and
5p49v5925 and
5p49v6901: (required) either or both of "xin", "clkin".
- 5p49v5933 and
- 5p49v5935: (optional) property not present or "clkin".
==Mapping between clock specifier and physical pins==
When referencing the provided clock in the DT using phandle and
clock specifier, the following mapping applies:
5P49V5923:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
5P49V5933:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT4
5P49V5925 and
5P49V5935:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
5P49V6901:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
==Example==
/* 25MHz reference crystal */
ref25: ref25m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
i2c-master-node {
/* IDT 5P49V5923 i2c clock generator */
vc5: clock-generator@6a {
compatible = "idt,5p49v5923";
reg = <0x6a>;
#clock-cells = <1>;
/* Connect XIN input to 25MHz reference */
clocks = <&ref25m>;
clock-names = "xin";
};
};
/* Consumer referencing the 5P49V5923 pin OUT1 */
consumer {
...
clocks = <&vc5 1>;
...
}

View File

@ -0,0 +1,154 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/idt,versaclock5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Binding for IDT VersaClock 5 and 6 programmable I2C clock generators
description: |
The IDT VersaClock 5 and VersaClock 6 are programmable I2C
clock generators providing from 3 to 12 output clocks.
When referencing the provided clock in the DT using phandle and clock
specifier, the following mapping applies:
- 5P49V5923:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
- 5P49V5933:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT4
- other parts:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
maintainers:
- Luca Ceresoli <luca@lucaceresoli.net>
properties:
compatible:
enum:
- idt,5p49v5923
- idt,5p49v5925
- idt,5p49v5933
- idt,5p49v5935
- idt,5p49v6901
- idt,5p49v6965
reg:
description: I2C device address
enum: [ 0x68, 0x6a ]
'#clock-cells':
const: 1
patternProperties:
"^OUT[1-4]$":
type: object
description:
Description of one of the outputs (OUT1..OUT4). See "Clock1 Output
Configuration" in the Versaclock 5/6/6E Family Register Description
and Programming Guide.
properties:
idt,mode:
description:
The output drive mode. Values defined in dt-bindings/clk/versaclock.h
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 6
idt,voltage-microvolt:
description: The output drive voltage.
enum: [ 1800000, 2500000, 3300000 ]
idt,slew-percent:
description: The Slew rate control for CMOS single-ended.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 80, 85, 90, 100 ]
required:
- compatible
- reg
- '#clock-cells'
allOf:
- if:
properties:
compatible:
enum:
- idt,5p49v5933
- idt,5p49v5935
then:
# Devices with builtin crystal + optional external input
properties:
clock-names:
const: clkin
clocks:
maxItems: 1
else:
# Devices without builtin crystal
properties:
clock-names:
minItems: 1
maxItems: 2
items:
enum: [ xin, clkin ]
clocks:
minItems: 1
maxItems: 2
required:
- clock-names
- clocks
examples:
- |
#include <dt-bindings/clk/versaclock.h>
/* 25MHz reference crystal */
ref25: ref25m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
i2c@0 {
reg = <0x0 0x100>;
#address-cells = <1>;
#size-cells = <0>;
/* IDT 5P49V5923 I2C clock generator */
vc5: clock-generator@6a {
compatible = "idt,5p49v5923";
reg = <0x6a>;
#clock-cells = <1>;
/* Connect XIN input to 25MHz reference */
clocks = <&ref25m>;
clock-names = "xin";
OUT1 {
idt,drive-mode = <VC5_CMOSD>;
idt,voltage-microvolts = <1800000>;
idt,slew-percent = <80>;
};
OUT4 {
idt,drive-mode = <VC5_LVDS>;
};
};
};
/* Consumer referencing the 5P49V5923 pin OUT1 */
consumer {
/* ... */
clocks = <&vc5 1>;
/* ... */
};
...

View File

@ -15,7 +15,9 @@ description:
properties: properties:
compatible: compatible:
const: qcom,msm8916-a53pll enum:
- qcom,ipq6018-a53pll
- qcom,msm8916-a53pll
reg: reg:
maxItems: 1 maxItems: 1
@ -23,6 +25,14 @@ properties:
'#clock-cells': '#clock-cells':
const: 0 const: 0
clocks:
items:
- description: board XO clock
clock-names:
items:
- const: xo
required: required:
- compatible - compatible
- reg - reg
@ -38,3 +48,12 @@ examples:
reg = <0xb016000 0x40>; reg = <0xb016000 0x40>;
#clock-cells = <0>; #clock-cells = <0>;
}; };
#Example 2 - A53 PLL found on IPQ6018 devices
- |
a53pll_ipq: clock-controller@b116000 {
compatible = "qcom,ipq6018-a53pll";
reg = <0x0b116000 0x40>;
#clock-cells = <0>;
clocks = <&xo>;
clock-names = "xo";
};

View File

@ -1,23 +1,31 @@
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/clock/qcom,sdm845-gpucc.yaml# $id: http://devicetree.org/schemas/clock/qcom,gpucc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Graphics Clock & Reset Controller Binding for SDM845 title: Qualcomm Graphics Clock & Reset Controller Binding
maintainers: maintainers:
- Taniya Das <tdas@codeaurora.org> - Taniya Das <tdas@codeaurora.org>
description: | description: |
Qualcomm graphics clock control module which supports the clocks, resets and Qualcomm graphics clock control module which supports the clocks, resets and
power domains on SDM845. power domains on SDM845/SC7180/SM8150/SM8250.
See also dt-bindings/clock/qcom,gpucc-sdm845.h. See also:
dt-bindings/clock/qcom,gpucc-sdm845.h
dt-bindings/clock/qcom,gpucc-sc7180.h
dt-bindings/clock/qcom,gpucc-sm8150.h
dt-bindings/clock/qcom,gpucc-sm8250.h
properties: properties:
compatible: compatible:
const: qcom,sdm845-gpucc enum:
- qcom,sdm845-gpucc
- qcom,sc7180-gpucc
- qcom,sm8150-gpucc
- qcom,sm8250-gpucc
clocks: clocks:
items: items:

View File

@ -0,0 +1,54 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,msm8996-apcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm clock controller for MSM8996 CPUs
maintainers:
- Loic Poulain <loic.poulain@linaro.org>
description: |
Qualcomm CPU clock controller for MSM8996 CPUs, clock 0 is for Power cluster
and clock 1 is for Perf cluster.
properties:
compatible:
enum:
- qcom,msm8996-apcc
reg:
maxItems: 1
'#clock-cells':
const: 1
clocks:
items:
- description: Primary PLL clock for power cluster (little)
- description: Primary PLL clock for perf cluster (big)
- description: Alternate PLL clock for power cluster (little)
- description: Alternate PLL clock for perf cluster (big)
clock-names:
items:
- const: pwrcl_pll
- const: perfcl_pll
- const: pwrcl_alt_pll
- const: perfcl_alt_pll
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
- |
kryocc: clock-controller@6400000 {
compatible = "qcom,msm8996-apcc";
reg = <0x6400000 0x90000>;
#clock-cells = <1>;
};

View File

@ -13,13 +13,17 @@ Required properties :
"qcom,rpmcc-msm8660", "qcom,rpmcc" "qcom,rpmcc-msm8660", "qcom,rpmcc"
"qcom,rpmcc-apq8060", "qcom,rpmcc" "qcom,rpmcc-apq8060", "qcom,rpmcc"
"qcom,rpmcc-msm8916", "qcom,rpmcc" "qcom,rpmcc-msm8916", "qcom,rpmcc"
"qcom,rpmcc-msm8936", "qcom,rpmcc"
"qcom,rpmcc-msm8974", "qcom,rpmcc" "qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-msm8976", "qcom,rpmcc" "qcom,rpmcc-msm8976", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc" "qcom,rpmcc-apq8064", "qcom,rpmcc"
"qcom,rpmcc-ipq806x", "qcom,rpmcc" "qcom,rpmcc-ipq806x", "qcom,rpmcc"
"qcom,rpmcc-msm8992",·"qcom,rpmcc"
"qcom,rpmcc-msm8994",·"qcom,rpmcc"
"qcom,rpmcc-msm8996", "qcom,rpmcc" "qcom,rpmcc-msm8996", "qcom,rpmcc"
"qcom,rpmcc-msm8998", "qcom,rpmcc" "qcom,rpmcc-msm8998", "qcom,rpmcc"
"qcom,rpmcc-qcs404", "qcom,rpmcc" "qcom,rpmcc-qcs404", "qcom,rpmcc"
"qcom,rpmcc-sdm660", "qcom,rpmcc"
- #clock-cells : shall contain 1 - #clock-cells : shall contain 1

View File

@ -1,74 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,sc7180-gpucc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Graphics Clock & Reset Controller Binding for SC7180
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm graphics clock control module which supports the clocks, resets and
power domains on SC7180.
See also dt-bindings/clock/qcom,gpucc-sc7180.h.
properties:
compatible:
const: qcom,sc7180-gpucc
clocks:
items:
- description: Board XO source
- description: GPLL0 main branch source
- description: GPLL0 div branch source
clock-names:
items:
- const: bi_tcxo
- const: gcc_gpu_gpll0_clk_src
- const: gcc_gpu_gpll0_div_clk_src
'#clock-cells':
const: 1
'#reset-cells':
const: 1
'#power-domain-cells':
const: 1
reg:
maxItems: 1
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
- '#reset-cells'
- '#power-domain-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/clock/qcom,rpmh.h>
clock-controller@5090000 {
compatible = "qcom,sc7180-gpucc";
reg = <0x05090000 0x9000>;
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_GPU_GPLL0_CLK_SRC>,
<&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
clock-names = "bi_tcxo",
"gcc_gpu_gpll0_clk_src",
"gcc_gpu_gpll0_div_clk_src";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...

View File

@ -0,0 +1,108 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,sc7180-lpasscorecc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm LPASS Core Clock Controller Binding for SC7180
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm LPASS core clock control module which supports the clocks and
power domains on SC7180.
See also:
- dt-bindings/clock/qcom,lpasscorecc-sc7180.h
properties:
compatible:
enum:
- qcom,sc7180-lpasshm
- qcom,sc7180-lpasscorecc
clocks:
items:
- description: gcc_lpass_sway clock from GCC
- description: Board XO source
clock-names:
items:
- const: iface
- const: bi_tcxo
power-domains:
maxItems: 1
'#clock-cells':
const: 1
'#power-domain-cells':
const: 1
reg:
minItems: 1
items:
- description: lpass core cc register
- description: lpass audio cc register
reg-names:
items:
- const: lpass_core_cc
- const: lpass_audio_cc
if:
properties:
compatible:
contains:
const: qcom,sc7180-lpasshm
then:
properties:
reg:
maxItems: 1
else:
properties:
reg:
minItems: 2
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
- '#power-domain-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
clock-controller@63000000 {
compatible = "qcom,sc7180-lpasshm";
reg = <0x63000000 0x28>;
clocks = <&gcc GCC_LPASS_CFG_NOC_SWAY_CLK>, <&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "bi_tcxo";
#clock-cells = <1>;
#power-domain-cells = <1>;
};
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
clock-controller@62d00000 {
compatible = "qcom,sc7180-lpasscorecc";
reg = <0x62d00000 0x50000>, <0x62780000 0x30000>;
reg-names = "lpass_core_cc", "lpass_audio_cc";
clocks = <&gcc GCC_LPASS_CFG_NOC_SWAY_CLK>, <&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "bi_tcxo";
power-domains = <&lpass_hm LPASS_CORE_HM_GDSCR>;
#clock-cells = <1>;
#power-domain-cells = <1>;
};
...

View File

@ -8324,8 +8324,9 @@ W: https://github.com/o2genum/ideapad-slidebar
F: drivers/input/misc/ideapad_slidebar.c F: drivers/input/misc/ideapad_slidebar.c
IDT VersaClock 5 CLOCK DRIVER IDT VersaClock 5 CLOCK DRIVER
M: Marek Vasut <marek.vasut@gmail.com> M: Luca Ceresoli <luca@lucaceresoli.net>
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
F: drivers/clk/clk-versaclock5.c F: drivers/clk/clk-versaclock5.c
IEEE 802.15.4 SUBSYSTEM IEEE 802.15.4 SUBSYSTEM

View File

@ -1,4 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
config CLK_BCM2711_DVP
tristate "Broadcom BCM2711 DVP support"
depends on ARCH_BCM2835 ||COMPILE_TEST
depends on COMMON_CLK
default ARCH_BCM2835
select RESET_SIMPLE
help
Enable common clock framework support for the Broadcom BCM2711
DVP Controller.
config CLK_BCM2835 config CLK_BCM2835
bool "Broadcom BCM2835 clock support" bool "Broadcom BCM2835 clock support"
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST

View File

@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
obj-$(CONFIG_CLK_BCM2711_DVP) += clk-bcm2711-dvp.o
obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o
obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o

View File

@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2020 Cerno
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#define DVP_HT_RPI_SW_INIT 0x04
#define DVP_HT_RPI_MISC_CONFIG 0x08
#define NR_CLOCKS 2
#define NR_RESETS 6
struct clk_dvp {
struct clk_hw_onecell_data *data;
struct reset_simple_data reset;
};
static const struct clk_parent_data clk_dvp_parent = {
.index = 0,
};
static int clk_dvp_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *data;
struct resource *res;
struct clk_dvp *dvp;
void __iomem *base;
int ret;
dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
if (!dvp)
return -ENOMEM;
platform_set_drvdata(pdev, dvp);
dvp->data = devm_kzalloc(&pdev->dev,
struct_size(dvp->data, hws, NR_CLOCKS),
GFP_KERNEL);
if (!dvp->data)
return -ENOMEM;
data = dvp->data;
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
return PTR_ERR(base);
dvp->reset.rcdev.owner = THIS_MODULE;
dvp->reset.rcdev.nr_resets = NR_RESETS;
dvp->reset.rcdev.ops = &reset_simple_ops;
dvp->reset.rcdev.of_node = pdev->dev.of_node;
dvp->reset.membase = base + DVP_HT_RPI_SW_INIT;
spin_lock_init(&dvp->reset.lock);
ret = devm_reset_controller_register(&pdev->dev, &dvp->reset.rcdev);
if (ret)
return ret;
data->hws[0] = clk_hw_register_gate_parent_data(&pdev->dev,
"hdmi0-108MHz",
&clk_dvp_parent, 0,
base + DVP_HT_RPI_MISC_CONFIG, 3,
CLK_GATE_SET_TO_DISABLE,
&dvp->reset.lock);
if (IS_ERR(data->hws[0]))
return PTR_ERR(data->hws[0]);
data->hws[1] = clk_hw_register_gate_parent_data(&pdev->dev,
"hdmi1-108MHz",
&clk_dvp_parent, 0,
base + DVP_HT_RPI_MISC_CONFIG, 4,
CLK_GATE_SET_TO_DISABLE,
&dvp->reset.lock);
if (IS_ERR(data->hws[1])) {
ret = PTR_ERR(data->hws[1]);
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)
goto unregister_clk1;
return 0;
unregister_clk1:
clk_hw_unregister_gate(data->hws[1]);
unregister_clk0:
clk_hw_unregister_gate(data->hws[0]);
return ret;
};
static int clk_dvp_remove(struct platform_device *pdev)
{
struct clk_dvp *dvp = platform_get_drvdata(pdev);
struct clk_hw_onecell_data *data = dvp->data;
clk_hw_unregister_gate(data->hws[1]);
clk_hw_unregister_gate(data->hws[0]);
return 0;
}
static const struct of_device_id clk_dvp_dt_ids[] = {
{ .compatible = "brcm,brcm2711-dvp", },
{ /* sentinel */ }
};
static struct platform_driver clk_dvp_driver = {
.probe = clk_dvp_probe,
.remove = clk_dvp_remove,
.driver = {
.name = "brcm2711-dvp",
.of_match_table = clk_dvp_dt_ids,
},
};
module_platform_driver(clk_dvp_driver);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_DESCRIPTION("BCM2711 DVP clock driver");
MODULE_LICENSE("GPL");

View File

@ -314,6 +314,7 @@ struct bcm2835_cprman {
struct device *dev; struct device *dev;
void __iomem *regs; void __iomem *regs;
spinlock_t regs_lock; /* spinlock for all clocks */ spinlock_t regs_lock; /* spinlock for all clocks */
unsigned int soc;
/* /*
* Real names of cprman clock parents looked up through * Real names of cprman clock parents looked up through
@ -421,6 +422,7 @@ struct bcm2835_pll_data {
u32 reference_enable_mask; u32 reference_enable_mask;
/* Bit in CM_LOCK to indicate when the PLL has locked. */ /* Bit in CM_LOCK to indicate when the PLL has locked. */
u32 lock_mask; u32 lock_mask;
u32 flags;
const struct bcm2835_pll_ana_bits *ana; const struct bcm2835_pll_ana_bits *ana;
@ -525,6 +527,20 @@ static int bcm2835_pll_is_on(struct clk_hw *hw)
A2W_PLL_CTRL_PRST_DISABLE; A2W_PLL_CTRL_PRST_DISABLE;
} }
static u32 bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman,
const struct bcm2835_pll_data *data)
{
/*
* On BCM2711 there isn't a pre-divisor available in the PLL feedback
* loop. Bits 13:14 of ANA1 (PLLA,PLLB,PLLC,PLLD) have been re-purposed
* for to for VCO RANGE bits.
*/
if (cprman->soc & SOC_BCM2711)
return 0;
return data->ana->fb_prediv_mask;
}
static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate, static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate,
unsigned long parent_rate, unsigned long parent_rate,
u32 *ndiv, u32 *fdiv) u32 *ndiv, u32 *fdiv)
@ -582,7 +598,7 @@ static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT; ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT;
pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT; pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT;
using_prediv = cprman_read(cprman, data->ana_reg_base + 4) & using_prediv = cprman_read(cprman, data->ana_reg_base + 4) &
data->ana->fb_prediv_mask; bcm2835_pll_get_prediv_mask(cprman, data);
if (using_prediv) { if (using_prediv) {
ndiv *= 2; ndiv *= 2;
@ -665,6 +681,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
struct bcm2835_cprman *cprman = pll->cprman; struct bcm2835_cprman *cprman = pll->cprman;
const struct bcm2835_pll_data *data = pll->data; const struct bcm2835_pll_data *data = pll->data;
u32 prediv_mask = bcm2835_pll_get_prediv_mask(cprman, data);
bool was_using_prediv, use_fb_prediv, do_ana_setup_first; bool was_using_prediv, use_fb_prediv, do_ana_setup_first;
u32 ndiv, fdiv, a2w_ctl; u32 ndiv, fdiv, a2w_ctl;
u32 ana[4]; u32 ana[4];
@ -682,7 +699,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
for (i = 3; i >= 0; i--) for (i = 3; i >= 0; i--)
ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4); ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4);
was_using_prediv = ana[1] & data->ana->fb_prediv_mask; was_using_prediv = ana[1] & prediv_mask;
ana[0] &= ~data->ana->mask0; ana[0] &= ~data->ana->mask0;
ana[0] |= data->ana->set0; ana[0] |= data->ana->set0;
@ -692,10 +709,10 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
ana[3] |= data->ana->set3; ana[3] |= data->ana->set3;
if (was_using_prediv && !use_fb_prediv) { if (was_using_prediv && !use_fb_prediv) {
ana[1] &= ~data->ana->fb_prediv_mask; ana[1] &= ~prediv_mask;
do_ana_setup_first = true; do_ana_setup_first = true;
} else if (!was_using_prediv && use_fb_prediv) { } else if (!was_using_prediv && use_fb_prediv) {
ana[1] |= data->ana->fb_prediv_mask; ana[1] |= prediv_mask;
do_ana_setup_first = false; do_ana_setup_first = false;
} else { } else {
do_ana_setup_first = true; do_ana_setup_first = true;
@ -1310,7 +1327,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
init.num_parents = 1; init.num_parents = 1;
init.name = pll_data->name; init.name = pll_data->name;
init.ops = &bcm2835_pll_clk_ops; init.ops = &bcm2835_pll_clk_ops;
init.flags = CLK_IGNORE_UNUSED; init.flags = pll_data->flags | CLK_IGNORE_UNUSED;
pll = kzalloc(sizeof(*pll), GFP_KERNEL); pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll) if (!pll)
@ -1684,10 +1701,33 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.fixed_divider = 1, .fixed_divider = 1,
.flags = CLK_SET_RATE_PARENT), .flags = CLK_SET_RATE_PARENT),
/* /* PLLB is used for the ARM's clock. */
* PLLB is used for the ARM's clock. Controlled by firmware, see [BCM2835_PLLB] = REGISTER_PLL(
* clk-raspberrypi.c. SOC_ALL,
*/ .name = "pllb",
.cm_ctrl_reg = CM_PLLB,
.a2w_ctrl_reg = A2W_PLLB_CTRL,
.frac_reg = A2W_PLLB_FRAC,
.ana_reg_base = A2W_PLLB_ANA0,
.reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
.lock_mask = CM_LOCK_FLOCKB,
.ana = &bcm2835_ana_default,
.min_rate = 600000000u,
.max_rate = 3000000000u,
.max_fb_rate = BCM2835_MAX_FB_RATE,
.flags = CLK_GET_RATE_NOCACHE),
[BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
SOC_ALL,
.name = "pllb_arm",
.source_pll = "pllb",
.cm_reg = CM_PLLB,
.a2w_reg = A2W_PLLB_ARM,
.load_mask = CM_PLLB_LOADARM,
.hold_mask = CM_PLLB_HOLDARM,
.fixed_divider = 1,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE),
/* /*
* PLLC is the core PLL, used to drive the core VPU clock. * PLLC is the core PLL, used to drive the core VPU clock.
@ -2238,6 +2278,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cprman); platform_set_drvdata(pdev, cprman);
cprman->onecell.num = asize; cprman->onecell.num = asize;
cprman->soc = pdata->soc;
hws = cprman->onecell.hws; hws = cprman->onecell.hws;
for (i = 0; i < asize; i++) { for (i = 0; i < asize; i++) {

View File

@ -6,6 +6,14 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <dt-bindings/clock/bcm3368-clock.h>
#include <dt-bindings/clock/bcm6318-clock.h>
#include <dt-bindings/clock/bcm6328-clock.h>
#include <dt-bindings/clock/bcm6358-clock.h>
#include <dt-bindings/clock/bcm6362-clock.h>
#include <dt-bindings/clock/bcm6368-clock.h>
#include <dt-bindings/clock/bcm63268-clock.h>
struct clk_bcm63xx_table_entry { struct clk_bcm63xx_table_entry {
const char * const name; const char * const name;
u8 bit; u8 bit;
@ -20,126 +28,458 @@ struct clk_bcm63xx_hw {
}; };
static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = { static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
{ .name = "mac", .bit = 3, }, {
{ .name = "tc", .bit = 5, }, .name = "mac",
{ .name = "us_top", .bit = 6, }, .bit = BCM3368_CLK_MAC,
{ .name = "ds_top", .bit = 7, }, }, {
{ .name = "acm", .bit = 8, }, .name = "tc",
{ .name = "spi", .bit = 9, }, .bit = BCM3368_CLK_TC,
{ .name = "usbs", .bit = 10, }, }, {
{ .name = "bmu", .bit = 11, }, .name = "us_top",
{ .name = "pcm", .bit = 12, }, .bit = BCM3368_CLK_US_TOP,
{ .name = "ntp", .bit = 13, }, }, {
{ .name = "acp_b", .bit = 14, }, .name = "ds_top",
{ .name = "acp_a", .bit = 15, }, .bit = BCM3368_CLK_DS_TOP,
{ .name = "emusb", .bit = 17, }, }, {
{ .name = "enet0", .bit = 18, }, .name = "acm",
{ .name = "enet1", .bit = 19, }, .bit = BCM3368_CLK_ACM,
{ .name = "usbsu", .bit = 20, }, }, {
{ .name = "ephy", .bit = 21, }, .name = "spi",
{ }, .bit = BCM3368_CLK_SPI,
}, {
.name = "usbs",
.bit = BCM3368_CLK_USBS,
}, {
.name = "bmu",
.bit = BCM3368_CLK_BMU,
}, {
.name = "pcm",
.bit = BCM3368_CLK_PCM,
}, {
.name = "ntp",
.bit = BCM3368_CLK_NTP,
}, {
.name = "acp_b",
.bit = BCM3368_CLK_ACP_B,
}, {
.name = "acp_a",
.bit = BCM3368_CLK_ACP_A,
}, {
.name = "emusb",
.bit = BCM3368_CLK_EMUSB,
}, {
.name = "enet0",
.bit = BCM3368_CLK_ENET0,
}, {
.name = "enet1",
.bit = BCM3368_CLK_ENET1,
}, {
.name = "usbsu",
.bit = BCM3368_CLK_USBSU,
}, {
.name = "ephy",
.bit = BCM3368_CLK_EPHY,
}, {
/* sentinel */
},
};
static const struct clk_bcm63xx_table_entry bcm6318_clocks[] = {
{
.name = "adsl_asb",
.bit = BCM6318_CLK_ADSL_ASB,
}, {
.name = "usb_asb",
.bit = BCM6318_CLK_USB_ASB,
}, {
.name = "mips_asb",
.bit = BCM6318_CLK_MIPS_ASB,
}, {
.name = "pcie_asb",
.bit = BCM6318_CLK_PCIE_ASB,
}, {
.name = "phymips_asb",
.bit = BCM6318_CLK_PHYMIPS_ASB,
}, {
.name = "robosw_asb",
.bit = BCM6318_CLK_ROBOSW_ASB,
}, {
.name = "sar_asb",
.bit = BCM6318_CLK_SAR_ASB,
}, {
.name = "sdr_asb",
.bit = BCM6318_CLK_SDR_ASB,
}, {
.name = "swreg_asb",
.bit = BCM6318_CLK_SWREG_ASB,
}, {
.name = "periph_asb",
.bit = BCM6318_CLK_PERIPH_ASB,
}, {
.name = "cpubus160",
.bit = BCM6318_CLK_CPUBUS160,
}, {
.name = "adsl",
.bit = BCM6318_CLK_ADSL,
}, {
.name = "sar125",
.bit = BCM6318_CLK_SAR125,
}, {
.name = "mips",
.bit = BCM6318_CLK_MIPS,
.flags = CLK_IS_CRITICAL,
}, {
.name = "pcie",
.bit = BCM6318_CLK_PCIE,
}, {
.name = "robosw250",
.bit = BCM6318_CLK_ROBOSW250,
}, {
.name = "robosw025",
.bit = BCM6318_CLK_ROBOSW025,
}, {
.name = "sdr",
.bit = BCM6318_CLK_SDR,
.flags = CLK_IS_CRITICAL,
}, {
.name = "usbd",
.bit = BCM6318_CLK_USBD,
}, {
.name = "hsspi",
.bit = BCM6318_CLK_HSSPI,
}, {
.name = "pcie25",
.bit = BCM6318_CLK_PCIE25,
}, {
.name = "phymips",
.bit = BCM6318_CLK_PHYMIPS,
}, {
.name = "afe",
.bit = BCM6318_CLK_AFE,
}, {
.name = "qproc",
.bit = BCM6318_CLK_QPROC,
}, {
/* sentinel */
},
};
static const struct clk_bcm63xx_table_entry bcm6318_ubus_clocks[] = {
{
.name = "adsl-ubus",
.bit = BCM6318_UCLK_ADSL,
}, {
.name = "arb-ubus",
.bit = BCM6318_UCLK_ARB,
.flags = CLK_IS_CRITICAL,
}, {
.name = "mips-ubus",
.bit = BCM6318_UCLK_MIPS,
.flags = CLK_IS_CRITICAL,
}, {
.name = "pcie-ubus",
.bit = BCM6318_UCLK_PCIE,
}, {
.name = "periph-ubus",
.bit = BCM6318_UCLK_PERIPH,
.flags = CLK_IS_CRITICAL,
}, {
.name = "phymips-ubus",
.bit = BCM6318_UCLK_PHYMIPS,
}, {
.name = "robosw-ubus",
.bit = BCM6318_UCLK_ROBOSW,
}, {
.name = "sar-ubus",
.bit = BCM6318_UCLK_SAR,
}, {
.name = "sdr-ubus",
.bit = BCM6318_UCLK_SDR,
}, {
.name = "usb-ubus",
.bit = BCM6318_UCLK_USB,
}, {
/* sentinel */
},
}; };
static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = { static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = {
{ .name = "phy_mips", .bit = 0, }, {
{ .name = "adsl_qproc", .bit = 1, }, .name = "phy_mips",
{ .name = "adsl_afe", .bit = 2, }, .bit = BCM6328_CLK_PHYMIPS,
{ .name = "adsl", .bit = 3, }, }, {
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, }, .name = "adsl_qproc",
{ .name = "sar", .bit = 5, }, .bit = BCM6328_CLK_ADSL_QPROC,
{ .name = "pcm", .bit = 6, }, }, {
{ .name = "usbd", .bit = 7, }, .name = "adsl_afe",
{ .name = "usbh", .bit = 8, }, .bit = BCM6328_CLK_ADSL_AFE,
{ .name = "hsspi", .bit = 9, }, }, {
{ .name = "pcie", .bit = 10, }, .name = "adsl",
{ .name = "robosw", .bit = 11, }, .bit = BCM6328_CLK_ADSL,
{ }, }, {
.name = "mips",
.bit = BCM6328_CLK_MIPS,
.flags = CLK_IS_CRITICAL,
}, {
.name = "sar",
.bit = BCM6328_CLK_SAR,
}, {
.name = "pcm",
.bit = BCM6328_CLK_PCM,
}, {
.name = "usbd",
.bit = BCM6328_CLK_USBD,
}, {
.name = "usbh",
.bit = BCM6328_CLK_USBH,
}, {
.name = "hsspi",
.bit = BCM6328_CLK_HSSPI,
}, {
.name = "pcie",
.bit = BCM6328_CLK_PCIE,
}, {
.name = "robosw",
.bit = BCM6328_CLK_ROBOSW,
}, {
/* sentinel */
},
}; };
static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = { static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = {
{ .name = "enet", .bit = 4, }, {
{ .name = "adslphy", .bit = 5, }, .name = "enet",
{ .name = "pcm", .bit = 8, }, .bit = BCM6358_CLK_ENET,
{ .name = "spi", .bit = 9, }, }, {
{ .name = "usbs", .bit = 10, }, .name = "adslphy",
{ .name = "sar", .bit = 11, }, .bit = BCM6358_CLK_ADSLPHY,
{ .name = "emusb", .bit = 17, }, }, {
{ .name = "enet0", .bit = 18, }, .name = "pcm",
{ .name = "enet1", .bit = 19, }, .bit = BCM6358_CLK_PCM,
{ .name = "usbsu", .bit = 20, }, }, {
{ .name = "ephy", .bit = 21, }, .name = "spi",
{ }, .bit = BCM6358_CLK_SPI,
}, {
.name = "usbs",
.bit = BCM6358_CLK_USBS,
}, {
.name = "sar",
.bit = BCM6358_CLK_SAR,
}, {
.name = "emusb",
.bit = BCM6358_CLK_EMUSB,
}, {
.name = "enet0",
.bit = BCM6358_CLK_ENET0,
}, {
.name = "enet1",
.bit = BCM6358_CLK_ENET1,
}, {
.name = "usbsu",
.bit = BCM6358_CLK_USBSU,
}, {
.name = "ephy",
.bit = BCM6358_CLK_EPHY,
}, {
/* sentinel */
},
}; };
static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = { static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = {
{ .name = "adsl_qproc", .bit = 1, }, {
{ .name = "adsl_afe", .bit = 2, }, .name = "adsl_qproc",
{ .name = "adsl", .bit = 3, }, .bit = BCM6362_CLK_ADSL_QPROC,
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, }, }, {
{ .name = "wlan_ocp", .bit = 5, }, .name = "adsl_afe",
{ .name = "swpkt_usb", .bit = 7, }, .bit = BCM6362_CLK_ADSL_AFE,
{ .name = "swpkt_sar", .bit = 8, }, }, {
{ .name = "sar", .bit = 9, }, .name = "adsl",
{ .name = "robosw", .bit = 10, }, .bit = BCM6362_CLK_ADSL,
{ .name = "pcm", .bit = 11, }, }, {
{ .name = "usbd", .bit = 12, }, .name = "mips",
{ .name = "usbh", .bit = 13, }, .bit = BCM6362_CLK_MIPS,
{ .name = "ipsec", .bit = 14, }, .flags = CLK_IS_CRITICAL,
{ .name = "spi", .bit = 15, }, }, {
{ .name = "hsspi", .bit = 16, }, .name = "wlan_ocp",
{ .name = "pcie", .bit = 17, }, .bit = BCM6362_CLK_WLAN_OCP,
{ .name = "fap", .bit = 18, }, }, {
{ .name = "phymips", .bit = 19, }, .name = "swpkt_usb",
{ .name = "nand", .bit = 20, }, .bit = BCM6362_CLK_SWPKT_USB,
{ }, }, {
.name = "swpkt_sar",
.bit = BCM6362_CLK_SWPKT_SAR,
}, {
.name = "sar",
.bit = BCM6362_CLK_SAR,
}, {
.name = "robosw",
.bit = BCM6362_CLK_ROBOSW,
}, {
.name = "pcm",
.bit = BCM6362_CLK_PCM,
}, {
.name = "usbd",
.bit = BCM6362_CLK_USBD,
}, {
.name = "usbh",
.bit = BCM6362_CLK_USBH,
}, {
.name = "ipsec",
.bit = BCM6362_CLK_IPSEC,
}, {
.name = "spi",
.bit = BCM6362_CLK_SPI,
}, {
.name = "hsspi",
.bit = BCM6362_CLK_HSSPI,
}, {
.name = "pcie",
.bit = BCM6362_CLK_PCIE,
}, {
.name = "fap",
.bit = BCM6362_CLK_FAP,
}, {
.name = "phymips",
.bit = BCM6362_CLK_PHYMIPS,
}, {
.name = "nand",
.bit = BCM6362_CLK_NAND,
}, {
/* sentinel */
},
}; };
static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = { static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = {
{ .name = "vdsl_qproc", .bit = 2, }, {
{ .name = "vdsl_afe", .bit = 3, }, .name = "vdsl_qproc",
{ .name = "vdsl_bonding", .bit = 4, }, .bit = BCM6368_CLK_VDSL_QPROC,
{ .name = "vdsl", .bit = 5, }, }, {
{ .name = "phymips", .bit = 6, }, .name = "vdsl_afe",
{ .name = "swpkt_usb", .bit = 7, }, .bit = BCM6368_CLK_VDSL_AFE,
{ .name = "swpkt_sar", .bit = 8, }, }, {
{ .name = "spi", .bit = 9, }, .name = "vdsl_bonding",
{ .name = "usbd", .bit = 10, }, .bit = BCM6368_CLK_VDSL_BONDING,
{ .name = "sar", .bit = 11, }, }, {
{ .name = "robosw", .bit = 12, }, .name = "vdsl",
{ .name = "utopia", .bit = 13, }, .bit = BCM6368_CLK_VDSL,
{ .name = "pcm", .bit = 14, }, }, {
{ .name = "usbh", .bit = 15, }, .name = "phymips",
{ .name = "disable_gless", .bit = 16, }, .bit = BCM6368_CLK_PHYMIPS,
{ .name = "nand", .bit = 17, }, }, {
{ .name = "ipsec", .bit = 18, }, .name = "swpkt_usb",
{ }, .bit = BCM6368_CLK_SWPKT_USB,
}, {
.name = "swpkt_sar",
.bit = BCM6368_CLK_SWPKT_SAR,
}, {
.name = "spi",
.bit = BCM6368_CLK_SPI,
}, {
.name = "usbd",
.bit = BCM6368_CLK_USBD,
}, {
.name = "sar",
.bit = BCM6368_CLK_SAR,
}, {
.name = "robosw",
.bit = BCM6368_CLK_ROBOSW,
}, {
.name = "utopia",
.bit = BCM6368_CLK_UTOPIA,
}, {
.name = "pcm",
.bit = BCM6368_CLK_PCM,
}, {
.name = "usbh",
.bit = BCM6368_CLK_USBH,
}, {
.name = "disable_gless",
.bit = BCM6368_CLK_DIS_GLESS,
}, {
.name = "nand",
.bit = BCM6368_CLK_NAND,
}, {
.name = "ipsec",
.bit = BCM6368_CLK_IPSEC,
}, {
/* sentinel */
},
}; };
static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = { static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = {
{ .name = "disable_gless", .bit = 0, }, {
{ .name = "vdsl_qproc", .bit = 1, }, .name = "disable_gless",
{ .name = "vdsl_afe", .bit = 2, }, .bit = BCM63268_CLK_DIS_GLESS,
{ .name = "vdsl", .bit = 3, }, }, {
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, }, .name = "vdsl_qproc",
{ .name = "wlan_ocp", .bit = 5, }, .bit = BCM63268_CLK_VDSL_QPROC,
{ .name = "dect", .bit = 6, }, }, {
{ .name = "fap0", .bit = 7, }, .name = "vdsl_afe",
{ .name = "fap1", .bit = 8, }, .bit = BCM63268_CLK_VDSL_AFE,
{ .name = "sar", .bit = 9, }, }, {
{ .name = "robosw", .bit = 10, }, .name = "vdsl",
{ .name = "pcm", .bit = 11, }, .bit = BCM63268_CLK_VDSL,
{ .name = "usbd", .bit = 12, }, }, {
{ .name = "usbh", .bit = 13, }, .name = "mips",
{ .name = "ipsec", .bit = 14, }, .bit = BCM63268_CLK_MIPS,
{ .name = "spi", .bit = 15, }, .flags = CLK_IS_CRITICAL,
{ .name = "hsspi", .bit = 16, }, }, {
{ .name = "pcie", .bit = 17, }, .name = "wlan_ocp",
{ .name = "phymips", .bit = 18, }, .bit = BCM63268_CLK_WLAN_OCP,
{ .name = "gmac", .bit = 19, }, }, {
{ .name = "nand", .bit = 20, }, .name = "dect",
{ .name = "tbus", .bit = 27, }, .bit = BCM63268_CLK_DECT,
{ .name = "robosw250", .bit = 31, }, }, {
{ }, .name = "fap0",
.bit = BCM63268_CLK_FAP0,
}, {
.name = "fap1",
.bit = BCM63268_CLK_FAP1,
}, {
.name = "sar",
.bit = BCM63268_CLK_SAR,
}, {
.name = "robosw",
.bit = BCM63268_CLK_ROBOSW,
}, {
.name = "pcm",
.bit = BCM63268_CLK_PCM,
}, {
.name = "usbd",
.bit = BCM63268_CLK_USBD,
}, {
.name = "usbh",
.bit = BCM63268_CLK_USBH,
}, {
.name = "ipsec",
.bit = BCM63268_CLK_IPSEC,
}, {
.name = "spi",
.bit = BCM63268_CLK_SPI,
}, {
.name = "hsspi",
.bit = BCM63268_CLK_HSSPI,
}, {
.name = "pcie",
.bit = BCM63268_CLK_PCIE,
}, {
.name = "phymips",
.bit = BCM63268_CLK_PHYMIPS,
}, {
.name = "gmac",
.bit = BCM63268_CLK_GMAC,
}, {
.name = "nand",
.bit = BCM63268_CLK_NAND,
}, {
.name = "tbus",
.bit = BCM63268_CLK_TBUS,
}, {
.name = "robosw250",
.bit = BCM63268_CLK_ROBOSW250,
}, {
/* sentinel */
},
}; };
static int clk_bcm63xx_probe(struct platform_device *pdev) static int clk_bcm63xx_probe(struct platform_device *pdev)
@ -155,6 +495,7 @@ static int clk_bcm63xx_probe(struct platform_device *pdev)
for (entry = table; entry->name; entry++) for (entry = table; entry->name; entry++)
maxbit = max_t(u8, maxbit, entry->bit); maxbit = max_t(u8, maxbit, entry->bit);
maxbit++;
hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit), hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
GFP_KERNEL); GFP_KERNEL);
@ -217,6 +558,8 @@ static int clk_bcm63xx_remove(struct platform_device *pdev)
static const struct of_device_id clk_bcm63xx_dt_ids[] = { static const struct of_device_id clk_bcm63xx_dt_ids[] = {
{ .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, }, { .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, },
{ .compatible = "brcm,bcm6318-clocks", .data = &bcm6318_clocks, },
{ .compatible = "brcm,bcm6318-ubus-clocks", .data = &bcm6318_ubus_clocks, },
{ .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, }, { .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, },
{ .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, }, { .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
{ .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, }, { .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },

View File

@ -18,30 +18,56 @@
#include <soc/bcm2835/raspberrypi-firmware.h> #include <soc/bcm2835/raspberrypi-firmware.h>
#define RPI_FIRMWARE_ARM_CLK_ID 0x00000003 enum rpi_firmware_clk_id {
RPI_FIRMWARE_EMMC_CLK_ID = 1,
RPI_FIRMWARE_UART_CLK_ID,
RPI_FIRMWARE_ARM_CLK_ID,
RPI_FIRMWARE_CORE_CLK_ID,
RPI_FIRMWARE_V3D_CLK_ID,
RPI_FIRMWARE_H264_CLK_ID,
RPI_FIRMWARE_ISP_CLK_ID,
RPI_FIRMWARE_SDRAM_CLK_ID,
RPI_FIRMWARE_PIXEL_CLK_ID,
RPI_FIRMWARE_PWM_CLK_ID,
RPI_FIRMWARE_HEVC_CLK_ID,
RPI_FIRMWARE_EMMC2_CLK_ID,
RPI_FIRMWARE_M2MC_CLK_ID,
RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
RPI_FIRMWARE_NUM_CLK_ID,
};
static char *rpi_firmware_clk_names[] = {
[RPI_FIRMWARE_EMMC_CLK_ID] = "emmc",
[RPI_FIRMWARE_UART_CLK_ID] = "uart",
[RPI_FIRMWARE_ARM_CLK_ID] = "arm",
[RPI_FIRMWARE_CORE_CLK_ID] = "core",
[RPI_FIRMWARE_V3D_CLK_ID] = "v3d",
[RPI_FIRMWARE_H264_CLK_ID] = "h264",
[RPI_FIRMWARE_ISP_CLK_ID] = "isp",
[RPI_FIRMWARE_SDRAM_CLK_ID] = "sdram",
[RPI_FIRMWARE_PIXEL_CLK_ID] = "pixel",
[RPI_FIRMWARE_PWM_CLK_ID] = "pwm",
[RPI_FIRMWARE_HEVC_CLK_ID] = "hevc",
[RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2",
[RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc",
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb",
};
#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
/*
* Even though the firmware interface alters 'pllb' the frequencies are
* provided as per 'pllb_arm'. We need to scale before passing them trough.
*/
#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
#define A2W_PLL_FRAC_BITS 20
struct raspberrypi_clk { struct raspberrypi_clk {
struct device *dev; struct device *dev;
struct rpi_firmware *firmware; struct rpi_firmware *firmware;
struct platform_device *cpufreq; struct platform_device *cpufreq;
};
unsigned long min_rate; struct raspberrypi_clk_data {
unsigned long max_rate; struct clk_hw hw;
struct clk_hw pllb; unsigned int id;
struct clk_hw *pllb_arm;
struct clk_lookup *pllb_arm_lookup; struct raspberrypi_clk *rpi;
}; };
/* /*
@ -64,11 +90,12 @@ struct raspberrypi_firmware_prop {
__le32 disable_turbo; __le32 disable_turbo;
} __packed; } __packed;
static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag, static int raspberrypi_clock_property(struct rpi_firmware *firmware,
u32 clk, u32 *val) const struct raspberrypi_clk_data *data,
u32 tag, u32 *val)
{ {
struct raspberrypi_firmware_prop msg = { struct raspberrypi_firmware_prop msg = {
.id = cpu_to_le32(clk), .id = cpu_to_le32(data->id),
.val = cpu_to_le32(*val), .val = cpu_to_le32(*val),
.disable_turbo = cpu_to_le32(1), .disable_turbo = cpu_to_le32(1),
}; };
@ -83,16 +110,16 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
return 0; return 0;
} }
static int raspberrypi_fw_pll_is_on(struct clk_hw *hw) static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, struct raspberrypi_clk_data *data =
pllb); container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0; u32 val = 0;
int ret; int ret;
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_CLOCK_STATE, RPI_FIRMWARE_GET_CLOCK_STATE, &val);
RPI_FIRMWARE_ARM_CLK_ID, &val);
if (ret) if (ret)
return 0; return 0;
@ -100,36 +127,34 @@ static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
} }
static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, struct raspberrypi_clk_data *data =
pllb); container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0; u32 val = 0;
int ret; int ret;
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_CLOCK_RATE, RPI_FIRMWARE_GET_CLOCK_RATE, &val);
RPI_FIRMWARE_ARM_CLK_ID,
&val);
if (ret) if (ret)
return ret; return ret;
return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; return val;
} }
static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, struct raspberrypi_clk_data *data =
pllb); container_of(hw, struct raspberrypi_clk_data, hw);
u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; struct raspberrypi_clk *rpi = data->rpi;
u32 _rate = rate;
int ret; int ret;
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_SET_CLOCK_RATE, RPI_FIRMWARE_SET_CLOCK_RATE, &_rate);
RPI_FIRMWARE_ARM_CLK_ID,
&new_rate);
if (ret) if (ret)
dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
clk_hw_get_name(hw), ret); clk_hw_get_name(hw), ret);
@ -137,111 +162,128 @@ static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
return ret; return ret;
} }
/* static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
* Sadly there is no firmware rate rounding interface. We borrowed it from
* clk-bcm2835.
*/
static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req) struct clk_rate_request *req)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, /*
pllb); * The firmware will do the rounding but that isn't part of
u64 div, final_rate; * the interface with the firmware, so we just do our best
u32 ndiv, fdiv; * here.
*/
/* We can't use req->rate directly as it would overflow */ req->rate = clamp(req->rate, req->min_rate, req->max_rate);
final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
div = (u64)final_rate << A2W_PLL_FRAC_BITS;
do_div(div, req->best_parent_rate);
ndiv = div >> A2W_PLL_FRAC_BITS;
fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
final_rate = ((u64)req->best_parent_rate *
((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
req->rate = final_rate >> A2W_PLL_FRAC_BITS;
return 0; return 0;
} }
static const struct clk_ops raspberrypi_firmware_pll_clk_ops = { static const struct clk_ops raspberrypi_firmware_clk_ops = {
.is_prepared = raspberrypi_fw_pll_is_on, .is_prepared = raspberrypi_fw_is_prepared,
.recalc_rate = raspberrypi_fw_pll_get_rate, .recalc_rate = raspberrypi_fw_get_rate,
.set_rate = raspberrypi_fw_pll_set_rate, .determine_rate = raspberrypi_fw_dumb_determine_rate,
.determine_rate = raspberrypi_pll_determine_rate, .set_rate = raspberrypi_fw_set_rate,
}; };
static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi) static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
unsigned int parent,
unsigned int id)
{ {
u32 min_rate = 0, max_rate = 0; struct raspberrypi_clk_data *data;
struct clk_init_data init; struct clk_init_data init = {};
u32 min_rate, max_rate;
int ret; int ret;
memset(&init, 0, sizeof(init)); data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
data->rpi = rpi;
data->id = id;
/* All of the PLLs derive from the external oscillator. */ init.name = devm_kasprintf(rpi->dev, GFP_KERNEL,
init.parent_names = (const char *[]){ "osc" }; "fw-clk-%s",
init.num_parents = 1; rpi_firmware_clk_names[id]);
init.name = "pllb"; init.ops = &raspberrypi_firmware_clk_ops;
init.ops = &raspberrypi_firmware_pll_clk_ops; init.flags = CLK_GET_RATE_NOCACHE;
init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
/* Get min & max rates set by the firmware */ data->hw.init = &init;
ret = raspberrypi_clock_property(rpi->firmware,
ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_MIN_CLOCK_RATE, RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&min_rate); &min_rate);
if (ret) { if (ret) {
dev_err(rpi->dev, "Failed to get %s min freq: %d\n", dev_err(rpi->dev, "Failed to get clock %d min freq: %d",
init.name, ret); id, ret);
return ret; return ERR_PTR(ret);
} }
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_MAX_CLOCK_RATE, RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&max_rate); &max_rate);
if (ret) { if (ret) {
dev_err(rpi->dev, "Failed to get %s max freq: %d\n", dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n",
init.name, ret); id, ret);
return ret; return ERR_PTR(ret);
} }
if (!min_rate || !max_rate) { ret = devm_clk_hw_register(rpi->dev, &data->hw);
dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n", if (ret)
min_rate, max_rate); return ERR_PTR(ret);
return -EINVAL;
clk_hw_set_rate_range(&data->hw, min_rate, max_rate);
if (id == RPI_FIRMWARE_ARM_CLK_ID) {
ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw,
NULL, "cpu0");
if (ret) {
dev_err(rpi->dev, "Failed to initialize clkdev\n");
return ERR_PTR(ret);
}
} }
dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n", return &data->hw;
min_rate, max_rate);
rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
rpi->pllb.init = &init;
return devm_clk_hw_register(rpi->dev, &rpi->pllb);
} }
static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) struct rpi_firmware_get_clocks_response {
u32 parent;
u32 id;
};
static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
struct clk_hw_onecell_data *data)
{ {
rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev, struct rpi_firmware_get_clocks_response *clks;
"pllb_arm", "pllb", int ret;
CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
1, 2);
if (IS_ERR(rpi->pllb_arm)) {
dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
return PTR_ERR(rpi->pllb_arm);
}
rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0"); clks = devm_kcalloc(rpi->dev,
if (!rpi->pllb_arm_lookup) { sizeof(*clks), RPI_FIRMWARE_NUM_CLK_ID,
dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); GFP_KERNEL);
clk_hw_unregister_fixed_factor(rpi->pllb_arm); if (!clks)
return -ENOMEM; return -ENOMEM;
ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS,
clks,
sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID);
if (ret)
return ret;
while (clks->id) {
struct clk_hw *hw;
switch (clks->id) {
case RPI_FIRMWARE_ARM_CLK_ID:
case RPI_FIRMWARE_CORE_CLK_ID:
case RPI_FIRMWARE_M2MC_CLK_ID:
case RPI_FIRMWARE_V3D_CLK_ID:
hw = raspberrypi_clk_register(rpi, clks->parent,
clks->id);
if (IS_ERR(hw))
return PTR_ERR(hw);
data->hws[clks->id] = hw;
data->num = clks->id + 1;
fallthrough;
default:
clks++;
break;
}
} }
return 0; return 0;
@ -249,12 +291,21 @@ static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
static int raspberrypi_clk_probe(struct platform_device *pdev) static int raspberrypi_clk_probe(struct platform_device *pdev)
{ {
struct clk_hw_onecell_data *clk_data;
struct device_node *firmware_node; struct device_node *firmware_node;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct rpi_firmware *firmware; struct rpi_firmware *firmware;
struct raspberrypi_clk *rpi; struct raspberrypi_clk *rpi;
int ret; int ret;
/*
* We can be probed either through the an old-fashioned
* platform device registration or through a DT node that is a
* child of the firmware node. Handle both cases.
*/
if (dev->of_node)
firmware_node = of_get_parent(dev->of_node);
else
firmware_node = of_find_compatible_node(NULL, NULL, firmware_node = of_find_compatible_node(NULL, NULL,
"raspberrypi,bcm2835-firmware"); "raspberrypi,bcm2835-firmware");
if (!firmware_node) { if (!firmware_node) {
@ -275,13 +326,18 @@ static int raspberrypi_clk_probe(struct platform_device *pdev)
rpi->firmware = firmware; rpi->firmware = firmware;
platform_set_drvdata(pdev, rpi); platform_set_drvdata(pdev, rpi);
ret = raspberrypi_register_pllb(rpi); clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
if (ret) { RPI_FIRMWARE_NUM_CLK_ID),
dev_err(dev, "Failed to initialize pllb, %d\n", ret); GFP_KERNEL);
return ret; if (!clk_data)
} return -ENOMEM;
ret = raspberrypi_register_pllb_arm(rpi); ret = raspberrypi_discover_clocks(rpi, clk_data);
if (ret)
return ret;
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clk_data);
if (ret) if (ret)
return ret; return ret;
@ -300,9 +356,16 @@ static int raspberrypi_clk_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id raspberrypi_clk_match[] = {
{ .compatible = "raspberrypi,firmware-clocks" },
{ },
};
MODULE_DEVICE_TABLE(of, raspberrypi_clk_match);
static struct platform_driver raspberrypi_clk_driver = { static struct platform_driver raspberrypi_clk_driver = {
.driver = { .driver = {
.name = "raspberrypi-clk", .name = "raspberrypi-clk",
.of_match_table = raspberrypi_clk_match,
}, },
.probe = raspberrypi_clk_probe, .probe = raspberrypi_clk_probe,
.remove = raspberrypi_clk_remove, .remove = raspberrypi_clk_remove,

View File

@ -24,6 +24,8 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <dt-bindings/clk/versaclock.h>
/* VersaClock5 registers */ /* VersaClock5 registers */
#define VC5_OTP_CONTROL 0x00 #define VC5_OTP_CONTROL 0x00
@ -89,6 +91,28 @@
/* Clock control register for clock 1,2 */ /* Clock control register for clock 1,2 */
#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n)) #define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
#define VC5_CLK_OUTPUT_CFG0_CFG_SHIFT 5
#define VC5_CLK_OUTPUT_CFG0_CFG_MASK GENMASK(7, VC5_CLK_OUTPUT_CFG0_CFG_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_CFG_LVPECL (VC5_LVPECL)
#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS (VC5_CMOS)
#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL33 (VC5_HCSL33)
#define VC5_CLK_OUTPUT_CFG0_CFG_LVDS (VC5_LVDS)
#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS2 (VC5_CMOS2)
#define VC5_CLK_OUTPUT_CFG0_CFG_CMOSD (VC5_CMOSD)
#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL25 (VC5_HCSL25)
#define VC5_CLK_OUTPUT_CFG0_PWR_SHIFT 3
#define VC5_CLK_OUTPUT_CFG0_PWR_MASK GENMASK(4, VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_PWR_18 (0<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_PWR_25 (2<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_PWR_33 (3<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT 0
#define VC5_CLK_OUTPUT_CFG0_SLEW_MASK GENMASK(1, VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_SLEW_80 (0<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_SLEW_85 (1<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_SLEW_90 (2<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
#define VC5_CLK_OUTPUT_CFG0_SLEW_100 (3<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0) #define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
#define VC5_CLK_OE_SHDN 0x68 #define VC5_CLK_OE_SHDN 0x68
@ -145,6 +169,14 @@ struct vc5_hw_data {
unsigned int num; unsigned int num;
}; };
struct vc5_out_data {
struct clk_hw hw;
struct vc5_driver_data *vc5;
unsigned int num;
unsigned int clk_output_cfg0;
unsigned int clk_output_cfg0_mask;
};
struct vc5_driver_data { struct vc5_driver_data {
struct i2c_client *client; struct i2c_client *client;
struct regmap *regmap; struct regmap *regmap;
@ -158,31 +190,7 @@ struct vc5_driver_data {
struct clk_hw clk_pfd; struct clk_hw clk_pfd;
struct vc5_hw_data clk_pll; struct vc5_hw_data clk_pll;
struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM]; struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM]; struct vc5_out_data clk_out[VC5_MAX_CLK_OUT_NUM];
};
static const char * const vc5_mux_names[] = {
"mux"
};
static const char * const vc5_dbl_names[] = {
"dbl"
};
static const char * const vc5_pfd_names[] = {
"pfd"
};
static const char * const vc5_pll_names[] = {
"pll"
};
static const char * const vc5_fod_names[] = {
"fod0", "fod1", "fod2", "fod3",
};
static const char * const vc5_clk_out_names[] = {
"out0_sel_i2cb", "out1", "out2", "out3", "out4",
}; };
/* /*
@ -565,7 +573,7 @@ static const struct clk_ops vc5_fod_ops = {
static int vc5_clk_out_prepare(struct clk_hw *hw) static int vc5_clk_out_prepare(struct clk_hw *hw)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM | const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
VC5_OUT_DIV_CONTROL_SEL_EXT | VC5_OUT_DIV_CONTROL_SEL_EXT |
@ -591,12 +599,23 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF); VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
if (hwdata->clk_output_cfg0_mask) {
dev_dbg(&vc5->client->dev, "Update output %d mask 0x%0X val 0x%0X\n",
hwdata->num, hwdata->clk_output_cfg0_mask,
hwdata->clk_output_cfg0);
regmap_update_bits(vc5->regmap,
VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
hwdata->clk_output_cfg0_mask,
hwdata->clk_output_cfg0);
}
return 0; return 0;
} }
static void vc5_clk_out_unprepare(struct clk_hw *hw) static void vc5_clk_out_unprepare(struct clk_hw *hw)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
/* Disable the clock buffer */ /* Disable the clock buffer */
@ -606,7 +625,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw) static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM | const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
VC5_OUT_DIV_CONTROL_SEL_EXT | VC5_OUT_DIV_CONTROL_SEL_EXT |
@ -636,7 +655,7 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index) static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
const u8 mask = VC5_OUT_DIV_CONTROL_RESET | const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
VC5_OUT_DIV_CONTROL_SELB_NORM | VC5_OUT_DIV_CONTROL_SELB_NORM |
@ -690,10 +709,125 @@ static int vc5_map_index_to_output(const enum vc5_model model,
} }
} }
static int vc5_update_mode(struct device_node *np_output,
struct vc5_out_data *clk_out)
{
u32 value;
if (!of_property_read_u32(np_output, "idt,mode", &value)) {
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_CFG_MASK;
switch (value) {
case VC5_CLK_OUTPUT_CFG0_CFG_LVPECL:
case VC5_CLK_OUTPUT_CFG0_CFG_CMOS:
case VC5_CLK_OUTPUT_CFG0_CFG_HCSL33:
case VC5_CLK_OUTPUT_CFG0_CFG_LVDS:
case VC5_CLK_OUTPUT_CFG0_CFG_CMOS2:
case VC5_CLK_OUTPUT_CFG0_CFG_CMOSD:
case VC5_CLK_OUTPUT_CFG0_CFG_HCSL25:
clk_out->clk_output_cfg0 |=
value << VC5_CLK_OUTPUT_CFG0_CFG_SHIFT;
break;
default:
return -EINVAL;
}
}
return 0;
}
static int vc5_update_power(struct device_node *np_output,
struct vc5_out_data *clk_out)
{
u32 value;
if (!of_property_read_u32(np_output,
"idt,voltage-microvolts", &value)) {
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK;
switch (value) {
case 1800000:
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_18;
break;
case 2500000:
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_25;
break;
case 3300000:
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_33;
break;
default:
return -EINVAL;
}
}
return 0;
}
static int vc5_update_slew(struct device_node *np_output,
struct vc5_out_data *clk_out)
{
u32 value;
if (!of_property_read_u32(np_output, "idt,slew-percent", &value)) {
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_SLEW_MASK;
switch (value) {
case 80:
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_80;
break;
case 85:
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_85;
break;
case 90:
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_90;
break;
case 100:
clk_out->clk_output_cfg0 |=
VC5_CLK_OUTPUT_CFG0_SLEW_100;
break;
default:
return -EINVAL;
}
}
return 0;
}
static int vc5_get_output_config(struct i2c_client *client,
struct vc5_out_data *clk_out)
{
struct device_node *np_output;
char *child_name;
int ret = 0;
child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1);
if (!child_name)
return -ENOMEM;
np_output = of_get_child_by_name(client->dev.of_node, child_name);
kfree(child_name);
if (!np_output)
return 0;
ret = vc5_update_mode(np_output, clk_out);
if (ret)
goto output_error;
ret = vc5_update_power(np_output, clk_out);
if (ret)
goto output_error;
ret = vc5_update_slew(np_output, clk_out);
output_error:
if (ret) {
dev_err(&client->dev,
"Invalid clock output configuration OUT%d\n",
clk_out->num + 1);
}
of_node_put(np_output);
return ret;
}
static const struct of_device_id clk_vc5_of_match[]; static const struct of_device_id clk_vc5_of_match[];
static int vc5_probe(struct i2c_client *client, static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
const struct i2c_device_id *id)
{ {
struct vc5_driver_data *vc5; struct vc5_driver_data *vc5;
struct clk_init_data init; struct clk_init_data init;
@ -702,7 +836,7 @@ static int vc5_probe(struct i2c_client *client,
int ret; int ret;
vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL); vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
if (vc5 == NULL) if (!vc5)
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(client, vc5); i2c_set_clientdata(client, vc5);
@ -750,115 +884,116 @@ static int vc5_probe(struct i2c_client *client,
return -EINVAL; return -EINVAL;
} }
init.name = vc5_mux_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.mux", client->dev.of_node);
init.ops = &vc5_mux_ops; init.ops = &vc5_mux_ops;
init.flags = 0; init.flags = 0;
init.parent_names = parent_names; init.parent_names = parent_names;
vc5->clk_mux.init = &init; vc5->clk_mux.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux); ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
if (ret) { if (ret)
dev_err(&client->dev, "unable to register %s\n", init.name); goto err_clk_register;
goto err_clk; kfree(init.name); /* clock framework made a copy of the name */
}
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) { if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
/* Register frequency doubler */ /* Register frequency doubler */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_dbl_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.dbl",
client->dev.of_node);
init.ops = &vc5_dbl_ops; init.ops = &vc5_dbl_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_mux_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_mul.init = &init; vc5->clk_mul.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul); ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
if (ret) { if (ret)
dev_err(&client->dev, "unable to register %s\n", goto err_clk_register;
init.name); kfree(init.name); /* clock framework made a copy of the name */
goto err_clk;
}
} }
/* Register PFD */ /* Register PFD */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_pfd_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.pfd", client->dev.of_node);
init.ops = &vc5_pfd_ops; init.ops = &vc5_pfd_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = parent_names;
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
init.parent_names = vc5_dbl_names; parent_names[0] = clk_hw_get_name(&vc5->clk_mul);
else else
init.parent_names = vc5_mux_names; parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_pfd.init = &init; vc5->clk_pfd.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd); ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
if (ret) { if (ret)
dev_err(&client->dev, "unable to register %s\n", init.name); goto err_clk_register;
goto err_clk; kfree(init.name); /* clock framework made a copy of the name */
}
/* Register PLL */ /* Register PLL */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_pll_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.pll", client->dev.of_node);
init.ops = &vc5_pll_ops; init.ops = &vc5_pll_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_pfd_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_pfd);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_pll.num = 0; vc5->clk_pll.num = 0;
vc5->clk_pll.vc5 = vc5; vc5->clk_pll.vc5 = vc5;
vc5->clk_pll.hw.init = &init; vc5->clk_pll.hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
if (ret) { if (ret)
dev_err(&client->dev, "unable to register %s\n", init.name); goto err_clk_register;
goto err_clk; kfree(init.name); /* clock framework made a copy of the name */
}
/* Register FODs */ /* Register FODs */
for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) { for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
idx = vc5_map_index_to_output(vc5->chip_info->model, n); idx = vc5_map_index_to_output(vc5->chip_info->model, n);
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_fod_names[idx]; init.name = kasprintf(GFP_KERNEL, "%pOFn.fod%d",
client->dev.of_node, idx);
init.ops = &vc5_fod_ops; init.ops = &vc5_fod_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_pll_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_pll.hw);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_fod[n].num = idx; vc5->clk_fod[n].num = idx;
vc5->clk_fod[n].vc5 = vc5; vc5->clk_fod[n].vc5 = vc5;
vc5->clk_fod[n].hw.init = &init; vc5->clk_fod[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
if (ret) { if (ret)
dev_err(&client->dev, "unable to register %s\n", goto err_clk_register;
init.name); kfree(init.name); /* clock framework made a copy of the name */
goto err_clk;
}
} }
/* Register MUX-connected OUT0_I2C_SELB output */ /* Register MUX-connected OUT0_I2C_SELB output */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_clk_out_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.out0_sel_i2cb",
client->dev.of_node);
init.ops = &vc5_clk_out_ops; init.ops = &vc5_clk_out_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_mux_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_out[0].num = idx; vc5->clk_out[0].num = idx;
vc5->clk_out[0].vc5 = vc5; vc5->clk_out[0].vc5 = vc5;
vc5->clk_out[0].hw.init = &init; vc5->clk_out[0].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
if (ret) { if (ret)
dev_err(&client->dev, "unable to register %s\n", goto err_clk_register;
init.name); kfree(init.name); /* clock framework made a copy of the name */
goto err_clk;
}
/* Register FOD-connected OUTx outputs */ /* Register FOD-connected OUTx outputs */
for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) { for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1); idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
parent_names[0] = vc5_fod_names[idx]; parent_names[0] = clk_hw_get_name(&vc5->clk_fod[idx].hw);
if (n == 1) if (n == 1)
parent_names[1] = vc5_mux_names[0]; parent_names[1] = clk_hw_get_name(&vc5->clk_mux);
else else
parent_names[1] = vc5_clk_out_names[n - 1]; parent_names[1] =
clk_hw_get_name(&vc5->clk_out[n - 1].hw);
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_clk_out_names[idx + 1]; init.name = kasprintf(GFP_KERNEL, "%pOFn.out%d",
client->dev.of_node, idx + 1);
init.ops = &vc5_clk_out_ops; init.ops = &vc5_clk_out_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = parent_names; init.parent_names = parent_names;
@ -866,14 +1001,16 @@ static int vc5_probe(struct i2c_client *client,
vc5->clk_out[n].num = idx; vc5->clk_out[n].num = idx;
vc5->clk_out[n].vc5 = vc5; vc5->clk_out[n].vc5 = vc5;
vc5->clk_out[n].hw.init = &init; vc5->clk_out[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
&vc5->clk_out[n].hw); if (ret)
if (ret) { goto err_clk_register;
dev_err(&client->dev, "unable to register %s\n", kfree(init.name); /* clock framework made a copy of the name */
init.name);
/* Fetch Clock Output configuration from DT (if specified) */
ret = vc5_get_output_config(client, &vc5->clk_out[n]);
if (ret)
goto err_clk; goto err_clk;
} }
}
ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5); ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
if (ret) { if (ret) {
@ -883,6 +1020,9 @@ static int vc5_probe(struct i2c_client *client,
return 0; return 0;
err_clk_register:
dev_err(&client->dev, "unable to register %s\n", init.name);
kfree(init.name); /* clock framework made a copy of the name */
err_clk: err_clk:
if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
clk_unregister_fixed_rate(vc5->pin_xin); clk_unregister_fixed_rate(vc5->pin_xin);

View File

@ -1400,6 +1400,21 @@ int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
} }
EXPORT_SYMBOL_GPL(__clk_determine_rate); EXPORT_SYMBOL_GPL(__clk_determine_rate);
/**
* clk_hw_round_rate() - round the given rate for a hw clk
* @hw: the hw clk for which we are rounding a rate
* @rate: the rate which is to be rounded
*
* Takes in a rate as input and rounds it to a rate that the clk can actually
* use.
*
* Context: prepare_lock must be held.
* For clk providers to call from within clk_ops such as .round_rate,
* .determine_rate.
*
* Return: returns rounded rate of hw clk if clk supports round_rate operation
* else returns the parent rate.
*/
unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate) unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
{ {
int ret; int ret;
@ -4120,6 +4135,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data)
/** /**
* devm_clk_unregister - resource managed clk_unregister() * devm_clk_unregister - resource managed clk_unregister()
* @dev: device that is unregistering the clock data
* @clk: clock to unregister * @clk: clock to unregister
* *
* Deallocate a clock allocated with devm_clk_register(). Normally * Deallocate a clock allocated with devm_clk_register(). Normally
@ -4309,6 +4325,8 @@ static void clk_core_reparent_orphans(void)
* @node: Pointer to device tree node of clock provider * @node: Pointer to device tree node of clock provider
* @get: Get clock callback. Returns NULL or a struct clk for the * @get: Get clock callback. Returns NULL or a struct clk for the
* given clock specifier * given clock specifier
* @get_hw: Get clk_hw callback. Returns NULL, ERR_PTR or a
* struct clk_hw for the given clock specifier
* @data: context pointer to be passed into @get callback * @data: context pointer to be passed into @get callback
*/ */
struct of_clk_provider { struct of_clk_provider {

View File

@ -37,6 +37,15 @@ config QCOM_CLK_APCS_MSM8916
Say Y if you want to support CPU frequency scaling on devices Say Y if you want to support CPU frequency scaling on devices
such as msm8916. such as msm8916.
config QCOM_CLK_APCC_MSM8996
tristate "MSM8996 CPU Clock Controller"
select QCOM_KRYO_L2_ACCESSORS
depends on ARM64
help
Support for the CPU clock controller on msm8996 devices.
Say Y if you want to support CPU clock scaling using CPUfreq
drivers for dyanmic power management.
config QCOM_CLK_RPM config QCOM_CLK_RPM
tristate "RPM based Clock Controller" tristate "RPM based Clock Controller"
depends on MFD_QCOM_RPM depends on MFD_QCOM_RPM
@ -89,6 +98,25 @@ config APQ_MMCC_8084
Say Y if you want to support multimedia devices such as display, Say Y if you want to support multimedia devices such as display,
graphics, video encode/decode, camera, etc. graphics, video encode/decode, camera, etc.
config IPQ_APSS_PLL
tristate "IPQ APSS PLL"
help
Support for APSS PLL on ipq devices. The APSS PLL is the main
clock that feeds the CPUs on ipq based devices.
Say Y if you want to support CPU frequency scaling on ipq based
devices.
config IPQ_APSS_6018
tristate "IPQ APSS Clock Controller"
select IPQ_APSS_PLL
depends on QCOM_APCS_IPC || COMPILE_TEST
help
Support for APSS clock controller on IPQ platforms. The
APSS clock controller manages the Mux and enable block that feeds the
CPUs.
Say Y if you want to support CPU frequency scaling on
ipq based devices.
config IPQ_GCC_4019 config IPQ_GCC_4019
tristate "IPQ4019 Global Clock Controller" tristate "IPQ4019 Global Clock Controller"
help help
@ -280,6 +308,15 @@ config SC_GCC_7180
Say Y if you want to use peripheral devices such as UART, SPI, Say Y if you want to use peripheral devices such as UART, SPI,
I2C, USB, UFS, SDCC, etc. I2C, USB, UFS, SDCC, etc.
config SC_LPASS_CORECC_7180
tristate "SC7180 LPASS Core Clock Controller"
select SC_GCC_7180
help
Support for the LPASS(Low Power Audio Subsystem) core clock controller
on SC7180 devices.
Say Y if you want to use LPASS clocks and power domains of the LPASS
core clock controller.
config SC_GPUCC_7180 config SC_GPUCC_7180
tristate "SC7180 Graphics Clock Controller" tristate "SC7180 Graphics Clock Controller"
select SC_GCC_7180 select SC_GCC_7180
@ -391,6 +428,22 @@ config SM_GCC_8250
Say Y if you want to use peripheral devices such as UART, Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc. SPI, I2C, USB, SD/UFS, PCIe etc.
config SM_GPUCC_8150
tristate "SM8150 Graphics Clock Controller"
select SM_GCC_8150
help
Support for the graphics clock controller on SM8150 devices.
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
config SM_GPUCC_8250
tristate "SM8250 Graphics Clock Controller"
select SM_GCC_8250
help
Support for the graphics clock controller on SM8250 devices.
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
config SPMI_PMIC_CLKDIV config SPMI_PMIC_CLKDIV
tristate "SPMI PMIC clkdiv Support" tristate "SPMI PMIC clkdiv Support"
depends on SPMI || COMPILE_TEST depends on SPMI || COMPILE_TEST

View File

@ -19,6 +19,8 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
# Keep alphabetically sorted by config # Keep alphabetically sorted by config
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o
obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
obj-$(CONFIG_IPQ_GCC_6018) += gcc-ipq6018.o obj-$(CONFIG_IPQ_GCC_6018) += gcc-ipq6018.o
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
@ -42,6 +44,7 @@ obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
obj-$(CONFIG_MSM_MMCC_8998) += mmcc-msm8998.o obj-$(CONFIG_MSM_MMCC_8998) += mmcc-msm8998.o
obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
obj-$(CONFIG_QCOM_CLK_APCC_MSM8996) += clk-cpu-8996.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
@ -51,6 +54,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o
obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o
obj-$(CONFIG_SC_LPASS_CORECC_7180) += lpasscorecc-sc7180.o
obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o
obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o
obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
@ -62,6 +66,8 @@ obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
obj-$(CONFIG_SM_GPUCC_8150) += gpucc-sm8150.o
obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o

View File

@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "clk-alpha-pll.h"
static const u8 ipq_pll_offsets[] = {
[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,
};
static struct clk_alpha_pll ipq_pll = {
.offset = 0x0,
.regs = ipq_pll_offsets,
.flags = SUPPORTS_DYNAMIC_UPDATE,
.clkr = {
.enable_reg = 0x0,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "a53pll",
.parent_data = &(const struct clk_parent_data) {
.fw_name = "xo",
},
.num_parents = 1,
.ops = &clk_alpha_pll_huayra_ops,
},
},
};
static const struct alpha_pll_config ipq_pll_config = {
.l = 0x37,
.config_ctl_val = 0x04141200,
.config_ctl_hi_val = 0x0,
.early_output_mask = BIT(3),
.main_output_mask = BIT(0),
};
static const struct regmap_config ipq_pll_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x40,
.fast_io = true,
};
static int apss_ipq_pll_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct regmap *regmap;
void __iomem *base;
int ret;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &ipq_pll_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
clk_alpha_pll_configure(&ipq_pll, regmap, &ipq_pll_config);
ret = devm_clk_register_regmap(dev, &ipq_pll.clkr);
if (ret)
return ret;
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
&ipq_pll.clkr.hw);
}
static const struct of_device_id apss_ipq_pll_match_table[] = {
{ .compatible = "qcom,ipq6018-a53pll" },
{ }
};
static struct platform_driver apss_ipq_pll_driver = {
.probe = apss_ipq_pll_probe,
.driver = {
.name = "qcom-ipq-apss-pll",
.of_match_table = apss_ipq_pll_match_table,
},
};
module_platform_driver(apss_ipq_pll_driver);
MODULE_DESCRIPTION("Qualcomm technology Inc APSS ALPHA PLL Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/module.h>
#include <dt-bindings/clock/qcom,apss-ipq.h>
#include "common.h"
#include "clk-regmap.h"
#include "clk-branch.h"
#include "clk-alpha-pll.h"
#include "clk-regmap-mux.h"
enum {
P_XO,
P_APSS_PLL_EARLY,
};
static const struct clk_parent_data parents_apcs_alias0_clk_src[] = {
{ .fw_name = "xo" },
{ .fw_name = "pll" },
};
static const struct parent_map parents_apcs_alias0_clk_src_map[] = {
{ P_XO, 0 },
{ P_APSS_PLL_EARLY, 5 },
};
static struct clk_regmap_mux apcs_alias0_clk_src = {
.reg = 0x0050,
.width = 3,
.shift = 7,
.parent_map = parents_apcs_alias0_clk_src_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "apcs_alias0_clk_src",
.parent_data = parents_apcs_alias0_clk_src,
.num_parents = 2,
.ops = &clk_regmap_mux_closest_ops,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_branch apcs_alias0_core_clk = {
.halt_reg = 0x0058,
.clkr = {
.enable_reg = 0x0058,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "apcs_alias0_core_clk",
.parent_hws = (const struct clk_hw *[]){
&apcs_alias0_clk_src.clkr.hw },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static const struct regmap_config apss_ipq6018_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x1000,
.fast_io = true,
};
static struct clk_regmap *apss_ipq6018_clks[] = {
[APCS_ALIAS0_CLK_SRC] = &apcs_alias0_clk_src.clkr,
[APCS_ALIAS0_CORE_CLK] = &apcs_alias0_core_clk.clkr,
};
static const struct qcom_cc_desc apss_ipq6018_desc = {
.config = &apss_ipq6018_regmap_config,
.clks = apss_ipq6018_clks,
.num_clks = ARRAY_SIZE(apss_ipq6018_clks),
};
static int apss_ipq6018_probe(struct platform_device *pdev)
{
struct regmap *regmap;
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap)
return -ENODEV;
return qcom_cc_really_probe(pdev, &apss_ipq6018_desc, regmap);
}
static struct platform_driver apss_ipq6018_driver = {
.probe = apss_ipq6018_probe,
.driver = {
.name = "qcom,apss-ipq6018-clk",
},
};
module_platform_driver(apss_ipq6018_driver);
MODULE_DESCRIPTION("QCOM APSS IPQ 6018 CLK Driver");
MODULE_LICENSE("GPL v2");

View File

@ -56,7 +56,6 @@
#define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS]) #define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS])
#define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE]) #define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE])
#define PLL_FRAC(p) ((p)->offset + (p)->regs[PLL_OFF_FRAC]) #define PLL_FRAC(p) ((p)->offset + (p)->regs[PLL_OFF_FRAC])
#define PLL_CAL_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_CAL_VAL])
const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
[CLK_ALPHA_PLL_TYPE_DEFAULT] = { [CLK_ALPHA_PLL_TYPE_DEFAULT] = {
@ -102,22 +101,6 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
[PLL_OFF_FRAC] = 0x38, [PLL_OFF_FRAC] = 0x38,
}, },
[CLK_ALPHA_PLL_TYPE_TRION] = { [CLK_ALPHA_PLL_TYPE_TRION] = {
[PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_CAL_L_VAL] = 0x08,
[PLL_OFF_USER_CTL] = 0x0c,
[PLL_OFF_USER_CTL_U] = 0x10,
[PLL_OFF_USER_CTL_U1] = 0x14,
[PLL_OFF_CONFIG_CTL] = 0x18,
[PLL_OFF_CONFIG_CTL_U] = 0x1c,
[PLL_OFF_CONFIG_CTL_U1] = 0x20,
[PLL_OFF_TEST_CTL] = 0x24,
[PLL_OFF_TEST_CTL_U] = 0x28,
[PLL_OFF_STATUS] = 0x30,
[PLL_OFF_OPMODE] = 0x38,
[PLL_OFF_ALPHA_VAL] = 0x40,
[PLL_OFF_CAL_VAL] = 0x44,
},
[CLK_ALPHA_PLL_TYPE_LUCID] = {
[PLL_OFF_L_VAL] = 0x04, [PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_CAL_L_VAL] = 0x08, [PLL_OFF_CAL_L_VAL] = 0x08,
[PLL_OFF_USER_CTL] = 0x0c, [PLL_OFF_USER_CTL] = 0x0c,
@ -156,9 +139,12 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
#define PLL_OUT_MASK 0x7 #define PLL_OUT_MASK 0x7
#define PLL_RATE_MARGIN 500 #define PLL_RATE_MARGIN 500
/* TRION PLL specific settings and offsets */
#define TRION_PLL_CAL_VAL 0x44
#define TRION_PCAL_DONE BIT(26)
/* LUCID PLL specific settings and offsets */ /* LUCID PLL specific settings and offsets */
#define LUCID_PLL_CAL_VAL 0x44 #define LUCID_PCAL_DONE BIT(27)
#define LUCID_PCAL_DONE BIT(26)
#define pll_alpha_width(p) \ #define pll_alpha_width(p) \
((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \ ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
@ -912,14 +898,14 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops); EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);
const struct clk_ops clk_trion_fixed_pll_ops = { const struct clk_ops clk_alpha_pll_fixed_trion_ops = {
.enable = clk_trion_pll_enable, .enable = clk_trion_pll_enable,
.disable = clk_trion_pll_disable, .disable = clk_trion_pll_disable,
.is_enabled = clk_trion_pll_is_enabled, .is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate, .recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate, .round_rate = clk_alpha_pll_round_rate,
}; };
EXPORT_SYMBOL_GPL(clk_trion_fixed_pll_ops); EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_trion_ops);
static unsigned long static unsigned long
clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
@ -1339,12 +1325,12 @@ clk_trion_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
val << PLL_POST_DIV_SHIFT); val << PLL_POST_DIV_SHIFT);
} }
const struct clk_ops clk_trion_pll_postdiv_ops = { const struct clk_ops clk_alpha_pll_postdiv_trion_ops = {
.recalc_rate = clk_trion_pll_postdiv_recalc_rate, .recalc_rate = clk_trion_pll_postdiv_recalc_rate,
.round_rate = clk_trion_pll_postdiv_round_rate, .round_rate = clk_trion_pll_postdiv_round_rate,
.set_rate = clk_trion_pll_postdiv_set_rate, .set_rate = clk_trion_pll_postdiv_set_rate,
}; };
EXPORT_SYMBOL_GPL(clk_trion_pll_postdiv_ops); EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_trion_ops);
static long clk_alpha_pll_postdiv_fabia_round_rate(struct clk_hw *hw, static long clk_alpha_pll_postdiv_fabia_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *prate) unsigned long rate, unsigned long *prate)
@ -1399,13 +1385,13 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
* @regmap: register map * @regmap: register map
* @config: configuration to apply for pll * @config: configuration to apply for pll
*/ */
void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config) const struct alpha_pll_config *config)
{ {
if (config->l) if (config->l)
regmap_write(regmap, PLL_L_VAL(pll), config->l); regmap_write(regmap, PLL_L_VAL(pll), config->l);
regmap_write(regmap, PLL_CAL_L_VAL(pll), LUCID_PLL_CAL_VAL); regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL);
if (config->alpha) if (config->alpha)
regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha); regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
@ -1458,13 +1444,13 @@ void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
/* Place the PLL in STANDBY mode */ /* Place the PLL in STANDBY mode */
regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
} }
EXPORT_SYMBOL_GPL(clk_lucid_pll_configure); EXPORT_SYMBOL_GPL(clk_trion_pll_configure);
/* /*
* The Lucid PLL requires a power-on self-calibration which happens when the * The TRION PLL requires a power-on self-calibration which happens when the
* PLL comes out of reset. Calibrate in case it is not completed. * PLL comes out of reset. Calibrate in case it is not completed.
*/ */
static int alpha_pll_lucid_prepare(struct clk_hw *hw) static int __alpha_pll_trion_prepare(struct clk_hw *hw, u32 pcal_done)
{ {
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 regval; u32 regval;
@ -1472,7 +1458,7 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw)
/* Return early if calibration is not needed. */ /* Return early if calibration is not needed. */
regmap_read(pll->clkr.regmap, PLL_STATUS(pll), &regval); regmap_read(pll->clkr.regmap, PLL_STATUS(pll), &regval);
if (regval & LUCID_PCAL_DONE) if (regval & pcal_done)
return 0; return 0;
/* On/off to calibrate */ /* On/off to calibrate */
@ -1483,7 +1469,17 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw)
return ret; return ret;
} }
static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate, static int alpha_pll_trion_prepare(struct clk_hw *hw)
{
return __alpha_pll_trion_prepare(hw, TRION_PCAL_DONE);
}
static int alpha_pll_lucid_prepare(struct clk_hw *hw)
{
return __alpha_pll_trion_prepare(hw, LUCID_PCAL_DONE);
}
static int alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long prate) unsigned long prate)
{ {
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
@ -1537,6 +1533,17 @@ static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate,
return 0; return 0;
} }
const struct clk_ops clk_alpha_pll_trion_ops = {
.prepare = alpha_pll_trion_prepare,
.enable = clk_trion_pll_enable,
.disable = clk_trion_pll_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
.set_rate = alpha_pll_trion_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_trion_ops);
const struct clk_ops clk_alpha_pll_lucid_ops = { const struct clk_ops clk_alpha_pll_lucid_ops = {
.prepare = alpha_pll_lucid_prepare, .prepare = alpha_pll_lucid_prepare,
.enable = clk_trion_pll_enable, .enable = clk_trion_pll_enable,
@ -1544,19 +1551,10 @@ const struct clk_ops clk_alpha_pll_lucid_ops = {
.is_enabled = clk_trion_pll_is_enabled, .is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate, .recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate, .round_rate = clk_alpha_pll_round_rate,
.set_rate = alpha_pll_lucid_set_rate, .set_rate = alpha_pll_trion_set_rate,
}; };
EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops); EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops);
const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
.enable = clk_trion_pll_enable,
.disable = clk_trion_pll_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_lucid_ops);
const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = { const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
.recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate,
.round_rate = clk_alpha_pll_postdiv_fabia_round_rate, .round_rate = clk_alpha_pll_postdiv_fabia_round_rate,

View File

@ -14,7 +14,7 @@ enum {
CLK_ALPHA_PLL_TYPE_BRAMMO, CLK_ALPHA_PLL_TYPE_BRAMMO,
CLK_ALPHA_PLL_TYPE_FABIA, CLK_ALPHA_PLL_TYPE_FABIA,
CLK_ALPHA_PLL_TYPE_TRION, CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_LUCID, CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_MAX, CLK_ALPHA_PLL_TYPE_MAX,
}; };
@ -47,6 +47,12 @@ struct pll_vco {
u32 val; u32 val;
}; };
#define VCO(a, b, c) { \
.val = a,\
.min_freq = b,\
.max_freq = c,\
}
/** /**
* struct clk_alpha_pll - phase locked loop (PLL) * struct clk_alpha_pll - phase locked loop (PLL)
* @offset: base address of registers * @offset: base address of registers
@ -128,18 +134,23 @@ extern const struct clk_ops clk_alpha_pll_fabia_ops;
extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops; extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops;
extern const struct clk_ops clk_alpha_pll_trion_ops;
extern const struct clk_ops clk_alpha_pll_fixed_trion_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_trion_ops;
extern const struct clk_ops clk_alpha_pll_lucid_ops; extern const struct clk_ops clk_alpha_pll_lucid_ops;
extern const struct clk_ops clk_alpha_pll_fixed_lucid_ops; #define clk_alpha_pll_fixed_lucid_ops clk_alpha_pll_fixed_trion_ops
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops; extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops;
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config); const struct alpha_pll_config *config);
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config); const struct alpha_pll_config *config);
void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config); const struct alpha_pll_config *config);
#define clk_lucid_pll_configure(pll, regmap, config) \
clk_trion_pll_configure(pll, regmap, config)
extern const struct clk_ops clk_trion_fixed_pll_ops;
extern const struct clk_ops clk_trion_pll_postdiv_ops;
#endif #endif

View File

@ -0,0 +1,538 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
/*
* Each of the CPU clusters (Power and Perf) on msm8996 are
* clocked via 2 PLLs, a primary and alternate. There are also
* 2 Mux'es, a primary and secondary all connected together
* as shown below
*
* +-------+
* XO | |
* +------------------>0 |
* | |
* PLL/2 | SMUX +----+
* +------->1 | |
* | | | |
* | +-------+ | +-------+
* | +---->0 |
* | | |
* +---------------+ | +----------->1 | CPU clk
* |Primary PLL +----+ PLL_EARLY | | +------>
* | +------+-----------+ +------>2 PMUX |
* +---------------+ | | | |
* | +------+ | +-->3 |
* +--^+ ACD +-----+ | +-------+
* +---------------+ +------+ |
* |Alt PLL | |
* | +---------------------------+
* +---------------+ PLL_EARLY
*
* The primary PLL is what drives the CPU clk, except for times
* when we are reprogramming the PLL itself (for rate changes) when
* we temporarily switch to an alternate PLL.
*
* The primary PLL operates on a single VCO range, between 600MHz
* and 3GHz. However the CPUs do support OPPs with frequencies
* between 300MHz and 600MHz. In order to support running the CPUs
* at those frequencies we end up having to lock the PLL at twice
* the rate and drive the CPU clk via the PLL/2 output and SMUX.
*
* So for frequencies above 600MHz we follow the following path
* Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
* and for frequencies between 300MHz and 600MHz we follow
* Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
*
* ACD stands for Adaptive Clock Distribution and is used to
* detect voltage droops.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <soc/qcom/kryo-l2-accessors.h>
#include "clk-alpha-pll.h"
#include "clk-regmap.h"
enum _pmux_input {
DIV_2_INDEX = 0,
PLL_INDEX,
ACD_INDEX,
ALT_INDEX,
NUM_OF_PMUX_INPUTS
};
#define DIV_2_THRESHOLD 600000000
#define PWRCL_REG_OFFSET 0x0
#define PERFCL_REG_OFFSET 0x80000
#define MUX_OFFSET 0x40
#define ALT_PLL_OFFSET 0x100
#define SSSCTL_OFFSET 0x160
static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
[PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_ALPHA_VAL] = 0x08,
[PLL_OFF_USER_CTL] = 0x10,
[PLL_OFF_CONFIG_CTL] = 0x18,
[PLL_OFF_CONFIG_CTL_U] = 0x1c,
[PLL_OFF_TEST_CTL] = 0x20,
[PLL_OFF_TEST_CTL_U] = 0x24,
[PLL_OFF_STATUS] = 0x28,
};
static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
[PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_ALPHA_VAL] = 0x08,
[PLL_OFF_ALPHA_VAL_U] = 0x0c,
[PLL_OFF_USER_CTL] = 0x10,
[PLL_OFF_USER_CTL_U] = 0x14,
[PLL_OFF_CONFIG_CTL] = 0x18,
[PLL_OFF_TEST_CTL] = 0x20,
[PLL_OFF_TEST_CTL_U] = 0x24,
[PLL_OFF_STATUS] = 0x28,
};
/* PLLs */
static const struct alpha_pll_config hfpll_config = {
.l = 60,
.config_ctl_val = 0x200d4aa8,
.config_ctl_hi_val = 0x006,
.pre_div_mask = BIT(12),
.post_div_mask = 0x3 << 8,
.post_div_val = 0x1 << 8,
.main_output_mask = BIT(0),
.early_output_mask = BIT(3),
};
static struct clk_alpha_pll perfcl_pll = {
.offset = PERFCL_REG_OFFSET,
.regs = prim_pll_regs,
.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
.clkr.hw.init = &(struct clk_init_data){
.name = "perfcl_pll",
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_huayra_ops,
},
};
static struct clk_alpha_pll pwrcl_pll = {
.offset = PWRCL_REG_OFFSET,
.regs = prim_pll_regs,
.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
.clkr.hw.init = &(struct clk_init_data){
.name = "pwrcl_pll",
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_huayra_ops,
},
};
static const struct pll_vco alt_pll_vco_modes[] = {
VCO(3, 250000000, 500000000),
VCO(2, 500000000, 750000000),
VCO(1, 750000000, 1000000000),
VCO(0, 1000000000, 2150400000),
};
static const struct alpha_pll_config altpll_config = {
.l = 16,
.vco_val = 0x3 << 20,
.vco_mask = 0x3 << 20,
.config_ctl_val = 0x4001051b,
.post_div_mask = 0x3 << 8,
.post_div_val = 0x1 << 8,
.main_output_mask = BIT(0),
.early_output_mask = BIT(3),
};
static struct clk_alpha_pll perfcl_alt_pll = {
.offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
.regs = alt_pll_regs,
.vco_table = alt_pll_vco_modes,
.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
.flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
.clkr.hw.init = &(struct clk_init_data) {
.name = "perfcl_alt_pll",
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_hwfsm_ops,
},
};
static struct clk_alpha_pll pwrcl_alt_pll = {
.offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
.regs = alt_pll_regs,
.vco_table = alt_pll_vco_modes,
.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
.flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
.clkr.hw.init = &(struct clk_init_data) {
.name = "pwrcl_alt_pll",
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_hwfsm_ops,
},
};
struct clk_cpu_8996_mux {
u32 reg;
u8 shift;
u8 width;
struct notifier_block nb;
struct clk_hw *pll;
struct clk_hw *pll_div_2;
struct clk_regmap clkr;
};
static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
void *data);
#define to_clk_cpu_8996_mux_nb(_nb) \
container_of(_nb, struct clk_cpu_8996_mux, nb)
static inline struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
{
return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr);
}
static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
u32 mask = GENMASK(cpuclk->width - 1, 0);
u32 val;
regmap_read(clkr->regmap, cpuclk->reg, &val);
val >>= cpuclk->shift;
return val & mask;
}
static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
u32 mask = GENMASK(cpuclk->width + cpuclk->shift - 1, cpuclk->shift);
u32 val;
val = index;
val <<= cpuclk->shift;
return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);
}
static int clk_cpu_8996_mux_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
struct clk_hw *parent = cpuclk->pll;
if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) {
if (req->rate < (DIV_2_THRESHOLD / 2))
return -EINVAL;
parent = cpuclk->pll_div_2;
}
req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
req->best_parent_hw = parent;
return 0;
}
static const struct clk_ops clk_cpu_8996_mux_ops = {
.set_parent = clk_cpu_8996_mux_set_parent,
.get_parent = clk_cpu_8996_mux_get_parent,
.determine_rate = clk_cpu_8996_mux_determine_rate,
};
static struct clk_cpu_8996_mux pwrcl_smux = {
.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
.shift = 2,
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
.name = "pwrcl_smux",
.parent_names = (const char *[]){
"xo",
"pwrcl_pll_main",
},
.num_parents = 2,
.ops = &clk_cpu_8996_mux_ops,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_cpu_8996_mux perfcl_smux = {
.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
.shift = 2,
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
.name = "perfcl_smux",
.parent_names = (const char *[]){
"xo",
"perfcl_pll_main",
},
.num_parents = 2,
.ops = &clk_cpu_8996_mux_ops,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_cpu_8996_mux pwrcl_pmux = {
.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
.shift = 0,
.width = 2,
.pll = &pwrcl_pll.clkr.hw,
.pll_div_2 = &pwrcl_smux.clkr.hw,
.nb.notifier_call = cpu_clk_notifier_cb,
.clkr.hw.init = &(struct clk_init_data) {
.name = "pwrcl_pmux",
.parent_names = (const char *[]){
"pwrcl_smux",
"pwrcl_pll",
"pwrcl_pll_acd",
"pwrcl_alt_pll",
},
.num_parents = 4,
.ops = &clk_cpu_8996_mux_ops,
/* CPU clock is critical and should never be gated */
.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
},
};
static struct clk_cpu_8996_mux perfcl_pmux = {
.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
.shift = 0,
.width = 2,
.pll = &perfcl_pll.clkr.hw,
.pll_div_2 = &perfcl_smux.clkr.hw,
.nb.notifier_call = cpu_clk_notifier_cb,
.clkr.hw.init = &(struct clk_init_data) {
.name = "perfcl_pmux",
.parent_names = (const char *[]){
"perfcl_smux",
"perfcl_pll",
"perfcl_pll_acd",
"perfcl_alt_pll",
},
.num_parents = 4,
.ops = &clk_cpu_8996_mux_ops,
/* CPU clock is critical and should never be gated */
.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
},
};
static const struct regmap_config cpu_msm8996_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x80210,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static struct clk_regmap *cpu_msm8996_clks[] = {
&perfcl_pll.clkr,
&pwrcl_pll.clkr,
&perfcl_alt_pll.clkr,
&pwrcl_alt_pll.clkr,
&perfcl_smux.clkr,
&pwrcl_smux.clkr,
&perfcl_pmux.clkr,
&pwrcl_pmux.clkr,
};
static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
struct regmap *regmap)
{
int i, ret;
perfcl_smux.pll = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",
"perfcl_pll",
CLK_SET_RATE_PARENT,
1, 2);
if (IS_ERR(perfcl_smux.pll)) {
dev_err(dev, "Failed to initialize perfcl_pll_main\n");
return PTR_ERR(perfcl_smux.pll);
}
pwrcl_smux.pll = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
"pwrcl_pll",
CLK_SET_RATE_PARENT,
1, 2);
if (IS_ERR(pwrcl_smux.pll)) {
dev_err(dev, "Failed to initialize pwrcl_pll_main\n");
clk_hw_unregister(perfcl_smux.pll);
return PTR_ERR(pwrcl_smux.pll);
}
for (i = 0; i < ARRAY_SIZE(cpu_msm8996_clks); i++) {
ret = devm_clk_register_regmap(dev, cpu_msm8996_clks[i]);
if (ret) {
clk_hw_unregister(perfcl_smux.pll);
clk_hw_unregister(pwrcl_smux.pll);
return ret;
}
}
clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
/* Enable alt PLLs */
clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
return ret;
}
static int qcom_cpu_clk_msm8996_unregister_clks(void)
{
int ret = 0;
ret = clk_notifier_unregister(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
if (ret)
return ret;
ret = clk_notifier_unregister(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
if (ret)
return ret;
clk_hw_unregister(perfcl_smux.pll);
clk_hw_unregister(pwrcl_smux.pll);
return 0;
}
#define CPU_AFINITY_MASK 0xFFF
#define PWRCL_CPU_REG_MASK 0x3
#define PERFCL_CPU_REG_MASK 0x103
#define L2ACDCR_REG 0x580ULL
#define L2ACDTD_REG 0x581ULL
#define L2ACDDVMRC_REG 0x584ULL
#define L2ACDSSCR_REG 0x589ULL
static DEFINE_SPINLOCK(qcom_clk_acd_lock);
static void __iomem *base;
static void qcom_cpu_clk_msm8996_acd_init(void __iomem *base)
{
u64 hwid;
unsigned long flags;
spin_lock_irqsave(&qcom_clk_acd_lock, flags);
hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
kryo_l2_set_indirect_reg(L2ACDTD_REG, 0x00006a11);
kryo_l2_set_indirect_reg(L2ACDDVMRC_REG, 0x000e0f0f);
kryo_l2_set_indirect_reg(L2ACDSSCR_REG, 0x00000601);
if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
writel(0xf, base + PWRCL_REG_OFFSET + SSSCTL_OFFSET);
kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd);
}
if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) {
kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd);
writel(0xf, base + PERFCL_REG_OFFSET + SSSCTL_OFFSET);
}
spin_unlock_irqrestore(&qcom_clk_acd_lock, flags);
}
static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
void *data)
{
struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
struct clk_notifier_data *cnd = data;
int ret;
switch (event) {
case PRE_RATE_CHANGE:
ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
qcom_cpu_clk_msm8996_acd_init(base);
break;
case POST_RATE_CHANGE:
if (cnd->new_rate < DIV_2_THRESHOLD)
ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
DIV_2_INDEX);
else
ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
ACD_INDEX);
break;
default:
ret = 0;
break;
}
return notifier_from_errno(ret);
};
static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
{
struct regmap *regmap;
struct clk_hw_onecell_data *data;
struct device *dev = &pdev->dev;
int ret;
data = devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL);
if (!data)
return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &cpu_msm8996_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
ret = qcom_cpu_clk_msm8996_register_clks(dev, regmap);
if (ret)
return ret;
qcom_cpu_clk_msm8996_acd_init(base);
data->hws[0] = &pwrcl_pmux.clkr.hw;
data->hws[1] = &perfcl_pmux.clkr.hw;
data->num = 2;
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
}
static int qcom_cpu_clk_msm8996_driver_remove(struct platform_device *pdev)
{
return qcom_cpu_clk_msm8996_unregister_clks();
}
static const struct of_device_id qcom_cpu_clk_msm8996_match_table[] = {
{ .compatible = "qcom,msm8996-apcc" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_cpu_clk_msm8996_match_table);
static struct platform_driver qcom_cpu_clk_msm8996_driver = {
.probe = qcom_cpu_clk_msm8996_driver_probe,
.remove = qcom_cpu_clk_msm8996_driver_remove,
.driver = {
.name = "qcom-msm8996-apcc",
.of_match_table = qcom_cpu_clk_msm8996_match_table,
},
};
module_platform_driver(qcom_cpu_clk_msm8996_driver);
MODULE_DESCRIPTION("QCOM MSM8996 CPU Clock Driver");
MODULE_LICENSE("GPL v2");

View File

@ -452,6 +452,55 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
.num_clks = ARRAY_SIZE(msm8916_clks), .num_clks = ARRAY_SIZE(msm8916_clks),
}; };
/* msm8936 */
DEFINE_CLK_SMD_RPM(msm8936, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8936, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8936, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8936, sysmmnoc_clk, sysmmnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM_QDSS(msm8936, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, bb_clk1, bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, bb_clk2, bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, rf_clk1, rf_clk1_a, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, rf_clk2, rf_clk2_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, bb_clk1_pin, bb_clk1_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, bb_clk2_pin, bb_clk2_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, rf_clk1_pin, rf_clk1_a_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, rf_clk2_pin, rf_clk2_a_pin, 5);
static struct clk_smd_rpm *msm8936_clks[] = {
[RPM_SMD_PCNOC_CLK] = &msm8936_pcnoc_clk,
[RPM_SMD_PCNOC_A_CLK] = &msm8936_pcnoc_a_clk,
[RPM_SMD_SNOC_CLK] = &msm8936_snoc_clk,
[RPM_SMD_SNOC_A_CLK] = &msm8936_snoc_a_clk,
[RPM_SMD_BIMC_CLK] = &msm8936_bimc_clk,
[RPM_SMD_BIMC_A_CLK] = &msm8936_bimc_a_clk,
[RPM_SMD_SYSMMNOC_CLK] = &msm8936_sysmmnoc_clk,
[RPM_SMD_SYSMMNOC_A_CLK] = &msm8936_sysmmnoc_a_clk,
[RPM_SMD_QDSS_CLK] = &msm8936_qdss_clk,
[RPM_SMD_QDSS_A_CLK] = &msm8936_qdss_a_clk,
[RPM_SMD_BB_CLK1] = &msm8936_bb_clk1,
[RPM_SMD_BB_CLK1_A] = &msm8936_bb_clk1_a,
[RPM_SMD_BB_CLK2] = &msm8936_bb_clk2,
[RPM_SMD_BB_CLK2_A] = &msm8936_bb_clk2_a,
[RPM_SMD_RF_CLK1] = &msm8936_rf_clk1,
[RPM_SMD_RF_CLK1_A] = &msm8936_rf_clk1_a,
[RPM_SMD_RF_CLK2] = &msm8936_rf_clk2,
[RPM_SMD_RF_CLK2_A] = &msm8936_rf_clk2_a,
[RPM_SMD_BB_CLK1_PIN] = &msm8936_bb_clk1_pin,
[RPM_SMD_BB_CLK1_A_PIN] = &msm8936_bb_clk1_a_pin,
[RPM_SMD_BB_CLK2_PIN] = &msm8936_bb_clk2_pin,
[RPM_SMD_BB_CLK2_A_PIN] = &msm8936_bb_clk2_a_pin,
[RPM_SMD_RF_CLK1_PIN] = &msm8936_rf_clk1_pin,
[RPM_SMD_RF_CLK1_A_PIN] = &msm8936_rf_clk1_a_pin,
[RPM_SMD_RF_CLK2_PIN] = &msm8936_rf_clk2_pin,
[RPM_SMD_RF_CLK2_A_PIN] = &msm8936_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8936 = {
.clks = msm8936_clks,
.num_clks = ARRAY_SIZE(msm8936_clks),
};
/* msm8974 */ /* msm8974 */
DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
@ -574,6 +623,175 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
.num_clks = ARRAY_SIZE(msm8976_clks), .num_clks = ARRAY_SIZE(msm8976_clks),
}; };
/* msm8992 */
DEFINE_CLK_SMD_RPM(msm8992, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8992, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8992, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8992, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8992, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8992, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, bb_clk1, bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, bb_clk1_pin, bb_clk1_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, bb_clk2, bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, bb_clk2_pin, bb_clk2_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk1, div_clk1_a, 11);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk2, div_clk2_a, 12);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk3, div_clk3_a, 13);
DEFINE_CLK_SMD_RPM(msm8992, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, ln_bb_clk, ln_bb_a_clk, 8);
DEFINE_CLK_SMD_RPM(msm8992, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk,
QCOM_SMD_RPM_BUS_CLK, 3);
DEFINE_CLK_SMD_RPM_QDSS(msm8992, qdss_clk, qdss_a_clk,
QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, rf_clk1, rf_clk1_a, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, rf_clk2, rf_clk2_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, rf_clk1_pin, rf_clk1_a_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, rf_clk2_pin, rf_clk2_a_pin, 5);
DEFINE_CLK_SMD_RPM(msm8992, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8992, ce2_clk, ce2_a_clk, QCOM_SMD_RPM_CE_CLK, 1);
static struct clk_smd_rpm *msm8992_clks[] = {
[RPM_SMD_PNOC_CLK] = &msm8992_pnoc_clk,
[RPM_SMD_PNOC_A_CLK] = &msm8992_pnoc_a_clk,
[RPM_SMD_OCMEMGX_CLK] = &msm8992_ocmemgx_clk,
[RPM_SMD_OCMEMGX_A_CLK] = &msm8992_ocmemgx_a_clk,
[RPM_SMD_BIMC_CLK] = &msm8992_bimc_clk,
[RPM_SMD_BIMC_A_CLK] = &msm8992_bimc_a_clk,
[RPM_SMD_CNOC_CLK] = &msm8992_cnoc_clk,
[RPM_SMD_CNOC_A_CLK] = &msm8992_cnoc_a_clk,
[RPM_SMD_GFX3D_CLK_SRC] = &msm8992_gfx3d_clk_src,
[RPM_SMD_GFX3D_A_CLK_SRC] = &msm8992_gfx3d_a_clk_src,
[RPM_SMD_SNOC_CLK] = &msm8992_snoc_clk,
[RPM_SMD_SNOC_A_CLK] = &msm8992_snoc_a_clk,
[RPM_SMD_BB_CLK1] = &msm8992_bb_clk1,
[RPM_SMD_BB_CLK1_A] = &msm8992_bb_clk1_a,
[RPM_SMD_BB_CLK1_PIN] = &msm8992_bb_clk1_pin,
[RPM_SMD_BB_CLK1_A_PIN] = &msm8992_bb_clk1_a_pin,
[RPM_SMD_BB_CLK2] = &msm8992_bb_clk2,
[RPM_SMD_BB_CLK2_A] = &msm8992_bb_clk2_a,
[RPM_SMD_BB_CLK2_PIN] = &msm8992_bb_clk2_pin,
[RPM_SMD_BB_CLK2_A_PIN] = &msm8992_bb_clk2_a_pin,
[RPM_SMD_DIV_CLK1] = &msm8992_div_clk1,
[RPM_SMD_DIV_A_CLK1] = &msm8992_div_clk1_a,
[RPM_SMD_DIV_CLK2] = &msm8992_div_clk2,
[RPM_SMD_DIV_A_CLK2] = &msm8992_div_clk2_a,
[RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
[RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
[RPM_SMD_IPA_CLK] = &msm8992_ipa_clk,
[RPM_SMD_IPA_A_CLK] = &msm8992_ipa_a_clk,
[RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
[RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
[RPM_SMD_MMSSNOC_AHB_CLK] = &msm8992_mmssnoc_ahb_clk,
[RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8992_mmssnoc_ahb_a_clk,
[RPM_SMD_QDSS_CLK] = &msm8992_qdss_clk,
[RPM_SMD_QDSS_A_CLK] = &msm8992_qdss_a_clk,
[RPM_SMD_RF_CLK1] = &msm8992_rf_clk1,
[RPM_SMD_RF_CLK1_A] = &msm8992_rf_clk1_a,
[RPM_SMD_RF_CLK2] = &msm8992_rf_clk2,
[RPM_SMD_RF_CLK2_A] = &msm8992_rf_clk2_a,
[RPM_SMD_RF_CLK1_PIN] = &msm8992_rf_clk1_pin,
[RPM_SMD_RF_CLK1_A_PIN] = &msm8992_rf_clk1_a_pin,
[RPM_SMD_RF_CLK2_PIN] = &msm8992_rf_clk2_pin,
[RPM_SMD_RF_CLK2_A_PIN] = &msm8992_rf_clk2_a_pin,
[RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
[RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
[RPM_SMD_CE2_CLK] = &msm8992_ce2_clk,
[RPM_SMD_CE2_A_CLK] = &msm8992_ce2_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8992 = {
.clks = msm8992_clks,
.num_clks = ARRAY_SIZE(msm8992_clks),
};
/* msm8994 */
DEFINE_CLK_SMD_RPM(msm8994, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8994, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8994, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8994, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8994, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8994, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, bb_clk1, bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, bb_clk1_pin, bb_clk1_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, bb_clk2, bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, bb_clk2_pin, bb_clk2_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, div_clk1, div_clk1_a, 11);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, div_clk2, div_clk2_a, 12);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, div_clk3, div_clk3_a, 13);
DEFINE_CLK_SMD_RPM(msm8994, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, ln_bb_clk, ln_bb_a_clk, 8);
DEFINE_CLK_SMD_RPM(msm8994, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk,
QCOM_SMD_RPM_BUS_CLK, 3);
DEFINE_CLK_SMD_RPM_QDSS(msm8994, qdss_clk, qdss_a_clk,
QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, rf_clk1, rf_clk1_a, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, rf_clk2, rf_clk2_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, rf_clk1_pin, rf_clk1_a_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, rf_clk2_pin, rf_clk2_a_pin, 5);
DEFINE_CLK_SMD_RPM(msm8994, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8994, ce2_clk, ce2_a_clk, QCOM_SMD_RPM_CE_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8994, ce3_clk, ce3_a_clk, QCOM_SMD_RPM_CE_CLK, 2);
static struct clk_smd_rpm *msm8994_clks[] = {
[RPM_SMD_PNOC_CLK] = &msm8994_pnoc_clk,
[RPM_SMD_PNOC_A_CLK] = &msm8994_pnoc_a_clk,
[RPM_SMD_OCMEMGX_CLK] = &msm8994_ocmemgx_clk,
[RPM_SMD_OCMEMGX_A_CLK] = &msm8994_ocmemgx_a_clk,
[RPM_SMD_BIMC_CLK] = &msm8994_bimc_clk,
[RPM_SMD_BIMC_A_CLK] = &msm8994_bimc_a_clk,
[RPM_SMD_CNOC_CLK] = &msm8994_cnoc_clk,
[RPM_SMD_CNOC_A_CLK] = &msm8994_cnoc_a_clk,
[RPM_SMD_GFX3D_CLK_SRC] = &msm8994_gfx3d_clk_src,
[RPM_SMD_GFX3D_A_CLK_SRC] = &msm8994_gfx3d_a_clk_src,
[RPM_SMD_SNOC_CLK] = &msm8994_snoc_clk,
[RPM_SMD_SNOC_A_CLK] = &msm8994_snoc_a_clk,
[RPM_SMD_BB_CLK1] = &msm8994_bb_clk1,
[RPM_SMD_BB_CLK1_A] = &msm8994_bb_clk1_a,
[RPM_SMD_BB_CLK1_PIN] = &msm8994_bb_clk1_pin,
[RPM_SMD_BB_CLK1_A_PIN] = &msm8994_bb_clk1_a_pin,
[RPM_SMD_BB_CLK2] = &msm8994_bb_clk2,
[RPM_SMD_BB_CLK2_A] = &msm8994_bb_clk2_a,
[RPM_SMD_BB_CLK2_PIN] = &msm8994_bb_clk2_pin,
[RPM_SMD_BB_CLK2_A_PIN] = &msm8994_bb_clk2_a_pin,
[RPM_SMD_DIV_CLK1] = &msm8994_div_clk1,
[RPM_SMD_DIV_A_CLK1] = &msm8994_div_clk1_a,
[RPM_SMD_DIV_CLK2] = &msm8994_div_clk2,
[RPM_SMD_DIV_A_CLK2] = &msm8994_div_clk2_a,
[RPM_SMD_DIV_CLK3] = &msm8994_div_clk3,
[RPM_SMD_DIV_A_CLK3] = &msm8994_div_clk3_a,
[RPM_SMD_IPA_CLK] = &msm8994_ipa_clk,
[RPM_SMD_IPA_A_CLK] = &msm8994_ipa_a_clk,
[RPM_SMD_LN_BB_CLK] = &msm8994_ln_bb_clk,
[RPM_SMD_LN_BB_A_CLK] = &msm8994_ln_bb_a_clk,
[RPM_SMD_MMSSNOC_AHB_CLK] = &msm8994_mmssnoc_ahb_clk,
[RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8994_mmssnoc_ahb_a_clk,
[RPM_SMD_QDSS_CLK] = &msm8994_qdss_clk,
[RPM_SMD_QDSS_A_CLK] = &msm8994_qdss_a_clk,
[RPM_SMD_RF_CLK1] = &msm8994_rf_clk1,
[RPM_SMD_RF_CLK1_A] = &msm8994_rf_clk1_a,
[RPM_SMD_RF_CLK2] = &msm8994_rf_clk2,
[RPM_SMD_RF_CLK2_A] = &msm8994_rf_clk2_a,
[RPM_SMD_RF_CLK1_PIN] = &msm8994_rf_clk1_pin,
[RPM_SMD_RF_CLK1_A_PIN] = &msm8994_rf_clk1_a_pin,
[RPM_SMD_RF_CLK2_PIN] = &msm8994_rf_clk2_pin,
[RPM_SMD_RF_CLK2_A_PIN] = &msm8994_rf_clk2_a_pin,
[RPM_SMD_CE1_CLK] = &msm8994_ce1_clk,
[RPM_SMD_CE1_A_CLK] = &msm8994_ce1_a_clk,
[RPM_SMD_CE2_CLK] = &msm8994_ce2_clk,
[RPM_SMD_CE2_A_CLK] = &msm8994_ce2_a_clk,
[RPM_SMD_CE3_CLK] = &msm8994_ce3_clk,
[RPM_SMD_CE3_A_CLK] = &msm8994_ce3_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8994 = {
.clks = msm8994_clks,
.num_clks = ARRAY_SIZE(msm8994_clks),
};
/* msm8996 */ /* msm8996 */
DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
@ -766,13 +984,92 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
.num_clks = ARRAY_SIZE(msm8998_clks), .num_clks = ARRAY_SIZE(msm8998_clks),
}; };
/* sdm660 */
DEFINE_CLK_SMD_RPM_BRANCH(sdm660, bi_tcxo, bi_tcxo_a, QCOM_SMD_RPM_MISC_CLK, 0,
19200000);
DEFINE_CLK_SMD_RPM(sdm660, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(sdm660, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(sdm660, cnoc_periph_clk, cnoc_periph_a_clk,
QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(sdm660, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(sdm660, mmssnoc_axi_clk, mmssnoc_axi_a_clk,
QCOM_SMD_RPM_MMAXI_CLK, 0);
DEFINE_CLK_SMD_RPM(sdm660, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM(sdm660, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM(sdm660, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 2);
DEFINE_CLK_SMD_RPM_QDSS(sdm660, qdss_clk, qdss_a_clk,
QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, rf_clk1, rf_clk1_a, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, div_clk1, div_clk1_a, 11);
DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, ln_bb_clk1, ln_bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, ln_bb_clk2, ln_bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, ln_bb_clk3, ln_bb_clk3_a, 3);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, rf_clk1_pin, rf_clk1_a_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk1_pin,
ln_bb_clk1_pin_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk2_pin,
ln_bb_clk2_pin_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk3_pin,
ln_bb_clk3_pin_a, 3);
static struct clk_smd_rpm *sdm660_clks[] = {
[RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
[RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
[RPM_SMD_SNOC_CLK] = &sdm660_snoc_clk,
[RPM_SMD_SNOC_A_CLK] = &sdm660_snoc_a_clk,
[RPM_SMD_CNOC_CLK] = &sdm660_cnoc_clk,
[RPM_SMD_CNOC_A_CLK] = &sdm660_cnoc_a_clk,
[RPM_SMD_CNOC_PERIPH_CLK] = &sdm660_cnoc_periph_clk,
[RPM_SMD_CNOC_PERIPH_A_CLK] = &sdm660_cnoc_periph_a_clk,
[RPM_SMD_BIMC_CLK] = &sdm660_bimc_clk,
[RPM_SMD_BIMC_A_CLK] = &sdm660_bimc_a_clk,
[RPM_SMD_MMSSNOC_AXI_CLK] = &sdm660_mmssnoc_axi_clk,
[RPM_SMD_MMSSNOC_AXI_CLK_A] = &sdm660_mmssnoc_axi_a_clk,
[RPM_SMD_IPA_CLK] = &sdm660_ipa_clk,
[RPM_SMD_IPA_A_CLK] = &sdm660_ipa_a_clk,
[RPM_SMD_CE1_CLK] = &sdm660_ce1_clk,
[RPM_SMD_CE1_A_CLK] = &sdm660_ce1_a_clk,
[RPM_SMD_AGGR2_NOC_CLK] = &sdm660_aggre2_noc_clk,
[RPM_SMD_AGGR2_NOC_A_CLK] = &sdm660_aggre2_noc_a_clk,
[RPM_SMD_QDSS_CLK] = &sdm660_qdss_clk,
[RPM_SMD_QDSS_A_CLK] = &sdm660_qdss_a_clk,
[RPM_SMD_RF_CLK1] = &sdm660_rf_clk1,
[RPM_SMD_RF_CLK1_A] = &sdm660_rf_clk1_a,
[RPM_SMD_DIV_CLK1] = &sdm660_div_clk1,
[RPM_SMD_DIV_A_CLK1] = &sdm660_div_clk1_a,
[RPM_SMD_LN_BB_CLK] = &sdm660_ln_bb_clk1,
[RPM_SMD_LN_BB_A_CLK] = &sdm660_ln_bb_clk1_a,
[RPM_SMD_LN_BB_CLK2] = &sdm660_ln_bb_clk2,
[RPM_SMD_LN_BB_CLK2_A] = &sdm660_ln_bb_clk2_a,
[RPM_SMD_LN_BB_CLK3] = &sdm660_ln_bb_clk3,
[RPM_SMD_LN_BB_CLK3_A] = &sdm660_ln_bb_clk3_a,
[RPM_SMD_RF_CLK1_PIN] = &sdm660_rf_clk1_pin,
[RPM_SMD_RF_CLK1_A_PIN] = &sdm660_rf_clk1_a_pin,
[RPM_SMD_LN_BB_CLK1_PIN] = &sdm660_ln_bb_clk1_pin,
[RPM_SMD_LN_BB_CLK1_A_PIN] = &sdm660_ln_bb_clk1_pin_a,
[RPM_SMD_LN_BB_CLK2_PIN] = &sdm660_ln_bb_clk2_pin,
[RPM_SMD_LN_BB_CLK2_A_PIN] = &sdm660_ln_bb_clk2_pin_a,
[RPM_SMD_LN_BB_CLK3_PIN] = &sdm660_ln_bb_clk3_pin,
[RPM_SMD_LN_BB_CLK3_A_PIN] = &sdm660_ln_bb_clk3_pin_a,
};
static const struct rpm_smd_clk_desc rpm_clk_sdm660 = {
.clks = sdm660_clks,
.num_clks = ARRAY_SIZE(sdm660_clks),
};
static const struct of_device_id rpm_smd_clk_match_table[] = { static const struct of_device_id rpm_smd_clk_match_table[] = {
{ .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 },
{ .compatible = "qcom,rpmcc-msm8936", .data = &rpm_clk_msm8936 },
{ .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 },
{ .compatible = "qcom,rpmcc-msm8976", .data = &rpm_clk_msm8976 }, { .compatible = "qcom,rpmcc-msm8976", .data = &rpm_clk_msm8976 },
{ .compatible = "qcom,rpmcc-msm8992", .data = &rpm_clk_msm8992 },
{ .compatible = "qcom,rpmcc-msm8994", .data = &rpm_clk_msm8994 },
{ .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 }, { .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 },
{ .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 }, { .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 },
{ .compatible = "qcom,rpmcc-qcs404", .data = &rpm_clk_qcs404 }, { .compatible = "qcom,rpmcc-qcs404", .data = &rpm_clk_qcs404 },
{ .compatible = "qcom,rpmcc-sdm660", .data = &rpm_clk_sdm660 },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table); MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table);

View File

@ -3089,7 +3089,7 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
regmap_write(regmap, 0x3cf8, 8); regmap_write(regmap, 0x3cf8, 8);
regmap_write(regmap, 0x3d18, 8); regmap_write(regmap, 0x3d18, 8);
return 0; return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
} }
static struct platform_driver gcc_ipq806x_driver = { static struct platform_driver gcc_ipq806x_driver = {

View File

@ -4316,6 +4316,62 @@ static struct clk_branch gcc_gp3_clk = {
}, },
}; };
static const struct freq_tbl ftbl_pcie_rchng_clk_src[] = {
F(19200000, P_XO, 1, 0, 0),
F(100000000, P_GPLL0, 8, 0, 0),
{ }
};
struct clk_rcg2 pcie0_rchng_clk_src = {
.cmd_rcgr = 0x75070,
.freq_tbl = ftbl_pcie_rchng_clk_src,
.hid_width = 5,
.parent_map = gcc_xo_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie0_rchng_clk_src",
.parent_hws = (const struct clk_hw *[]) {
&gpll0.clkr.hw },
.num_parents = 2,
.ops = &clk_rcg2_ops,
},
};
static struct clk_branch gcc_pcie0_rchng_clk = {
.halt_reg = 0x75070,
.halt_bit = 31,
.clkr = {
.enable_reg = 0x75070,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie0_rchng_clk",
.parent_hws = (const struct clk_hw *[]){
&pcie0_rchng_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_pcie0_axi_s_bridge_clk = {
.halt_reg = 0x75048,
.halt_bit = 31,
.clkr = {
.enable_reg = 0x75048,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie0_axi_s_bridge_clk",
.parent_hws = (const struct clk_hw *[]){
&pcie0_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_hw *gcc_ipq8074_hws[] = { static struct clk_hw *gcc_ipq8074_hws[] = {
&gpll0_out_main_div2.hw, &gpll0_out_main_div2.hw,
&gpll6_out_main_div2.hw, &gpll6_out_main_div2.hw,
@ -4551,6 +4607,9 @@ static struct clk_regmap *gcc_ipq8074_clks[] = {
[GCC_GP1_CLK] = &gcc_gp1_clk.clkr, [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
[GCC_GP2_CLK] = &gcc_gp2_clk.clkr, [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
[GCC_GP3_CLK] = &gcc_gp3_clk.clkr, [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
[GCC_PCIE0_RCHNG_CLK_SRC] = &pcie0_rchng_clk_src.clkr,
[GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr,
[GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr,
}; };
static const struct qcom_reset_map gcc_ipq8074_resets[] = { static const struct qcom_reset_map gcc_ipq8074_resets[] = {
@ -4678,6 +4737,7 @@ static const struct qcom_reset_map gcc_ipq8074_resets[] = {
[GCC_PCIE0_AXI_SLAVE_ARES] = { 0x75040, 4 }, [GCC_PCIE0_AXI_SLAVE_ARES] = { 0x75040, 4 },
[GCC_PCIE0_AHB_ARES] = { 0x75040, 5 }, [GCC_PCIE0_AHB_ARES] = { 0x75040, 5 },
[GCC_PCIE0_AXI_MASTER_STICKY_ARES] = { 0x75040, 6 }, [GCC_PCIE0_AXI_MASTER_STICKY_ARES] = { 0x75040, 6 },
[GCC_PCIE0_AXI_SLAVE_STICKY_ARES] = { 0x75040, 7 },
[GCC_PCIE1_PIPE_ARES] = { 0x76040, 0 }, [GCC_PCIE1_PIPE_ARES] = { 0x76040, 0 },
[GCC_PCIE1_SLEEP_ARES] = { 0x76040, 1 }, [GCC_PCIE1_SLEEP_ARES] = { 0x76040, 1 },
[GCC_PCIE1_CORE_STICKY_ARES] = { 0x76040, 2 }, [GCC_PCIE1_CORE_STICKY_ARES] = { 0x76040, 2 },

View File

@ -1061,7 +1061,7 @@ static struct clk_branch gcc_disp_gpll0_clk_src = {
.hw = &gpll0.clkr.hw, .hw = &gpll0.clkr.hw,
}, },
.num_parents = 1, .num_parents = 1,
.ops = &clk_branch2_ops, .ops = &clk_branch2_aon_ops,
}, },
}, },
}; };
@ -2251,6 +2251,19 @@ static struct clk_branch gcc_mss_q6_memnoc_axi_clk = {
}, },
}; };
static struct clk_branch gcc_lpass_cfg_noc_sway_clk = {
.halt_reg = 0x47018,
.halt_check = BRANCH_HALT_DELAY,
.clkr = {
.enable_reg = 0x47018,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_lpass_cfg_noc_sway_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc ufs_phy_gdsc = { static struct gdsc ufs_phy_gdsc = {
.gdscr = 0x77004, .gdscr = 0x77004,
.pd = { .pd = {
@ -2428,6 +2441,7 @@ static struct clk_regmap *gcc_sc7180_clocks[] = {
[GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr, [GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr,
[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr, [GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
[GCC_SEC_CTRL_CLK_SRC] = &gcc_sec_ctrl_clk_src.clkr, [GCC_SEC_CTRL_CLK_SRC] = &gcc_sec_ctrl_clk_src.clkr,
[GCC_LPASS_CFG_NOC_SWAY_CLK] = &gcc_lpass_cfg_noc_sway_clk.clkr,
}; };
static const struct qcom_reset_map gcc_sc7180_resets[] = { static const struct qcom_reset_map gcc_sc7180_resets[] = {

View File

@ -1715,6 +1715,9 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = {
static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = { static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
.halt_reg = 0x8a004, .halt_reg = 0x8a004,
.halt_check = BRANCH_HALT,
.hwcg_reg = 0x8a004,
.hwcg_bit = 1,
.clkr = { .clkr = {
.enable_reg = 0x8a004, .enable_reg = 0x8a004,
.enable_mask = BIT(0), .enable_mask = BIT(0),
@ -2402,6 +2405,7 @@ static const struct qcom_reset_map gcc_sdm660_resets[] = {
[GCC_USB_20_BCR] = { 0x2f000 }, [GCC_USB_20_BCR] = { 0x2f000 },
[GCC_USB_30_BCR] = { 0xf000 }, [GCC_USB_30_BCR] = { 0xf000 },
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
[GCC_MSS_RESTART] = { 0x79000 },
}; };
static const struct regmap_config gcc_sdm660_regmap_config = { static const struct regmap_config gcc_sdm660_regmap_config = {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
@ -1344,7 +1344,7 @@ static struct clk_branch gcc_disp_gpll0_clk_src = {
"gpll0", "gpll0",
}, },
.num_parents = 1, .num_parents = 1,
.ops = &clk_branch2_ops, .ops = &clk_branch2_aon_ops,
}, },
}, },
}; };

View File

@ -34,14 +34,8 @@ enum {
P_SLEEP_CLK, P_SLEEP_CLK,
}; };
static const struct pll_vco trion_vco[] = {
{ 249600000, 2000000000, 0 },
};
static struct clk_alpha_pll gpll0 = { static struct clk_alpha_pll gpll0 = {
.offset = 0x0, .offset = 0x0,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION], .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = { .clkr = {
.enable_reg = 0x52000, .enable_reg = 0x52000,
@ -53,7 +47,7 @@ static struct clk_alpha_pll gpll0 = {
.name = "bi_tcxo", .name = "bi_tcxo",
}, },
.num_parents = 1, .num_parents = 1,
.ops = &clk_trion_fixed_pll_ops, .ops = &clk_alpha_pll_fixed_trion_ops,
}, },
}, },
}; };
@ -79,14 +73,12 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = {
.hw = &gpll0.clkr.hw, .hw = &gpll0.clkr.hw,
}, },
.num_parents = 1, .num_parents = 1,
.ops = &clk_trion_pll_postdiv_ops, .ops = &clk_alpha_pll_postdiv_trion_ops,
}, },
}; };
static struct clk_alpha_pll gpll7 = { static struct clk_alpha_pll gpll7 = {
.offset = 0x1a000, .offset = 0x1a000,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION], .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = { .clkr = {
.enable_reg = 0x52000, .enable_reg = 0x52000,
@ -98,15 +90,13 @@ static struct clk_alpha_pll gpll7 = {
.name = "bi_tcxo", .name = "bi_tcxo",
}, },
.num_parents = 1, .num_parents = 1,
.ops = &clk_trion_fixed_pll_ops, .ops = &clk_alpha_pll_fixed_trion_ops,
}, },
}, },
}; };
static struct clk_alpha_pll gpll9 = { static struct clk_alpha_pll gpll9 = {
.offset = 0x1c000, .offset = 0x1c000,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION], .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = { .clkr = {
.enable_reg = 0x52000, .enable_reg = 0x52000,
@ -118,7 +108,7 @@ static struct clk_alpha_pll gpll9 = {
.name = "bi_tcxo", .name = "bi_tcxo",
}, },
.num_parents = 1, .num_parents = 1,
.ops = &clk_trion_fixed_pll_ops, .ops = &clk_alpha_pll_fixed_trion_ops,
}, },
}, },
}; };
@ -1617,6 +1607,7 @@ static struct clk_branch gcc_gpu_cfg_ahb_clk = {
}; };
static struct clk_branch gcc_gpu_gpll0_clk_src = { static struct clk_branch gcc_gpu_gpll0_clk_src = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = { .clkr = {
.enable_reg = 0x52004, .enable_reg = 0x52004,
.enable_mask = BIT(15), .enable_mask = BIT(15),
@ -1632,13 +1623,14 @@ static struct clk_branch gcc_gpu_gpll0_clk_src = {
}; };
static struct clk_branch gcc_gpu_gpll0_div_clk_src = { static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = { .clkr = {
.enable_reg = 0x52004, .enable_reg = 0x52004,
.enable_mask = BIT(16), .enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_div_clk_src", .name = "gcc_gpu_gpll0_div_clk_src",
.parent_hws = (const struct clk_hw *[]){ .parent_hws = (const struct clk_hw *[]){
&gcc_gpu_gpll0_clk_src.clkr.hw }, &gpll0_out_even.clkr.hw },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops, .ops = &clk_branch2_ops,
@ -1729,6 +1721,7 @@ static struct clk_branch gcc_npu_cfg_ahb_clk = {
}; };
static struct clk_branch gcc_npu_gpll0_clk_src = { static struct clk_branch gcc_npu_gpll0_clk_src = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = { .clkr = {
.enable_reg = 0x52004, .enable_reg = 0x52004,
.enable_mask = BIT(18), .enable_mask = BIT(18),
@ -1744,13 +1737,14 @@ static struct clk_branch gcc_npu_gpll0_clk_src = {
}; };
static struct clk_branch gcc_npu_gpll0_div_clk_src = { static struct clk_branch gcc_npu_gpll0_div_clk_src = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = { .clkr = {
.enable_reg = 0x52004, .enable_reg = 0x52004,
.enable_mask = BIT(19), .enable_mask = BIT(19),
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "gcc_npu_gpll0_div_clk_src", .name = "gcc_npu_gpll0_div_clk_src",
.parent_hws = (const struct clk_hw *[]){ .parent_hws = (const struct clk_hw *[]){
&gcc_npu_gpll0_clk_src.clkr.hw }, &gpll0_out_even.clkr.hw },
.num_parents = 1, .num_parents = 1,
.flags = CLK_SET_RATE_PARENT, .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops, .ops = &clk_branch2_ops,

View File

@ -6,6 +6,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/export.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ktime.h> #include <linux/ktime.h>
@ -29,6 +30,7 @@
/* CFG_GDSCR */ /* CFG_GDSCR */
#define GDSC_POWER_UP_COMPLETE BIT(16) #define GDSC_POWER_UP_COMPLETE BIT(16)
#define GDSC_POWER_DOWN_COMPLETE BIT(15) #define GDSC_POWER_DOWN_COMPLETE BIT(15)
#define GDSC_RETAIN_FF_ENABLE BIT(11)
#define CFG_GDSCR_OFFSET 0x4 #define CFG_GDSCR_OFFSET 0x4
/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
@ -216,6 +218,14 @@ static inline void gdsc_assert_reset_aon(struct gdsc *sc)
regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, regmap_update_bits(sc->regmap, sc->clamp_io_ctrl,
GMEM_RESET_MASK, 0); GMEM_RESET_MASK, 0);
} }
static void gdsc_retain_ff_on(struct gdsc *sc)
{
u32 mask = GDSC_RETAIN_FF_ENABLE;
regmap_update_bits(sc->regmap, sc->gdscr, mask, mask);
}
static int gdsc_enable(struct generic_pm_domain *domain) static int gdsc_enable(struct generic_pm_domain *domain)
{ {
struct gdsc *sc = domain_to_gdsc(domain); struct gdsc *sc = domain_to_gdsc(domain);
@ -268,6 +278,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
udelay(1); udelay(1);
} }
if (sc->flags & RETAIN_FF_ENABLE)
gdsc_retain_ff_on(sc);
return 0; return 0;
} }
@ -433,3 +446,29 @@ void gdsc_unregister(struct gdsc_desc *desc)
} }
of_genpd_del_provider(dev->of_node); of_genpd_del_provider(dev->of_node);
} }
/*
* On SDM845+ the GPU GX domain is *almost* entirely controlled by the GMU
* running in the CX domain so the CPU doesn't need to know anything about the
* GX domain EXCEPT....
*
* Hardware constraints dictate that the GX be powered down before the CX. If
* the GMU crashes it could leave the GX on. In order to successfully bring back
* the device the CPU needs to disable the GX headswitch. There being no sane
* way to reach in and touch that register from deep inside the GPU driver we
* need to set up the infrastructure to be able to ensure that the GPU can
* ensure that the GX is off during this super special case. We do this by
* defining a GX gdsc with a dummy enable function and a "default" disable
* function.
*
* This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
* driver. During power up, nothing will happen from the CPU (and the GMU will
* power up normally but during power down this will ensure that the GX domain
* is *really* off - this gives us a semi standard way of doing what we need.
*/
int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain)
{
/* Do nothing but give genpd the impression that we were successful */
return 0;
}
EXPORT_SYMBOL_GPL(gdsc_gx_do_nothing_enable);

View File

@ -50,6 +50,7 @@ struct gdsc {
#define AON_RESET BIT(4) #define AON_RESET BIT(4)
#define POLL_CFG_GDSCR BIT(5) #define POLL_CFG_GDSCR BIT(5)
#define ALWAYS_ON BIT(6) #define ALWAYS_ON BIT(6)
#define RETAIN_FF_ENABLE BIT(7)
struct reset_controller_dev *rcdev; struct reset_controller_dev *rcdev;
unsigned int *resets; unsigned int *resets;
unsigned int reset_count; unsigned int reset_count;
@ -68,6 +69,7 @@ struct gdsc_desc {
int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *, int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *,
struct regmap *); struct regmap *);
void gdsc_unregister(struct gdsc_desc *desc); void gdsc_unregister(struct gdsc_desc *desc);
int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain);
#else #else
static inline int gdsc_register(struct gdsc_desc *desc, static inline int gdsc_register(struct gdsc_desc *desc,
struct reset_controller_dev *rcdev, struct reset_controller_dev *rcdev,

View File

@ -170,37 +170,12 @@ static struct gdsc cx_gdsc = {
.flags = VOTABLE, .flags = VOTABLE,
}; };
/*
* On SC7180 the GPU GX domain is *almost* entirely controlled by the GMU
* running in the CX domain so the CPU doesn't need to know anything about the
* GX domain EXCEPT....
*
* Hardware constraints dictate that the GX be powered down before the CX. If
* the GMU crashes it could leave the GX on. In order to successfully bring back
* the device the CPU needs to disable the GX headswitch. There being no sane
* way to reach in and touch that register from deep inside the GPU driver we
* need to set up the infrastructure to be able to ensure that the GPU can
* ensure that the GX is off during this super special case. We do this by
* defining a GX gdsc with a dummy enable function and a "default" disable
* function.
*
* This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
* driver. During power up, nothing will happen from the CPU (and the GMU will
* power up normally but during power down this will ensure that the GX domain
* is *really* off - this gives us a semi standard way of doing what we need.
*/
static int gx_gdsc_enable(struct generic_pm_domain *domain)
{
/* Do nothing but give genpd the impression that we were successful */
return 0;
}
static struct gdsc gx_gdsc = { static struct gdsc gx_gdsc = {
.gdscr = 0x100c, .gdscr = 0x100c,
.clamp_io_ctrl = 0x1508, .clamp_io_ctrl = 0x1508,
.pd = { .pd = {
.name = "gx_gdsc", .name = "gx_gdsc",
.power_on = gx_gdsc_enable, .power_on = gdsc_gx_do_nothing_enable,
}, },
.pwrsts = PWRSTS_OFF_ON, .pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO, .flags = CLAMP_IO,

View File

@ -131,37 +131,12 @@ static struct gdsc gpu_cx_gdsc = {
.flags = VOTABLE, .flags = VOTABLE,
}; };
/*
* On SDM845 the GPU GX domain is *almost* entirely controlled by the GMU
* running in the CX domain so the CPU doesn't need to know anything about the
* GX domain EXCEPT....
*
* Hardware constraints dictate that the GX be powered down before the CX. If
* the GMU crashes it could leave the GX on. In order to successfully bring back
* the device the CPU needs to disable the GX headswitch. There being no sane
* way to reach in and touch that register from deep inside the GPU driver we
* need to set up the infrastructure to be able to ensure that the GPU can
* ensure that the GX is off during this super special case. We do this by
* defining a GX gdsc with a dummy enable function and a "default" disable
* function.
*
* This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
* driver. During power up, nothing will happen from the CPU (and the GMU will
* power up normally but during power down this will ensure that the GX domain
* is *really* off - this gives us a semi standard way of doing what we need.
*/
static int gx_gdsc_enable(struct generic_pm_domain *domain)
{
/* Do nothing but give genpd the impression that we were successful */
return 0;
}
static struct gdsc gpu_gx_gdsc = { static struct gdsc gpu_gx_gdsc = {
.gdscr = 0x100c, .gdscr = 0x100c,
.clamp_io_ctrl = 0x1508, .clamp_io_ctrl = 0x1508,
.pd = { .pd = {
.name = "gpu_gx_gdsc", .name = "gpu_gx_gdsc",
.power_on = gx_gdsc_enable, .power_on = gdsc_gx_do_nothing_enable,
}, },
.pwrsts = PWRSTS_OFF_ON, .pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR, .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,

View File

@ -0,0 +1,320 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/qcom,gpucc-sm8150.h>
#include "common.h"
#include "clk-alpha-pll.h"
#include "clk-branch.h"
#include "clk-pll.h"
#include "clk-rcg.h"
#include "clk-regmap.h"
#include "reset.h"
#include "gdsc.h"
enum {
P_BI_TCXO,
P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_MAIN,
P_GPLL0_OUT_MAIN_DIV,
P_GPU_CC_PLL1_OUT_MAIN,
};
static const struct pll_vco trion_vco[] = {
{ 249600000, 2000000000, 0 },
};
static struct alpha_pll_config gpu_cc_pll1_config = {
.l = 0x1a,
.alpha = 0xaaa,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002267,
.config_ctl_hi1_val = 0x00000024,
.test_ctl_val = 0x00000000,
.test_ctl_hi_val = 0x00000002,
.test_ctl_hi1_val = 0x00000000,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x000000d0,
};
static struct clk_alpha_pll gpu_cc_pll1 = {
.offset = 0x100,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_pll1",
.parent_data = &(const struct clk_parent_data){
.fw_name = "bi_tcxo",
},
.num_parents = 1,
.ops = &clk_alpha_pll_trion_ops,
},
},
};
static const struct parent_map gpu_cc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_GPU_CC_PLL1_OUT_MAIN, 3 },
{ P_GPLL0_OUT_MAIN, 5 },
{ P_GPLL0_OUT_MAIN_DIV, 6 },
};
static const struct clk_parent_data gpu_cc_parent_data_0[] = {
{ .fw_name = "bi_tcxo" },
{ .hw = &gpu_cc_pll1.clkr.hw },
{ .fw_name = "gcc_gpu_gpll0_clk_src" },
{ .fw_name = "gcc_gpu_gpll0_div_clk_src" },
};
static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
{ }
};
static struct clk_rcg2 gpu_cc_gmu_clk_src = {
.cmd_rcgr = 0x1120,
.mnd_width = 0,
.hid_width = 5,
.parent_map = gpu_cc_parent_map_0,
.freq_tbl = ftbl_gpu_cc_gmu_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gpu_cc_gmu_clk_src",
.parent_data = gpu_cc_parent_data_0,
.num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
},
};
static struct clk_branch gpu_cc_ahb_clk = {
.halt_reg = 0x1078,
.halt_check = BRANCH_HALT_DELAY,
.clkr = {
.enable_reg = 0x1078,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_crc_ahb_clk = {
.halt_reg = 0x107c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x107c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_crc_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cx_apb_clk = {
.halt_reg = 0x1088,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x1088,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_apb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cx_gmu_clk = {
.halt_reg = 0x1098,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x1098,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_gmu_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &gpu_cc_gmu_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
.halt_reg = 0x108c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x108c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_snoc_dvm_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cxo_aon_clk = {
.halt_reg = 0x1004,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x1004,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cxo_aon_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cxo_clk = {
.halt_reg = 0x109c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x109c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cxo_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_gx_gmu_clk = {
.halt_reg = 0x1064,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x1064,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_gx_gmu_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &gpu_cc_gmu_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc gpu_cx_gdsc = {
.gdscr = 0x106c,
.gds_hw_ctrl = 0x1540,
.pd = {
.name = "gpu_cx_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = VOTABLE,
};
static struct gdsc gpu_gx_gdsc = {
.gdscr = 0x100c,
.clamp_io_ctrl = 0x1508,
.pd = {
.name = "gpu_gx_gdsc",
.power_on = gdsc_gx_do_nothing_enable,
},
.pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
};
static struct clk_regmap *gpu_cc_sm8150_clocks[] = {
[GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
[GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
[GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
[GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
[GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
[GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
[GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
[GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
[GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
};
static const struct qcom_reset_map gpu_cc_sm8150_resets[] = {
[GPUCC_GPU_CC_CX_BCR] = { 0x1068 },
[GPUCC_GPU_CC_GMU_BCR] = { 0x111c },
[GPUCC_GPU_CC_GX_BCR] = { 0x1008 },
[GPUCC_GPU_CC_SPDM_BCR] = { 0x1110 },
[GPUCC_GPU_CC_XO_BCR] = { 0x1000 },
};
static struct gdsc *gpu_cc_sm8150_gdscs[] = {
[GPU_CX_GDSC] = &gpu_cx_gdsc,
[GPU_GX_GDSC] = &gpu_gx_gdsc,
};
static const struct regmap_config gpu_cc_sm8150_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x8008,
.fast_io = true,
};
static const struct qcom_cc_desc gpu_cc_sm8150_desc = {
.config = &gpu_cc_sm8150_regmap_config,
.clks = gpu_cc_sm8150_clocks,
.num_clks = ARRAY_SIZE(gpu_cc_sm8150_clocks),
.resets = gpu_cc_sm8150_resets,
.num_resets = ARRAY_SIZE(gpu_cc_sm8150_resets),
.gdscs = gpu_cc_sm8150_gdscs,
.num_gdscs = ARRAY_SIZE(gpu_cc_sm8150_gdscs),
};
static const struct of_device_id gpu_cc_sm8150_match_table[] = {
{ .compatible = "qcom,sm8150-gpucc" },
{ }
};
MODULE_DEVICE_TABLE(of, gpu_cc_sm8150_match_table);
static int gpu_cc_sm8150_probe(struct platform_device *pdev)
{
struct regmap *regmap;
regmap = qcom_cc_map(pdev, &gpu_cc_sm8150_desc);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
clk_trion_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
return qcom_cc_really_probe(pdev, &gpu_cc_sm8150_desc, regmap);
}
static struct platform_driver gpu_cc_sm8150_driver = {
.probe = gpu_cc_sm8150_probe,
.driver = {
.name = "sm8150-gpucc",
.of_match_table = gpu_cc_sm8150_match_table,
},
};
static int __init gpu_cc_sm8150_init(void)
{
return platform_driver_register(&gpu_cc_sm8150_driver);
}
subsys_initcall(gpu_cc_sm8150_init);
static void __exit gpu_cc_sm8150_exit(void)
{
platform_driver_unregister(&gpu_cc_sm8150_driver);
}
module_exit(gpu_cc_sm8150_exit);
MODULE_DESCRIPTION("QTI GPUCC SM8150 Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,348 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/qcom,gpucc-sm8250.h>
#include "common.h"
#include "clk-alpha-pll.h"
#include "clk-branch.h"
#include "clk-pll.h"
#include "clk-rcg.h"
#include "clk-regmap.h"
#include "reset.h"
#include "gdsc.h"
#define CX_GMU_CBCR_SLEEP_MASK 0xf
#define CX_GMU_CBCR_SLEEP_SHIFT 4
#define CX_GMU_CBCR_WAKE_MASK 0xf
#define CX_GMU_CBCR_WAKE_SHIFT 8
enum {
P_BI_TCXO,
P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_MAIN,
P_GPLL0_OUT_MAIN_DIV,
P_GPU_CC_PLL0_OUT_MAIN,
P_GPU_CC_PLL1_OUT_MAIN,
};
static struct pll_vco lucid_vco[] = {
{ 249600000, 2000000000, 0 },
};
static const struct alpha_pll_config gpu_cc_pll1_config = {
.l = 0x1a,
.alpha = 0xaaa,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002261,
.config_ctl_hi1_val = 0x029a699c,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x00000000,
};
static struct clk_alpha_pll gpu_cc_pll1 = {
.offset = 0x100,
.vco_table = lucid_vco,
.num_vco = ARRAY_SIZE(lucid_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_pll1",
.parent_data = &(const struct clk_parent_data){
.fw_name = "bi_tcxo",
},
.num_parents = 1,
.ops = &clk_alpha_pll_lucid_ops,
},
},
};
static const struct parent_map gpu_cc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_GPU_CC_PLL1_OUT_MAIN, 3 },
{ P_GPLL0_OUT_MAIN, 5 },
{ P_GPLL0_OUT_MAIN_DIV, 6 },
};
static const struct clk_parent_data gpu_cc_parent_data_0[] = {
{ .fw_name = "bi_tcxo" },
{ .hw = &gpu_cc_pll1.clkr.hw },
{ .fw_name = "gcc_gpu_gpll0_clk_src" },
{ .fw_name = "gcc_gpu_gpll0_div_clk_src" },
};
static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
{ }
};
static struct clk_rcg2 gpu_cc_gmu_clk_src = {
.cmd_rcgr = 0x1120,
.mnd_width = 0,
.hid_width = 5,
.parent_map = gpu_cc_parent_map_0,
.freq_tbl = ftbl_gpu_cc_gmu_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gpu_cc_gmu_clk_src",
.parent_data = gpu_cc_parent_data_0,
.num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
},
};
static struct clk_branch gpu_cc_ahb_clk = {
.halt_reg = 0x1078,
.halt_check = BRANCH_HALT_DELAY,
.clkr = {
.enable_reg = 0x1078,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_crc_ahb_clk = {
.halt_reg = 0x107c,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x107c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_crc_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cx_apb_clk = {
.halt_reg = 0x1088,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x1088,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_apb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cx_gmu_clk = {
.halt_reg = 0x1098,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x1098,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_gmu_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &gpu_cc_gmu_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
.halt_reg = 0x108c,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x108c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_snoc_dvm_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cxo_aon_clk = {
.halt_reg = 0x1004,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x1004,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cxo_aon_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_cxo_clk = {
.halt_reg = 0x109c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x109c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cxo_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_gx_gmu_clk = {
.halt_reg = 0x1064,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x1064,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_gx_gmu_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &gpu_cc_gmu_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
.halt_reg = 0x5000,
.halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x5000,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc gpu_cx_gdsc = {
.gdscr = 0x106c,
.gds_hw_ctrl = 0x1540,
.pd = {
.name = "gpu_cx_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = VOTABLE,
};
static struct gdsc gpu_gx_gdsc = {
.gdscr = 0x100c,
.clamp_io_ctrl = 0x1508,
.pd = {
.name = "gpu_gx_gdsc",
.power_on = gdsc_gx_do_nothing_enable,
},
.pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
};
static struct clk_regmap *gpu_cc_sm8250_clocks[] = {
[GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
[GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
[GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
[GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
[GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
[GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
[GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
[GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
[GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
[GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
};
static const struct qcom_reset_map gpu_cc_sm8250_resets[] = {
[GPUCC_GPU_CC_ACD_BCR] = { 0x1160 },
[GPUCC_GPU_CC_CX_BCR] = { 0x1068 },
[GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 },
[GPUCC_GPU_CC_GMU_BCR] = { 0x111c },
[GPUCC_GPU_CC_GX_BCR] = { 0x1008 },
[GPUCC_GPU_CC_XO_BCR] = { 0x1000 },
};
static struct gdsc *gpu_cc_sm8250_gdscs[] = {
[GPU_CX_GDSC] = &gpu_cx_gdsc,
[GPU_GX_GDSC] = &gpu_gx_gdsc,
};
static const struct regmap_config gpu_cc_sm8250_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x8008,
.fast_io = true,
};
static const struct qcom_cc_desc gpu_cc_sm8250_desc = {
.config = &gpu_cc_sm8250_regmap_config,
.clks = gpu_cc_sm8250_clocks,
.num_clks = ARRAY_SIZE(gpu_cc_sm8250_clocks),
.resets = gpu_cc_sm8250_resets,
.num_resets = ARRAY_SIZE(gpu_cc_sm8250_resets),
.gdscs = gpu_cc_sm8250_gdscs,
.num_gdscs = ARRAY_SIZE(gpu_cc_sm8250_gdscs),
};
static const struct of_device_id gpu_cc_sm8250_match_table[] = {
{ .compatible = "qcom,sm8250-gpucc" },
{ }
};
MODULE_DEVICE_TABLE(of, gpu_cc_sm8250_match_table);
static int gpu_cc_sm8250_probe(struct platform_device *pdev)
{
struct regmap *regmap;
unsigned int value, mask;
regmap = qcom_cc_map(pdev, &gpu_cc_sm8250_desc);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
clk_lucid_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
/*
* Configure gpu_cc_cx_gmu_clk with recommended
* wakeup/sleep settings
*/
mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT;
mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT;
value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT;
regmap_update_bits(regmap, 0x1098, mask, value);
return qcom_cc_really_probe(pdev, &gpu_cc_sm8250_desc, regmap);
}
static struct platform_driver gpu_cc_sm8250_driver = {
.probe = gpu_cc_sm8250_probe,
.driver = {
.name = "sm8250-gpucc",
.of_match_table = gpu_cc_sm8250_match_table,
},
};
static int __init gpu_cc_sm8250_init(void)
{
return platform_driver_register(&gpu_cc_sm8250_driver);
}
subsys_initcall(gpu_cc_sm8250_init);
static void __exit gpu_cc_sm8250_exit(void)
{
platform_driver_unregister(&gpu_cc_sm8250_driver);
}
module_exit(gpu_cc_sm8250_exit);
MODULE_DESCRIPTION("QTI GPU_CC SM8250 Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,476 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
#include "clk-alpha-pll.h"
#include "clk-branch.h"
#include "clk-rcg.h"
#include "clk-regmap.h"
#include "common.h"
#include "gdsc.h"
enum {
P_BI_TCXO,
P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD,
P_SLEEP_CLK,
};
static struct pll_vco fabia_vco[] = {
{ 249600000, 2000000000, 0 },
};
static const struct alpha_pll_config lpass_lpaaudio_dig_pll_config = {
.l = 0x20,
.alpha = 0x0,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002067,
.test_ctl_val = 0x40000000,
.test_ctl_hi_val = 0x00000000,
.user_ctl_val = 0x00005105,
.user_ctl_hi_val = 0x00004805,
};
static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = {
[CLK_ALPHA_PLL_TYPE_FABIA] = {
[PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_CAL_L_VAL] = 0x8,
[PLL_OFF_USER_CTL] = 0x0c,
[PLL_OFF_USER_CTL_U] = 0x10,
[PLL_OFF_USER_CTL_U1] = 0x14,
[PLL_OFF_CONFIG_CTL] = 0x18,
[PLL_OFF_CONFIG_CTL_U] = 0x1C,
[PLL_OFF_CONFIG_CTL_U1] = 0x20,
[PLL_OFF_TEST_CTL] = 0x24,
[PLL_OFF_TEST_CTL_U] = 0x28,
[PLL_OFF_STATUS] = 0x30,
[PLL_OFF_OPMODE] = 0x38,
[PLL_OFF_FRAC] = 0x40,
},
};
static struct clk_alpha_pll lpass_lpaaudio_dig_pll = {
.offset = 0x1000,
.vco_table = fabia_vco,
.num_vco = ARRAY_SIZE(fabia_vco),
.regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_FABIA],
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "lpass_lpaaudio_dig_pll",
.parent_data = &(const struct clk_parent_data){
.fw_name = "bi_tcxo",
},
.num_parents = 1,
.ops = &clk_alpha_pll_fabia_ops,
},
},
};
static const struct clk_div_table
post_div_table_lpass_lpaaudio_dig_pll_out_odd[] = {
{ 0x5, 5 },
{ }
};
static struct clk_alpha_pll_postdiv lpass_lpaaudio_dig_pll_out_odd = {
.offset = 0x1000,
.post_div_shift = 12,
.post_div_table = post_div_table_lpass_lpaaudio_dig_pll_out_odd,
.num_post_div =
ARRAY_SIZE(post_div_table_lpass_lpaaudio_dig_pll_out_odd),
.width = 4,
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
.clkr.hw.init = &(struct clk_init_data){
.name = "lpass_lpaaudio_dig_pll_out_odd",
.parent_data = &(const struct clk_parent_data){
.hw = &lpass_lpaaudio_dig_pll.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_alpha_pll_postdiv_fabia_ops,
},
};
static const struct parent_map lpass_core_cc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5 },
};
static const struct clk_parent_data lpass_core_cc_parent_data_0[] = {
{ .fw_name = "bi_tcxo" },
{ .hw = &lpass_lpaaudio_dig_pll_out_odd.clkr.hw },
};
static const struct parent_map lpass_core_cc_parent_map_2[] = {
{ P_BI_TCXO, 0 },
};
static struct clk_rcg2 core_clk_src = {
.cmd_rcgr = 0x1d000,
.mnd_width = 8,
.hid_width = 5,
.parent_map = lpass_core_cc_parent_map_2,
.clkr.hw.init = &(struct clk_init_data){
.name = "core_clk_src",
.parent_data = &(const struct clk_parent_data){
.fw_name = "bi_tcxo",
},
.num_parents = 1,
.ops = &clk_rcg2_ops,
},
};
static const struct freq_tbl ftbl_ext_mclk0_clk_src[] = {
F(9600000, P_BI_TCXO, 2, 0, 0),
F(19200000, P_BI_TCXO, 1, 0, 0),
{ }
};
static const struct freq_tbl ftbl_ext_lpaif_clk_src[] = {
F(256000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 32),
F(512000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 16),
F(768000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 16),
F(1024000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 8),
F(1536000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 8),
F(2048000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 4),
F(3072000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 4),
F(4096000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 2),
F(6144000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 2),
F(8192000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 0, 0),
F(9600000, P_BI_TCXO, 2, 0, 0),
F(12288000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 0, 0),
F(19200000, P_BI_TCXO, 1, 0, 0),
F(24576000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5, 0, 0),
{ }
};
static struct clk_rcg2 ext_mclk0_clk_src = {
.cmd_rcgr = 0x20000,
.mnd_width = 8,
.hid_width = 5,
.parent_map = lpass_core_cc_parent_map_0,
.freq_tbl = ftbl_ext_mclk0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "ext_mclk0_clk_src",
.parent_data = lpass_core_cc_parent_data_0,
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
},
};
static struct clk_rcg2 lpaif_pri_clk_src = {
.cmd_rcgr = 0x10000,
.mnd_width = 16,
.hid_width = 5,
.parent_map = lpass_core_cc_parent_map_0,
.freq_tbl = ftbl_ext_lpaif_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "lpaif_pri_clk_src",
.parent_data = lpass_core_cc_parent_data_0,
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
},
};
static struct clk_rcg2 lpaif_sec_clk_src = {
.cmd_rcgr = 0x11000,
.mnd_width = 16,
.hid_width = 5,
.parent_map = lpass_core_cc_parent_map_0,
.freq_tbl = ftbl_ext_lpaif_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "lpaif_sec_clk_src",
.parent_data = lpass_core_cc_parent_data_0,
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
},
};
static struct clk_branch lpass_audio_core_ext_mclk0_clk = {
.halt_reg = 0x20014,
.halt_check = BRANCH_HALT,
.hwcg_reg = 0x20014,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0x20014,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_ext_mclk0_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &ext_mclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch lpass_audio_core_lpaif_pri_ibit_clk = {
.halt_reg = 0x10018,
.halt_check = BRANCH_HALT,
.hwcg_reg = 0x10018,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0x10018,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_lpaif_pri_ibit_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &lpaif_pri_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch lpass_audio_core_lpaif_sec_ibit_clk = {
.halt_reg = 0x11018,
.halt_check = BRANCH_HALT,
.hwcg_reg = 0x11018,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0x11018,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_lpaif_sec_ibit_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &lpaif_sec_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch lpass_audio_core_sysnoc_mport_core_clk = {
.halt_reg = 0x23000,
.halt_check = BRANCH_HALT,
.hwcg_reg = 0x23000,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0x23000,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_sysnoc_mport_core_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_regmap *lpass_core_cc_sc7180_clocks[] = {
[EXT_MCLK0_CLK_SRC] = &ext_mclk0_clk_src.clkr,
[LPAIF_PRI_CLK_SRC] = &lpaif_pri_clk_src.clkr,
[LPAIF_SEC_CLK_SRC] = &lpaif_sec_clk_src.clkr,
[CORE_CLK_SRC] = &core_clk_src.clkr,
[LPASS_AUDIO_CORE_EXT_MCLK0_CLK] = &lpass_audio_core_ext_mclk0_clk.clkr,
[LPASS_AUDIO_CORE_LPAIF_PRI_IBIT_CLK] =
&lpass_audio_core_lpaif_pri_ibit_clk.clkr,
[LPASS_AUDIO_CORE_LPAIF_SEC_IBIT_CLK] =
&lpass_audio_core_lpaif_sec_ibit_clk.clkr,
[LPASS_AUDIO_CORE_SYSNOC_MPORT_CORE_CLK] =
&lpass_audio_core_sysnoc_mport_core_clk.clkr,
[LPASS_LPAAUDIO_DIG_PLL] = &lpass_lpaaudio_dig_pll.clkr,
[LPASS_LPAAUDIO_DIG_PLL_OUT_ODD] = &lpass_lpaaudio_dig_pll_out_odd.clkr,
};
static struct gdsc lpass_pdc_hm_gdsc = {
.gdscr = 0x3090,
.pd = {
.name = "lpass_pdc_hm_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = VOTABLE,
};
static struct gdsc lpass_audio_hm_gdsc = {
.gdscr = 0x9090,
.pd = {
.name = "lpass_audio_hm_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
};
static struct gdsc lpass_core_hm_gdsc = {
.gdscr = 0x0,
.pd = {
.name = "lpass_core_hm_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = RETAIN_FF_ENABLE,
};
static struct gdsc *lpass_core_hm_sc7180_gdscs[] = {
[LPASS_CORE_HM_GDSCR] = &lpass_core_hm_gdsc,
};
static struct gdsc *lpass_audio_hm_sc7180_gdscs[] = {
[LPASS_PDC_HM_GDSCR] = &lpass_pdc_hm_gdsc,
[LPASS_AUDIO_HM_GDSCR] = &lpass_audio_hm_gdsc,
};
static struct regmap_config lpass_core_cc_sc7180_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
};
static const struct qcom_cc_desc lpass_core_hm_sc7180_desc = {
.config = &lpass_core_cc_sc7180_regmap_config,
.gdscs = lpass_core_hm_sc7180_gdscs,
.num_gdscs = ARRAY_SIZE(lpass_core_hm_sc7180_gdscs),
};
static const struct qcom_cc_desc lpass_core_cc_sc7180_desc = {
.config = &lpass_core_cc_sc7180_regmap_config,
.clks = lpass_core_cc_sc7180_clocks,
.num_clks = ARRAY_SIZE(lpass_core_cc_sc7180_clocks),
};
static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = {
.config = &lpass_core_cc_sc7180_regmap_config,
.gdscs = lpass_audio_hm_sc7180_gdscs,
.num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs),
};
static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
{
const struct qcom_cc_desc *desc;
struct regmap *regmap;
int ret;
lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc";
desc = &lpass_audio_hm_sc7180_desc;
ret = qcom_cc_probe_by_index(pdev, 1, desc);
if (ret)
return ret;
lpass_core_cc_sc7180_regmap_config.name = "lpass_core_cc";
regmap = qcom_cc_map(pdev, &lpass_core_cc_sc7180_desc);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
/*
* Keep the CLK always-ON
* LPASS_AUDIO_CORE_SYSNOC_SWAY_CORE_CLK
*/
regmap_update_bits(regmap, 0x24000, BIT(0), BIT(0));
/* PLL settings */
regmap_write(regmap, 0x1008, 0x20);
regmap_update_bits(regmap, 0x1014, BIT(0), BIT(0));
clk_fabia_pll_configure(&lpass_lpaaudio_dig_pll, regmap,
&lpass_lpaaudio_dig_pll_config);
return qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
}
static int lpass_hm_core_probe(struct platform_device *pdev)
{
const struct qcom_cc_desc *desc;
lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core";
desc = &lpass_core_hm_sc7180_desc;
return qcom_cc_probe_by_index(pdev, 0, desc);
}
static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
{
.compatible = "qcom,sc7180-lpasshm",
.data = lpass_hm_core_probe,
},
{
.compatible = "qcom,sc7180-lpasscorecc",
.data = lpass_core_cc_sc7180_probe,
},
{ }
};
MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table);
static int lpass_core_sc7180_probe(struct platform_device *pdev)
{
int (*clk_probe)(struct platform_device *p);
int ret;
pm_runtime_enable(&pdev->dev);
ret = pm_clk_create(&pdev->dev);
if (ret)
return ret;
ret = pm_clk_add(&pdev->dev, "iface");
if (ret < 0) {
dev_err(&pdev->dev, "failed to acquire iface clock\n");
goto disable_pm_runtime;
}
clk_probe = of_device_get_match_data(&pdev->dev);
if (!clk_probe)
return -EINVAL;
ret = clk_probe(pdev);
if (ret)
goto destroy_pm_clk;
return 0;
destroy_pm_clk:
pm_clk_destroy(&pdev->dev);
disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
return ret;
}
static const struct dev_pm_ops lpass_core_cc_pm_ops = {
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
};
static struct platform_driver lpass_core_cc_sc7180_driver = {
.probe = lpass_core_sc7180_probe,
.driver = {
.name = "lpass_core_cc-sc7180",
.of_match_table = lpass_core_cc_sc7180_match_table,
.pm = &lpass_core_cc_pm_ops,
},
};
static int __init lpass_core_cc_sc7180_init(void)
{
return platform_driver_register(&lpass_core_cc_sc7180_driver);
}
subsys_initcall(lpass_core_cc_sc7180_init);
static void __exit lpass_core_cc_sc7180_exit(void)
{
platform_driver_unregister(&lpass_core_cc_sc7180_driver);
}
module_exit(lpass_core_cc_sc7180_exit);
MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver");
MODULE_LICENSE("GPL v2");

View File

@ -208,6 +208,20 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
static void rpi_register_clk_driver(struct device *dev) static void rpi_register_clk_driver(struct device *dev)
{ {
struct device_node *firmware;
/*
* Earlier DTs don't have a node for the firmware clocks but
* rely on us creating a platform device by hand. If we do
* have a node for the firmware clocks, just bail out here.
*/
firmware = of_get_compatible_child(dev->of_node,
"raspberrypi,firmware-clocks");
if (firmware) {
of_node_put(firmware);
return;
}
rpi_clk = platform_device_register_data(dev, "raspberrypi-clk", rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
-1, NULL, 0); -1, NULL, 0);
} }

View File

@ -82,6 +82,7 @@ config FSL_IMX8_DDR_PMU
config QCOM_L2_PMU config QCOM_L2_PMU
bool "Qualcomm Technologies L2-cache PMU" bool "Qualcomm Technologies L2-cache PMU"
depends on ARCH_QCOM && ARM64 && ACPI depends on ARCH_QCOM && ARM64 && ACPI
select QCOM_KRYO_L2_ACCESSORS
help help
Provides support for the L2 cache performance monitor unit (PMU) Provides support for the L2 cache performance monitor unit (PMU)
in Qualcomm Technologies processors. in Qualcomm Technologies processors.

View File

@ -23,6 +23,7 @@
#include <asm/barrier.h> #include <asm/barrier.h>
#include <asm/local64.h> #include <asm/local64.h>
#include <asm/sysreg.h> #include <asm/sysreg.h>
#include <soc/qcom/kryo-l2-accessors.h>
#define MAX_L2_CTRS 9 #define MAX_L2_CTRS 9
@ -79,8 +80,6 @@
#define L2_COUNTER_RELOAD BIT_ULL(31) #define L2_COUNTER_RELOAD BIT_ULL(31)
#define L2_CYCLE_COUNTER_RELOAD BIT_ULL(63) #define L2_CYCLE_COUNTER_RELOAD BIT_ULL(63)
#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
#define reg_idx(reg, i) (((i) * IA_L2_REG_OFFSET) + reg##_BASE) #define reg_idx(reg, i) (((i) * IA_L2_REG_OFFSET) + reg##_BASE)
@ -99,48 +98,7 @@
#define L2_EVENT_STREX 0x421 #define L2_EVENT_STREX 0x421
#define L2_EVENT_CLREX 0x422 #define L2_EVENT_CLREX 0x422
static DEFINE_RAW_SPINLOCK(l2_access_lock);
/**
* set_l2_indirect_reg: write value to an L2 register
* @reg: Address of L2 register.
* @value: Value to be written to register.
*
* Use architecturally required barriers for ordering between system register
* accesses
*/
static void set_l2_indirect_reg(u64 reg, u64 val)
{
unsigned long flags;
raw_spin_lock_irqsave(&l2_access_lock, flags);
write_sysreg_s(reg, L2CPUSRSELR_EL1);
isb();
write_sysreg_s(val, L2CPUSRDR_EL1);
isb();
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
/**
* get_l2_indirect_reg: read an L2 register value
* @reg: Address of L2 register.
*
* Use architecturally required barriers for ordering between system register
* accesses
*/
static u64 get_l2_indirect_reg(u64 reg)
{
u64 val;
unsigned long flags;
raw_spin_lock_irqsave(&l2_access_lock, flags);
write_sysreg_s(reg, L2CPUSRSELR_EL1);
isb();
val = read_sysreg_s(L2CPUSRDR_EL1);
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return val;
}
struct cluster_pmu; struct cluster_pmu;
@ -211,28 +169,28 @@ static inline struct cluster_pmu *get_cluster_pmu(
static void cluster_pmu_reset(void) static void cluster_pmu_reset(void)
{ {
/* Reset all counters */ /* Reset all counters */
set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL); kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
set_l2_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask); kryo_l2_set_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask);
set_l2_indirect_reg(L2PMINTENCLR, l2_counter_present_mask); kryo_l2_set_indirect_reg(L2PMINTENCLR, l2_counter_present_mask);
set_l2_indirect_reg(L2PMOVSCLR, l2_counter_present_mask); kryo_l2_set_indirect_reg(L2PMOVSCLR, l2_counter_present_mask);
} }
static inline void cluster_pmu_enable(void) static inline void cluster_pmu_enable(void)
{ {
set_l2_indirect_reg(L2PMCR, L2PMCR_COUNTERS_ENABLE); kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_COUNTERS_ENABLE);
} }
static inline void cluster_pmu_disable(void) static inline void cluster_pmu_disable(void)
{ {
set_l2_indirect_reg(L2PMCR, L2PMCR_COUNTERS_DISABLE); kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_COUNTERS_DISABLE);
} }
static inline void cluster_pmu_counter_set_value(u32 idx, u64 value) static inline void cluster_pmu_counter_set_value(u32 idx, u64 value)
{ {
if (idx == l2_cycle_ctr_idx) if (idx == l2_cycle_ctr_idx)
set_l2_indirect_reg(L2PMCCNTR, value); kryo_l2_set_indirect_reg(L2PMCCNTR, value);
else else
set_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx), value); kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx), value);
} }
static inline u64 cluster_pmu_counter_get_value(u32 idx) static inline u64 cluster_pmu_counter_get_value(u32 idx)
@ -240,46 +198,46 @@ static inline u64 cluster_pmu_counter_get_value(u32 idx)
u64 value; u64 value;
if (idx == l2_cycle_ctr_idx) if (idx == l2_cycle_ctr_idx)
value = get_l2_indirect_reg(L2PMCCNTR); value = kryo_l2_get_indirect_reg(L2PMCCNTR);
else else
value = get_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx)); value = kryo_l2_get_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx));
return value; return value;
} }
static inline void cluster_pmu_counter_enable(u32 idx) static inline void cluster_pmu_counter_enable(u32 idx)
{ {
set_l2_indirect_reg(L2PMCNTENSET, idx_to_reg_bit(idx)); kryo_l2_set_indirect_reg(L2PMCNTENSET, idx_to_reg_bit(idx));
} }
static inline void cluster_pmu_counter_disable(u32 idx) static inline void cluster_pmu_counter_disable(u32 idx)
{ {
set_l2_indirect_reg(L2PMCNTENCLR, idx_to_reg_bit(idx)); kryo_l2_set_indirect_reg(L2PMCNTENCLR, idx_to_reg_bit(idx));
} }
static inline void cluster_pmu_counter_enable_interrupt(u32 idx) static inline void cluster_pmu_counter_enable_interrupt(u32 idx)
{ {
set_l2_indirect_reg(L2PMINTENSET, idx_to_reg_bit(idx)); kryo_l2_set_indirect_reg(L2PMINTENSET, idx_to_reg_bit(idx));
} }
static inline void cluster_pmu_counter_disable_interrupt(u32 idx) static inline void cluster_pmu_counter_disable_interrupt(u32 idx)
{ {
set_l2_indirect_reg(L2PMINTENCLR, idx_to_reg_bit(idx)); kryo_l2_set_indirect_reg(L2PMINTENCLR, idx_to_reg_bit(idx));
} }
static inline void cluster_pmu_set_evccntcr(u32 val) static inline void cluster_pmu_set_evccntcr(u32 val)
{ {
set_l2_indirect_reg(L2PMCCNTCR, val); kryo_l2_set_indirect_reg(L2PMCCNTCR, val);
} }
static inline void cluster_pmu_set_evcntcr(u32 ctr, u32 val) static inline void cluster_pmu_set_evcntcr(u32 ctr, u32 val)
{ {
set_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTCR, ctr), val); kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVCNTCR, ctr), val);
} }
static inline void cluster_pmu_set_evtyper(u32 ctr, u32 val) static inline void cluster_pmu_set_evtyper(u32 ctr, u32 val)
{ {
set_l2_indirect_reg(reg_idx(IA_L2PMXEVTYPER, ctr), val); kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVTYPER, ctr), val);
} }
static void cluster_pmu_set_resr(struct cluster_pmu *cluster, static void cluster_pmu_set_resr(struct cluster_pmu *cluster,
@ -295,11 +253,11 @@ static void cluster_pmu_set_resr(struct cluster_pmu *cluster,
spin_lock_irqsave(&cluster->pmu_lock, flags); spin_lock_irqsave(&cluster->pmu_lock, flags);
resr_val = get_l2_indirect_reg(L2PMRESR); resr_val = kryo_l2_get_indirect_reg(L2PMRESR);
resr_val &= ~(L2PMRESR_GROUP_MASK << shift); resr_val &= ~(L2PMRESR_GROUP_MASK << shift);
resr_val |= field; resr_val |= field;
resr_val |= L2PMRESR_EN; resr_val |= L2PMRESR_EN;
set_l2_indirect_reg(L2PMRESR, resr_val); kryo_l2_set_indirect_reg(L2PMRESR, resr_val);
spin_unlock_irqrestore(&cluster->pmu_lock, flags); spin_unlock_irqrestore(&cluster->pmu_lock, flags);
} }
@ -315,14 +273,14 @@ static inline void cluster_pmu_set_evfilter_sys_mode(u32 ctr)
L2PMXEVFILTER_ORGFILTER_IDINDEP | L2PMXEVFILTER_ORGFILTER_IDINDEP |
L2PMXEVFILTER_ORGFILTER_ALL; L2PMXEVFILTER_ORGFILTER_ALL;
set_l2_indirect_reg(reg_idx(IA_L2PMXEVFILTER, ctr), val); kryo_l2_set_indirect_reg(reg_idx(IA_L2PMXEVFILTER, ctr), val);
} }
static inline u32 cluster_pmu_getreset_ovsr(void) static inline u32 cluster_pmu_getreset_ovsr(void)
{ {
u32 result = get_l2_indirect_reg(L2PMOVSSET); u32 result = kryo_l2_get_indirect_reg(L2PMOVSSET);
set_l2_indirect_reg(L2PMOVSCLR, result); kryo_l2_set_indirect_reg(L2PMOVSCLR, result);
return result; return result;
} }
@ -767,7 +725,7 @@ static int get_num_counters(void)
{ {
int val; int val;
val = get_l2_indirect_reg(L2PMCR); val = kryo_l2_get_indirect_reg(L2PMCR);
/* /*
* Read number of counters from L2PMCR and add 1 * Read number of counters from L2PMCR and add 1

View File

@ -11,6 +11,7 @@
* Maxime Ripard <maxime.ripard@free-electrons.com> * Maxime Ripard <maxime.ripard@free-electrons.com>
*/ */
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
@ -18,10 +19,9 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include "reset-simple.h"
static inline struct reset_simple_data * static inline struct reset_simple_data *
to_reset_simple_data(struct reset_controller_dev *rcdev) to_reset_simple_data(struct reset_controller_dev *rcdev)
{ {
@ -64,6 +64,24 @@ static int reset_simple_deassert(struct reset_controller_dev *rcdev,
return reset_simple_update(rcdev, id, false); return reset_simple_update(rcdev, id, false);
} }
static int reset_simple_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct reset_simple_data *data = to_reset_simple_data(rcdev);
int ret;
if (!data->reset_us)
return -ENOTSUPP;
ret = reset_simple_assert(rcdev, id);
if (ret)
return ret;
usleep_range(data->reset_us, data->reset_us * 2);
return reset_simple_deassert(rcdev, id);
}
static int reset_simple_status(struct reset_controller_dev *rcdev, static int reset_simple_status(struct reset_controller_dev *rcdev,
unsigned long id) unsigned long id)
{ {
@ -81,6 +99,7 @@ static int reset_simple_status(struct reset_controller_dev *rcdev,
const struct reset_control_ops reset_simple_ops = { const struct reset_control_ops reset_simple_ops = {
.assert = reset_simple_assert, .assert = reset_simple_assert,
.deassert = reset_simple_deassert, .deassert = reset_simple_deassert,
.reset = reset_simple_reset,
.status = reset_simple_status, .status = reset_simple_status,
}; };
EXPORT_SYMBOL_GPL(reset_simple_ops); EXPORT_SYMBOL_GPL(reset_simple_ops);

View File

@ -11,13 +11,12 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/reset/socfpga.h> #include <linux/reset/socfpga.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include "reset-simple.h"
#define SOCFPGA_NR_BANKS 8 #define SOCFPGA_NR_BANKS 8
static int a10_reset_init(struct device_node *np) static int a10_reset_init(struct device_node *np)

View File

@ -14,13 +14,12 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/reset/sunxi.h> #include <linux/reset/sunxi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include "reset-simple.h"
static int sunxi_reset_init(struct device_node *np) static int sunxi_reset_init(struct device_node *np)
{ {
struct reset_simple_data *data; struct reset_simple_data *data;

View File

@ -9,8 +9,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/reset/reset-simple.h>
#include "reset-simple.h"
#define MAX_CLKS 2 #define MAX_CLKS 2
#define MAX_RSTS 2 #define MAX_RSTS 2

View File

@ -53,6 +53,10 @@ config QCOM_LLCC
SDM845. This provides interfaces to clients that use the LLCC. SDM845. This provides interfaces to clients that use the LLCC.
Say yes here to enable LLCC slice driver. Say yes here to enable LLCC slice driver.
config QCOM_KRYO_L2_ACCESSORS
bool
depends on ARCH_QCOM && ARM64 || COMPILE_TEST
config QCOM_MDT_LOADER config QCOM_MDT_LOADER
tristate tristate
select QCOM_SCM select QCOM_SCM

View File

@ -24,3 +24,4 @@ obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include <linux/spinlock.h>
#include <asm/barrier.h>
#include <asm/sysreg.h>
#include <soc/qcom/kryo-l2-accessors.h>
#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
static DEFINE_RAW_SPINLOCK(l2_access_lock);
/**
* kryo_l2_set_indirect_reg() - write value to an L2 register
* @reg: Address of L2 register.
* @value: Value to be written to register.
*
* Use architecturally required barriers for ordering between system register
* accesses, and system registers with respect to device memory
*/
void kryo_l2_set_indirect_reg(u64 reg, u64 val)
{
unsigned long flags;
raw_spin_lock_irqsave(&l2_access_lock, flags);
write_sysreg_s(reg, L2CPUSRSELR_EL1);
isb();
write_sysreg_s(val, L2CPUSRDR_EL1);
isb();
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(kryo_l2_set_indirect_reg);
/**
* kryo_l2_get_indirect_reg() - read an L2 register value
* @reg: Address of L2 register.
*
* Use architecturally required barriers for ordering between system register
* accesses, and system registers with respect to device memory
*/
u64 kryo_l2_get_indirect_reg(u64 reg)
{
u64 val;
unsigned long flags;
raw_spin_lock_irqsave(&l2_access_lock, flags);
write_sysreg_s(reg, L2CPUSRSELR_EL1);
isb();
val = read_sysreg_s(L2CPUSRDR_EL1);
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return val;
}
EXPORT_SYMBOL(kryo_l2_get_indirect_reg);

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* This file defines field values used by the versaclock 6 family
* for defining output type
*/
#define VC5_LVPECL 0
#define VC5_CMOS 1
#define VC5_HCSL33 2
#define VC5_LVDS 3
#define VC5_CMOS2 4
#define VC5_CMOSD 5
#define VC5_HCSL25 6

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM3368_H
#define __DT_BINDINGS_CLOCK_BCM3368_H
#define BCM3368_CLK_MAC 3
#define BCM3368_CLK_TC 5
#define BCM3368_CLK_US_TOP 6
#define BCM3368_CLK_DS_TOP 7
#define BCM3368_CLK_ACM 8
#define BCM3368_CLK_SPI 9
#define BCM3368_CLK_USBS 10
#define BCM3368_CLK_BMU 11
#define BCM3368_CLK_PCM 12
#define BCM3368_CLK_NTP 13
#define BCM3368_CLK_ACP_B 14
#define BCM3368_CLK_ACP_A 15
#define BCM3368_CLK_EMUSB 17
#define BCM3368_CLK_ENET0 18
#define BCM3368_CLK_ENET1 19
#define BCM3368_CLK_USBSU 20
#define BCM3368_CLK_EPHY 21
#endif /* __DT_BINDINGS_CLOCK_BCM3368_H */

View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6318_H
#define __DT_BINDINGS_CLOCK_BCM6318_H
#define BCM6318_CLK_ADSL_ASB 0
#define BCM6318_CLK_USB_ASB 1
#define BCM6318_CLK_MIPS_ASB 2
#define BCM6318_CLK_PCIE_ASB 3
#define BCM6318_CLK_PHYMIPS_ASB 4
#define BCM6318_CLK_ROBOSW_ASB 5
#define BCM6318_CLK_SAR_ASB 6
#define BCM6318_CLK_SDR_ASB 7
#define BCM6318_CLK_SWREG_ASB 8
#define BCM6318_CLK_PERIPH_ASB 9
#define BCM6318_CLK_CPUBUS160 10
#define BCM6318_CLK_ADSL 11
#define BCM6318_CLK_SAR125 12
#define BCM6318_CLK_MIPS 13
#define BCM6318_CLK_PCIE 14
#define BCM6318_CLK_ROBOSW250 16
#define BCM6318_CLK_ROBOSW025 17
#define BCM6318_CLK_SDR 19
#define BCM6318_CLK_USBD 20
#define BCM6318_CLK_HSSPI 25
#define BCM6318_CLK_PCIE25 27
#define BCM6318_CLK_PHYMIPS 28
#define BCM6318_CLK_AFE 29
#define BCM6318_CLK_QPROC 30
#define BCM6318_UCLK_ADSL 0
#define BCM6318_UCLK_ARB 1
#define BCM6318_UCLK_MIPS 2
#define BCM6318_UCLK_PCIE 3
#define BCM6318_UCLK_PERIPH 4
#define BCM6318_UCLK_PHYMIPS 5
#define BCM6318_UCLK_ROBOSW 6
#define BCM6318_UCLK_SAR 7
#define BCM6318_UCLK_SDR 8
#define BCM6318_UCLK_USB 9
#endif /* __DT_BINDINGS_CLOCK_BCM6318_H */

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM63268_H
#define __DT_BINDINGS_CLOCK_BCM63268_H
#define BCM63268_CLK_DIS_GLESS 0
#define BCM63268_CLK_VDSL_QPROC 1
#define BCM63268_CLK_VDSL_AFE 2
#define BCM63268_CLK_VDSL 3
#define BCM63268_CLK_MIPS 4
#define BCM63268_CLK_WLAN_OCP 5
#define BCM63268_CLK_DECT 6
#define BCM63268_CLK_FAP0 7
#define BCM63268_CLK_FAP1 8
#define BCM63268_CLK_SAR 9
#define BCM63268_CLK_ROBOSW 10
#define BCM63268_CLK_PCM 11
#define BCM63268_CLK_USBD 12
#define BCM63268_CLK_USBH 13
#define BCM63268_CLK_IPSEC 14
#define BCM63268_CLK_SPI 15
#define BCM63268_CLK_HSSPI 16
#define BCM63268_CLK_PCIE 17
#define BCM63268_CLK_PHYMIPS 18
#define BCM63268_CLK_GMAC 19
#define BCM63268_CLK_NAND 20
#define BCM63268_CLK_TBUS 27
#define BCM63268_CLK_ROBOSW250 31
#endif /* __DT_BINDINGS_CLOCK_BCM63268_H */

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6328_H
#define __DT_BINDINGS_CLOCK_BCM6328_H
#define BCM6328_CLK_PHYMIPS 0
#define BCM6328_CLK_ADSL_QPROC 1
#define BCM6328_CLK_ADSL_AFE 2
#define BCM6328_CLK_ADSL 3
#define BCM6328_CLK_MIPS 4
#define BCM6328_CLK_SAR 5
#define BCM6328_CLK_PCM 6
#define BCM6328_CLK_USBD 7
#define BCM6328_CLK_USBH 8
#define BCM6328_CLK_HSSPI 9
#define BCM6328_CLK_PCIE 10
#define BCM6328_CLK_ROBOSW 11
#endif /* __DT_BINDINGS_CLOCK_BCM6328_H */

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6358_H
#define __DT_BINDINGS_CLOCK_BCM6358_H
#define BCM6358_CLK_ENET 4
#define BCM6358_CLK_ADSLPHY 5
#define BCM6358_CLK_PCM 8
#define BCM6358_CLK_SPI 9
#define BCM6358_CLK_USBS 10
#define BCM6358_CLK_SAR 11
#define BCM6358_CLK_EMUSB 17
#define BCM6358_CLK_ENET0 18
#define BCM6358_CLK_ENET1 19
#define BCM6358_CLK_USBSU 20
#define BCM6358_CLK_EPHY 21
#endif /* __DT_BINDINGS_CLOCK_BCM6358_H */

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6362_H
#define __DT_BINDINGS_CLOCK_BCM6362_H
#define BCM6362_CLK_ADSL_QPROC 1
#define BCM6362_CLK_ADSL_AFE 2
#define BCM6362_CLK_ADSL 3
#define BCM6362_CLK_MIPS 4
#define BCM6362_CLK_WLAN_OCP 5
#define BCM6362_CLK_SWPKT_USB 7
#define BCM6362_CLK_SWPKT_SAR 8
#define BCM6362_CLK_SAR 9
#define BCM6362_CLK_ROBOSW 10
#define BCM6362_CLK_PCM 11
#define BCM6362_CLK_USBD 12
#define BCM6362_CLK_USBH 13
#define BCM6362_CLK_IPSEC 14
#define BCM6362_CLK_SPI 15
#define BCM6362_CLK_HSSPI 16
#define BCM6362_CLK_PCIE 17
#define BCM6362_CLK_FAP 18
#define BCM6362_CLK_PHYMIPS 19
#define BCM6362_CLK_NAND 20
#endif /* __DT_BINDINGS_CLOCK_BCM6362_H */

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6368_H
#define __DT_BINDINGS_CLOCK_BCM6368_H
#define BCM6368_CLK_VDSL_QPROC 2
#define BCM6368_CLK_VDSL_AFE 3
#define BCM6368_CLK_VDSL_BONDING 4
#define BCM6368_CLK_VDSL 5
#define BCM6368_CLK_PHYMIPS 6
#define BCM6368_CLK_SWPKT_USB 7
#define BCM6368_CLK_SWPKT_SAR 8
#define BCM6368_CLK_SPI 9
#define BCM6368_CLK_USBD 10
#define BCM6368_CLK_SAR 11
#define BCM6368_CLK_ROBOSW 12
#define BCM6368_CLK_UTOPIA 13
#define BCM6368_CLK_PCM 14
#define BCM6368_CLK_USBH 15
#define BCM6368_CLK_DIS_GLESS 16
#define BCM6368_CLK_NAND 17
#define BCM6368_CLK_IPSEC 18
#endif /* __DT_BINDINGS_CLOCK_BCM6368_H */

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#ifndef _DT_BINDINGS_CLOCK_QCA_APSS_IPQ6018_H
#define _DT_BINDINGS_CLOCK_QCA_APSS_IPQ6018_H
#define APCS_ALIAS0_CLK_SRC 0
#define APCS_ALIAS0_CORE_CLK 1
#endif

View File

@ -230,6 +230,9 @@
#define GCC_GP1_CLK 221 #define GCC_GP1_CLK 221
#define GCC_GP2_CLK 222 #define GCC_GP2_CLK 222
#define GCC_GP3_CLK 223 #define GCC_GP3_CLK 223
#define GCC_PCIE0_AXI_S_BRIDGE_CLK 224
#define GCC_PCIE0_RCHNG_CLK_SRC 225
#define GCC_PCIE0_RCHNG_CLK 226
#define GCC_BLSP1_BCR 0 #define GCC_BLSP1_BCR 0
#define GCC_BLSP1_QUP1_BCR 1 #define GCC_BLSP1_QUP1_BCR 1
@ -362,5 +365,6 @@
#define GCC_PCIE1_AXI_SLAVE_ARES 128 #define GCC_PCIE1_AXI_SLAVE_ARES 128
#define GCC_PCIE1_AHB_ARES 129 #define GCC_PCIE1_AHB_ARES 129
#define GCC_PCIE1_AXI_MASTER_STICKY_ARES 130 #define GCC_PCIE1_AXI_MASTER_STICKY_ARES 130
#define GCC_PCIE0_AXI_SLAVE_STICKY_ARES 131
#endif #endif

View File

@ -138,6 +138,7 @@
#define GCC_MSS_Q6_MEMNOC_AXI_CLK 128 #define GCC_MSS_Q6_MEMNOC_AXI_CLK 128
#define GCC_MSS_SNOC_AXI_CLK 129 #define GCC_MSS_SNOC_AXI_CLK 129
#define GCC_SEC_CTRL_CLK_SRC 130 #define GCC_SEC_CTRL_CLK_SRC 130
#define GCC_LPASS_CFG_NOC_SWAY_CLK 131
/* GCC resets */ /* GCC resets */
#define GCC_QUSB2PHY_PRIM_BCR 0 #define GCC_QUSB2PHY_PRIM_BCR 0

View File

@ -152,5 +152,6 @@
#define GCC_USB_20_BCR 6 #define GCC_USB_20_BCR 6
#define GCC_USB_30_BCR 7 #define GCC_USB_30_BCR 7
#define GCC_USB_PHY_CFG_AHB2PHY_BCR 8 #define GCC_USB_PHY_CFG_AHB2PHY_BCR 8
#define GCC_MSS_RESTART 9
#endif #endif

View File

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8150_H
#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8150_H
/* GPU_CC clock registers */
#define GPU_CC_AHB_CLK 0
#define GPU_CC_CRC_AHB_CLK 1
#define GPU_CC_CX_APB_CLK 2
#define GPU_CC_CX_GMU_CLK 3
#define GPU_CC_CX_SNOC_DVM_CLK 4
#define GPU_CC_CXO_AON_CLK 5
#define GPU_CC_CXO_CLK 6
#define GPU_CC_GMU_CLK_SRC 7
#define GPU_CC_GX_GMU_CLK 8
#define GPU_CC_PLL1 9
/* GPU_CC Resets */
#define GPUCC_GPU_CC_CX_BCR 0
#define GPUCC_GPU_CC_GFX3D_AON_BCR 1
#define GPUCC_GPU_CC_GMU_BCR 2
#define GPUCC_GPU_CC_GX_BCR 3
#define GPUCC_GPU_CC_SPDM_BCR 4
#define GPUCC_GPU_CC_XO_BCR 5
/* GPU_CC GDSCRs */
#define GPU_CX_GDSC 0
#define GPU_GX_GDSC 1
#endif

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8250_H
#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8250_H
/* GPU_CC clock registers */
#define GPU_CC_AHB_CLK 0
#define GPU_CC_CRC_AHB_CLK 1
#define GPU_CC_CX_APB_CLK 2
#define GPU_CC_CX_GMU_CLK 3
#define GPU_CC_CX_SNOC_DVM_CLK 4
#define GPU_CC_CXO_AON_CLK 5
#define GPU_CC_CXO_CLK 6
#define GPU_CC_GMU_CLK_SRC 7
#define GPU_CC_GX_GMU_CLK 8
#define GPU_CC_PLL1 9
#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK 10
/* GPU_CC Resets */
#define GPUCC_GPU_CC_ACD_BCR 0
#define GPUCC_GPU_CC_CX_BCR 1
#define GPUCC_GPU_CC_GFX3D_AON_BCR 2
#define GPUCC_GPU_CC_GMU_BCR 3
#define GPUCC_GPU_CC_GX_BCR 4
#define GPUCC_GPU_CC_XO_BCR 5
/* GPU_CC GDSCRs */
#define GPU_CX_GDSC 0
#define GPU_GX_GDSC 1
#endif

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef _DT_BINDINGS_CLK_QCOM_LPASS_CORE_CC_SC7180_H
#define _DT_BINDINGS_CLK_QCOM_LPASS_CORE_CC_SC7180_H
/* LPASS_CORE_CC clocks */
#define LPASS_LPAAUDIO_DIG_PLL 0
#define LPASS_LPAAUDIO_DIG_PLL_OUT_ODD 1
#define CORE_CLK_SRC 2
#define EXT_MCLK0_CLK_SRC 3
#define LPAIF_PRI_CLK_SRC 4
#define LPAIF_SEC_CLK_SRC 5
#define LPASS_AUDIO_CORE_CORE_CLK 6
#define LPASS_AUDIO_CORE_EXT_MCLK0_CLK 7
#define LPASS_AUDIO_CORE_LPAIF_PRI_IBIT_CLK 8
#define LPASS_AUDIO_CORE_LPAIF_SEC_IBIT_CLK 9
#define LPASS_AUDIO_CORE_SYSNOC_MPORT_CORE_CLK 10
/* LPASS Core power domains */
#define LPASS_CORE_HM_GDSCR 0
/* LPASS Audio power domains */
#define LPASS_AUDIO_HM_GDSCR 0
#define LPASS_PDC_HM_GDSCR 1
#endif

View File

@ -133,5 +133,21 @@
#define RPM_SMD_RF_CLK3_A 87 #define RPM_SMD_RF_CLK3_A 87
#define RPM_SMD_RF_CLK3_PIN 88 #define RPM_SMD_RF_CLK3_PIN 88
#define RPM_SMD_RF_CLK3_A_PIN 89 #define RPM_SMD_RF_CLK3_A_PIN 89
#define RPM_SMD_MMSSNOC_AXI_CLK 90
#define RPM_SMD_MMSSNOC_AXI_CLK_A 91
#define RPM_SMD_CNOC_PERIPH_CLK 92
#define RPM_SMD_CNOC_PERIPH_A_CLK 93
#define RPM_SMD_LN_BB_CLK3 94
#define RPM_SMD_LN_BB_CLK3_A 95
#define RPM_SMD_LN_BB_CLK1_PIN 96
#define RPM_SMD_LN_BB_CLK1_A_PIN 97
#define RPM_SMD_LN_BB_CLK2_PIN 98
#define RPM_SMD_LN_BB_CLK2_A_PIN 99
#define RPM_SMD_SYSMMNOC_CLK 100
#define RPM_SMD_SYSMMNOC_A_CLK 101
#define RPM_SMD_CE2_CLK 102
#define RPM_SMD_CE2_A_CLK 103
#define RPM_SMD_CE3_CLK 104
#define RPM_SMD_CE3_A_CLK 105
#endif #endif

View File

@ -189,7 +189,7 @@ struct clk_duty {
* and >= numerator) Return 0 on success, otherwise -EERROR. * and >= numerator) Return 0 on success, otherwise -EERROR.
* *
* @init: Perform platform-specific initialization magic. * @init: Perform platform-specific initialization magic.
* This is not not used by any of the basic clock types. * This is not used by any of the basic clock types.
* This callback exist for HW which needs to perform some * This callback exist for HW which needs to perform some
* initialisation magic for CCF to get an accurate view of the * initialisation magic for CCF to get an accurate view of the
* clock. It may also be used dynamic resource allocation is * clock. It may also be used dynamic resource allocation is

View File

@ -27,6 +27,12 @@
* @status_active_low: if true, bits read back as cleared while the reset is * @status_active_low: if true, bits read back as cleared while the reset is
* asserted. Otherwise, bits read back as set while the * asserted. Otherwise, bits read back as set while the
* reset is asserted. * reset is asserted.
* @reset_us: Minimum delay in microseconds needed that needs to be
* waited for between an assert and a deassert to reset the
* device. If multiple consumers with different delay
* requirements are connected to this controller, it must
* be the largest minimum delay. 0 means that such a delay is
* unknown and the reset operation is unsupported.
*/ */
struct reset_simple_data { struct reset_simple_data {
spinlock_t lock; spinlock_t lock;
@ -34,6 +40,7 @@ struct reset_simple_data {
struct reset_controller_dev rcdev; struct reset_controller_dev rcdev;
bool active_low; bool active_low;
bool status_active_low; bool status_active_low;
unsigned int reset_us;
}; };
extern const struct reset_control_ops reset_simple_ops; extern const struct reset_control_ops reset_simple_ops;

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#ifndef __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H
#define __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H
void kryo_l2_set_indirect_reg(u64 reg, u64 val);
u64 kryo_l2_get_indirect_reg(u64 reg);
#endif