summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt14
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml59
-rw-r--r--Documentation/devicetree/bindings/clock/brcm,bcm2711-dvp.yaml47
-rw-r--r--Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt2
-rw-r--r--Documentation/devicetree/bindings/clock/idt,versaclock5.txt33
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,a53pll.yaml21
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,msm8996-apcc.yaml56
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,rpmcc.txt2
-rw-r--r--drivers/clk/bcm/Kconfig11
-rw-r--r--drivers/clk/bcm/Makefile1
-rw-r--r--drivers/clk/bcm/clk-bcm2711-dvp.c124
-rw-r--r--drivers/clk/bcm/clk-bcm2835.c34
-rw-r--r--drivers/clk/bcm/clk-bcm63xx-gate.c553
-rw-r--r--drivers/clk/bcm/clk-raspberrypi.c311
-rw-r--r--drivers/clk/clk-versaclock5.c240
-rw-r--r--drivers/clk/clk.c15
-rw-r--r--drivers/clk/qcom/Kconfig28
-rw-r--r--drivers/clk/qcom/Makefile3
-rw-r--r--drivers/clk/qcom/apss-ipq-pll.c95
-rw-r--r--drivers/clk/qcom/apss-ipq6018.c106
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h6
-rw-r--r--drivers/clk/qcom/clk-cpu-8996.c538
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c126
-rw-r--r--drivers/clk/socfpga/clk-agilex.c8
-rw-r--r--drivers/firmware/raspberrypi.c14
-rw-r--r--drivers/perf/Kconfig1
-rw-r--r--drivers/perf/qcom_l2_pmu.c90
-rw-r--r--drivers/reset/reset-simple.c23
-rw-r--r--drivers/reset/reset-socfpga.c3
-rw-r--r--drivers/reset/reset-sunxi.c3
-rw-r--r--drivers/reset/reset-uniphier-glue.c3
-rw-r--r--drivers/soc/qcom/Kconfig4
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/kryo-l2-accessors.c57
-rw-r--r--include/dt-bindings/clk/versaclock.h13
-rw-r--r--include/dt-bindings/clock/agilex-clock.h4
-rw-r--r--include/dt-bindings/clock/bcm3368-clock.h24
-rw-r--r--include/dt-bindings/clock/bcm6318-clock.h42
-rw-r--r--include/dt-bindings/clock/bcm63268-clock.h30
-rw-r--r--include/dt-bindings/clock/bcm6328-clock.h19
-rw-r--r--include/dt-bindings/clock/bcm6358-clock.h18
-rw-r--r--include/dt-bindings/clock/bcm6362-clock.h26
-rw-r--r--include/dt-bindings/clock/bcm6368-clock.h24
-rw-r--r--include/dt-bindings/clock/qcom,apss-ipq.h12
-rw-r--r--include/dt-bindings/clock/qcom,rpmcc.h12
-rw-r--r--include/linux/reset/reset-simple.h (renamed from drivers/reset/reset-simple.h)7
-rw-r--r--include/soc/qcom/kryo-l2-accessors.h12
47 files changed, 2502 insertions, 373 deletions
diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt
deleted file mode 100644
index 6824b3180ffb..000000000000
--- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Raspberry Pi VideoCore firmware driver
-
-Required properties:
-
-- compatible: Should be "raspberrypi,bcm2835-firmware"
-- mboxes: Phandle to the firmware device's Mailbox.
- (See: ../mailbox/mailbox.txt for more information)
-
-Example:
-
-firmware {
- compatible = "raspberrypi,bcm2835-firmware";
- mboxes = <&mailbox>;
-};
diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
new file mode 100644
index 000000000000..b48ed875eb8e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
@@ -0,0 +1,59 @@
+# 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>
+
+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>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2711-dvp.yaml b/Documentation/devicetree/bindings/clock/brcm,bcm2711-dvp.yaml
new file mode 100644
index 000000000000..08543ecbe35b
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/brcm,bcm2711-dvp.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/brcm,bcm2711-dvp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM2711 HDMI DVP Device Tree Bindings
+
+maintainers:
+ - Maxime Ripard <mripard@kernel.org>
+
+properties:
+ "#clock-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 1
+
+ compatible:
+ const: brcm,brcm2711-dvp
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+required:
+ - "#clock-cells"
+ - "#reset-cells"
+ - compatible
+ - reg
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ dvp: clock@7ef00000 {
+ compatible = "brcm,brcm2711-dvp";
+ reg = <0x7ef00000 0x10>;
+ clocks = <&clk_108MHz>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt
index 3041657e2f96..3e7ca5530775 100644
--- a/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt
@@ -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"
diff --git a/Documentation/devicetree/bindings/clock/idt,versaclock5.txt b/Documentation/devicetree/bindings/clock/idt,versaclock5.txt
index bcff681a4bd0..6165b6ddb1a9 100644
--- a/Documentation/devicetree/bindings/clock/idt,versaclock5.txt
+++ b/Documentation/devicetree/bindings/clock/idt,versaclock5.txt
@@ -31,6 +31,29 @@ Required properties:
- 5p49v5933 and
- 5p49v5935: (optional) property not present or "clkin".
+For all output ports, a corresponding, optional child node named OUT1,
+OUT2, etc. can represent a each output, and the node can be used to
+specify the following:
+
+- itd,mode: can be one of the following:
+ - VC5_LVPECL
+ - VC5_CMOS
+ - VC5_HCSL33
+ - VC5_LVDS
+ - VC5_CMOS2
+ - VC5_CMOSD
+ - VC5_HCSL25
+
+- idt,voltage-microvolts: can be one of the following
+ - 1800000
+ - 2500000
+ - 3300000
+- idt,slew-percent: Percent of normal, can be one of
+ - 80
+ - 85
+ - 90
+ - 100
+
==Mapping between clock specifier and physical pins==
When referencing the provided clock in the DT using phandle and
@@ -81,6 +104,16 @@ i2c-master-node {
/* Connect XIN input to 25MHz reference */
clocks = <&ref25m>;
clock-names = "xin";
+
+ OUT1 {
+ itd,mode = <VC5_CMOS>;
+ idt,voltage-microvolts = <1800000>;
+ idt,slew-percent = <80>;
+ };
+ OUT2 {
+ ...
+ };
+ ...
};
};
diff --git a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml
index 20d2638b4cd2..db3d0ea6bc7a 100644
--- a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml
@@ -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";
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,msm8996-apcc.yaml b/Documentation/devicetree/bindings/clock/qcom,msm8996-apcc.yaml
new file mode 100644
index 000000000000..d673edeed98d
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,msm8996-apcc.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,kryocc.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:
+ # Example for msm8996
+ - |
+ kryocc: clock-controller@6400000 {
+ compatible = "qcom,msm8996-apcc";
+ reg = <0x6400000 0x90000>;
+ #clock-cells = <1>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
index 90a1349bc713..8786d19ffe17 100644
--- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
@@ -13,6 +13,7 @@ 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"
@@ -20,6 +21,7 @@ Required properties :
"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
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index 8c83977a7dc4..784f12c72365 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -1,4 +1,15 @@
# 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
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 0070ddf6cdd2..edb66b44cb27 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -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
diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-bcm2711-dvp.c
new file mode 100644
index 000000000000..8333e20dc9d2
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm2711-dvp.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2020 Cerno
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reset/reset-simple.h>
+
+#define DVP_HT_RPI_SW_INIT 0x04
+#define DVP_HT_RPI_MISC_CONFIG 0x08
+
+#define NR_CLOCKS 2
+#define NR_RESETS 6
+
+struct clk_dvp {
+ struct clk_hw_onecell_data *data;
+ struct reset_simple_data reset;
+};
+
+static const struct clk_parent_data clk_dvp_parent = {
+ .index = 0,
+};
+
+static int clk_dvp_probe(struct platform_device *pdev)
+{
+ struct clk_hw_onecell_data *data;
+ struct resource *res;
+ struct clk_dvp *dvp;
+ void __iomem *base;
+ int ret;
+
+ dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
+ if (!dvp)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, dvp);
+
+ dvp->data = devm_kzalloc(&pdev->dev,
+ struct_size(dvp->data, hws, NR_CLOCKS),
+ GFP_KERNEL);
+ if (!dvp->data)
+ return -ENOMEM;
+ data = dvp->data;
+
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ dvp->reset.rcdev.owner = THIS_MODULE;
+ dvp->reset.rcdev.nr_resets = NR_RESETS;
+ dvp->reset.rcdev.ops = &reset_simple_ops;
+ dvp->reset.rcdev.of_node = pdev->dev.of_node;
+ dvp->reset.membase = base + DVP_HT_RPI_SW_INIT;
+ spin_lock_init(&dvp->reset.lock);
+
+ ret = devm_reset_controller_register(&pdev->dev, &dvp->reset.rcdev);
+ if (ret)
+ return ret;
+
+ data->hws[0] = clk_hw_register_gate_parent_data(&pdev->dev,
+ "hdmi0-108MHz",
+ &clk_dvp_parent, 0,
+ base + DVP_HT_RPI_MISC_CONFIG, 3,
+ CLK_GATE_SET_TO_DISABLE,
+ &dvp->reset.lock);
+ if (IS_ERR(data->hws[0]))
+ return PTR_ERR(data->hws[0]);
+
+ data->hws[1] = clk_hw_register_gate_parent_data(&pdev->dev,
+ "hdmi1-108MHz",
+ &clk_dvp_parent, 0,
+ base + DVP_HT_RPI_MISC_CONFIG, 4,
+ CLK_GATE_SET_TO_DISABLE,
+ &dvp->reset.lock);
+ if (IS_ERR(data->hws[1])) {
+ ret = PTR_ERR(data->hws[1]);
+ goto unregister_clk0;
+ }
+
+ data->num = NR_CLOCKS;
+ ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+ data);
+ if (ret)
+ goto unregister_clk1;
+
+ return 0;
+
+unregister_clk1:
+ clk_hw_unregister_gate(data->hws[1]);
+
+unregister_clk0:
+ clk_hw_unregister_gate(data->hws[0]);
+ return ret;
+};
+
+static int clk_dvp_remove(struct platform_device *pdev)
+{
+ struct clk_dvp *dvp = platform_get_drvdata(pdev);
+ struct clk_hw_onecell_data *data = dvp->data;
+
+ clk_hw_unregister_gate(data->hws[1]);
+ clk_hw_unregister_gate(data->hws[0]);
+
+ return 0;
+}
+
+static const struct of_device_id clk_dvp_dt_ids[] = {
+ { .compatible = "brcm,brcm2711-dvp", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_dvp_driver = {
+ .probe = clk_dvp_probe,
+ .remove = clk_dvp_remove,
+ .driver = {
+ .name = "brcm2711-dvp",
+ .of_match_table = clk_dvp_dt_ids,
+ },
+};
+module_platform_driver(clk_dvp_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_DESCRIPTION("BCM2711 DVP clock driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 6bb7efa12037..027eba31f793 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -421,6 +421,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;
@@ -1310,7 +1311,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 +1685,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.
diff --git a/drivers/clk/bcm/clk-bcm63xx-gate.c b/drivers/clk/bcm/clk-bcm63xx-gate.c
index 98e884957db8..89297c57881e 100644
--- a/drivers/clk/bcm/clk-bcm63xx-gate.c
+++ b/drivers/clk/bcm/clk-bcm63xx-gate.c
@@ -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, },
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
index 1654fd0eedc9..5cc82954e1ce 100644
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
@@ -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;
+};
- unsigned long min_rate;
- unsigned long max_rate;
+struct raspberrypi_clk_data {
+ struct clk_hw hw;
- struct clk_hw pllb;
- struct clk_hw *pllb_arm;
- struct clk_lookup *pllb_arm_lookup;
+ unsigned int id;
+
+ 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,
- unsigned long parent_rate)
+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,
- unsigned long parent_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,
- struct clk_rate_request *req)
+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,14 +291,23 @@ 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;
- firmware_node = of_find_compatible_node(NULL, NULL,
- "raspberrypi,bcm2835-firmware");
+ /*
+ * 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) {
dev_err(dev, "Missing firmware node\n");
return -ENOENT;
@@ -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,
diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
index fa96659f8023..9a5fb3834b9a 100644
--- a/drivers/clk/clk-versaclock5.c
+++ b/drivers/clk/clk-versaclock5.c
@@ -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
@@ -143,6 +167,8 @@ struct vc5_hw_data {
u32 div_int;
u32 div_frc;
unsigned int num;
+ unsigned int clk_output_cfg0;
+ unsigned int clk_output_cfg0_mask;
};
struct vc5_driver_data {
@@ -161,30 +187,6 @@ struct vc5_driver_data {
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",
-};
-
/*
* VersaClock5 i2c regmap
*/
@@ -591,6 +593,17 @@ 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;
}
@@ -690,10 +703,123 @@ static int vc5_map_index_to_output(const enum vc5_model model,
}
}
+static int vc5_update_mode(struct device_node *np_output,
+ struct vc5_hw_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_hw_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_hw_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_hw_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);
+ np_output = of_get_child_by_name(client->dev.of_node, child_name);
+ kfree(child_name);
+ if (!np_output)
+ goto output_done;
+
+ 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);
+
+output_done:
+ 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;
@@ -742,7 +868,7 @@ static int vc5_probe(struct i2c_client *client,
if (!IS_ERR(vc5->pin_clkin)) {
vc5->clk_mux_ins |= VC5_MUX_IN_CLKIN;
parent_names[init.num_parents++] =
- __clk_get_name(vc5->pin_clkin);
+ __clk_get_name(vc5->pin_clkin);
}
if (!init.num_parents) {
@@ -750,12 +876,13 @@ 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);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
@@ -764,13 +891,16 @@ static int vc5_probe(struct i2c_client *client,
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);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
@@ -780,16 +910,18 @@ static int vc5_probe(struct i2c_client *client,
/* 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);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
@@ -797,15 +929,17 @@ static int vc5_probe(struct i2c_client *client,
/* 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);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
@@ -815,15 +949,18 @@ static int vc5_probe(struct i2c_client *client,
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);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
@@ -833,32 +970,36 @@ static int vc5_probe(struct i2c_client *client,
/* 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);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
- dev_err(&client->dev, "unable to register %s\n",
- init.name);
+ dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
/* 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,13 +1007,18 @@ 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);
+ ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
+ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
+
+ /* 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);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 3f588ed06ce3..236923b25543 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -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;
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index cde6ca90a06b..318c0adfaae1 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -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
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 7ec8561a1270..ae0979bebe18 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -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
diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c
new file mode 100644
index 000000000000..30be87fb222a
--- /dev/null
+++ b/drivers/clk/qcom/apss-ipq-pll.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "clk-alpha-pll.h"
+
+static const u8 ipq_pll_offsets[] = {
+ [PLL_OFF_L_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL] = 0x10,
+ [PLL_OFF_USER_CTL] = 0x18,
+ [PLL_OFF_CONFIG_CTL] = 0x20,
+ [PLL_OFF_CONFIG_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+ [PLL_OFF_TEST_CTL] = 0x30,
+ [PLL_OFF_TEST_CTL_U] = 0x34,
+};
+
+static struct clk_alpha_pll ipq_pll = {
+ .offset = 0x0,
+ .regs = ipq_pll_offsets,
+ .flags = SUPPORTS_DYNAMIC_UPDATE,
+ .clkr = {
+ .enable_reg = 0x0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "a53pll",
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+ },
+};
+
+static const struct alpha_pll_config ipq_pll_config = {
+ .l = 0x37,
+ .config_ctl_val = 0x04141200,
+ .config_ctl_hi_val = 0x0,
+ .early_output_mask = BIT(3),
+ .main_output_mask = BIT(0),
+};
+
+static const struct regmap_config ipq_pll_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x40,
+ .fast_io = true,
+};
+
+static int apss_ipq_pll_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ void __iomem *base;
+ int ret;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &ipq_pll_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_alpha_pll_configure(&ipq_pll, regmap, &ipq_pll_config);
+
+ ret = devm_clk_register_regmap(dev, &ipq_pll.clkr);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &ipq_pll.clkr.hw);
+}
+
+static const struct of_device_id apss_ipq_pll_match_table[] = {
+ { .compatible = "qcom,ipq6018-a53pll" },
+ { }
+};
+
+static struct platform_driver apss_ipq_pll_driver = {
+ .probe = apss_ipq_pll_probe,
+ .driver = {
+ .name = "qcom-ipq-apss-pll",
+ .of_match_table = apss_ipq_pll_match_table,
+ },
+};
+module_platform_driver(apss_ipq_pll_driver);
+
+MODULE_DESCRIPTION("Qualcomm technology Inc APSS ALPHA PLL Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/apss-ipq6018.c b/drivers/clk/qcom/apss-ipq6018.c
new file mode 100644
index 000000000000..d78ff2f310bf
--- /dev/null
+++ b/drivers/clk/qcom/apss-ipq6018.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+
+#include <dt-bindings/clock/qcom,apss-ipq.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-branch.h"
+#include "clk-alpha-pll.h"
+#include "clk-regmap-mux.h"
+
+enum {
+ P_XO,
+ P_APSS_PLL_EARLY,
+};
+
+static const struct clk_parent_data parents_apcs_alias0_clk_src[] = {
+ { .fw_name = "xo" },
+ { .fw_name = "pll" },
+};
+
+static const struct parent_map parents_apcs_alias0_clk_src_map[] = {
+ { P_XO, 0 },
+ { P_APSS_PLL_EARLY, 5 },
+};
+
+static struct clk_regmap_mux apcs_alias0_clk_src = {
+ .reg = 0x0050,
+ .width = 3,
+ .shift = 7,
+ .parent_map = parents_apcs_alias0_clk_src_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "apcs_alias0_clk_src",
+ .parent_data = parents_apcs_alias0_clk_src,
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_branch apcs_alias0_core_clk = {
+ .halt_reg = 0x0058,
+ .clkr = {
+ .enable_reg = 0x0058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "apcs_alias0_core_clk",
+ .parent_hws = (const struct clk_hw *[]){
+ &apcs_alias0_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static const struct regmap_config apss_ipq6018_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1000,
+ .fast_io = true,
+};
+
+static struct clk_regmap *apss_ipq6018_clks[] = {
+ [APCS_ALIAS0_CLK_SRC] = &apcs_alias0_clk_src.clkr,
+ [APCS_ALIAS0_CORE_CLK] = &apcs_alias0_core_clk.clkr,
+};
+
+static const struct qcom_cc_desc apss_ipq6018_desc = {
+ .config = &apss_ipq6018_regmap_config,
+ .clks = apss_ipq6018_clks,
+ .num_clks = ARRAY_SIZE(apss_ipq6018_clks),
+};
+
+static int apss_ipq6018_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ return qcom_cc_really_probe(pdev, &apss_ipq6018_desc, regmap);
+}
+
+static struct platform_driver apss_ipq6018_driver = {
+ .probe = apss_ipq6018_probe,
+ .driver = {
+ .name = "qcom,apss-ipq6018-clk",
+ },
+};
+
+module_platform_driver(apss_ipq6018_driver);
+
+MODULE_DESCRIPTION("QCOM APSS IPQ 6018 CLK Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 704674a153b6..1ba82be93dd5 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -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
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
new file mode 100644
index 000000000000..77a2d2806e58
--- /dev/null
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -0,0 +1,538 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+/*
+ * Each of the CPU clusters (Power and Perf) on msm8996 are
+ * clocked via 2 PLLs, a primary and alternate. There are also
+ * 2 Mux'es, a primary and secondary all connected together
+ * as shown below
+ *
+ * +-------+
+ * XO | |
+ * +------------------>0 |
+ * | |
+ * PLL/2 | SMUX +----+
+ * +------->1 | |
+ * | | | |
+ * | +-------+ | +-------+
+ * | +---->0 |
+ * | | |
+ * +---------------+ | +----------->1 | CPU clk
+ * |Primary PLL +----+ PLL_EARLY | | +------>
+ * | +------+-----------+ +------>2 PMUX |
+ * +---------------+ | | | |
+ * | +------+ | +-->3 |
+ * +--^+ ACD +-----+ | +-------+
+ * +---------------+ +------+ |
+ * |Alt PLL | |
+ * | +---------------------------+
+ * +---------------+ PLL_EARLY
+ *
+ * The primary PLL is what drives the CPU clk, except for times
+ * when we are reprogramming the PLL itself (for rate changes) when
+ * we temporarily switch to an alternate PLL.
+ *
+ * The primary PLL operates on a single VCO range, between 600MHz
+ * and 3GHz. However the CPUs do support OPPs with frequencies
+ * between 300MHz and 600MHz. In order to support running the CPUs
+ * at those frequencies we end up having to lock the PLL at twice
+ * the rate and drive the CPU clk via the PLL/2 output and SMUX.
+ *
+ * So for frequencies above 600MHz we follow the following path
+ * Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
+ * and for frequencies between 300MHz and 600MHz we follow
+ * Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
+ *
+ * ACD stands for Adaptive Clock Distribution and is used to
+ * detect voltage droops.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-regmap.h"
+
+enum _pmux_input {
+ DIV_2_INDEX = 0,
+ PLL_INDEX,
+ ACD_INDEX,
+ ALT_INDEX,
+ NUM_OF_PMUX_INPUTS
+};
+
+#define DIV_2_THRESHOLD 600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000
+#define MUX_OFFSET 0x40
+#define ALT_PLL_OFFSET 0x100
+#define SSSCTL_OFFSET 0x160
+
+static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_USER_CTL] = 0x10,
+ [PLL_OFF_CONFIG_CTL] = 0x18,
+ [PLL_OFF_CONFIG_CTL_U] = 0x1c,
+ [PLL_OFF_TEST_CTL] = 0x20,
+ [PLL_OFF_TEST_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+ [PLL_OFF_USER_CTL] = 0x10,
+ [PLL_OFF_USER_CTL_U] = 0x14,
+ [PLL_OFF_CONFIG_CTL] = 0x18,
+ [PLL_OFF_TEST_CTL] = 0x20,
+ [PLL_OFF_TEST_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+ .l = 60,
+ .config_ctl_val = 0x200d4aa8,
+ .config_ctl_hi_val = 0x006,
+ .pre_div_mask = BIT(12),
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+ .offset = PERFCL_REG_OFFSET,
+ .regs = prim_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "perfcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+ .offset = PWRCL_REG_OFFSET,
+ .regs = prim_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pwrcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+ VCO(3, 250000000, 500000000),
+ VCO(2, 500000000, 750000000),
+ VCO(1, 750000000, 1000000000),
+ VCO(0, 1000000000, 2150400000),
+};
+
+static const struct alpha_pll_config altpll_config = {
+ .l = 16,
+ .vco_val = 0x3 << 20,
+ .vco_mask = 0x3 << 20,
+ .config_ctl_val = 0x4001051b,
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+ .offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
+ .regs = alt_pll_regs,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+ .offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
+ .regs = alt_pll_regs,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+struct clk_cpu_8996_mux {
+ u32 reg;
+ u8 shift;
+ u8 width;
+ struct notifier_block nb;
+ struct clk_hw *pll;
+ struct clk_hw *pll_div_2;
+ struct clk_regmap clkr;
+};
+
+static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data);
+
+#define to_clk_cpu_8996_mux_nb(_nb) \
+ container_of(_nb, struct clk_cpu_8996_mux, nb)
+
+static inline struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr);
+}
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ u32 mask = GENMASK(cpuclk->width - 1, 0);
+ u32 val;
+
+ regmap_read(clkr->regmap, cpuclk->reg, &val);
+ val >>= cpuclk->shift;
+
+ return val & mask;
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ u32 mask = GENMASK(cpuclk->width + cpuclk->shift - 1, cpuclk->shift);
+ u32 val;
+
+ val = index;
+ val <<= cpuclk->shift;
+
+ return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);
+}
+
+static int clk_cpu_8996_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ struct clk_hw *parent = cpuclk->pll;
+
+ if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) {
+ if (req->rate < (DIV_2_THRESHOLD / 2))
+ return -EINVAL;
+
+ parent = cpuclk->pll_div_2;
+ }
+
+ req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+ req->best_parent_hw = parent;
+
+ return 0;
+}
+
+static const struct clk_ops clk_cpu_8996_mux_ops = {
+ .set_parent = clk_cpu_8996_mux_set_parent,
+ .get_parent = clk_cpu_8996_mux_get_parent,
+ .determine_rate = clk_cpu_8996_mux_determine_rate,
+};
+
+static struct clk_cpu_8996_mux pwrcl_smux = {
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "pwrcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_smux = {
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "perfcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 0,
+ .width = 2,
+ .pll = &pwrcl_pll.clkr.hw,
+ .pll_div_2 = &pwrcl_smux.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_pmux",
+ .parent_names = (const char *[]){
+ "pwrcl_smux",
+ "pwrcl_pll",
+ "pwrcl_pll_acd",
+ "pwrcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ /* CPU clock is critical and should never be gated */
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 0,
+ .width = 2,
+ .pll = &perfcl_pll.clkr.hw,
+ .pll_div_2 = &perfcl_smux.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_pmux",
+ .parent_names = (const char *[]){
+ "perfcl_smux",
+ "perfcl_pll",
+ "perfcl_pll_acd",
+ "perfcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ /* CPU clock is critical and should never be gated */
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x80210,
+ .fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+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");
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index 52f63ad787ba..083399affc8e 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -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);
@@ -766,13 +815,90 @@ 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-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);
diff --git a/drivers/clk/socfpga/clk-agilex.c b/drivers/clk/socfpga/clk-agilex.c
index 699527f7e764..8fb12cbe0208 100644
--- a/drivers/clk/socfpga/clk-agilex.c
+++ b/drivers/clk/socfpga/clk-agilex.c
@@ -252,7 +252,7 @@ static const struct stratix10_gate_clock agilex_gate_clks[] = {
0, 0, 0, 0, 0x30, 0, 0},
{ AGILEX_MPU_PERIPH_CLK, "mpu_periph_clk", "mpu_clk", NULL, 1, 0, 0x24,
0, 0, 0, 0, 0, 0, 4},
- { AGILEX_MPU_L2RAM_CLK, "mpu_l2ram_clk", "mpu_clk", NULL, 1, 0, 0x24,
+ { AGILEX_MPU_CCU_CLK, "mpu_ccu_clk", "mpu_clk", NULL, 1, 0, 0x24,
0, 0, 0, 0, 0, 0, 2},
{ AGILEX_L4_MAIN_CLK, "l4_main_clk", "noc_clk", NULL, 1, 0, 0x24,
1, 0x44, 0, 2, 0, 0, 0},
@@ -294,8 +294,12 @@ static const struct stratix10_gate_clock agilex_gate_clks[] = {
8, 0, 0, 0, 0, 0, 0},
{ AGILEX_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0x7C,
9, 0, 0, 0, 0, 0, 0},
- { AGILEX_NAND_CLK, "nand_clk", "l4_main_clk", NULL, 1, 0, 0x7C,
+ { AGILEX_NAND_X_CLK, "nand_x_clk", "l4_mp_clk", NULL, 1, 0, 0x7C,
10, 0, 0, 0, 0, 0, 0},
+ { AGILEX_NAND_CLK, "nand_clk", "nand_x_clk", NULL, 1, 0, 0x7C,
+ 10, 0, 0, 0, 0, 0, 4},
+ { AGILEX_NAND_ECC_CLK, "nand_ecc_clk", "nand_x_clk", NULL, 1, 0, 0x7C,
+ 10, 0, 0, 0, 0, 0, 4},
};
static int agilex_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index ef8098856a47..b25901a77c09 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -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);
}
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index a9261cf48293..7305d57d1890 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -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.
diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c
index 21d6991dbe0b..02ca1fadbedd 100644
--- a/drivers/perf/qcom_l2_pmu.c
+++ b/drivers/perf/qcom_l2_pmu.c
@@ -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
diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c
index 067e7e7b34f1..e066614818a3 100644
--- a/drivers/reset/reset-simple.c
+++ b/drivers/reset/reset-simple.c
@@ -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);
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index 96953992c2bb..bdd984296196 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -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)
diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c
index e7f169e57bcf..e752594b6971 100644
--- a/drivers/reset/reset-sunxi.c
+++ b/drivers/reset/reset-sunxi.c
@@ -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;
diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c
index 2b188b3bb69a..027990b79f61 100644
--- a/drivers/reset/reset-uniphier-glue.c
+++ b/drivers/reset/reset-uniphier-glue.c
@@ -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
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 07bb261a63d2..cdc4f46d64ef 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -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
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 7d7e2ecbdce6..93392d9dc7f7 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -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
diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c
new file mode 100644
index 000000000000..c20cb92077c0
--- /dev/null
+++ b/drivers/soc/qcom/kryo-l2-accessors.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/spinlock.h>
+#include <asm/barrier.h>
+#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
+#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
+
+static DEFINE_RAW_SPINLOCK(l2_access_lock);
+
+/**
+ * kryo_l2_set_indirect_reg() - write value to an L2 register
+ * @reg: Address of L2 register.
+ * @value: Value to be written to register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+void kryo_l2_set_indirect_reg(u64 reg, u64 val)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ write_sysreg_s(val, L2CPUSRDR_EL1);
+ isb();
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+}
+EXPORT_SYMBOL(kryo_l2_set_indirect_reg);
+
+/**
+ * kryo_l2_get_indirect_reg() - read an L2 register value
+ * @reg: Address of L2 register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+u64 kryo_l2_get_indirect_reg(u64 reg)
+{
+ u64 val;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ val = read_sysreg_s(L2CPUSRDR_EL1);
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL(kryo_l2_get_indirect_reg);
diff --git a/include/dt-bindings/clk/versaclock.h b/include/dt-bindings/clk/versaclock.h
new file mode 100644
index 000000000000..c6a6a0946564
--- /dev/null
+++ b/include/dt-bindings/clk/versaclock.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* This file defines field values used by the versaclock 6 family
+ * for defining output type
+ */
+
+#define VC5_LVPECL 0
+#define VC5_CMOS 1
+#define VC5_HCSL33 2
+#define VC5_LVDS 3
+#define VC5_CMOS2 4
+#define VC5_CMOSD 5
+#define VC5_HCSL25 6
diff --git a/include/dt-bindings/clock/agilex-clock.h b/include/dt-bindings/clock/agilex-clock.h
index f19cf8ccbdd2..06feca07e08e 100644
--- a/include/dt-bindings/clock/agilex-clock.h
+++ b/include/dt-bindings/clock/agilex-clock.h
@@ -65,6 +65,8 @@
#define AGILEX_SDMMC_CLK 50
#define AGILEX_SPI_M_CLK 51
#define AGILEX_USB_CLK 52
-#define AGILEX_NUM_CLKS 53
+#define AGILEX_NAND_X_CLK 53
+#define AGILEX_NAND_ECC_CLK 54
+#define AGILEX_NUM_CLKS 55
#endif /* __AGILEX_CLOCK_H */
diff --git a/include/dt-bindings/clock/bcm3368-clock.h b/include/dt-bindings/clock/bcm3368-clock.h
new file mode 100644
index 000000000000..74a7382f77b8
--- /dev/null
+++ b/include/dt-bindings/clock/bcm3368-clock.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM3368_H
+#define __DT_BINDINGS_CLOCK_BCM3368_H
+
+#define BCM3368_CLK_MAC 3
+#define BCM3368_CLK_TC 5
+#define BCM3368_CLK_US_TOP 6
+#define BCM3368_CLK_DS_TOP 7
+#define BCM3368_CLK_ACM 8
+#define BCM3368_CLK_SPI 9
+#define BCM3368_CLK_USBS 10
+#define BCM3368_CLK_BMU 11
+#define BCM3368_CLK_PCM 12
+#define BCM3368_CLK_NTP 13
+#define BCM3368_CLK_ACP_B 14
+#define BCM3368_CLK_ACP_A 15
+#define BCM3368_CLK_EMUSB 17
+#define BCM3368_CLK_ENET0 18
+#define BCM3368_CLK_ENET1 19
+#define BCM3368_CLK_USBSU 20
+#define BCM3368_CLK_EPHY 21
+
+#endif /* __DT_BINDINGS_CLOCK_BCM3368_H */
diff --git a/include/dt-bindings/clock/bcm6318-clock.h b/include/dt-bindings/clock/bcm6318-clock.h
new file mode 100644
index 000000000000..c4417f8983ab
--- /dev/null
+++ b/include/dt-bindings/clock/bcm6318-clock.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM6318_H
+#define __DT_BINDINGS_CLOCK_BCM6318_H
+
+#define BCM6318_CLK_ADSL_ASB 0
+#define BCM6318_CLK_USB_ASB 1
+#define BCM6318_CLK_MIPS_ASB 2
+#define BCM6318_CLK_PCIE_ASB 3
+#define BCM6318_CLK_PHYMIPS_ASB 4
+#define BCM6318_CLK_ROBOSW_ASB 5
+#define BCM6318_CLK_SAR_ASB 6
+#define BCM6318_CLK_SDR_ASB 7
+#define BCM6318_CLK_SWREG_ASB 8
+#define BCM6318_CLK_PERIPH_ASB 9
+#define BCM6318_CLK_CPUBUS160 10
+#define BCM6318_CLK_ADSL 11
+#define BCM6318_CLK_SAR125 12
+#define BCM6318_CLK_MIPS 13
+#define BCM6318_CLK_PCIE 14
+#define BCM6318_CLK_ROBOSW250 16
+#define BCM6318_CLK_ROBOSW025 17
+#define BCM6318_CLK_SDR 19
+#define BCM6318_CLK_USBD 20
+#define BCM6318_CLK_HSSPI 25
+#define BCM6318_CLK_PCIE25 27
+#define BCM6318_CLK_PHYMIPS 28
+#define BCM6318_CLK_AFE 29
+#define BCM6318_CLK_QPROC 30
+
+#define BCM6318_UCLK_ADSL 0
+#define BCM6318_UCLK_ARB 1
+#define BCM6318_UCLK_MIPS 2
+#define BCM6318_UCLK_PCIE 3
+#define BCM6318_UCLK_PERIPH 4
+#define BCM6318_UCLK_PHYMIPS 5
+#define BCM6318_UCLK_ROBOSW 6
+#define BCM6318_UCLK_SAR 7
+#define BCM6318_UCLK_SDR 8
+#define BCM6318_UCLK_USB 9
+
+#endif /* __DT_BINDINGS_CLOCK_BCM6318_H */
diff --git a/include/dt-bindings/clock/bcm63268-clock.h b/include/dt-bindings/clock/bcm63268-clock.h
new file mode 100644
index 000000000000..da23e691d359
--- /dev/null
+++ b/include/dt-bindings/clock/bcm63268-clock.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM63268_H
+#define __DT_BINDINGS_CLOCK_BCM63268_H
+
+#define BCM63268_CLK_DIS_GLESS 0
+#define BCM63268_CLK_VDSL_QPROC 1
+#define BCM63268_CLK_VDSL_AFE 2
+#define BCM63268_CLK_VDSL 3
+#define BCM63268_CLK_MIPS 4
+#define BCM63268_CLK_WLAN_OCP 5
+#define BCM63268_CLK_DECT 6
+#define BCM63268_CLK_FAP0 7
+#define BCM63268_CLK_FAP1 8
+#define BCM63268_CLK_SAR 9
+#define BCM63268_CLK_ROBOSW 10
+#define BCM63268_CLK_PCM 11
+#define BCM63268_CLK_USBD 12
+#define BCM63268_CLK_USBH 13
+#define BCM63268_CLK_IPSEC 14
+#define BCM63268_CLK_SPI 15
+#define BCM63268_CLK_HSSPI 16
+#define BCM63268_CLK_PCIE 17
+#define BCM63268_CLK_PHYMIPS 18
+#define BCM63268_CLK_GMAC 19
+#define BCM63268_CLK_NAND 20
+#define BCM63268_CLK_TBUS 27
+#define BCM63268_CLK_ROBOSW250 31
+
+#endif /* __DT_BINDINGS_CLOCK_BCM63268_H */
diff --git a/include/dt-bindings/clock/bcm6328-clock.h b/include/dt-bindings/clock/bcm6328-clock.h
new file mode 100644
index 000000000000..1f6a3103f3dc
--- /dev/null
+++ b/include/dt-bindings/clock/bcm6328-clock.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM6328_H
+#define __DT_BINDINGS_CLOCK_BCM6328_H
+
+#define BCM6328_CLK_PHYMIPS 0
+#define BCM6328_CLK_ADSL_QPROC 1
+#define BCM6328_CLK_ADSL_AFE 2
+#define BCM6328_CLK_ADSL 3
+#define BCM6328_CLK_MIPS 4
+#define BCM6328_CLK_SAR 5
+#define BCM6328_CLK_PCM 6
+#define BCM6328_CLK_USBD 7
+#define BCM6328_CLK_USBH 8
+#define BCM6328_CLK_HSSPI 9
+#define BCM6328_CLK_PCIE 10
+#define BCM6328_CLK_ROBOSW 11
+
+#endif /* __DT_BINDINGS_CLOCK_BCM6328_H */
diff --git a/include/dt-bindings/clock/bcm6358-clock.h b/include/dt-bindings/clock/bcm6358-clock.h
new file mode 100644
index 000000000000..980c9cac4765
--- /dev/null
+++ b/include/dt-bindings/clock/bcm6358-clock.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM6358_H
+#define __DT_BINDINGS_CLOCK_BCM6358_H
+
+#define BCM6358_CLK_ENET 4
+#define BCM6358_CLK_ADSLPHY 5
+#define BCM6358_CLK_PCM 8
+#define BCM6358_CLK_SPI 9
+#define BCM6358_CLK_USBS 10
+#define BCM6358_CLK_SAR 11
+#define BCM6358_CLK_EMUSB 17
+#define BCM6358_CLK_ENET0 18
+#define BCM6358_CLK_ENET1 19
+#define BCM6358_CLK_USBSU 20
+#define BCM6358_CLK_EPHY 21
+
+#endif /* __DT_BINDINGS_CLOCK_BCM6358_H */
diff --git a/include/dt-bindings/clock/bcm6362-clock.h b/include/dt-bindings/clock/bcm6362-clock.h
new file mode 100644
index 000000000000..17655cd5bf25
--- /dev/null
+++ b/include/dt-bindings/clock/bcm6362-clock.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM6362_H
+#define __DT_BINDINGS_CLOCK_BCM6362_H
+
+#define BCM6362_CLK_ADSL_QPROC 1
+#define BCM6362_CLK_ADSL_AFE 2
+#define BCM6362_CLK_ADSL 3
+#define BCM6362_CLK_MIPS 4
+#define BCM6362_CLK_WLAN_OCP 5
+#define BCM6362_CLK_SWPKT_USB 7
+#define BCM6362_CLK_SWPKT_SAR 8
+#define BCM6362_CLK_SAR 9
+#define BCM6362_CLK_ROBOSW 10
+#define BCM6362_CLK_PCM 11
+#define BCM6362_CLK_USBD 12
+#define BCM6362_CLK_USBH 13
+#define BCM6362_CLK_IPSEC 14
+#define BCM6362_CLK_SPI 15
+#define BCM6362_CLK_HSSPI 16
+#define BCM6362_CLK_PCIE 17
+#define BCM6362_CLK_FAP 18
+#define BCM6362_CLK_PHYMIPS 19
+#define BCM6362_CLK_NAND 20
+
+#endif /* __DT_BINDINGS_CLOCK_BCM6362_H */
diff --git a/include/dt-bindings/clock/bcm6368-clock.h b/include/dt-bindings/clock/bcm6368-clock.h
new file mode 100644
index 000000000000..f161d5333883
--- /dev/null
+++ b/include/dt-bindings/clock/bcm6368-clock.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BCM6368_H
+#define __DT_BINDINGS_CLOCK_BCM6368_H
+
+#define BCM6368_CLK_VDSL_QPROC 2
+#define BCM6368_CLK_VDSL_AFE 3
+#define BCM6368_CLK_VDSL_BONDING 4
+#define BCM6368_CLK_VDSL 5
+#define BCM6368_CLK_PHYMIPS 6
+#define BCM6368_CLK_SWPKT_USB 7
+#define BCM6368_CLK_SWPKT_SAR 8
+#define BCM6368_CLK_SPI 9
+#define BCM6368_CLK_USBD 10
+#define BCM6368_CLK_SAR 11
+#define BCM6368_CLK_ROBOSW 12
+#define BCM6368_CLK_UTOPIA 13
+#define BCM6368_CLK_PCM 14
+#define BCM6368_CLK_USBH 15
+#define BCM6368_CLK_DIS_GLESS 16
+#define BCM6368_CLK_NAND 17
+#define BCM6368_CLK_IPSEC 18
+
+#endif /* __DT_BINDINGS_CLOCK_BCM6368_H */
diff --git a/include/dt-bindings/clock/qcom,apss-ipq.h b/include/dt-bindings/clock/qcom,apss-ipq.h
new file mode 100644
index 000000000000..77b6e05492e2
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,apss-ipq.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_QCA_APSS_IPQ6018_H
+#define _DT_BINDINGS_CLOCK_QCA_APSS_IPQ6018_H
+
+#define APCS_ALIAS0_CLK_SRC 0
+#define APCS_ALIAS0_CORE_CLK 1
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h
index ae74c43c485d..e98ed70d91b3 100644
--- a/include/dt-bindings/clock/qcom,rpmcc.h
+++ b/include/dt-bindings/clock/qcom,rpmcc.h
@@ -133,5 +133,17 @@
#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
#endif
diff --git a/drivers/reset/reset-simple.h b/include/linux/reset/reset-simple.h
index 08ccb25a55e6..c3e44f45b0f7 100644
--- a/drivers/reset/reset-simple.h
+++ b/include/linux/reset/reset-simple.h
@@ -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;
diff --git a/include/soc/qcom/kryo-l2-accessors.h b/include/soc/qcom/kryo-l2-accessors.h
new file mode 100644
index 000000000000..673c5344afe3
--- /dev/null
+++ b/include/soc/qcom/kryo-l2-accessors.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H
+#define __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H
+
+void kryo_l2_set_indirect_reg(u64 reg, u64 val);
+u64 kryo_l2_get_indirect_reg(u64 reg);
+
+#endif