Commit c63e2a7a authored by Stephen Boyd's avatar Stephen Boyd

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
  ...
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>;
};
# 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>;
};
};
...
# 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>;
};
...
......@@ -3,6 +3,8 @@ Gated Clock Controller Bindings for MIPS based BCM63XX SoCs
Required properties:
- compatible: must be one of:
"brcm,bcm3368-clocks"
"brcm,bcm6318-clocks"
"brcm,bcm6318-ubus-clocks"
"brcm,bcm6328-clocks"
"brcm,bcm6358-clocks"
"brcm,bcm6362-clocks"
......
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>;
...
}
# 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>;
/* ... */
};
...
......@@ -15,7 +15,9 @@ description:
properties:
compatible:
const: qcom,msm8916-a53pll
enum:
- qcom,ipq6018-a53pll
- qcom,msm8916-a53pll
reg:
maxItems: 1
......@@ -23,6 +25,14 @@ properties:
'#clock-cells':
const: 0
clocks:
items:
- description: board XO clock
clock-names:
items:
- const: xo
required:
- compatible
- reg
......@@ -38,3 +48,12 @@ examples:
reg = <0xb016000 0x40>;
#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";
};
# SPDX-License-Identifier: GPL-2.0-only
%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#
title: Qualcomm Graphics Clock & Reset Controller Binding for SDM845
title: Qualcomm Graphics Clock & Reset Controller Binding
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
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:
compatible:
const: qcom,sdm845-gpucc
enum:
- qcom,sdm845-gpucc
- qcom,sc7180-gpucc
- qcom,sm8150-gpucc
- qcom,sm8250-gpucc
clocks:
items:
......
# 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>;
};
......@@ -13,13 +13,17 @@ Required properties :
"qcom,rpmcc-msm8660", "qcom,rpmcc"
"qcom,rpmcc-apq8060", "qcom,rpmcc"
"qcom,rpmcc-msm8916", "qcom,rpmcc"
"qcom,rpmcc-msm8936", "qcom,rpmcc"
"qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-msm8976", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc"
"qcom,rpmcc-ipq806x", "qcom,rpmcc"
"qcom,rpmcc-msm8992",·"qcom,rpmcc"
"qcom,rpmcc-msm8994",·"qcom,rpmcc"
"qcom,rpmcc-msm8996", "qcom,rpmcc"
"qcom,rpmcc-msm8998", "qcom,rpmcc"
"qcom,rpmcc-qcs404", "qcom,rpmcc"
"qcom,rpmcc-sdm660", "qcom,rpmcc"
- #clock-cells : shall contain 1
......
# 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>;
};
...
# 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>;
};
...
......@@ -8324,8 +8324,9 @@ W: https://github.com/o2genum/ideapad-slidebar
F: drivers/input/misc/ideapad_slidebar.c
IDT VersaClock 5 CLOCK DRIVER
M: Marek Vasut <marek.vasut@gmail.com>
M: Luca Ceresoli <luca@lucaceresoli.net>
S: Maintained
F: Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
F: drivers/clk/clk-versaclock5.c
IEEE 802.15.4 SUBSYSTEM
......
# 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
bool "Broadcom BCM2835 clock support"
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
......
......@@ -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-bcm21664.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-aux.o
obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o
......
// 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");
......@@ -314,6 +314,7 @@ struct bcm2835_cprman {
struct device *dev;
void __iomem *regs;
spinlock_t regs_lock; /* spinlock for all clocks */
unsigned int soc;
/*
* Real names of cprman clock parents looked up through
......@@ -421,6 +422,7 @@ struct bcm2835_pll_data {
u32 reference_enable_mask;
/* Bit in CM_LOCK to indicate when the PLL has locked. */
u32 lock_mask;
u32 flags;
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;
}
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,
unsigned long parent_rate,
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;
pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT;
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) {
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_cprman *cprman = pll->cprman;
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;
u32 ndiv, fdiv, a2w_ctl;
u32 ana[4];
......@@ -682,7 +699,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
for (i = 3; i >= 0; i--)
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->set0;
......@@ -692,10 +709,10 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
ana[3] |= data->ana->set3;
if (was_using_prediv && !use_fb_prediv) {
ana[1] &= ~data->ana->fb_prediv_mask;
ana[1] &= ~prediv_mask;
do_ana_setup_first = true;
} else if (!was_using_prediv && use_fb_prediv) {
ana[1] |= data->ana->fb_prediv_mask;
ana[1] |= prediv_mask;
do_ana_setup_first = false;
} else {
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.name = pll_data->name;
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);
if (!pll)
......@@ -1684,10 +1701,33 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.fixed_divider = 1,
.flags = CLK_SET_RATE_PARENT),
/*
* PLLB is used for the ARM's clock. Controlled by firmware, see
* clk-raspberrypi.c.
*/
/* PLLB is used for the ARM's clock. */
[BCM2835_PLLB] = REGISTER_PLL(
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.
......@@ -2238,6 +2278,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cprman);
cprman->onecell.num = asize;
cprman->soc = pdata->soc;
hws = cprman->onecell.hws;
for (i = 0; i < asize; i++) {
......
......@@ -6,6 +6,14 @@
#include <linux/of_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 {
const char * const name;
u8 bit;
......@@ -20,126 +28,458 @@ struct clk_bcm63xx_hw {
};
static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
{ .name = "mac", .bit = 3, },
{ .name = "tc", .bit = 5, },
{ .name = "us_top", .bit = 6, },
{ .name = "ds_top", .bit = 7, },
{ .name = "acm", .bit = 8, },
{ .name = "spi", .bit = 9, },
{ .name = "usbs", .bit = 10, },
{ .name = "bmu", .bit = 11, },
{ .name = "pcm", .bit = 12, },
{ .name = "ntp", .bit = 13, },
{ .name = "acp_b", .bit = 14, },
{ .name = "acp_a", .bit = 15, },
{ .name = "emusb", .bit = 17, },
{ .name = "enet0", .bit = 18, },
{ .name = "enet1", .bit = 19, },
{ .name = "usbsu", .bit = 20, },
{ .name = "ephy", .bit = 21, },
{ },
{
.name = "mac",
.bit = BCM3368_CLK_MAC,
}, {
.name = "tc",
.bit = BCM3368_CLK_TC,
}, {
.name = "us_top",
.bit = BCM3368_CLK_US_TOP,
}, {
.name = "ds_top",
.bit = BCM3368_CLK_DS_TOP,
}, {
.name = "acm",
.bit = BCM3368_CLK_ACM,
}, {
.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[] = {
{ .name = "phy_mips", .bit = 0, },
{ .name = "adsl_qproc", .bit = 1, },
{ .name = "adsl_afe", .bit = 2, },
{ .name = "adsl", .bit = 3, },
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
{ .name = "sar", .bit = 5, },
{ .name = "pcm", .bit = 6, },
{ .name = "usbd", .bit = 7, },
{ .name = "usbh", .bit = 8, },
{ .name = "hsspi", .bit = 9, },
{ .name = "pcie", .bit = 10, },
{ .name = "robosw", .bit = 11, },
{ },
{
.name = "phy_mips",
.bit = BCM6328_CLK_PHYMIPS,
}, {
.name = "adsl_qproc",
.bit = BCM6328_CLK_ADSL_QPROC,
}, {
.name = "adsl_afe",
.bit = BCM6328_CLK_ADSL_AFE,
}, {
.name = "adsl",
.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[] = {
{ .name = "enet", .bit = 4, },
{ .name = "adslphy", .bit = 5, },
{ .name = "pcm", .bit = 8, },
{ .name = "spi", .bit = 9, },
{ .name = "usbs", .bit = 10, },
{ .name = "sar", .bit = 11, },
{ .name = "emusb", .bit = 17, },
{ .name = "enet0", .bit = 18, },
{ .name = "enet1", .bit = 19, },
{ .name = "usbsu", .bit = 20, },
{ .name = "ephy", .bit = 21, },
{ },
{
.name = "enet",
.bit = BCM6358_CLK_ENET,
}, {
.name = "adslphy",
.bit = BCM6358_CLK_ADSLPHY,
}, {
.name = "pcm",
.bit = BCM6358_CLK_PCM,
}, {
.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[] = {
{ .name = "adsl_qproc", .bit = 1, },
{ .name = "adsl_afe", .bit = 2, },
{ .name = "adsl", .bit = 3, },
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
{ .name = "wlan_ocp", .bit = 5, },
{ .name = "swpkt_usb", .bit = 7, },
{ .name = "swpkt_sar", .bit = 8, },
{ .name = "sar", .bit = 9, },
{ .name = "robosw", .bit = 10, },
{ .name = "pcm", .bit = 11, },
{ .name = "usbd", .bit = 12, },
{ .name = "usbh", .bit = 13, },
{ .name = "ipsec", .bit = 14, },
{ .name = "spi", .bit = 15, },
{ .name = "hsspi", .bit = 16, },
{ .name = "pcie", .bit = 17, },
{ .name = "fap", .bit = 18, },
{ .name = "phymips", .bit = 19, },
{ .name = "nand", .bit = 20, },
{ },
{
.name = "adsl_qproc",
.bit = BCM6362_CLK_ADSL_QPROC,
}, {
.name = "adsl_afe",
.bit = BCM6362_CLK_ADSL_AFE,
}, {
.name = "adsl",
.bit = BCM6362_CLK_ADSL,
}, {
.name = "mips",
.bit = BCM6362_CLK_MIPS,
.flags = CLK_IS_CRITICAL,
}, {
.name = "wlan_ocp",
.bit = BCM6362_CLK_WLAN_OCP,
}, {
.name = "swpkt_usb",
.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[] = {
{ .name = "vdsl_qproc", .bit = 2, },
{ .name = "vdsl_afe", .bit = 3, },
{ .name = "vdsl_bonding", .bit = 4, },
{ .name = "vdsl", .bit = 5, },
{ .name = "phymips", .bit = 6, },
{ .name = "swpkt_usb", .bit = 7, },
{ .name = "swpkt_sar", .bit = 8, },
{ .name = "spi", .bit = 9, },
{ .name = "usbd", .bit = 10, },
{ .name = "sar", .bit = 11, },
{ .name = "robosw", .bit = 12, },
{ .name = "utopia", .bit = 13, },
{ .name = "pcm", .bit = 14, },
{ .name = "usbh", .bit = 15, },
{ .name = "disable_gless", .bit = 16, },
{ .name = "nand", .bit = 17, },
{ .name = "ipsec", .bit = 18, },
{ },
{
.name = "vdsl_qproc",
.bit = BCM6368_CLK_VDSL_QPROC,
}, {
.name = "vdsl_afe",
.bit = BCM6368_CLK_VDSL_AFE,
}, {
.name = "vdsl_bonding",
.bit = BCM6368_CLK_VDSL_BONDING,
}, {
.name = "vdsl",
.bit = BCM6368_CLK_VDSL,
}, {
.name = "phymips",
.bit = BCM6368_CLK_PHYMIPS,
}, {
.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[] = {
{ .name = "disable_gless", .bit = 0, },
{ .name = "vdsl_qproc", .bit = 1, },
{ .name = "vdsl_afe", .bit = 2, },
{ .name = "vdsl", .bit = 3, },
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
{ .name = "wlan_ocp", .bit = 5, },
{ .name = "dect", .bit = 6, },
{ .name = "fap0", .bit = 7, },
{ .name = "fap1", .bit = 8, },
{ .name = "sar", .bit = 9, },
{ .name = "robosw", .bit = 10, },
{ .name = "pcm", .bit = 11, },
{ .name = "usbd", .bit = 12, },
{ .name = "usbh", .bit = 13, },
{ .name = "ipsec", .bit = 14, },
{ .name = "spi", .bit = 15, },
{ .name = "hsspi", .bit = 16, },
{ .name = "pcie", .bit = 17, },
{ .name = "phymips", .bit = 18, },
{ .name = "gmac", .bit = 19, },
{ .name = "nand", .bit = 20, },
{ .name = "tbus", .bit = 27, },
{ .name = "robosw250", .bit = 31, },
{ },
{
.name = "disable_gless",
.bit = BCM63268_CLK_DIS_GLESS,
}, {
.name = "vdsl_qproc",
.bit = BCM63268_CLK_VDSL_QPROC,
}, {
.name = "vdsl_afe",
.bit = BCM63268_CLK_VDSL_AFE,
}, {
.name = "vdsl",
.bit = BCM63268_CLK_VDSL,
}, {
.name = "mips",
.bit = BCM63268_CLK_MIPS,
.flags = CLK_IS_CRITICAL,
}, {
.name = "wlan_ocp",
.bit = BCM63268_CLK_WLAN_OCP,
}, {
.name = "dect",
.bit = BCM63268_CLK_DECT,
}, {
.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)
......@@ -155,6 +495,7 @@ static int clk_bcm63xx_probe(struct platform_device *pdev)
for (entry = table; entry->name; entry++)
maxbit = max_t(u8, maxbit, entry->bit);
maxbit++;
hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
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[] = {
{ .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,bcm6358-clocks", .data = &bcm6358_clocks, },
{ .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },
......
......@@ -18,30 +18,56 @@
#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_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 device *dev;
struct rpi_firmware *firmware;
struct platform_device *cpufreq;
};
struct raspberrypi_clk_data {
struct clk_hw hw;
unsigned long min_rate;
unsigned long max_rate;
unsigned int id;
struct clk_hw pllb;
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;
} __packed;
static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
u32 clk, u32 *val)
static int raspberrypi_clock_property(struct rpi_firmware *firmware,
const struct raspberrypi_clk_data *data,
u32 tag, u32 *val)
{
struct raspberrypi_firmware_prop msg = {
.id = cpu_to_le32(clk),
.id = cpu_to_le32(data->id),
.val = cpu_to_le32(*val),
.disable_turbo = cpu_to_le32(1),
};
......@@ -83,16 +110,16 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
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,
pllb);
struct raspberrypi_clk_data *data =
container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0;
int ret;
ret = raspberrypi_clock_property(rpi->firmware,
RPI_FIRMWARE_GET_CLOCK_STATE,
RPI_FIRMWARE_ARM_CLK_ID, &val);
ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_CLOCK_STATE, &val);
if (ret)
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)
{
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
pllb);
struct raspberrypi_clk_data *data =
container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0;
int ret;
ret = raspberrypi_clock_property(rpi->firmware,
RPI_FIRMWARE_GET_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&val);
ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_CLOCK_RATE, &val);
if (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)
{
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
pllb);
u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
struct raspberrypi_clk_data *data =
container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 _rate = rate;
int ret;
ret = raspberrypi_clock_property(rpi->firmware,
RPI_FIRMWARE_SET_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&new_rate);
ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_SET_CLOCK_RATE, &_rate);
if (ret)
dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
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;
}
/*
* Sadly there is no firmware rate rounding interface. We borrowed it from
* clk-bcm2835.
*/
static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
pllb);
u64 div, final_rate;
u32 ndiv, fdiv;
/* We can't use req->rate directly as it would overflow */
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;
/*
* The firmware will do the rounding but that isn't part of
* the interface with the firmware, so we just do our best
* here.
*/
req->rate = clamp(req->rate, req->min_rate, req->max_rate);
return 0;
}
static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
.is_prepared = raspberrypi_fw_pll_is_on,
.recalc_rate = raspberrypi_fw_pll_get_rate,
.set_rate = raspberrypi_fw_pll_set_rate,
.determine_rate = raspberrypi_pll_determine_rate,
static const struct clk_ops raspberrypi_firmware_clk_ops = {
.is_prepared = raspberrypi_fw_is_prepared,
.recalc_rate = raspberrypi_fw_get_rate,
.determine_rate = raspberrypi_fw_dumb_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 clk_init_data init;
struct raspberrypi_clk_data *data;
struct clk_init_data init = {};
u32 min_rate, max_rate;
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.parent_names = (const char *[]){ "osc" };
init.num_parents = 1;
init.name = "pllb";
init.ops = &raspberrypi_firmware_pll_clk_ops;
init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
init.name = devm_kasprintf(rpi->dev, GFP_KERNEL,
"fw-clk-%s",
rpi_firmware_clk_names[id]);
init.ops = &raspberrypi_firmware_clk_ops;
init.flags = CLK_GET_RATE_NOCACHE;
/* Get min & max rates set by the firmware */
ret = raspberrypi_clock_property(rpi->firmware,
data->hw.init = &init;
ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&min_rate);
if (ret) {
dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
init.name, ret);
return ret;
dev_err(rpi->dev, "Failed to get clock %d min freq: %d",
id, 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_ARM_CLK_ID,
&max_rate);
if (ret) {
dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
init.name, ret);
return ret;
}
if (!min_rate || !max_rate) {
dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
min_rate, max_rate);
return -EINVAL;
dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n",
id, ret);
return ERR_PTR(ret);
}
dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
min_rate, max_rate);
ret = devm_clk_hw_register(rpi->dev, &data->hw);
if (ret)
return ERR_PTR(ret);
rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
clk_hw_set_rate_range(&data->hw, min_rate, max_rate);
rpi->pllb.init = &init;
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);
}
}
return devm_clk_hw_register(rpi->dev, &rpi->pllb);
return &data->hw;
}
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,
"pllb_arm", "pllb",
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);
}
struct rpi_firmware_get_clocks_response *clks;
int ret;
rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
if (!rpi->pllb_arm_lookup) {
dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
clk_hw_unregister_fixed_factor(rpi->pllb_arm);
clks = devm_kcalloc(rpi->dev,
sizeof(*clks), RPI_FIRMWARE_NUM_CLK_ID,
GFP_KERNEL);
if (!clks)
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;
......@@ -249,12 +291,21 @@ static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
static int raspberrypi_clk_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data;
struct device_node *firmware_node;
struct device *dev = &pdev->dev;
struct rpi_firmware *firmware;
struct raspberrypi_clk *rpi;
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,
"raspberrypi,bcm2835-firmware");
if (!firmware_node) {
......@@ -275,13 +326,18 @@ static int raspberrypi_clk_probe(struct platform_device *pdev)
rpi->firmware = firmware;
platform_set_drvdata(pdev, rpi);
ret = raspberrypi_register_pllb(rpi);
if (ret) {
dev_err(dev, "Failed to initialize pllb, %d\n", ret);
clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
RPI_FIRMWARE_NUM_CLK_ID),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
ret = raspberrypi_discover_clocks(rpi, clk_data);
if (ret)
return ret;
}
ret = raspberrypi_register_pllb_arm(rpi);
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clk_data);
if (ret)
return ret;
......@@ -300,9 +356,16 @@ static int raspberrypi_clk_remove(struct platform_device *pdev)
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 = {
.driver = {
.name = "raspberrypi-clk",
.of_match_table = raspberrypi_clk_match,
},
.probe = raspberrypi_clk_probe,
.remove = raspberrypi_clk_remove,
......
......@@ -24,6 +24,8 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <dt-bindings/clk/versaclock.h>
/* VersaClock5 registers */
#define VC5_OTP_CONTROL 0x00
......@@ -89,6 +91,28 @@
/* Clock control register for clock 1,2 */
#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_OE_SHDN 0x68
......@@ -145,6 +169,14 @@ struct vc5_hw_data {
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 i2c_client *client;
struct regmap *regmap;
......@@ -158,31 +190,7 @@ struct vc5_driver_data {
struct clk_hw clk_pfd;
struct vc5_hw_data clk_pll;
struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
struct vc5_hw_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",
struct vc5_out_data clk_out[VC5_MAX_CLK_OUT_NUM];
};
/*
......@@ -565,7 +573,7 @@ static const struct clk_ops vc5_fod_ops = {
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;
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
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),
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;
}
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;
/* 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)
{
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;
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
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)
{
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;
const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
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 int vc5_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct vc5_driver_data *vc5;
struct clk_init_data init;
......@@ -702,7 +836,7 @@ static int vc5_probe(struct i2c_client *client,
int ret;
vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
if (vc5 == NULL)
if (!vc5)
return -ENOMEM;
i2c_set_clientdata(client, vc5);
......@@ -750,115 +884,116 @@ static int vc5_probe(struct i2c_client *client,
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.flags = 0;
init.parent_names = parent_names;
vc5->clk_mux.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
/* Register frequency doubler */
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.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;
vc5->clk_mul.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
}
/* Register PFD */
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.flags = CLK_SET_RATE_PARENT;
init.parent_names = parent_names;
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
init.parent_names = vc5_mux_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1;
vc5->clk_pfd.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
/* Register PLL */
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.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;
vc5->clk_pll.num = 0;
vc5->clk_pll.vc5 = vc5;
vc5->clk_pll.hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
/* Register FODs */
for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
idx = vc5_map_index_to_output(vc5->chip_info->model, n);
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.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;
vc5->clk_fod[n].num = idx;
vc5->clk_fod[n].vc5 = vc5;
vc5->clk_fod[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
}
/* Register MUX-connected OUT0_I2C_SELB output */
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.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;
vc5->clk_out[0].num = idx;
vc5->clk_out[0].vc5 = vc5;
vc5->clk_out[0].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
/* Register FOD-connected OUTx outputs */
for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
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)
parent_names[1] = vc5_mux_names[0];
parent_names[1] = clk_hw_get_name(&vc5->clk_mux);
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));
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.flags = CLK_SET_RATE_PARENT;
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].vc5 = vc5;
vc5->clk_out[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev,
&vc5->clk_out[n].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */
/* Fetch Clock Output configuration from DT (if specified) */
ret = vc5_get_output_config(client, &vc5->clk_out[n]);
if (ret)
goto err_clk;
}
}
ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
if (ret) {
......@@ -883,6 +1020,9 @@ static int vc5_probe(struct i2c_client *client,
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:
if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
clk_unregister_fixed_rate(vc5->pin_xin);
......
......@@ -1400,6 +1400,21 @@ int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
}
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)
{
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()
* @dev: device that is unregistering the clock data
* @clk: clock to unregister
*
* 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
* @get: Get clock callback. Returns NULL or a struct clk for the
* 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
*/
struct of_clk_provider {
......
......@@ -37,6 +37,15 @@ config QCOM_CLK_APCS_MSM8916
Say Y if you want to support CPU frequency scaling on devices
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
tristate "RPM based Clock Controller"
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,
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
tristate "IPQ4019 Global Clock Controller"
help
......@@ -280,6 +308,15 @@ config SC_GCC_7180
Say Y if you want to use peripheral devices such as UART, SPI,
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
tristate "SC7180 Graphics Clock Controller"
select SC_GCC_7180
......@@ -391,6 +428,22 @@ config SM_GCC_8250
Say Y if you want to use peripheral devices such as UART,
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
tristate "SPMI PMIC clkdiv Support"
depends on SPMI || COMPILE_TEST
......
......@@ -19,6 +19,8 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
# Keep alphabetically sorted by config
obj-$(CONFIG_APQ_GCC_8084) += gcc-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_6018) += gcc-ipq6018.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_QCOM_A53PLL) += a53-pll.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_RPMH) += clk-rpmh.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_GCC_7180) += gcc-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_VIDEOCC_7180) += videocc-sc7180.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_SM_GCC_8150) += gcc-sm8150.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_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
......
// 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");
// 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");
......@@ -56,7 +56,6 @@
#define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS])
#define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE])
#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] = {
[CLK_ALPHA_PLL_TYPE_DEFAULT] = {
......@@ -102,22 +101,6 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
[PLL_OFF_FRAC] = 0x38,
},
[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_CAL_L_VAL] = 0x08,
[PLL_OFF_USER_CTL] = 0x0c,
......@@ -156,9 +139,12 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
#define PLL_OUT_MASK 0x7
#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 */
#define LUCID_PLL_CAL_VAL 0x44
#define LUCID_PCAL_DONE BIT(26)
#define LUCID_PCAL_DONE BIT(27)
#define pll_alpha_width(p) \
((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);
const struct clk_ops clk_trion_fixed_pll_ops = {
const struct clk_ops clk_alpha_pll_fixed_trion_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_trion_fixed_pll_ops);
EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_trion_ops);
static unsigned long
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);
}
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,
.round_rate = clk_trion_pll_postdiv_round_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,
unsigned long rate, unsigned long *prate)
......@@ -1399,13 +1385,13 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
* @regmap: register map
* @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)
{
if (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)
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 */
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.
*/
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);
u32 regval;
......@@ -1472,7 +1458,7 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw)
/* Return early if calibration is not needed. */
regmap_read(pll->clkr.regmap, PLL_STATUS(pll), &regval);
if (regval & LUCID_PCAL_DONE)
if (regval & pcal_done)
return 0;
/* On/off to calibrate */
......@@ -1483,7 +1469,17 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw)
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)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
......@@ -1537,25 +1533,27 @@ static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
const struct clk_ops clk_alpha_pll_lucid_ops = {
.prepare = alpha_pll_lucid_prepare,
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_lucid_set_rate,
.set_rate = alpha_pll_trion_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops);
EXPORT_SYMBOL_GPL(clk_alpha_pll_trion_ops);
const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
const struct clk_ops clk_alpha_pll_lucid_ops = {
.prepare = alpha_pll_lucid_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_fixed_lucid_ops);
EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops);
const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
.recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate,
......
......@@ -14,7 +14,7 @@ enum {
CLK_ALPHA_PLL_TYPE_BRAMMO,
CLK_ALPHA_PLL_TYPE_FABIA,
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,
};
......@@ -47,6 +47,12 @@ struct pll_vco {
u32 val;
};
#define VCO(a, b, c) { \
.val = a,\
.min_freq = b,\
.max_freq = c,\
}
/**
* struct clk_alpha_pll - phase locked loop (PLL)
* @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_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_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;
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
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);
#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
// 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");
......@@ -452,6 +452,55 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
.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 */
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);
......@@ -574,6 +623,175 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
.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 */
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);
......@@ -766,13 +984,92 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
.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[] = {
{ .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-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-msm8998", .data = &rpm_clk_msm8998 },
{ .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);
......
......@@ -3089,7 +3089,7 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
regmap_write(regmap, 0x3cf8, 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 = {
......
......@@ -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[] = {
&gpll0_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_GP2_CLK] = &gcc_gp2_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[] = {
......@@ -4678,6 +4737,7 @@ static const struct qcom_reset_map gcc_ipq8074_resets[] = {
[GCC_PCIE0_AXI_SLAVE_ARES] = { 0x75040, 4 },
[GCC_PCIE0_AHB_ARES] = { 0x75040, 5 },
[GCC_PCIE0_AXI_MASTER_STICKY_ARES] = { 0x75040, 6 },
[GCC_PCIE0_AXI_SLAVE_STICKY_ARES] = { 0x75040, 7 },
[GCC_PCIE1_PIPE_ARES] = { 0x76040, 0 },
[GCC_PCIE1_SLEEP_ARES] = { 0x76040, 1 },
[GCC_PCIE1_CORE_STICKY_ARES] = { 0x76040, 2 },
......
......@@ -1061,7 +1061,7 @@ static struct clk_branch gcc_disp_gpll0_clk_src = {
.hw = &gpll0.clkr.hw,
},
.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 = {
.gdscr = 0x77004,
.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_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.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[] = {
......
......@@ -1715,6 +1715,9 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = {
static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
.halt_reg = 0x8a004,
.halt_check = BRANCH_HALT,
.hwcg_reg = 0x8a004,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0x8a004,
.enable_mask = BIT(0),
......@@ -2402,6 +2405,7 @@ static const struct qcom_reset_map gcc_sdm660_resets[] = {
[GCC_USB_20_BCR] = { 0x2f000 },
[GCC_USB_30_BCR] = { 0xf000 },
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
[GCC_MSS_RESTART] = { 0x79000 },
};
static const struct regmap_config gcc_sdm660_regmap_config = {
......
// 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>
......@@ -1344,7 +1344,7 @@ static struct clk_branch gcc_disp_gpll0_clk_src = {
"gpll0",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
.ops = &clk_branch2_aon_ops,
},
},
};
......
......@@ -34,14 +34,8 @@ enum {
P_SLEEP_CLK,
};
static const struct pll_vco trion_vco[] = {
{ 249600000, 2000000000, 0 },
};
static struct clk_alpha_pll gpll0 = {
.offset = 0x0,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = {
.enable_reg = 0x52000,
......@@ -53,7 +47,7 @@ static struct clk_alpha_pll gpll0 = {
.name = "bi_tcxo",
},
.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,
},
.num_parents = 1,
.ops = &clk_trion_pll_postdiv_ops,
.ops = &clk_alpha_pll_postdiv_trion_ops,
},
};
static struct clk_alpha_pll gpll7 = {
.offset = 0x1a000,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = {
.enable_reg = 0x52000,
......@@ -98,15 +90,13 @@ static struct clk_alpha_pll gpll7 = {
.name = "bi_tcxo",
},
.num_parents = 1,
.ops = &clk_trion_fixed_pll_ops,
.ops = &clk_alpha_pll_fixed_trion_ops,
},
},
};
static struct clk_alpha_pll gpll9 = {
.offset = 0x1c000,
.vco_table = trion_vco,
.num_vco = ARRAY_SIZE(trion_vco),
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
.clkr = {
.enable_reg = 0x52000,
......@@ -118,7 +108,7 @@ static struct clk_alpha_pll gpll9 = {
.name = "bi_tcxo",
},
.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 = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52004,
.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 = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52004,
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_div_clk_src",
.parent_hws = (const struct clk_hw *[]){
&gcc_gpu_gpll0_clk_src.clkr.hw },
&gpll0_out_even.clkr.hw },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.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 = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52004,
.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 = {
.halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52004,
.enable_mask = BIT(19),
.hw.init = &(struct clk_init_data){
.name = "gcc_npu_gpll0_div_clk_src",
.parent_hws = (const struct clk_hw *[]){
&gcc_npu_gpll0_clk_src.clkr.hw },
&gpll0_out_even.clkr.hw },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
......
......@@ -6,6 +6,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
......@@ -29,6 +30,7 @@
/* CFG_GDSCR */
#define GDSC_POWER_UP_COMPLETE BIT(16)
#define GDSC_POWER_DOWN_COMPLETE BIT(15)
#define GDSC_RETAIN_FF_ENABLE BIT(11)
#define CFG_GDSCR_OFFSET 0x4
/* 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,
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)
{
struct gdsc *sc = domain_to_gdsc(domain);
......@@ -268,6 +278,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
udelay(1);
}
if (sc->flags & RETAIN_FF_ENABLE)
gdsc_retain_ff_on(sc);
return 0;
}
......@@ -433,3 +446,29 @@ void gdsc_unregister(struct gdsc_desc *desc)
}
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);
......@@ -50,6 +50,7 @@ struct gdsc {
#define AON_RESET BIT(4)
#define POLL_CFG_GDSCR BIT(5)
#define ALWAYS_ON BIT(6)
#define RETAIN_FF_ENABLE BIT(7)
struct reset_controller_dev *rcdev;
unsigned int *resets;
unsigned int reset_count;
......@@ -68,6 +69,7 @@ struct gdsc_desc {
int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *,
struct regmap *);
void gdsc_unregister(struct gdsc_desc *desc);
int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain);
#else
static inline int gdsc_register(struct gdsc_desc *desc,
struct reset_controller_dev *rcdev,
......
......@@ -170,37 +170,12 @@ static struct gdsc cx_gdsc = {
.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 = {
.gdscr = 0x100c,
.clamp_io_ctrl = 0x1508,
.pd = {
.name = "gx_gdsc",
.power_on = gx_gdsc_enable,
.power_on = gdsc_gx_do_nothing_enable,
},
.pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO,
......
......@@ -131,37 +131,12 @@ static struct gdsc gpu_cx_gdsc = {
.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 = {
.gdscr = 0x100c,
.clamp_io_ctrl = 0x1508,
.pd = {
.name = "gpu_gx_gdsc",
.power_on = gx_gdsc_enable,
.power_on = gdsc_gx_do_nothing_enable,
},
.pwrsts = PWRSTS_OFF_ON,
.flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
......
// 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");
// 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");
// 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");
......@@ -208,6 +208,20 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
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",
-1, NULL, 0);
}
......
......@@ -82,6 +82,7 @@ config FSL_IMX8_DDR_PMU
config QCOM_L2_PMU
bool "Qualcomm Technologies L2-cache PMU"
depends on ARCH_QCOM && ARM64 && ACPI
select QCOM_KRYO_L2_ACCESSORS
help
Provides support for the L2 cache performance monitor unit (PMU)
in Qualcomm Technologies processors.
......
......@@ -23,6 +23,7 @@
#include <asm/barrier.h>
#include <asm/local64.h>
#include <asm/sysreg.h>
#include <soc/qcom/kryo-l2-accessors.h>
#define MAX_L2_CTRS 9
......@@ -79,8 +80,6 @@
#define L2_COUNTER_RELOAD BIT_ULL(31)
#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)
......@@ -99,48 +98,7 @@
#define L2_EVENT_STREX 0x421
#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;
......@@ -211,28 +169,28 @@ static inline struct cluster_pmu *get_cluster_pmu(
static void cluster_pmu_reset(void)
{
/* Reset all counters */
set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
set_l2_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask);
set_l2_indirect_reg(L2PMINTENCLR, l2_counter_present_mask);
set_l2_indirect_reg(L2PMOVSCLR, l2_counter_present_mask);
kryo_l2_set_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
kryo_l2_set_indirect_reg(L2PMCNTENCLR, l2_counter_present_mask);
kryo_l2_set_indirect_reg(L2PMINTENCLR, l2_counter_present_mask);
kryo_l2_set_indirect_reg(L2PMOVSCLR, l2_counter_present_mask);
}
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)
{
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)
{
if (idx == l2_cycle_ctr_idx)
set_l2_indirect_reg(L2PMCCNTR, value);
kryo_l2_set_indirect_reg(L2PMCCNTR, value);
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)
......@@ -240,46 +198,46 @@ static inline u64 cluster_pmu_counter_get_value(u32 idx)
u64 value;
if (idx == l2_cycle_ctr_idx)
value = get_l2_indirect_reg(L2PMCCNTR);
value = kryo_l2_get_indirect_reg(L2PMCCNTR);
else
value = get_l2_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx));
value = kryo_l2_get_indirect_reg(reg_idx(IA_L2PMXEVCNTR, idx));
return value;
}
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)
{
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)
{
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)
{
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)
{
set_l2_indirect_reg(L2PMCCNTCR, val);
kryo_l2_set_indirect_reg(L2PMCCNTCR, 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)
{
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,
......@@ -295,11 +253,11 @@ static void cluster_pmu_set_resr(struct cluster_pmu *cluster,
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 |= field;
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);
}
......@@ -315,14 +273,14 @@ static inline void cluster_pmu_set_evfilter_sys_mode(u32 ctr)
L2PMXEVFILTER_ORGFILTER_IDINDEP |
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)
{
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;
}
......@@ -767,7 +725,7 @@ static int get_num_counters(void)
{
int val;
val = get_l2_indirect_reg(L2PMCR);
val = kryo_l2_get_indirect_reg(L2PMCR);
/*
* Read number of counters from L2PMCR and add 1
......
......@@ -11,6 +11,7 @@
* Maxime Ripard <maxime.ripard@free-electrons.com>
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
......@@ -18,10 +19,9 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/spinlock.h>
#include "reset-simple.h"
static inline struct reset_simple_data *
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);
}
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,
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 = {
.assert = reset_simple_assert,
.deassert = reset_simple_deassert,
.reset = reset_simple_reset,
.status = reset_simple_status,
};
EXPORT_SYMBOL_GPL(reset_simple_ops);
......
......@@ -11,13 +11,12 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/reset/socfpga.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "reset-simple.h"
#define SOCFPGA_NR_BANKS 8
static int a10_reset_init(struct device_node *np)
......
......@@ -14,13 +14,12 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/reset/sunxi.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "reset-simple.h"
static int sunxi_reset_init(struct device_node *np)
{
struct reset_simple_data *data;
......
......@@ -9,8 +9,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include "reset-simple.h"
#include <linux/reset/reset-simple.h>
#define MAX_CLKS 2
#define MAX_RSTS 2
......
......@@ -53,6 +53,10 @@ config QCOM_LLCC
SDM845. This provides interfaces to clients that use the LLCC.
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
tristate
select QCOM_SCM
......
......@@ -24,3 +24,4 @@ obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
// 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);
/* 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
/* 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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
......@@ -230,6 +230,9 @@
#define GCC_GP1_CLK 221
#define GCC_GP2_CLK 222
#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_QUP1_BCR 1
......@@ -362,5 +365,6 @@
#define GCC_PCIE1_AXI_SLAVE_ARES 128
#define GCC_PCIE1_AHB_ARES 129
#define GCC_PCIE1_AXI_MASTER_STICKY_ARES 130
#define GCC_PCIE0_AXI_SLAVE_STICKY_ARES 131
#endif
......@@ -138,6 +138,7 @@
#define GCC_MSS_Q6_MEMNOC_AXI_CLK 128
#define GCC_MSS_SNOC_AXI_CLK 129
#define GCC_SEC_CTRL_CLK_SRC 130
#define GCC_LPASS_CFG_NOC_SWAY_CLK 131
/* GCC resets */
#define GCC_QUSB2PHY_PRIM_BCR 0
......
......@@ -152,5 +152,6 @@
#define GCC_USB_20_BCR 6
#define GCC_USB_30_BCR 7
#define GCC_USB_PHY_CFG_AHB2PHY_BCR 8
#define GCC_MSS_RESTART 9
#endif
/* 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
/* 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
/* 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
......@@ -133,5 +133,21 @@
#define RPM_SMD_RF_CLK3_A 87
#define RPM_SMD_RF_CLK3_PIN 88
#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
......@@ -189,7 +189,7 @@ struct clk_duty {
* and >= numerator) Return 0 on success, otherwise -EERROR.
*
* @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
* initialisation magic for CCF to get an accurate view of the
* clock. It may also be used dynamic resource allocation is
......
......@@ -27,6 +27,12 @@
* @status_active_low: if true, bits read back as cleared while the reset is
* asserted. Otherwise, bits read back as set while the
* 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 {
spinlock_t lock;
......@@ -34,6 +40,7 @@ struct reset_simple_data {
struct reset_controller_dev rcdev;
bool active_low;
bool status_active_low;
unsigned int reset_us;
};
extern const struct reset_control_ops reset_simple_ops;
......
/* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment