Merge branches 'clk-imx6-mmdc', 'clk-qcom-krait', 'clk-rockchip' and 'clk-smp2s11-match' into clk-next
- iMX6 MMDC clks - Qualcomm Krait CPU clk support * clk-imx6-mmdc: clk: imx6q: add mmdc0 ipg clock clk: imx6sl: add mmdc ipg clocks clk: imx6sll: add mmdc1 ipg clock clk: imx6sx: add mmdc1 ipg clock clk: imx6ul: add mmdc1 ipg clock * clk-qcom-krait: clk: qcom: Add safe switch hook for krait mux clocks dt-bindings: clock: Document qcom,krait-cc clk: qcom: Add Krait clock controller driver dt-bindings: arm: Document qcom,kpss-gcc clk: qcom: Add KPSS ACC/GCC driver clk: qcom: Add support for Krait clocks clk: qcom: Add IPQ806X's HFPLLs clk: qcom: Add MSM8960/APQ8064's HFPLLs dt-bindings: clock: Document qcom,hfpll clk: qcom: Add HFPLL driver clk: qcom: Add support for High-Frequency PLLs (HFPLLs) ARM: Add Krait L2 register accessor functions * clk-rockchip: clk: rockchip: Fix static checker warning in rockchip_ddrclk_get_parent call clk: rockchip: use the newly added clock-id for hdmi on RK3066 clk: rockchip: add clock-id for HCLK_HDMI on rk3066 clk: rockchip: fix wrong mmc sample phase shift for rk3328 clk: rockchip: improve rk3288 pll rates for better hdmi output * clk-smp2s11-match: clk: s2mps11: Add used attribute to s2mps11_dt_match clk: s2mps11: Fix matching when built as module and DT node contains compatible
This commit is contained in:
commit
1578968f77
|
@ -21,10 +21,29 @@ PROPERTIES
|
|||
the register region. An optional second element specifies
|
||||
the base address and size of the alias register region.
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: reference to the pll parents.
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "pll8_vote", "pxo".
|
||||
|
||||
- clock-output-names:
|
||||
Usage: optional
|
||||
Value type: <string>
|
||||
Definition: Name of the output clock. Typically acpuX_aux where X is a
|
||||
CPU number starting at 0.
|
||||
|
||||
Example:
|
||||
|
||||
clock-controller@2088000 {
|
||||
compatible = "qcom,kpss-acc-v2";
|
||||
reg = <0x02088000 0x1000>,
|
||||
<0x02008000 0x1000>;
|
||||
clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
|
||||
clock-names = "pll8_vote", "pxo";
|
||||
clock-output-names = "acpu0_aux";
|
||||
};
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
Krait Processor Sub-system (KPSS) Global Clock Controller (GCC)
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: should be one of the following. The generic compatible
|
||||
"qcom,kpss-gcc" should also be included.
|
||||
"qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc"
|
||||
"qcom,kpss-gcc-apq8064", "qcom,kpss-gcc"
|
||||
"qcom,kpss-gcc-msm8974", "qcom,kpss-gcc"
|
||||
"qcom,kpss-gcc-msm8960", "qcom,kpss-gcc"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: base address and size of the register region
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: reference to the pll parents.
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "pll8_vote", "pxo".
|
||||
|
||||
- clock-output-names:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Name of the output clock. Typically acpu_l2_aux indicating
|
||||
an L2 cache auxiliary clock.
|
||||
|
||||
Example:
|
||||
|
||||
l2cc: clock-controller@2011000 {
|
||||
compatible = "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc";
|
||||
reg = <0x2011000 0x1000>;
|
||||
clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
|
||||
clock-names = "pll8_vote", "pxo";
|
||||
clock-output-names = "acpu_l2_aux";
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
High-Frequency PLL (HFPLL)
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>:
|
||||
shall contain only one of the following. The generic
|
||||
compatible "qcom,hfpll" should be also included.
|
||||
|
||||
"qcom,hfpll-ipq8064", "qcom,hfpll"
|
||||
"qcom,hfpll-apq8064", "qcom,hfpll"
|
||||
"qcom,hfpll-msm8974", "qcom,hfpll"
|
||||
"qcom,hfpll-msm8960", "qcom,hfpll"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: address and size of HPLL registers. An optional second
|
||||
element specifies the address and size of the alias
|
||||
register region.
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: reference to the xo clock.
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "xo".
|
||||
|
||||
- clock-output-names:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Name of the PLL. Typically hfpllX where X is a CPU number
|
||||
starting at 0. Otherwise hfpll_Y where Y is more specific
|
||||
such as "l2".
|
||||
|
||||
Example:
|
||||
|
||||
1) An HFPLL for the L2 cache.
|
||||
|
||||
clock-controller@f9016000 {
|
||||
compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
|
||||
reg = <0xf9016000 0x30>;
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "xo";
|
||||
clock-output-names = "hfpll_l2";
|
||||
};
|
||||
|
||||
2) An HFPLL for CPU0. This HFPLL has the alias register region.
|
||||
|
||||
clock-controller@f908a000 {
|
||||
compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
|
||||
reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "xo";
|
||||
clock-output-names = "hfpll0";
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
Krait Clock Controller
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,krait-cc-v1"
|
||||
"qcom,krait-cc-v2"
|
||||
|
||||
- #clock-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: must be 1
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: reference to the clock parents of hfpll, secondary muxes.
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb".
|
||||
|
||||
Example:
|
||||
|
||||
kraitcc: clock-controller {
|
||||
compatible = "qcom,krait-cc-v1";
|
||||
clocks = <&hfpll0>, <&hfpll1>, <&acpu0_aux>, <&acpu1_aux>, <qsb>;
|
||||
clock-names = "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb";
|
||||
#clock-cells = <1>;
|
||||
};
|
|
@ -7,6 +7,9 @@ config DMABOUNCE
|
|||
bool
|
||||
select ZONE_DMA
|
||||
|
||||
config KRAIT_L2_ACCESSORS
|
||||
bool
|
||||
|
||||
config SHARP_LOCOMO
|
||||
bool
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ obj-y += firmware.o
|
|||
|
||||
obj-$(CONFIG_SA1111) += sa1111.o
|
||||
obj-$(CONFIG_DMABOUNCE) += dmabounce.o
|
||||
obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o
|
||||
obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
|
||||
obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
|
||||
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/krait-l2-accessors.h>
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(krait_l2_lock);
|
||||
|
||||
void krait_set_l2_indirect_reg(u32 addr, u32 val)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&krait_l2_lock, flags);
|
||||
/*
|
||||
* Select the L2 window by poking l2cpselr, then write to the window
|
||||
* via l2cpdr.
|
||||
*/
|
||||
asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
|
||||
isb();
|
||||
asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val));
|
||||
isb();
|
||||
|
||||
raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(krait_set_l2_indirect_reg);
|
||||
|
||||
u32 krait_get_l2_indirect_reg(u32 addr)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&krait_l2_lock, flags);
|
||||
/*
|
||||
* Select the L2 window by poking l2cpselr, then read from the window
|
||||
* via l2cpdr.
|
||||
*/
|
||||
asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
|
||||
isb();
|
||||
asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val));
|
||||
|
||||
raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(krait_get_l2_indirect_reg);
|
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H
|
||||
#define __ASMARM_KRAIT_L2_ACCESSORS_H
|
||||
|
||||
extern void krait_set_l2_indirect_reg(u32 addr, u32 val);
|
||||
extern u32 krait_get_l2_indirect_reg(u32 addr);
|
||||
|
||||
#endif
|
|
@ -229,6 +229,36 @@ static const struct platform_device_id s2mps11_clk_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/*
|
||||
* Device is instantiated through parent MFD device and device matching is done
|
||||
* through platform_device_id.
|
||||
*
|
||||
* However if device's DT node contains proper clock compatible and driver is
|
||||
* built as a module, then the *module* matching will be done trough DT aliases.
|
||||
* This requires of_device_id table. In the same time this will not change the
|
||||
* actual *device* matching so do not add .of_match_table.
|
||||
*/
|
||||
static const struct of_device_id s2mps11_dt_match[] __used = {
|
||||
{
|
||||
.compatible = "samsung,s2mps11-clk",
|
||||
.data = (void *)S2MPS11X,
|
||||
}, {
|
||||
.compatible = "samsung,s2mps13-clk",
|
||||
.data = (void *)S2MPS13X,
|
||||
}, {
|
||||
.compatible = "samsung,s2mps14-clk",
|
||||
.data = (void *)S2MPS14X,
|
||||
}, {
|
||||
.compatible = "samsung,s5m8767-clk",
|
||||
.data = (void *)S5M8767X,
|
||||
}, {
|
||||
/* Sentinel */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s2mps11_dt_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver s2mps11_clk_driver = {
|
||||
.driver = {
|
||||
.name = "s2mps11-clk",
|
||||
|
|
|
@ -789,6 +789,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
|||
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18);
|
||||
clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
|
||||
clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
|
||||
clk[IMX6QDL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
|
||||
clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28);
|
||||
clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30);
|
||||
clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);
|
||||
|
|
|
@ -386,6 +386,8 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
|
|||
clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6);
|
||||
clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8);
|
||||
clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10);
|
||||
clks[IMX6SL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
|
||||
clks[IMX6SL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
|
||||
clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
|
||||
clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
|
||||
clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
|
||||
|
|
|
@ -293,6 +293,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
|
|||
clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
|
||||
clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
|
||||
clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
|
||||
clks[IMX6SLL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
|
||||
clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate_flags("ocram","ahb", base + 0x74, 28, CLK_IS_CRITICAL);
|
||||
|
||||
/* CCGR4 */
|
||||
|
|
|
@ -431,6 +431,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
|||
clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
|
||||
clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
|
||||
clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
|
||||
clks[IMX6SX_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
|
||||
clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
|
||||
|
||||
/* CCGR4 */
|
||||
|
|
|
@ -408,6 +408,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
|
|||
clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
|
||||
clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
|
||||
clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
|
||||
clks[IMX6UL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
|
||||
clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL);
|
||||
|
||||
/* CCGR4 */
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
config KRAIT_CLOCKS
|
||||
bool
|
||||
select KRAIT_L2_ACCESSORS
|
||||
|
||||
config QCOM_GDSC
|
||||
bool
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
|
@ -297,3 +301,27 @@ config SPMI_PMIC_CLKDIV
|
|||
Technologies, Inc. SPMI PMIC. It configures the frequency of
|
||||
clkdiv outputs of the PMIC. These clocks are typically wired
|
||||
through alternate functions on GPIO pins.
|
||||
|
||||
config QCOM_HFPLL
|
||||
tristate "High-Frequency PLL (HFPLL) Clock Controller"
|
||||
depends on COMMON_CLK_QCOM
|
||||
help
|
||||
Support for the high-frequency PLLs present on Qualcomm devices.
|
||||
Say Y if you want to support CPU frequency scaling on devices
|
||||
such as MSM8974, APQ8084, etc.
|
||||
|
||||
config KPSS_XCC
|
||||
tristate "KPSS Clock Controller"
|
||||
depends on COMMON_CLK_QCOM
|
||||
help
|
||||
Support for the Krait ACC and GCC clock controllers. Say Y
|
||||
if you want to support CPU frequency scaling on devices such
|
||||
as MSM8960, APQ8064, etc.
|
||||
|
||||
config KRAITCC
|
||||
tristate "Krait Clock Controller"
|
||||
depends on COMMON_CLK_QCOM && ARM
|
||||
select KRAIT_CLOCKS
|
||||
help
|
||||
Support for the Krait CPU clocks on Qualcomm devices.
|
||||
Say Y if you want to support CPU frequency scaling.
|
||||
|
|
|
@ -11,6 +11,8 @@ clk-qcom-y += clk-branch.o
|
|||
clk-qcom-y += clk-regmap-divider.o
|
||||
clk-qcom-y += clk-regmap-mux.o
|
||||
clk-qcom-y += clk-regmap-mux-div.o
|
||||
clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
|
||||
clk-qcom-y += clk-hfpll.o
|
||||
clk-qcom-y += reset.o
|
||||
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
|
||||
|
||||
|
@ -46,3 +48,6 @@ obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
|
|||
obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
|
||||
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
|
||||
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
|
||||
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
|
||||
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
|
||||
obj-$(CONFIG_KRAITCC) += krait-cc.o
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-hfpll.h"
|
||||
|
||||
#define PLL_OUTCTRL BIT(0)
|
||||
#define PLL_BYPASSNL BIT(1)
|
||||
#define PLL_RESET_N BIT(2)
|
||||
|
||||
/* Initialize a HFPLL at a given rate and enable it. */
|
||||
static void __clk_hfpll_init_once(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
|
||||
if (likely(h->init_done))
|
||||
return;
|
||||
|
||||
/* Configure PLL parameters for integer mode. */
|
||||
if (hd->config_val)
|
||||
regmap_write(regmap, hd->config_reg, hd->config_val);
|
||||
regmap_write(regmap, hd->m_reg, 0);
|
||||
regmap_write(regmap, hd->n_reg, 1);
|
||||
|
||||
if (hd->user_reg) {
|
||||
u32 regval = hd->user_val;
|
||||
unsigned long rate;
|
||||
|
||||
rate = clk_hw_get_rate(hw);
|
||||
|
||||
/* Pick the right VCO. */
|
||||
if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
|
||||
regval |= hd->user_vco_mask;
|
||||
regmap_write(regmap, hd->user_reg, regval);
|
||||
}
|
||||
|
||||
if (hd->droop_reg)
|
||||
regmap_write(regmap, hd->droop_reg, hd->droop_val);
|
||||
|
||||
h->init_done = true;
|
||||
}
|
||||
|
||||
static void __clk_hfpll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
u32 val;
|
||||
|
||||
__clk_hfpll_init_once(hw);
|
||||
|
||||
/* Disable PLL bypass mode. */
|
||||
regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
|
||||
|
||||
/*
|
||||
* H/W requires a 5us delay between disabling the bypass and
|
||||
* de-asserting the reset. Delay 10us just to be safe.
|
||||
*/
|
||||
udelay(10);
|
||||
|
||||
/* De-assert active-low PLL reset. */
|
||||
regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
|
||||
|
||||
/* Wait for PLL to lock. */
|
||||
if (hd->status_reg) {
|
||||
do {
|
||||
regmap_read(regmap, hd->status_reg, &val);
|
||||
} while (!(val & BIT(hd->lock_bit)));
|
||||
} else {
|
||||
udelay(60);
|
||||
}
|
||||
|
||||
/* Enable PLL output. */
|
||||
regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
|
||||
}
|
||||
|
||||
/* Enable an already-configured HFPLL. */
|
||||
static int clk_hfpll_enable(struct clk_hw *hw)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
u32 mode;
|
||||
|
||||
spin_lock_irqsave(&h->lock, flags);
|
||||
regmap_read(regmap, hd->mode_reg, &mode);
|
||||
if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
|
||||
__clk_hfpll_enable(hw);
|
||||
spin_unlock_irqrestore(&h->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __clk_hfpll_disable(struct clk_hfpll *h)
|
||||
{
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
|
||||
/*
|
||||
* Disable the PLL output, disable test mode, enable the bypass mode,
|
||||
* and assert the reset.
|
||||
*/
|
||||
regmap_update_bits(regmap, hd->mode_reg,
|
||||
PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
|
||||
}
|
||||
|
||||
static void clk_hfpll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&h->lock, flags);
|
||||
__clk_hfpll_disable(h);
|
||||
spin_unlock_irqrestore(&h->lock, flags);
|
||||
}
|
||||
|
||||
static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
unsigned long rrate;
|
||||
|
||||
rate = clamp(rate, hd->min_rate, hd->max_rate);
|
||||
|
||||
rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
|
||||
if (rrate > hd->max_rate)
|
||||
rrate -= *parent_rate;
|
||||
|
||||
return rrate;
|
||||
}
|
||||
|
||||
/*
|
||||
* For optimization reasons, assumes no downstream clocks are actively using
|
||||
* it.
|
||||
*/
|
||||
static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
unsigned long flags;
|
||||
u32 l_val, val;
|
||||
bool enabled;
|
||||
|
||||
l_val = rate / parent_rate;
|
||||
|
||||
spin_lock_irqsave(&h->lock, flags);
|
||||
|
||||
enabled = __clk_is_enabled(hw->clk);
|
||||
if (enabled)
|
||||
__clk_hfpll_disable(h);
|
||||
|
||||
/* Pick the right VCO. */
|
||||
if (hd->user_reg && hd->user_vco_mask) {
|
||||
regmap_read(regmap, hd->user_reg, &val);
|
||||
if (rate <= hd->low_vco_max_rate)
|
||||
val &= ~hd->user_vco_mask;
|
||||
else
|
||||
val |= hd->user_vco_mask;
|
||||
regmap_write(regmap, hd->user_reg, val);
|
||||
}
|
||||
|
||||
regmap_write(regmap, hd->l_reg, l_val);
|
||||
|
||||
if (enabled)
|
||||
__clk_hfpll_enable(hw);
|
||||
|
||||
spin_unlock_irqrestore(&h->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
u32 l_val;
|
||||
|
||||
regmap_read(regmap, hd->l_reg, &l_val);
|
||||
|
||||
return l_val * parent_rate;
|
||||
}
|
||||
|
||||
static void clk_hfpll_init(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
u32 mode, status;
|
||||
|
||||
regmap_read(regmap, hd->mode_reg, &mode);
|
||||
if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
|
||||
__clk_hfpll_init_once(hw);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hd->status_reg) {
|
||||
regmap_read(regmap, hd->status_reg, &status);
|
||||
if (!(status & BIT(hd->lock_bit))) {
|
||||
WARN(1, "HFPLL %s is ON, but not locked!\n",
|
||||
__clk_get_name(hw->clk));
|
||||
clk_hfpll_disable(hw);
|
||||
__clk_hfpll_init_once(hw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int hfpll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hfpll *h = to_clk_hfpll(hw);
|
||||
struct hfpll_data const *hd = h->d;
|
||||
struct regmap *regmap = h->clkr.regmap;
|
||||
u32 mode;
|
||||
|
||||
regmap_read(regmap, hd->mode_reg, &mode);
|
||||
mode &= 0x7;
|
||||
return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_ops_hfpll = {
|
||||
.enable = clk_hfpll_enable,
|
||||
.disable = clk_hfpll_disable,
|
||||
.is_enabled = hfpll_is_enabled,
|
||||
.round_rate = clk_hfpll_round_rate,
|
||||
.set_rate = clk_hfpll_set_rate,
|
||||
.recalc_rate = clk_hfpll_recalc_rate,
|
||||
.init = clk_hfpll_init,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_ops_hfpll);
|
|
@ -0,0 +1,44 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __QCOM_CLK_HFPLL_H__
|
||||
#define __QCOM_CLK_HFPLL_H__
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "clk-regmap.h"
|
||||
|
||||
struct hfpll_data {
|
||||
u32 mode_reg;
|
||||
u32 l_reg;
|
||||
u32 m_reg;
|
||||
u32 n_reg;
|
||||
u32 user_reg;
|
||||
u32 droop_reg;
|
||||
u32 config_reg;
|
||||
u32 status_reg;
|
||||
u8 lock_bit;
|
||||
|
||||
u32 droop_val;
|
||||
u32 config_val;
|
||||
u32 user_val;
|
||||
u32 user_vco_mask;
|
||||
unsigned long low_vco_max_rate;
|
||||
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
struct clk_hfpll {
|
||||
struct hfpll_data const *d;
|
||||
int init_done;
|
||||
|
||||
struct clk_regmap clkr;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define to_clk_hfpll(_hw) \
|
||||
container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
|
||||
|
||||
extern const struct clk_ops clk_ops_hfpll;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,126 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/krait-l2-accessors.h>
|
||||
|
||||
#include "clk-krait.h"
|
||||
|
||||
/* Secondary and primary muxes share the same cp15 register */
|
||||
static DEFINE_SPINLOCK(krait_clock_reg_lock);
|
||||
|
||||
#define LPL_SHIFT 8
|
||||
static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 regval;
|
||||
|
||||
spin_lock_irqsave(&krait_clock_reg_lock, flags);
|
||||
regval = krait_get_l2_indirect_reg(mux->offset);
|
||||
regval &= ~(mux->mask << mux->shift);
|
||||
regval |= (sel & mux->mask) << mux->shift;
|
||||
if (mux->lpl) {
|
||||
regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
|
||||
regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
|
||||
}
|
||||
krait_set_l2_indirect_reg(mux->offset, regval);
|
||||
spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
|
||||
|
||||
/* Wait for switch to complete. */
|
||||
mb();
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct krait_mux_clk *mux = to_krait_mux_clk(hw);
|
||||
u32 sel;
|
||||
|
||||
sel = clk_mux_index_to_val(mux->parent_map, 0, index);
|
||||
mux->en_mask = sel;
|
||||
/* Don't touch mux if CPU is off as it won't work */
|
||||
if (__clk_is_enabled(hw->clk))
|
||||
__krait_mux_set_sel(mux, sel);
|
||||
|
||||
mux->reparent = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 krait_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct krait_mux_clk *mux = to_krait_mux_clk(hw);
|
||||
u32 sel;
|
||||
|
||||
sel = krait_get_l2_indirect_reg(mux->offset);
|
||||
sel >>= mux->shift;
|
||||
sel &= mux->mask;
|
||||
mux->en_mask = sel;
|
||||
|
||||
return clk_mux_val_to_index(hw, mux->parent_map, 0, sel);
|
||||
}
|
||||
|
||||
const struct clk_ops krait_mux_clk_ops = {
|
||||
.set_parent = krait_mux_set_parent,
|
||||
.get_parent = krait_mux_get_parent,
|
||||
.determine_rate = __clk_mux_determine_rate_closest,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
|
||||
|
||||
/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
|
||||
static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
|
||||
return DIV_ROUND_UP(*parent_rate, 2);
|
||||
}
|
||||
|
||||
static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct krait_div2_clk *d = to_krait_div2_clk(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
u32 mask = BIT(d->width) - 1;
|
||||
|
||||
if (d->lpl)
|
||||
mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
|
||||
|
||||
spin_lock_irqsave(&krait_clock_reg_lock, flags);
|
||||
val = krait_get_l2_indirect_reg(d->offset);
|
||||
val &= ~mask;
|
||||
krait_set_l2_indirect_reg(d->offset, val);
|
||||
spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct krait_div2_clk *d = to_krait_div2_clk(hw);
|
||||
u32 mask = BIT(d->width) - 1;
|
||||
u32 div;
|
||||
|
||||
div = krait_get_l2_indirect_reg(d->offset);
|
||||
div >>= d->shift;
|
||||
div &= mask;
|
||||
div = (div + 1) * 2;
|
||||
|
||||
return DIV_ROUND_UP(parent_rate, div);
|
||||
}
|
||||
|
||||
const struct clk_ops krait_div2_clk_ops = {
|
||||
.round_rate = krait_div2_round_rate,
|
||||
.set_rate = krait_div2_set_rate,
|
||||
.recalc_rate = krait_div2_recalc_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
|
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __QCOM_CLK_KRAIT_H
|
||||
#define __QCOM_CLK_KRAIT_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct krait_mux_clk {
|
||||
unsigned int *parent_map;
|
||||
u32 offset;
|
||||
u32 mask;
|
||||
u32 shift;
|
||||
u32 en_mask;
|
||||
bool lpl;
|
||||
u8 safe_sel;
|
||||
u8 old_index;
|
||||
bool reparent;
|
||||
|
||||
struct clk_hw hw;
|
||||
struct notifier_block clk_nb;
|
||||
};
|
||||
|
||||
#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
|
||||
|
||||
extern const struct clk_ops krait_mux_clk_ops;
|
||||
|
||||
struct krait_div2_clk {
|
||||
u32 offset;
|
||||
u8 width;
|
||||
u32 shift;
|
||||
bool lpl;
|
||||
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
|
||||
|
||||
extern const struct clk_ops krait_div2_clk_ops;
|
||||
|
||||
#endif
|
|
@ -30,6 +30,7 @@
|
|||
#include "clk-pll.h"
|
||||
#include "clk-rcg.h"
|
||||
#include "clk-branch.h"
|
||||
#include "clk-hfpll.h"
|
||||
#include "reset.h"
|
||||
|
||||
static struct clk_pll pll0 = {
|
||||
|
@ -113,6 +114,84 @@ static struct clk_regmap pll8_vote = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll0_data = {
|
||||
.mode_reg = 0x3200,
|
||||
.l_reg = 0x3208,
|
||||
.m_reg = 0x320c,
|
||||
.n_reg = 0x3210,
|
||||
.config_reg = 0x3204,
|
||||
.status_reg = 0x321c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3214,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll0 = {
|
||||
.d = &hfpll0_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll0",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll1_data = {
|
||||
.mode_reg = 0x3240,
|
||||
.l_reg = 0x3248,
|
||||
.m_reg = 0x324c,
|
||||
.n_reg = 0x3250,
|
||||
.config_reg = 0x3244,
|
||||
.status_reg = 0x325c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3314,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll1 = {
|
||||
.d = &hfpll1_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll1",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll_l2_data = {
|
||||
.mode_reg = 0x3300,
|
||||
.l_reg = 0x3308,
|
||||
.m_reg = 0x330c,
|
||||
.n_reg = 0x3310,
|
||||
.config_reg = 0x3304,
|
||||
.status_reg = 0x331c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3314,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll_l2 = {
|
||||
.d = &hfpll_l2_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll_l2",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
|
||||
};
|
||||
|
||||
static struct clk_pll pll14 = {
|
||||
.l_reg = 0x31c4,
|
||||
.m_reg = 0x31c8,
|
||||
|
@ -2797,6 +2876,9 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
|
|||
[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
|
||||
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
|
||||
[NSSTCM_CLK] = &nss_tcm_clk.clkr,
|
||||
[PLL9] = &hfpll0.clkr,
|
||||
[PLL10] = &hfpll1.clkr,
|
||||
[PLL12] = &hfpll_l2.clkr,
|
||||
};
|
||||
|
||||
static const struct qcom_reset_map gcc_ipq806x_resets[] = {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "clk-pll.h"
|
||||
#include "clk-rcg.h"
|
||||
#include "clk-branch.h"
|
||||
#include "clk-hfpll.h"
|
||||
#include "reset.h"
|
||||
|
||||
static struct clk_pll pll3 = {
|
||||
|
@ -86,6 +87,164 @@ static struct clk_regmap pll8_vote = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll0_data = {
|
||||
.mode_reg = 0x3200,
|
||||
.l_reg = 0x3208,
|
||||
.m_reg = 0x320c,
|
||||
.n_reg = 0x3210,
|
||||
.config_reg = 0x3204,
|
||||
.status_reg = 0x321c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3214,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll0 = {
|
||||
.d = &hfpll0_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll0",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll1_8064_data = {
|
||||
.mode_reg = 0x3240,
|
||||
.l_reg = 0x3248,
|
||||
.m_reg = 0x324c,
|
||||
.n_reg = 0x3250,
|
||||
.config_reg = 0x3244,
|
||||
.status_reg = 0x325c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3254,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll1_data = {
|
||||
.mode_reg = 0x3300,
|
||||
.l_reg = 0x3308,
|
||||
.m_reg = 0x330c,
|
||||
.n_reg = 0x3310,
|
||||
.config_reg = 0x3304,
|
||||
.status_reg = 0x331c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3314,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll1 = {
|
||||
.d = &hfpll1_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll1",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll2_data = {
|
||||
.mode_reg = 0x3280,
|
||||
.l_reg = 0x3288,
|
||||
.m_reg = 0x328c,
|
||||
.n_reg = 0x3290,
|
||||
.config_reg = 0x3284,
|
||||
.status_reg = 0x329c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3294,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll2 = {
|
||||
.d = &hfpll2_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll2",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll2.lock),
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll3_data = {
|
||||
.mode_reg = 0x32c0,
|
||||
.l_reg = 0x32c8,
|
||||
.m_reg = 0x32cc,
|
||||
.n_reg = 0x32d0,
|
||||
.config_reg = 0x32c4,
|
||||
.status_reg = 0x32dc,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x32d4,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll3 = {
|
||||
.d = &hfpll3_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll3",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll3.lock),
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll_l2_8064_data = {
|
||||
.mode_reg = 0x3300,
|
||||
.l_reg = 0x3308,
|
||||
.m_reg = 0x330c,
|
||||
.n_reg = 0x3310,
|
||||
.config_reg = 0x3304,
|
||||
.status_reg = 0x331c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3314,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct hfpll_data hfpll_l2_data = {
|
||||
.mode_reg = 0x3400,
|
||||
.l_reg = 0x3408,
|
||||
.m_reg = 0x340c,
|
||||
.n_reg = 0x3410,
|
||||
.config_reg = 0x3404,
|
||||
.status_reg = 0x341c,
|
||||
.config_val = 0x7845c665,
|
||||
.droop_reg = 0x3414,
|
||||
.droop_val = 0x0108c000,
|
||||
.min_rate = 600000000UL,
|
||||
.max_rate = 1800000000UL,
|
||||
};
|
||||
|
||||
static struct clk_hfpll hfpll_l2 = {
|
||||
.d = &hfpll_l2_data,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.name = "hfpll_l2",
|
||||
.ops = &clk_ops_hfpll,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
|
||||
};
|
||||
|
||||
static struct clk_pll pll14 = {
|
||||
.l_reg = 0x31c4,
|
||||
.m_reg = 0x31c8,
|
||||
|
@ -3107,6 +3266,9 @@ static struct clk_regmap *gcc_msm8960_clks[] = {
|
|||
[PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
|
||||
[PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
|
||||
[RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
|
||||
[PLL9] = &hfpll0.clkr,
|
||||
[PLL10] = &hfpll1.clkr,
|
||||
[PLL12] = &hfpll_l2.clkr,
|
||||
};
|
||||
|
||||
static const struct qcom_reset_map gcc_msm8960_resets[] = {
|
||||
|
@ -3318,6 +3480,11 @@ static struct clk_regmap *gcc_apq8064_clks[] = {
|
|||
[PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
|
||||
[PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
|
||||
[RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
|
||||
[PLL9] = &hfpll0.clkr,
|
||||
[PLL10] = &hfpll1.clkr,
|
||||
[PLL12] = &hfpll_l2.clkr,
|
||||
[PLL16] = &hfpll2.clkr,
|
||||
[PLL17] = &hfpll3.clkr,
|
||||
};
|
||||
|
||||
static const struct qcom_reset_map gcc_apq8064_resets[] = {
|
||||
|
@ -3477,6 +3644,11 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (match->data == &gcc_apq8064_desc) {
|
||||
hfpll1.d = &hfpll1_8064_data;
|
||||
hfpll_l2.d = &hfpll_l2_8064_data;
|
||||
}
|
||||
|
||||
tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1,
|
||||
NULL, 0);
|
||||
if (IS_ERR(tsens))
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-hfpll.h"
|
||||
|
||||
static const struct hfpll_data hdata = {
|
||||
.mode_reg = 0x00,
|
||||
.l_reg = 0x04,
|
||||
.m_reg = 0x08,
|
||||
.n_reg = 0x0c,
|
||||
.user_reg = 0x10,
|
||||
.config_reg = 0x14,
|
||||
.config_val = 0x430405d,
|
||||
.status_reg = 0x1c,
|
||||
.lock_bit = 16,
|
||||
|
||||
.user_val = 0x8,
|
||||
.user_vco_mask = 0x100000,
|
||||
.low_vco_max_rate = 1248000000,
|
||||
.min_rate = 537600000UL,
|
||||
.max_rate = 2900000000UL,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_hfpll_match_table[] = {
|
||||
{ .compatible = "qcom,hfpll" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
|
||||
|
||||
static const struct regmap_config hfpll_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0x30,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int qcom_hfpll_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *base;
|
||||
struct regmap *regmap;
|
||||
struct clk_hfpll *h;
|
||||
struct clk_init_data init = {
|
||||
.parent_names = (const char *[]){ "xo" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_ops_hfpll,
|
||||
};
|
||||
|
||||
h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
if (of_property_read_string_index(dev->of_node, "clock-output-names",
|
||||
0, &init.name))
|
||||
return -ENODEV;
|
||||
|
||||
h->d = &hdata;
|
||||
h->clkr.hw.init = &init;
|
||||
spin_lock_init(&h->lock);
|
||||
|
||||
return devm_clk_register_regmap(&pdev->dev, &h->clkr);
|
||||
}
|
||||
|
||||
static struct platform_driver qcom_hfpll_driver = {
|
||||
.probe = qcom_hfpll_probe,
|
||||
.driver = {
|
||||
.name = "qcom-hfpll",
|
||||
.of_match_table = qcom_hfpll_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(qcom_hfpll_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:qcom-hfpll");
|
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
static const char *aux_parents[] = {
|
||||
"pll8_vote",
|
||||
"pxo",
|
||||
};
|
||||
|
||||
static unsigned int aux_parent_map[] = {
|
||||
3,
|
||||
0,
|
||||
};
|
||||
|
||||
static const struct of_device_id kpss_xcc_match_table[] = {
|
||||
{ .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL },
|
||||
{ .compatible = "qcom,kpss-gcc" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kpss_xcc_match_table);
|
||||
|
||||
static int kpss_xcc_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *id;
|
||||
struct clk *clk;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
const char *name;
|
||||
|
||||
id = of_match_device(kpss_xcc_match_table, &pdev->dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
if (id->data) {
|
||||
if (of_property_read_string_index(pdev->dev.of_node,
|
||||
"clock-output-names",
|
||||
0, &name))
|
||||
return -ENODEV;
|
||||
base += 0x14;
|
||||
} else {
|
||||
name = "acpu_l2_aux";
|
||||
base += 0x28;
|
||||
}
|
||||
|
||||
clk = clk_register_mux_table(&pdev->dev, name, aux_parents,
|
||||
ARRAY_SIZE(aux_parents), 0, base, 0, 0x3,
|
||||
0, aux_parent_map, NULL);
|
||||
|
||||
platform_set_drvdata(pdev, clk);
|
||||
|
||||
return PTR_ERR_OR_ZERO(clk);
|
||||
}
|
||||
|
||||
static int kpss_xcc_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
clk_unregister_mux(platform_get_drvdata(pdev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver kpss_xcc_driver = {
|
||||
.probe = kpss_xcc_driver_probe,
|
||||
.remove = kpss_xcc_driver_remove,
|
||||
.driver = {
|
||||
.name = "kpss-xcc",
|
||||
.of_match_table = kpss_xcc_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(kpss_xcc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:kpss-xcc");
|
|
@ -0,0 +1,397 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk-krait.h"
|
||||
|
||||
static unsigned int sec_mux_map[] = {
|
||||
2,
|
||||
0,
|
||||
};
|
||||
|
||||
static unsigned int pri_mux_map[] = {
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Notifier function for switching the muxes to safe parent
|
||||
* while the hfpll is getting reprogrammed.
|
||||
*/
|
||||
static int krait_notifier_cb(struct notifier_block *nb,
|
||||
unsigned long event,
|
||||
void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
|
||||
clk_nb);
|
||||
/* Switch to safe parent */
|
||||
if (event == PRE_RATE_CHANGE) {
|
||||
mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
|
||||
ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
|
||||
mux->reparent = false;
|
||||
/*
|
||||
* By the time POST_RATE_CHANGE notifier is called,
|
||||
* clk framework itself would have changed the parent for the new rate.
|
||||
* Only otherwise, put back to the old parent.
|
||||
*/
|
||||
} else if (event == POST_RATE_CHANGE) {
|
||||
if (!mux->reparent)
|
||||
ret = krait_mux_clk_ops.set_parent(&mux->hw,
|
||||
mux->old_index);
|
||||
}
|
||||
|
||||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
static int krait_notifier_register(struct device *dev, struct clk *clk,
|
||||
struct krait_mux_clk *mux)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mux->clk_nb.notifier_call = krait_notifier_cb;
|
||||
ret = clk_notifier_register(clk, &mux->clk_nb);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to register clock notifier: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
|
||||
{
|
||||
struct krait_div2_clk *div;
|
||||
struct clk_init_data init = {
|
||||
.num_parents = 1,
|
||||
.ops = &krait_div2_clk_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
};
|
||||
const char *p_names[1];
|
||||
struct clk *clk;
|
||||
|
||||
div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
|
||||
if (!div)
|
||||
return -ENOMEM;
|
||||
|
||||
div->width = 2;
|
||||
div->shift = 6;
|
||||
div->lpl = id >= 0;
|
||||
div->offset = offset;
|
||||
div->hw.init = &init;
|
||||
|
||||
init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
init.parent_names = p_names;
|
||||
p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
|
||||
if (!p_names[0]) {
|
||||
kfree(init.name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clk = devm_clk_register(dev, &div->hw);
|
||||
kfree(p_names[0]);
|
||||
kfree(init.name);
|
||||
|
||||
return PTR_ERR_OR_ZERO(clk);
|
||||
}
|
||||
|
||||
static int
|
||||
krait_add_sec_mux(struct device *dev, int id, const char *s,
|
||||
unsigned int offset, bool unique_aux)
|
||||
{
|
||||
int ret;
|
||||
struct krait_mux_clk *mux;
|
||||
static const char *sec_mux_list[] = {
|
||||
"acpu_aux",
|
||||
"qsb",
|
||||
};
|
||||
struct clk_init_data init = {
|
||||
.parent_names = sec_mux_list,
|
||||
.num_parents = ARRAY_SIZE(sec_mux_list),
|
||||
.ops = &krait_mux_clk_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
};
|
||||
struct clk *clk;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return -ENOMEM;
|
||||
|
||||
mux->offset = offset;
|
||||
mux->lpl = id >= 0;
|
||||
mux->mask = 0x3;
|
||||
mux->shift = 2;
|
||||
mux->parent_map = sec_mux_map;
|
||||
mux->hw.init = &init;
|
||||
mux->safe_sel = 0;
|
||||
|
||||
init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
if (unique_aux) {
|
||||
sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
|
||||
if (!sec_mux_list[0]) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto err_aux;
|
||||
}
|
||||
}
|
||||
|
||||
clk = devm_clk_register(dev, &mux->hw);
|
||||
|
||||
ret = krait_notifier_register(dev, clk, mux);
|
||||
if (ret)
|
||||
goto unique_aux;
|
||||
|
||||
unique_aux:
|
||||
if (unique_aux)
|
||||
kfree(sec_mux_list[0]);
|
||||
err_aux:
|
||||
kfree(init.name);
|
||||
return PTR_ERR_OR_ZERO(clk);
|
||||
}
|
||||
|
||||
static struct clk *
|
||||
krait_add_pri_mux(struct device *dev, int id, const char *s,
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct krait_mux_clk *mux;
|
||||
const char *p_names[3];
|
||||
struct clk_init_data init = {
|
||||
.parent_names = p_names,
|
||||
.num_parents = ARRAY_SIZE(p_names),
|
||||
.ops = &krait_mux_clk_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
};
|
||||
struct clk *clk;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mux->mask = 0x3;
|
||||
mux->shift = 0;
|
||||
mux->offset = offset;
|
||||
mux->lpl = id >= 0;
|
||||
mux->parent_map = pri_mux_map;
|
||||
mux->hw.init = &init;
|
||||
mux->safe_sel = 2;
|
||||
|
||||
init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
|
||||
if (!init.name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
|
||||
if (!p_names[0]) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto err_p0;
|
||||
}
|
||||
|
||||
p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
|
||||
if (!p_names[1]) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto err_p1;
|
||||
}
|
||||
|
||||
p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
|
||||
if (!p_names[2]) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto err_p2;
|
||||
}
|
||||
|
||||
clk = devm_clk_register(dev, &mux->hw);
|
||||
|
||||
ret = krait_notifier_register(dev, clk, mux);
|
||||
if (ret)
|
||||
goto err_p3;
|
||||
err_p3:
|
||||
kfree(p_names[2]);
|
||||
err_p2:
|
||||
kfree(p_names[1]);
|
||||
err_p1:
|
||||
kfree(p_names[0]);
|
||||
err_p0:
|
||||
kfree(init.name);
|
||||
return clk;
|
||||
}
|
||||
|
||||
/* id < 0 for L2, otherwise id == physical CPU number */
|
||||
static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
|
||||
{
|
||||
int ret;
|
||||
unsigned int offset;
|
||||
void *p = NULL;
|
||||
const char *s;
|
||||
struct clk *clk;
|
||||
|
||||
if (id >= 0) {
|
||||
offset = 0x4501 + (0x1000 * id);
|
||||
s = p = kasprintf(GFP_KERNEL, "%d", id);
|
||||
if (!s)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
} else {
|
||||
offset = 0x500;
|
||||
s = "_l2";
|
||||
}
|
||||
|
||||
ret = krait_add_div(dev, id, s, offset);
|
||||
if (ret) {
|
||||
clk = ERR_PTR(ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
|
||||
if (ret) {
|
||||
clk = ERR_PTR(ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
clk = krait_add_pri_mux(dev, id, s, offset);
|
||||
err:
|
||||
kfree(p);
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
unsigned int idx = clkspec->args[0];
|
||||
struct clk **clks = data;
|
||||
|
||||
if (idx >= 5) {
|
||||
pr_err("%s: invalid clock index %d\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return clks[idx] ? : ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static const struct of_device_id krait_cc_match_table[] = {
|
||||
{ .compatible = "qcom,krait-cc-v1", (void *)1UL },
|
||||
{ .compatible = "qcom,krait-cc-v2" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, krait_cc_match_table);
|
||||
|
||||
static int krait_cc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *id;
|
||||
unsigned long cur_rate, aux_rate;
|
||||
int cpu;
|
||||
struct clk *clk;
|
||||
struct clk **clks;
|
||||
struct clk *l2_pri_mux_clk;
|
||||
|
||||
id = of_match_device(krait_cc_match_table, dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
/* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
|
||||
clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
if (!id->data) {
|
||||
clk = clk_register_fixed_factor(dev, "acpu_aux",
|
||||
"gpll0_vote", 0, 1, 2);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
/* Krait configurations have at most 4 CPUs and one L2 */
|
||||
clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
clk = krait_add_clks(dev, cpu, id->data);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
clks[cpu] = clk;
|
||||
}
|
||||
|
||||
l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
|
||||
if (IS_ERR(l2_pri_mux_clk))
|
||||
return PTR_ERR(l2_pri_mux_clk);
|
||||
clks[4] = l2_pri_mux_clk;
|
||||
|
||||
/*
|
||||
* We don't want the CPU or L2 clocks to be turned off at late init
|
||||
* if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
|
||||
* refcount of these clocks. Any cpufreq/hotplug manager can assume
|
||||
* that the clocks have already been prepared and enabled by the time
|
||||
* they take over.
|
||||
*/
|
||||
for_each_online_cpu(cpu) {
|
||||
clk_prepare_enable(l2_pri_mux_clk);
|
||||
WARN(clk_prepare_enable(clks[cpu]),
|
||||
"Unable to turn on CPU%d clock", cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Force reinit of HFPLLs and muxes to overwrite any potential
|
||||
* incorrect configuration of HFPLLs and muxes by the bootloader.
|
||||
* While at it, also make sure the cores are running at known rates
|
||||
* and print the current rate.
|
||||
*
|
||||
* The clocks are set to aux clock rate first to make sure the
|
||||
* secondary mux is not sourcing off of QSB. The rate is then set to
|
||||
* two different rates to force a HFPLL reinit under all
|
||||
* circumstances.
|
||||
*/
|
||||
cur_rate = clk_get_rate(l2_pri_mux_clk);
|
||||
aux_rate = 384000000;
|
||||
if (cur_rate == 1) {
|
||||
pr_info("L2 @ QSB rate. Forcing new rate.\n");
|
||||
cur_rate = aux_rate;
|
||||
}
|
||||
clk_set_rate(l2_pri_mux_clk, aux_rate);
|
||||
clk_set_rate(l2_pri_mux_clk, 2);
|
||||
clk_set_rate(l2_pri_mux_clk, cur_rate);
|
||||
pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
|
||||
for_each_possible_cpu(cpu) {
|
||||
clk = clks[cpu];
|
||||
cur_rate = clk_get_rate(clk);
|
||||
if (cur_rate == 1) {
|
||||
pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
|
||||
cur_rate = aux_rate;
|
||||
}
|
||||
|
||||
clk_set_rate(clk, aux_rate);
|
||||
clk_set_rate(clk, 2);
|
||||
clk_set_rate(clk, cur_rate);
|
||||
pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
|
||||
}
|
||||
|
||||
of_clk_add_provider(dev->of_node, krait_of_get, clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver krait_cc_driver = {
|
||||
.probe = krait_cc_probe,
|
||||
.driver = {
|
||||
.name = "krait-cc",
|
||||
.of_match_table = krait_cc_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(krait_cc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Krait CPU Clock Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:krait-cc");
|
|
@ -80,16 +80,12 @@ static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw,
|
|||
static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
u32 val;
|
||||
|
||||
val = clk_readl(ddrclk->reg_base +
|
||||
ddrclk->mux_offset) >> ddrclk->mux_shift;
|
||||
val &= GENMASK(ddrclk->mux_width - 1, 0);
|
||||
|
||||
if (val >= num_parents)
|
||||
return -EINVAL;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
|
@ -645,7 +645,7 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
|
|||
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
|
||||
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
|
||||
GATE(HCLK_CIF1, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS),
|
||||
GATE(0, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
|
||||
GATE(HCLK_HDMI, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
|
||||
|
||||
GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED,
|
||||
RK2928_CLKGATE_CON(5), 14, GFLAGS),
|
||||
|
|
|
@ -83,22 +83,43 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
|
|||
RK3066_PLL_RATE( 768000000, 1, 64, 2),
|
||||
RK3066_PLL_RATE( 742500000, 8, 495, 2),
|
||||
RK3066_PLL_RATE( 696000000, 1, 58, 2),
|
||||
RK3066_PLL_RATE_NB(621000000, 1, 207, 8, 1),
|
||||
RK3066_PLL_RATE( 600000000, 1, 50, 2),
|
||||
RK3066_PLL_RATE_NB(594000000, 1, 198, 8, 1),
|
||||
RK3066_PLL_RATE( 552000000, 1, 46, 2),
|
||||
RK3066_PLL_RATE( 504000000, 1, 84, 4),
|
||||
RK3066_PLL_RATE( 500000000, 3, 125, 2),
|
||||
RK3066_PLL_RATE( 456000000, 1, 76, 4),
|
||||
RK3066_PLL_RATE( 428000000, 1, 107, 6),
|
||||
RK3066_PLL_RATE( 408000000, 1, 68, 4),
|
||||
RK3066_PLL_RATE( 400000000, 3, 100, 2),
|
||||
RK3066_PLL_RATE_NB( 394000000, 1, 197, 12, 1),
|
||||
RK3066_PLL_RATE( 384000000, 2, 128, 4),
|
||||
RK3066_PLL_RATE( 360000000, 1, 60, 4),
|
||||
RK3066_PLL_RATE_NB( 356000000, 1, 178, 12, 1),
|
||||
RK3066_PLL_RATE_NB( 324000000, 1, 189, 14, 1),
|
||||
RK3066_PLL_RATE( 312000000, 1, 52, 4),
|
||||
RK3066_PLL_RATE( 300000000, 1, 50, 4),
|
||||
RK3066_PLL_RATE( 297000000, 2, 198, 8),
|
||||
RK3066_PLL_RATE_NB( 308000000, 1, 154, 12, 1),
|
||||
RK3066_PLL_RATE_NB( 303000000, 1, 202, 16, 1),
|
||||
RK3066_PLL_RATE( 300000000, 1, 75, 6),
|
||||
RK3066_PLL_RATE_NB( 297750000, 2, 397, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 293250000, 2, 391, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 292500000, 1, 195, 16, 1),
|
||||
RK3066_PLL_RATE( 273600000, 1, 114, 10),
|
||||
RK3066_PLL_RATE_NB( 273000000, 1, 182, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 270000000, 1, 180, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 266250000, 2, 355, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 256500000, 1, 171, 16, 1),
|
||||
RK3066_PLL_RATE( 252000000, 1, 84, 8),
|
||||
RK3066_PLL_RATE( 216000000, 1, 72, 8),
|
||||
RK3066_PLL_RATE( 148500000, 2, 99, 8),
|
||||
RK3066_PLL_RATE_NB( 250500000, 1, 167, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 243428571, 1, 142, 14, 1),
|
||||
RK3066_PLL_RATE( 238000000, 1, 119, 12),
|
||||
RK3066_PLL_RATE_NB( 219750000, 2, 293, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 216000000, 1, 144, 16, 1),
|
||||
RK3066_PLL_RATE_NB( 213000000, 1, 142, 16, 1),
|
||||
RK3066_PLL_RATE( 195428571, 1, 114, 14),
|
||||
RK3066_PLL_RATE( 160000000, 1, 80, 12),
|
||||
RK3066_PLL_RATE( 157500000, 1, 105, 16),
|
||||
RK3066_PLL_RATE( 126000000, 1, 84, 16),
|
||||
RK3066_PLL_RATE( 48000000, 1, 64, 32),
|
||||
{ /* sentinel */ },
|
||||
|
|
|
@ -813,22 +813,22 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|||
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc",
|
||||
RK3328_SDMMC_CON0, 1),
|
||||
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc",
|
||||
RK3328_SDMMC_CON1, 1),
|
||||
RK3328_SDMMC_CON1, 0),
|
||||
|
||||
MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio",
|
||||
RK3328_SDIO_CON0, 1),
|
||||
MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio",
|
||||
RK3328_SDIO_CON1, 1),
|
||||
RK3328_SDIO_CON1, 0),
|
||||
|
||||
MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc",
|
||||
RK3328_EMMC_CON0, 1),
|
||||
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc",
|
||||
RK3328_EMMC_CON1, 1),
|
||||
RK3328_EMMC_CON1, 0),
|
||||
|
||||
MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext",
|
||||
RK3328_SDMMC_EXT_CON0, 1),
|
||||
MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext",
|
||||
RK3328_SDMMC_EXT_CON1, 1),
|
||||
RK3328_SDMMC_EXT_CON1, 0),
|
||||
};
|
||||
|
||||
static const char *const rk3328_critical_clocks[] __initconst = {
|
||||
|
|
|
@ -273,6 +273,7 @@
|
|||
#define IMX6QDL_CLK_MLB_PODF 260
|
||||
#define IMX6QDL_CLK_EPIT1 261
|
||||
#define IMX6QDL_CLK_EPIT2 262
|
||||
#define IMX6QDL_CLK_END 263
|
||||
#define IMX6QDL_CLK_MMDC_P0_IPG 263
|
||||
#define IMX6QDL_CLK_END 264
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
|
||||
|
|
|
@ -175,6 +175,8 @@
|
|||
#define IMX6SL_CLK_SSI2_IPG 162
|
||||
#define IMX6SL_CLK_SSI3_IPG 163
|
||||
#define IMX6SL_CLK_SPDIF_GCLK 164
|
||||
#define IMX6SL_CLK_END 165
|
||||
#define IMX6SL_CLK_MMDC_P0_IPG 165
|
||||
#define IMX6SL_CLK_MMDC_P1_IPG 166
|
||||
#define IMX6SL_CLK_END 167
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX6SL_H */
|
||||
|
|
|
@ -203,7 +203,8 @@
|
|||
#define IMX6SLL_CLK_GPIO4 176
|
||||
#define IMX6SLL_CLK_GPIO5 177
|
||||
#define IMX6SLL_CLK_GPIO6 178
|
||||
#define IMX6SLL_CLK_MMDC_P1_IPG 179
|
||||
|
||||
#define IMX6SLL_CLK_END 179
|
||||
#define IMX6SLL_CLK_END 180
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX6SLL_H */
|
||||
|
|
|
@ -279,6 +279,7 @@
|
|||
#define IMX6SX_CLK_LVDS2_OUT 266
|
||||
#define IMX6SX_CLK_LVDS2_IN 267
|
||||
#define IMX6SX_CLK_ANACLK2 268
|
||||
#define IMX6SX_CLK_CLK_END 269
|
||||
#define IMX6SX_CLK_MMDC_P1_IPG 269
|
||||
#define IMX6SX_CLK_CLK_END 270
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX6SX_H */
|
||||
|
|
|
@ -259,7 +259,8 @@
|
|||
#define IMX6UL_CLK_GPIO3 246
|
||||
#define IMX6UL_CLK_GPIO4 247
|
||||
#define IMX6UL_CLK_GPIO5 248
|
||||
#define IMX6UL_CLK_MMDC_P1_IPG 249
|
||||
|
||||
#define IMX6UL_CLK_END 249
|
||||
#define IMX6UL_CLK_END 250
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */
|
||||
|
|
|
@ -319,5 +319,7 @@
|
|||
#define CE3_SRC 303
|
||||
#define CE3_CORE_CLK 304
|
||||
#define CE3_H_CLK 305
|
||||
#define PLL16 306
|
||||
#define PLL17 307
|
||||
|
||||
#endif
|
||||
|
|
|
@ -139,8 +139,9 @@
|
|||
#define HCLK_CIF1 470
|
||||
#define HCLK_VEPU 471
|
||||
#define HCLK_VDPU 472
|
||||
#define HCLK_HDMI 473
|
||||
|
||||
#define CLK_NR_CLKS (HCLK_VDPU + 1)
|
||||
#define CLK_NR_CLKS (HCLK_HDMI + 1)
|
||||
|
||||
/* soft-reset indices */
|
||||
#define SRST_MCORE 2
|
||||
|
|
Loading…
Reference in New Issue