Commit b5a53b61 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk updates from Stephen Boyd:
 "Sort of on the quieter side this time, which is probably due more to
  me not catching up as quickly on patch review than anything else.
  Overall it seems normal though, a few small changes to the core,
  mostly small non-critical fixes here and there as well as driver
  updates for new and existing hardware support.

  The biggest things are the TI clk driver rework to lay the groundwork
  for clkctrl support in the next merge window and the AmLogic
  audio/graphics clk support.

  Core:
   - clk_possible_parents debugfs file so we know which parents a clk
     could possibly have
   - Fix to make clk rate change notifiers stop on the first failure
     instead of continuing

  New Drivers:
   - Mediatek MT6797 SoCs
   - hi655x PMIC clks
   - AmLogic Meson SoC i2s and spdif audio clks and Mali graphics clks
   - Allwinner H5 SoCs and PRCM hardware

  Updates:
   - Nvidia Tegra T210 cleanups and non-critical fixes
   - TI OMAP cleanups in preparation for clkctrl support
   - trivial fixes like kcalloc(), devm_* conversions, and seq_puts()
   - ZTE zx296718 SoC VGA clks
   - Rockchip clk-ids, fixups, and rename of rk1108 to rv1108
   - IDT VersaClock 5P49V5935 support
   - Renesas R-Car H3 and M3-W IMR clks and ES2.0 rev of R-Car H3
     support"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (151 commits)
  clk: x86: pmc-atom: Checking for IS_ERR() instead of NULL
  clk: ti: divider: try to fix ti_clk_register_divider
  clk: mvebu: Use kcalloc() in two functions
  clk: mvebu: Use kcalloc() in of_cpu_clk_setup()
  clk: nomadik: Delete error messages for a failed memory allocation in two functions
  clk: nomadik: Use seq_puts() in nomadik_src_clk_show()
  clk: Improve a size determination in two functions
  clk: Replace four seq_printf() calls by seq_putc()
  clk: si5351: Delete an error message for a failed memory allocation in si5351_i2c_probe()
  clk: si5351: Use devm_kcalloc() in si5351_i2c_probe()
  clk: at91: Use kcalloc() in of_at91_clk_pll_get_characteristics()
  reset: mediatek: Add MT2701 ethsys reset controller include file
  clk: mediatek: add mt2701 ethernet reset
  clk: hi6220: Add the hi655x's pmic clock
  clk: ti: fix building without legacy omap3
  clk: ti: fix linker error with !SOC_OMAP4
  clk: hi3620: Fix a typo in one variable name
  clk: hi3620: Delete error messages for a failed memory allocation in two functions
  clk: hi3620: Use kcalloc() in hi3620_mmc_clk_init()
  clk: hisilicon: Delete error messages for failed memory allocations in hisi_clk_init()
  ...
parents c70422f7 0119dc61
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-apmixedsys"
- "mediatek,mt6797-apmixedsys"
- "mediatek,mt8135-apmixedsys"
- "mediatek,mt8173-apmixedsys"
- #clock-cells: Must be 1
......
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-imgsys", "syscon"
- "mediatek,mt6797-imgsys", "syscon"
- "mediatek,mt8173-imgsys", "syscon"
- #clock-cells: Must be 1
......
......@@ -8,6 +8,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-infracfg", "syscon"
- "mediatek,mt6797-infracfg", "syscon"
- "mediatek,mt8135-infracfg", "syscon"
- "mediatek,mt8173-infracfg", "syscon"
- #clock-cells: Must be 1
......
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-mmsys", "syscon"
- "mediatek,mt6797-mmsys", "syscon"
- "mediatek,mt8173-mmsys", "syscon"
- #clock-cells: Must be 1
......
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-topckgen"
- "mediatek,mt6797-topckgen"
- "mediatek,mt8135-topckgen"
- "mediatek,mt8173-topckgen"
- #clock-cells: Must be 1
......
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-vdecsys", "syscon"
- "mediatek,mt6797-vdecsys", "syscon"
- "mediatek,mt8173-vdecsys", "syscon"
- #clock-cells: Must be 1
......
......@@ -5,7 +5,8 @@ The Mediatek vencsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be:
- compatible: Should be one of:
- "mediatek,mt6797-vencsys", "syscon"
- "mediatek,mt8173-vencsys", "syscon"
- #clock-cells: Must be 1
......
......@@ -6,18 +6,21 @@ from 3 to 12 output clocks.
==I2C device node==
Required properties:
- compatible: shall be one of "idt,5p49v5923" , "idt,5p49v5933".
- compatible: shall be one of "idt,5p49v5923" , "idt,5p49v5933" ,
"idt,5p49v5935".
- reg: i2c device address, shall be 0x68 or 0x6a.
- #clock-cells: from common clock binding; shall be set to 1.
- clocks: from common clock binding; list of parent clock handles,
- 5p49v5923: (required) either or both of XTAL or CLKIN
reference clock.
- 5p49v5933: (optional) property not present (internal
- 5p49v5933 and
- 5p49v5935: (optional) property not present (internal
Xtal used) or CLKIN reference
clock.
- clock-names: from common clock binding; clock input names, can be
- 5p49v5923: (required) either or both of "xin", "clkin".
- 5p49v5933: (optional) property not present or "clkin".
- 5p49v5933 and
- 5p49v5935: (optional) property not present or "clkin".
==Mapping between clock specifier and physical pins==
......@@ -34,6 +37,13 @@ clock specifier, the following mapping applies:
1 -- OUT1
2 -- OUT4
5P49V5935:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
==Example==
/* 25MHz reference crystal */
......
* Rockchip RK1108 Clock and Reset Unit
* Rockchip RV1108 Clock and Reset Unit
The RK1108 clock controller generates and supplies clock to various
The RV1108 clock controller generates and supplies clock to various
controllers within the SoC and also implements a reset controller for SoC
peripherals.
Required Properties:
- compatible: should be "rockchip,rk1108-cru"
- compatible: should be "rockchip,rv1108-cru"
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
......@@ -19,7 +19,7 @@ Optional Properties:
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/rk1108-cru.h headers and can be
preprocessor macros in the dt-bindings/clock/rv1108-cru.h headers and can be
used in device tree sources. Similar macros exist for the reset sources in
these files.
......@@ -38,7 +38,7 @@ clock-output-names:
Example: Clock controller node:
cru: cru@20200000 {
compatible = "rockchip,rk1108-cru";
compatible = "rockchip,rv1108-cru";
reg = <0x20200000 0x1000>;
rockchip,grf = <&grf>;
......@@ -50,7 +50,7 @@ Example: UART controller node that consumes the clock generated by the clock
controller:
uart0: serial@10230000 {
compatible = "rockchip,rk1108-uart", "snps,dw-apb-uart";
compatible = "rockchip,rv1108-uart", "snps,dw-apb-uart";
reg = <0x10230000 0x100>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
......
......@@ -7,9 +7,12 @@ Required properties :
- "allwinner,sun8i-a23-ccu"
- "allwinner,sun8i-a33-ccu"
- "allwinner,sun8i-h3-ccu"
- "allwinner,sun8i-h3-r-ccu"
- "allwinner,sun8i-v3s-ccu"
- "allwinner,sun9i-a80-ccu"
- "allwinner,sun50i-a64-ccu"
- "allwinner,sun50i-a64-r-ccu"
- "allwinner,sun50i-h5-ccu"
- reg: Must contain the registers base address and length
- clocks: phandle to the oscillators feeding the CCU. Two are needed:
......@@ -19,7 +22,10 @@ Required properties :
- #clock-cells : must contain 1
- #reset-cells : must contain 1
Example:
For the PRCM CCUs on H3/A64, one more clock is needed:
- "iosc": the SoC's internal frequency oscillator
Example for generic CCU:
ccu: clock@01c20000 {
compatible = "allwinner,sun8i-h3-ccu";
reg = <0x01c20000 0x400>;
......@@ -28,3 +34,13 @@ ccu: clock@01c20000 {
#clock-cells = <1>;
#reset-cells = <1>;
};
Example for PRCM CCU:
r_ccu: clock@01f01400 {
compatible = "allwinner,sun50i-a64-r-ccu";
reg = <0x01f01400 0x100>;
clocks = <&osc24M>, <&osc32k>, <&iosc>;
clock-names = "hosc", "losc", "iosc";
#clock-cells = <1>;
#reset-cells = <1>;
};
......@@ -1085,6 +1085,16 @@ F: drivers/pinctrl/meson/
F: drivers/mmc/host/meson*
N: meson
ARM/Amlogic Meson SoC CLOCK FRAMEWORK
M: Neil Armstrong <narmstrong@baylibre.com>
M: Jerome Brunet <jbrunet@baylibre.com>
L: linux-amlogic@lists.infradead.org
S: Maintained
F: drivers/clk/meson/
F: include/dt-bindings/clock/meson*
F: include/dt-bindings/clock/gxbb*
F: Documentation/devicetree/bindings/clock/amlogic*
ARM/Annapurna Labs ALPINE ARCHITECTURE
M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
M: Antoine Tenart <antoine.tenart@free-electrons.com>
......
......@@ -41,7 +41,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/rk1108-cru.h>
#include <dt-bindings/clock/rv1108-cru.h>
#include <dt-bindings/pinctrl/rockchip.h>
/ {
#address-cells = <1>;
......
......@@ -138,7 +138,8 @@ int omap2_reprogram_dpllcore(struct clk_hw *hw, unsigned long rate,
if (!dd)
return -EINVAL;
tmpset.cm_clksel1_pll = readl_relaxed(dd->mult_div1_reg);
tmpset.cm_clksel1_pll =
omap_clk_ll_ops.clk_readl(&dd->mult_div1_reg);
tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
dd->div1_mask);
div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
......
......@@ -54,9 +54,10 @@ u16 cpu_mask;
#define OMAP3PLUS_DPLL_FINT_MIN 32000
#define OMAP3PLUS_DPLL_FINT_MAX 52000000
static struct ti_clk_ll_ops omap_clk_ll_ops = {
struct ti_clk_ll_ops omap_clk_ll_ops = {
.clkdm_clk_enable = clkdm_clk_enable,
.clkdm_clk_disable = clkdm_clk_disable,
.clkdm_lookup = clkdm_lookup,
.cm_wait_module_ready = omap_cm_wait_module_ready,
.cm_split_idlest_reg = cm_split_idlest_reg,
};
......@@ -78,38 +79,6 @@ int __init omap2_clk_setup_ll_ops(void)
* OMAP2+ specific clock functions
*/
/* Public functions */
/**
* omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
* @clk: OMAP clock struct ptr to use
*
* Convert a clockdomain name stored in a struct clk 'clk' into a
* clockdomain pointer, and save it into the struct clk. Intended to be
* called during clk_register(). No return value.
*/
void omap2_init_clk_clkdm(struct clk_hw *hw)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct clockdomain *clkdm;
const char *clk_name;
if (!clk->clkdm_name)
return;
clk_name = __clk_get_name(hw->clk);
clkdm = clkdm_lookup(clk->clkdm_name);
if (clkdm) {
pr_debug("clock: associated clk %s to clkdm %s\n",
clk_name, clk->clkdm_name);
clk->clkdm = clkdm;
} else {
pr_debug("clock: could not associate clk %s to clkdm %s\n",
clk_name, clk->clkdm_name);
}
}
/**
* ti_clk_init_features - init clock features struct for the SoC
*
......
......@@ -64,6 +64,8 @@
#define OMAP4XXX_EN_DPLL_FRBYPASS 0x6
#define OMAP4XXX_EN_DPLL_LOCKED 0x7
extern struct ti_clk_ll_ops omap_clk_ll_ops;
extern u16 cpu_mask;
extern const struct clkops clkops_omap2_dflt_wait;
......
......@@ -23,6 +23,7 @@
#define MAX_MODULE_READY_TIME 2000
# ifndef __ASSEMBLER__
#include <linux/clk/ti.h>
extern void __iomem *cm_base;
extern void __iomem *cm2_base;
extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2);
......@@ -50,7 +51,7 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2);
* @module_disable: ptr to the SoC CM-specific module_disable impl
*/
struct cm_ll_data {
int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst,
int (*split_idlest_reg)(struct clk_omap_reg *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id);
int (*wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg,
u8 idlest_shift);
......@@ -60,7 +61,7 @@ struct cm_ll_data {
void (*module_disable)(u8 part, u16 inst, u16 clkctrl_offs);
};
extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
extern int cm_split_idlest_reg(struct clk_omap_reg *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id);
int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg,
u8 idlest_shift);
......
......@@ -204,7 +204,7 @@ void omap2xxx_cm_apll96_disable(void)
* XXX This function is only needed until absolute register addresses are
* removed from the OMAP struct clk records.
*/
static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
static int omap2xxx_cm_split_idlest_reg(struct clk_omap_reg *idlest_reg,
s16 *prcm_inst,
u8 *idlest_reg_id)
{
......@@ -212,10 +212,7 @@ static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
u8 idlest_offs;
int i;
if (idlest_reg < cm_base || idlest_reg > (cm_base + 0x0fff))
return -EINVAL;
idlest_offs = (unsigned long)idlest_reg & 0xff;
idlest_offs = idlest_reg->offset & 0xff;
for (i = 0; i < ARRAY_SIZE(omap2xxx_cm_idlest_offs); i++) {
if (idlest_offs == omap2xxx_cm_idlest_offs[i]) {
*idlest_reg_id = i + 1;
......@@ -226,7 +223,7 @@ static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
if (i == ARRAY_SIZE(omap2xxx_cm_idlest_offs))
return -EINVAL;
offs = idlest_reg - cm_base;
offs = idlest_reg->offset;
offs &= 0xff00;
*prcm_inst = offs;
......
......@@ -118,7 +118,7 @@ static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
* XXX This function is only needed until absolute register addresses are
* removed from the OMAP struct clk records.
*/
static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
static int omap3xxx_cm_split_idlest_reg(struct clk_omap_reg *idlest_reg,
s16 *prcm_inst,
u8 *idlest_reg_id)
{
......@@ -126,11 +126,7 @@ static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
u8 idlest_offs;
int i;
if (idlest_reg < (cm_base + OMAP3430_IVA2_MOD) ||
idlest_reg > (cm_base + 0x1ffff))
return -EINVAL;
idlest_offs = (unsigned long)idlest_reg & 0xff;
idlest_offs = idlest_reg->offset & 0xff;
for (i = 0; i < ARRAY_SIZE(omap3xxx_cm_idlest_offs); i++) {
if (idlest_offs == omap3xxx_cm_idlest_offs[i]) {
*idlest_reg_id = i + 1;
......@@ -141,7 +137,7 @@ static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
if (i == ARRAY_SIZE(omap3xxx_cm_idlest_offs))
return -EINVAL;
offs = idlest_reg - cm_base;
offs = idlest_reg->offset;
offs &= 0xff00;
*prcm_inst = offs;
......
......@@ -65,7 +65,7 @@ void __init omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2)
* or 0 upon success. XXX This function is only needed until absolute
* register addresses are removed from the OMAP struct clk records.
*/
int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
int cm_split_idlest_reg(struct clk_omap_reg *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id)
{
if (!cm_ll_data->split_idlest_reg) {
......
......@@ -47,6 +47,14 @@ config COMMON_CLK_RK808
clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
by control register.
config COMMON_CLK_HI655X
tristate "Clock driver for Hi655x"
depends on MFD_HI655X_PMIC || COMPILE_TEST
---help---
This driver supports the hi655x PMIC clock. This
multi-function device has one fixed-rate oscillator, clocked
at 32KHz.
config COMMON_CLK_SCPI
tristate "Clock driver controlled via SCPI interface"
depends on ARM_SCPI_PROTOCOL || COMPILE_TEST
......
......@@ -36,6 +36,7 @@ obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
......
......@@ -399,18 +399,18 @@ of_at91_clk_pll_get_characteristics(struct device_node *np)
if (!characteristics)
return NULL;
output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL);
output = kcalloc(num_output, sizeof(*output), GFP_KERNEL);
if (!output)
goto out_free_characteristics;
if (num_cells > 2) {
out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL);
out = kcalloc(num_output, sizeof(*out), GFP_KERNEL);
if (!out)
goto out_free_output;
}
if (num_cells > 3) {
icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL);
icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL);
if (!icpll)
goto out_free_output;
}
......
......@@ -277,7 +277,7 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index,
if (rate >= VCO_LOW && rate < VCO_HIGH) {
ki = 4;
kp_index = KP_BAND_MID;
} else if (rate >= VCO_HIGH && rate && rate < VCO_HIGH_HIGH) {
} else if (rate >= VCO_HIGH && rate < VCO_HIGH_HIGH) {
ki = 3;
kp_index = KP_BAND_HIGH;
} else if (rate >= VCO_HIGH_HIGH && rate < VCO_MAX) {
......
......@@ -103,7 +103,7 @@ CLK_OF_DECLARE(ns2_genpll_src_clk, "brcm,ns2-genpll-scr",
static const struct iproc_pll_ctrl genpll_sw = {
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL,
.aon = AON_VAL(0x0, 2, 9, 8),
.aon = AON_VAL(0x0, 1, 11, 10),
.reset = RESET_VAL(0x4, 2, 1),
.dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 2, 3),
.ndiv_int = REG_VAL(0x8, 4, 10),
......
......@@ -36,15 +36,35 @@
/* DEVICE_CTRL */
#define PLL_UNLOCK (1 << 7)
#define AUXOUTDIS (1 << 1)
#define CLKOUTDIS (1 << 0)
/* DEVICE_CFG1 */
#define RSEL(x) (((x) & 0x3) << 3)
#define RSEL_MASK RSEL(0x3)
#define ENDEV1 (0x1)
/* DEVICE_CFG2 */
#define AUTORMOD (1 << 3)
#define LOCKCLK(x) (((x) & 0x3) << 1)
#define LOCKCLK_MASK LOCKCLK(0x3)
#define FRACNSRC_MASK (1 << 0)
#define FRACNSRC_STATIC (0 << 0)
#define FRACNSRC_DYNAMIC (1 << 1)
/* GLOBAL_CFG */
#define ENDEV2 (0x1)
/* FUNC_CFG1 */
#define CLKSKIPEN (1 << 7)
#define REFCLKDIV(x) (((x) & 0x3) << 3)
#define REFCLKDIV_MASK REFCLKDIV(0x3)
/* FUNC_CFG2 */
#define LFRATIO_MASK (1 << 3)
#define LFRATIO_20_12 (0 << 3)
#define LFRATIO_12_20 (1 << 3)
#define CH_SIZE_ERR(ch) ((ch < 0) || (ch >= CH_MAX))
#define hw_to_priv(_hw) container_of(_hw, struct cs2000_priv, hw)
#define priv_to_client(priv) (priv->client)
......@@ -110,6 +130,17 @@ static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
if (ret < 0)
return ret;
ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN,
enable ? CLKSKIPEN : 0);
if (ret < 0)
return ret;
/* FIXME: for Static ratio mode */
ret = cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK,
LFRATIO_12_20);
if (ret < 0)
return ret;
return 0;
}
......@@ -127,7 +158,9 @@ static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
else
return -EINVAL;
return cs2000_bset(priv, FUNC_CFG1, 0x3 << 3, val << 3);
return cs2000_bset(priv, FUNC_CFG1,
REFCLKDIV_MASK,
REFCLKDIV(val));
}
static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
......@@ -153,7 +186,10 @@ static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
{
/* enable both AUX_OUT, CLK_OUT */
return cs2000_write(priv, DEVICE_CTRL, enable ? 0 : 0x3);
return cs2000_bset(priv, DEVICE_CTRL,
(AUXOUTDIS | CLKOUTDIS),
enable ? 0 :
(AUXOUTDIS | CLKOUTDIS));
}
static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
......@@ -243,7 +279,9 @@ static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
if (ret < 0)
return ret;
ret = cs2000_write(priv, DEVICE_CFG2, 0x0);
ret = cs2000_bset(priv, DEVICE_CFG2,
(AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK),
(LOCKCLK(ch) | FRACNSRC_STATIC));
if (ret < 0)
return ret;
......@@ -351,8 +389,7 @@ static const struct clk_ops cs2000_ops = {
static int cs2000_clk_get(struct cs2000_priv *priv)
{
struct i2c_client *client = priv_to_client(priv);
struct device *dev = &client->dev;
struct device *dev = priv_to_dev(priv);
struct clk *clk_in, *ref_clk;
clk_in = devm_clk_get(dev, "clk_in");
......@@ -420,8 +457,7 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
static int cs2000_version_print(struct cs2000_priv *priv)
{
struct i2c_client *client = priv_to_client(priv);
struct device *dev = &client->dev;
struct device *dev = priv_to_dev(priv);
s32 val;
const char *revision;
......@@ -452,7 +488,7 @@ static int cs2000_version_print(struct cs2000_priv *priv)
static int cs2000_remove(struct i2c_client *client)
{
struct cs2000_priv *priv = i2c_get_clientdata(client);
struct device *dev = &client->dev;
struct device *dev = priv_to_dev(priv);
struct device_node *np = dev->of_node;
of_clk_del_provider(np);
......
/*
* Clock driver for Hi655x
*
* Copyright (c) 2017, Linaro Ltd.
*
* Author: Daniel Lezcano <daniel.lezcano@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/mfd/hi655x-pmic.h>
#define HI655X_CLK_BASE HI655X_BUS_ADDR(0x1c)
#define HI655X_CLK_SET BIT(6)
struct hi655x_clk {
struct hi655x_pmic *hi655x;
struct clk_hw clk_hw;
};
static unsigned long hi655x_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return 32768;
}
static int hi655x_clk_enable(struct clk_hw *hw, bool enable)
{
struct hi655x_clk *hi655x_clk =
container_of(hw, struct hi655x_clk, clk_hw);
struct hi655x_pmic *hi655x = hi655x_clk->hi655x;
return regmap_update_bits(hi655x->regmap, HI655X_CLK_BASE,
HI655X_CLK_SET, enable ? HI655X_CLK_SET : 0);
}
static int hi655x_clk_prepare(struct clk_hw *hw)
{
return hi655x_clk_enable(hw, true);
}
static void hi655x_clk_unprepare(struct clk_hw *hw)
{
hi655x_clk_enable(hw, false);
}
static int hi655x_clk_is_prepared(struct clk_hw *hw)
{
struct hi655x_clk *hi655x_clk =
container_of(hw, struct hi655x_clk, clk_hw);
struct hi655x_pmic *hi655x = hi655x_clk->hi655x;
int ret;
uint32_t val;
ret = regmap_read(hi655x->regmap, HI655X_CLK_BASE, &val);
if (ret < 0)
return ret;
return val & HI655X_CLK_BASE;
}
static const struct clk_ops hi655x_clk_ops = {
.prepare = hi655x_clk_prepare,
.unprepare = hi655x_clk_unprepare,
.is_prepared = hi655x_clk_is_prepared,
.recalc_rate = hi655x_clk_recalc_rate,
};
static int hi655x_clk_probe(struct platform_device *pdev)
{
struct device *parent = pdev->dev.parent;
struct hi655x_pmic *hi655x = dev_get_drvdata(parent);
struct hi655x_clk *hi655x_clk;
const char *clk_name = "hi655x-clk";
struct clk_init_data init = {
.name = clk_name,
.ops = &hi655x_clk_ops
};
int ret;
hi655x_clk = devm_kzalloc(&pdev->dev, sizeof(*hi655x_clk), GFP_KERNEL);
if (!hi655x_clk)
return -ENOMEM;
of_property_read_string_index(parent->of_node, "clock-output-names",
0, &clk_name);
hi655x_clk->clk_hw.init = &init;
hi655x_clk->hi655x = hi655x;
platform_set_drvdata(pdev, hi655x_clk);
ret = devm_clk_hw_register(&pdev->dev, &hi655x_clk->clk_hw);
if (ret)
return ret;
return of_clk_add_hw_provider(parent->of_node, of_clk_hw_simple_get,
&hi655x_clk->clk_hw);
}
static struct platform_driver hi655x_clk_driver = {
.probe = hi655x_clk_probe,
.driver = {
.name = "hi655x-clk",
},
};
module_platform_driver(hi655x_clk_driver);
MODULE_DESCRIPTION("Clk driver for the hi655x series PMICs");
MODULE_AUTHOR("Daniel Lezcano <daniel.lezcano@linaro.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:hi655x-clk");
......@@ -267,10 +267,8 @@ pll_clk_register(struct device *dev, const char *name,
}
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll) {
pr_err("%s: could not allocate PLL clk\n", __func__);
if (!pll)
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &pll_clk_ops;
......@@ -356,11 +354,9 @@ src_clk_register(struct device *dev, const char *name,
struct clk_init_data init;
sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
if (!sclk) {
pr_err("could not allocate SRC clock %s\n",
name);
if (!sclk)
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &src_clk_ops;
/* Do not force-disable the static SDRAM controller */
......@@ -467,7 +463,7 @@ static int nomadik_src_clk_show(struct seq_file *s, void *what)
u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
seq_printf(s, "Clock: Boot: Now: Request: ASKED:\n");
seq_puts(s, "Clock: Boot: Now: Request: ASKED:\n");
for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
......
......@@ -1354,10 +1354,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
return -EINVAL;
drvdata = devm_kzalloc(&client->dev, sizeof(*drvdata), GFP_KERNEL);
if (drvdata == NULL) {
dev_err(&client->dev, "unable to allocate driver data\n");
if (!drvdata)
return -ENOMEM;
}
i2c_set_clientdata(client, drvdata);
drvdata->client = client;
......@@ -1535,9 +1533,9 @@ static int si5351_i2c_probe(struct i2c_client *client,
else
parent_names[1] = si5351_pll_names[1];
drvdata->msynth = devm_kzalloc(&client->dev, num_clocks *
drvdata->msynth = devm_kcalloc(&client->dev, num_clocks,
sizeof(*drvdata->msynth), GFP_KERNEL);
drvdata->clkout = devm_kzalloc(&client->dev, num_clocks *
drvdata->clkout = devm_kcalloc(&client->dev, num_clocks,
sizeof(*drvdata->clkout), GFP_KERNEL);
drvdata->num_clkout = num_clocks;
......
......@@ -531,19 +531,26 @@ static int stm32f4_pll_is_enabled(struct clk_hw *hw)
return clk_gate_ops.is_enabled(hw);
}
#define PLL_TIMEOUT 10000
static int stm32f4_pll_enable(struct clk_hw *hw)
{
struct clk_gate *gate = to_clk_gate(hw);
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
int ret = 0;
unsigned long reg;
int bit_status;
unsigned int timeout = PLL_TIMEOUT;
ret = clk_gate_ops.enable(hw);
if (clk_gate_ops.is_enabled(hw))
return 0;
ret = readl_relaxed_poll_timeout_atomic(base + STM32F4_RCC_CR, reg,
reg & (1 << pll->bit_rdy_idx), 0, 10000);
clk_gate_ops.enable(hw);
return ret;
do {
bit_status = !(readl(gate->reg) & BIT(pll->bit_rdy_idx));
} while (bit_status && --timeout);
return bit_status;
}
static void stm32f4_pll_disable(struct clk_hw *hw)
......@@ -834,24 +841,32 @@ struct stm32_rgate {
u8 bit_rdy_idx;
};
#define RTC_TIMEOUT 1000000
#define RGATE_TIMEOUT 50000
static int rgclk_enable(struct clk_hw *hw)
{
struct clk_gate *gate = to_clk_gate(hw);
struct stm32_rgate *rgate = to_rgclk(gate);
u32 reg;
int ret;
int bit_status;
unsigned int timeout = RGATE_TIMEOUT;
if (clk_gate_ops.is_enabled(hw))
return 0;
disable_power_domain_write_protection();
clk_gate_ops.enable(hw);
ret = readl_relaxed_poll_timeout_atomic(gate->reg, reg,
reg & rgate->bit_rdy_idx, 1000, RTC_TIMEOUT);
do {
bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy_idx));
if (bit_status)
udelay(100);
} while (bit_status && --timeout);
enable_power_domain_write_protection();
return ret;
return bit_status;
}
static void rgclk_disable(struct clk_hw *hw)
......@@ -1533,7 +1548,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
}
clks[CLK_LSI] = clk_register_rgate(NULL, "lsi", "clk-lsi", 0,
base + STM32F4_RCC_CSR, 0, 2, 0, &stm32f4_clk_lock);
base + STM32F4_RCC_CSR, 0, 1, 0, &stm32f4_clk_lock);
if (IS_ERR(clks[CLK_LSI])) {
pr_err("Unable to register lsi clock\n");
......@@ -1541,7 +1556,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
}
clks[CLK_LSE] = clk_register_rgate(NULL, "lse", "clk-lse", 0,
base + STM32F4_RCC_BDCR, 0, 2, 0, &stm32f4_clk_lock);
base + STM32F4_RCC_BDCR, 0, 1, 0, &stm32f4_clk_lock);
if (IS_ERR(clks[CLK_LSE])) {
pr_err("Unable to register lse clock\n");
......
......@@ -113,10 +113,29 @@
#define VC5_MUX_IN_XIN BIT(0)
#define VC5_MUX_IN_CLKIN BIT(1)
/* Maximum number of clk_out supported by this driver */
#define VC5_MAX_CLK_OUT_NUM 5
/* Maximum number of FODs supported by this driver */
#define VC5_MAX_FOD_NUM 4
/* flags to describe chip features */
/* chip has built-in oscilator */
#define VC5_HAS_INTERNAL_XTAL BIT(0)
/* Supported IDT VC5 models. */
enum vc5_model {
IDT_VC5_5P49V5923,
IDT_VC5_5P49V5933,
IDT_VC5_5P49V5935,
};
/* Structure to describe features of a particular VC5 model */
struct vc5_chip_info {
const enum vc5_model model;
const unsigned int clk_fod_cnt;
const unsigned int clk_out_cnt;
const u32 flags;
};
struct vc5_driver_data;
......@@ -132,15 +151,15 @@ struct vc5_hw_data {
struct vc5_driver_data {
struct i2c_client *client;
struct regmap *regmap;
enum vc5_model model;
const struct vc5_chip_info *chip_info;
struct clk *pin_xin;
struct clk *pin_clkin;
unsigned char clk_mux_ins;
struct clk_hw clk_mux;
struct vc5_hw_data clk_pll;
struct vc5_hw_data clk_fod[2];
struct vc5_hw_data clk_out[3];
struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
};
static const char * const vc5_mux_names[] = {
......@@ -563,7 +582,7 @@ static struct clk_hw *vc5_of_clk_get(struct of_phandle_args *clkspec,
struct vc5_driver_data *vc5 = data;
unsigned int idx = clkspec->args[0];
if (idx > 2)
if (idx >= vc5->chip_info->clk_out_cnt)
return ERR_PTR(-EINVAL);
return &vc5->clk_out[idx].hw;
......@@ -576,6 +595,7 @@ static int vc5_map_index_to_output(const enum vc5_model model,
case IDT_VC5_5P49V5933:
return (n == 0) ? 0 : 3;
case IDT_VC5_5P49V5923:
case IDT_VC5_5P49V5935:
default:
return n;
}
......@@ -586,12 +606,10 @@ static const struct of_device_id clk_vc5_of_match[];
static int vc5_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct of_device_id *of_id =
of_match_device(clk_vc5_of_match, &client->dev);
struct vc5_driver_data *vc5;
struct clk_init_data init;
const char *parent_names[2];
unsigned int n, idx;
unsigned int n, idx = 0;
int ret;
vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
......@@ -600,7 +618,7 @@ static int vc5_probe(struct i2c_client *client,
i2c_set_clientdata(client, vc5);
vc5->client = client;
vc5->model = (enum vc5_model)of_id->data;
vc5->chip_info = of_device_get_match_data(&client->dev);
vc5->pin_xin = devm_clk_get(&client->dev, "xin");
if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER)
......@@ -622,8 +640,7 @@ static int vc5_probe(struct i2c_client *client,
if (!IS_ERR(vc5->pin_xin)) {
vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
} else if (vc5->model == IDT_VC5_5P49V5933) {
/* IDT VC5 5P49V5933 has built-in oscilator. */
} else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) {
vc5->pin_xin = clk_register_fixed_rate(&client->dev,
"internal-xtal", NULL,
0, 25000000);
......@@ -672,8 +689,8 @@ static int vc5_probe(struct i2c_client *client,
}
/* Register FODs */
for (n = 0; n < 2; n++) {
idx = vc5_map_index_to_output(vc5->model, n);
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.ops = &vc5_fod_ops;
......@@ -709,8 +726,8 @@ static int vc5_probe(struct i2c_client *client,
}
/* Register FOD-connected OUTx outputs */
for (n = 1; n < 3; n++) {
idx = vc5_map_index_to_output(vc5->model, n - 1);
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];
if (n == 1)
parent_names[1] = vc5_mux_names[0];
......@@ -744,7 +761,7 @@ static int vc5_probe(struct i2c_client *client,
return 0;
err_clk:
if (vc5->model == IDT_VC5_5P49V5933)
if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
clk_unregister_fixed_rate(vc5->pin_xin);
return ret;
}
......@@ -755,22 +772,45 @@ static int vc5_remove(struct i2c_client *client)
of_clk_del_provider(client->dev.of_node);
if (vc5->model == IDT_VC5_5P49V5933)
if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
clk_unregister_fixed_rate(vc5->pin_xin);
return 0;
}
static const struct vc5_chip_info idt_5p49v5923_info = {
.model = IDT_VC5_5P49V5923,
.clk_fod_cnt = 2,
.clk_out_cnt = 3,
.flags = 0,
};
static const struct vc5_chip_info idt_5p49v5933_info = {
.model = IDT_VC5_5P49V5933,
.clk_fod_cnt = 2,
.clk_out_cnt = 3,
.flags = VC5_HAS_INTERNAL_XTAL,
};
static const struct vc5_chip_info idt_5p49v5935_info = {
.model = IDT_VC5_5P49V5935,
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = VC5_HAS_INTERNAL_XTAL,
};
static const struct i2c_device_id vc5_id[] = {
{ "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
{ "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
{ "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
{ }
};
MODULE_DEVICE_TABLE(i2c, vc5_id);
static const struct of_device_id clk_vc5_of_match[] = {
{ .compatible = "idt,5p49v5923", .data = (void *)IDT_VC5_5P49V5923 },
{ .compatible = "idt,5p49v5933", .data = (void *)IDT_VC5_5P49V5933 },
{ .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
{ .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
{ .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
{ },
};
MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
......
......@@ -966,6 +966,8 @@ static int __clk_notify(struct clk_core *core, unsigned long msg,
cnd.clk = cn->clk;
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
&cnd);
if (ret & NOTIFY_STOP_MASK)
return ret;
}
}
......@@ -2081,11 +2083,11 @@ static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
clk_dump_one(s, c, level);
hlist_for_each_entry(child, &c->children, child_node) {
seq_printf(s, ",");
seq_putc(s, ',');
clk_dump_subtree(s, child, level + 1);
}
seq_printf(s, "}");
seq_putc(s, '}');
}
static int clk_dump(struct seq_file *s, void *data)
......@@ -2094,14 +2096,13 @@ static int clk_dump(struct seq_file *s, void *data)
bool first_node = true;
struct hlist_head **lists = (struct hlist_head **)s->private;
seq_printf(s, "{");
seq_putc(s, '{');
clk_prepare_lock();
for (; *lists; lists++) {
hlist_for_each_entry(c, *lists, child_node) {
if (!first_node)
seq_puts(s, ",");
seq_putc(s, ',');
first_node = false;
clk_dump_subtree(s, c, 0);
}
......@@ -2126,6 +2127,31 @@ static const struct file_operations clk_dump_fops = {
.release = single_release,
};
static int possible_parents_dump(struct seq_file *s, void *data)
{
struct clk_core *core = s->private;
int i;
for (i = 0; i < core->num_parents - 1; i++)
seq_printf(s, "%s ", core->parent_names[i]);
seq_printf(s, "%s\n", core->parent_names[i]);
return 0;
}
static int possible_parents_open(struct inode *inode, struct file *file)
{
return single_open(file, possible_parents_dump, inode->i_private);
}
static const struct file_operations possible_parents_fops = {
.open = possible_parents_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
{
struct dentry *d;
......@@ -2177,6 +2203,13 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
if (!d)
goto err_out;
if (core->num_parents > 1) {
d = debugfs_create_file("clk_possible_parents", S_IRUGO,
core->dentry, core, &possible_parents_fops);
if (!d)
goto err_out;
}
if (core->ops->debug_init) {
ret = core->ops->debug_init(core->hw, core->dentry);
if (ret)
......@@ -2940,7 +2973,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
/* if clk wasn't in the notifier list, allocate new clk_notifier */
if (cn->clk != clk) {
cn = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
cn = kzalloc(sizeof(*cn), GFP_KERNEL);
if (!cn)
goto out;
......@@ -3088,7 +3121,7 @@ int of_clk_add_provider(struct device_node *np,
struct of_clk_provider *cp;
int ret;
cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp)
return -ENOMEM;
......
......@@ -144,7 +144,7 @@ static struct hisi_divider_clock hi3620_div_clks[] __initdata = {
{ HI3620_MMC3_DIV, "mmc3_div", "mmc3_mux", 0, 0x140, 5, 4, CLK_DIVIDER_HIWORD_MASK, NULL, },
};
static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = {
static struct hisi_gate_clock hi3620_separated_gate_clks[] __initdata = {
{ HI3620_TIMERCLK01, "timerclk01", "timer_rclk01", CLK_SET_RATE_PARENT, 0x20, 0, 0, },
{ HI3620_TIMER_RCLK01, "timer_rclk01", "rclk_tcxo", CLK_SET_RATE_PARENT, 0x20, 1, 0, },
{ HI3620_TIMERCLK23, "timerclk23", "timer_rclk23", CLK_SET_RATE_PARENT, 0x20, 2, 0, },
......@@ -224,8 +224,8 @@ static void __init hi3620_clk_init(struct device_node *np)
clk_data);
hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
clk_data);
hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
ARRAY_SIZE(hi3620_seperated_gate_clks),
hisi_clk_register_gate_sep(hi3620_separated_gate_clks,
ARRAY_SIZE(hi3620_separated_gate_clks),
clk_data);
}
CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
......@@ -430,10 +430,8 @@ static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
struct clk_init_data init;
mclk = kzalloc(sizeof(*mclk), GFP_KERNEL);
if (!mclk) {
pr_err("%s: fail to allocate mmc clk\n", __func__);
if (!mclk)
return ERR_PTR(-ENOMEM);
}
init.name = mmc_clk->name;
init.ops = &clk_mmc_ops;
......@@ -482,11 +480,9 @@ static void __init hi3620_mmc_clk_init(struct device_node *node)
if (WARN_ON(!clk_data))
return;
clk_data->clks = kzalloc(sizeof(struct clk *) * num, GFP_KERNEL);
if (!clk_data->clks) {
pr_err("%s: fail to allocate mmc clk\n", __func__);
clk_data->clks = kcalloc(num, sizeof(*clk_data->clks), GFP_KERNEL);
if (!clk_data->clks)
return;
}
for (i = 0; i < num; i++) {
struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
......
......@@ -134,6 +134,7 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
{ HI6220_UART4_PCLK, "uart4_pclk", "uart4_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8, 0, },
{ HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, },
{ HI6220_TSENSOR_CLK, "tsensor_clk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 12, 0, },
{ HI6220_DAPB_CLK, "dapb_clk", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IS_CRITICAL, 0x230, 18, 0, },
{ HI6220_MMU_CLK, "mmu_clk", "ddrc_axi1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
{ HI6220_HIFI_SEL, "hifi_sel", "hifi_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0, 0, },
{ HI6220_MMC0_SYSPLL, "mmc0_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1, 0, },
......
......@@ -54,7 +54,8 @@ struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,
if (!clk_data->base)
return NULL;
clk_table = devm_kmalloc(&pdev->dev, sizeof(struct clk *) * nr_clks,
clk_table = devm_kmalloc_array(&pdev->dev, nr_clks,
sizeof(*clk_table),
GFP_KERNEL);
if (!clk_table)
return NULL;
......@@ -80,17 +81,14 @@ struct hisi_clock_data *hisi_clk_init(struct device_node *np,
}
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data) {
pr_err("%s: could not allocate clock data\n", __func__);
if (!clk_data)
goto err;
}
clk_data->base = base;
clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
if (!clk_table) {
pr_err("%s: could not allocate clock lookup table\n", __func__);
clk_data->base = base;
clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL);
if (!clk_table)
goto err_data;
}
clk_data->clk_data.clks = clk_table;
clk_data->clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
......
......@@ -73,7 +73,7 @@ static struct clk *clks[IMX6UL_CLK_END];
static struct clk_onecell_data clk_data;
static int const clks_init_on[] __initconst = {
IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, IMX6UL_CLK_AIPSTZ3,
IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2,
IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM,
IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
};
......@@ -341,9 +341,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26);
clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
if (clk_on_imx6ul())
clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
else if (clk_on_imx6ull())
if (clk_on_imx6ull())
clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18);
/* CCGR1 */
......@@ -360,7 +358,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
/* CCGR2 */
if (clk_on_imx6ull()) {
......@@ -482,6 +480,9 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
if (clk_on_imx6ull())
clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]);
clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]);
......
......@@ -386,7 +386,7 @@ static int const clks_init_on[] __initconst = {
IMX7D_PLL_SYS_MAIN_480M_CLK, IMX7D_NAND_USDHC_BUS_ROOT_CLK,
IMX7D_DRAM_PHYM_ROOT_CLK, IMX7D_DRAM_ROOT_CLK,
IMX7D_DRAM_PHYM_ALT_ROOT_CLK, IMX7D_DRAM_ALT_ROOT_CLK,
IMX7D_AHB_CHANNEL_ROOT_CLK,
IMX7D_AHB_CHANNEL_ROOT_CLK, IMX7D_IPG_ROOT_CLK,
};
static struct clk_onecell_data clk_data;
......@@ -724,8 +724,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
clks[IMX7D_NAND_USDHC_BUS_ROOT_DIV] = imx_clk_divider2("nand_usdhc_post_div", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_post_div", "ahb_pre_div", base + 0x9000, 0, 6);
clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider2("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2);
clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
......@@ -796,9 +797,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "axi_post_div", base + 0x4110, 0);
clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_post_div", base + 0x4120, 0);
clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_gate4("nand_usdhc_root_clk", "nand_usdhc_post_div", base + 0x4130, 0);
clks[IMX7D_AHB_CHANNEL_ROOT_CLK] = imx_clk_gate4("ahb_root_clk", "ahb_post_div", base + 0x4200, 0);
clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
......
......@@ -50,6 +50,38 @@ config COMMON_CLK_MT2701_BDPSYS
---help---
This driver supports Mediatek MT2701 bdpsys clocks.
config COMMON_CLK_MT6797
bool "Clock driver for Mediatek MT6797"
depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
select COMMON_CLK_MEDIATEK
default ARCH_MEDIATEK && ARM64
---help---
This driver supports Mediatek MT6797 basic clocks.
config COMMON_CLK_MT6797_MMSYS
bool "Clock driver for Mediatek MT6797 mmsys"
depends on COMMON_CLK_MT6797
---help---
This driver supports Mediatek MT6797 mmsys clocks.
config COMMON_CLK_MT6797_IMGSYS
bool "Clock driver for Mediatek MT6797 imgsys"
depends on COMMON_CLK_MT6797
---help---
This driver supports Mediatek MT6797 imgsys clocks.
config COMMON_CLK_MT6797_VDECSYS
bool "Clock driver for Mediatek MT6797 vdecsys"
depends on COMMON_CLK_MT6797
---help---
This driver supports Mediatek MT6797 vdecsys clocks.
config COMMON_CLK_MT6797_VENCSYS
bool "Clock driver for Mediatek MT6797 vencsys"
depends on COMMON_CLK_MT6797
---help---
This driver supports Mediatek MT6797 vencsys clocks.
config COMMON_CLK_MT8135
bool "Clock driver for Mediatek MT8135"
depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
......
obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
obj-$(CONFIG_COMMON_CLK_MT6797) += clk-mt6797.o
obj-$(CONFIG_COMMON_CLK_MT6797_IMGSYS) += clk-mt6797-img.o
obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o
obj-$(CONFIG_COMMON_CLK_MT6797_VDECSYS) += clk-mt6797-vdec.o
obj-$(CONFIG_COMMON_CLK_MT6797_VENCSYS) += clk-mt6797-venc.o
obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
obj-$(CONFIG_COMMON_CLK_MT2701_BDPSYS) += clk-mt2701-bdp.o
obj-$(CONFIG_COMMON_CLK_MT2701_ETHSYS) += clk-mt2701-eth.o
......
......@@ -66,6 +66,8 @@ static int clk_mt2701_eth_probe(struct platform_device *pdev)
"could not register clock provider: %s: %d\n",
pdev->name, r);
mtk_register_reset_controller(node, 1, 0x34);
return r;
}
......
/* Copyright (c) 2017 MediaTek Inc.
* Author: Kevin Chen <kevin-cw.chen@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/mt6797-clk.h>
#include "clk-mtk.h"
#include "clk-gate.h"
static const struct mtk_gate_regs img_cg_regs = {
.set_ofs = 0x0004,
.clr_ofs = 0x0008,
.sta_ofs = 0x0000,
};
#define GATE_IMG(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &img_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
static const struct mtk_gate img_clks[] = {
GATE_IMG(CLK_IMG_FDVT, "img_fdvt", "mm_sel", 11),
GATE_IMG(CLK_IMG_DPE, "img_dpe", "mm_sel", 10),
GATE_IMG(CLK_IMG_DIP, "img_dip", "mm_sel", 6),
GATE_IMG(CLK_IMG_LARB6, "img_larb6", "mm_sel", 0),
};
static const struct of_device_id of_match_clk_mt6797_img[] = {
{ .compatible = "mediatek,mt6797-imgsys", },
{}
};
static int clk_mt6797_img_probe(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
int r;
struct device_node *node = pdev->dev.of_node;
clk_data = mtk_alloc_clk_data(CLK_IMG_NR);
mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt6797_img_drv = {
.probe = clk_mt6797_img_probe,
.driver = {
.name = "clk-mt6797-img",
.of_match_table = of_match_clk_mt6797_img,
},
};
builtin_platform_driver(clk_mt6797_img_drv);
/*
* Copyright (c) 2017 MediaTek Inc.
* Author: Kevin Chen <kevin-cw.chen@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/mt6797-clk.h>
#include "clk-mtk.h"
#include "clk-gate.h"
static const struct mtk_gate_regs mm0_cg_regs = {
.set_ofs = 0x0104,
.clr_ofs = 0x0108,
.sta_ofs = 0x0100,
};
static const struct mtk_gate_regs mm1_cg_regs = {
.set_ofs = 0x0114,
.clr_ofs = 0x0118,
.sta_ofs = 0x0110,
};
#define GATE_MM0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm0_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
#define GATE_MM1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &mm1_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
static const struct mtk_gate mm_clks[] = {
GATE_MM0(CLK_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 0),
GATE_MM0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1),
GATE_MM0(CLK_MM_SMI_LARB5, "mm_smi_larb5", "mm_sel", 2),
GATE_MM0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 3),
GATE_MM0(CLK_MM_MDP_RDMA0, "mm_mdp_rdma0", "mm_sel", 4),
GATE_MM0(CLK_MM_MDP_RDMA1, "mm_mdp_rdma1", "mm_sel", 5),
GATE_MM0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 6),
GATE_MM0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 7),
GATE_MM0(CLK_MM_MDP_RSZ2, "mm_mdp_rsz2", "mm_sel", 8),
GATE_MM0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 9),
GATE_MM0(CLK_MM_MDP_COLOR, "mm_mdp_color", "mm_sel", 10),
GATE_MM0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11),
GATE_MM0(CLK_MM_MDP_WROT0, "mm_mdp_wrot0", "mm_sel", 12),
GATE_MM0(CLK_MM_MDP_WROT1, "mm_mdp_wrot1", "mm_sel", 13),
GATE_MM0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 14),
GATE_MM0(CLK_MM_DISP_OVL0, "mm_disp_ovl0", "mm_sel", 15),
GATE_MM0(CLK_MM_DISP_OVL1, "mm_disp_ovl1", "mm_sel", 16),
GATE_MM0(CLK_MM_DISP_OVL0_2L, "mm_disp_ovl0_2l", "mm_sel", 17),
GATE_MM0(CLK_MM_DISP_OVL1_2L, "mm_disp_ovl1_2l", "mm_sel", 18),
GATE_MM0(CLK_MM_DISP_RDMA0, "mm_disp_rdma0", "mm_sel", 19),
GATE_MM0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 20),
GATE_MM0(CLK_MM_DISP_WDMA0, "mm_disp_wdma0", "mm_sel", 21),
GATE_MM0(CLK_MM_DISP_WDMA1, "mm_disp_wdma1", "mm_sel", 22),
GATE_MM0(CLK_MM_DISP_COLOR, "mm_disp_color", "mm_sel", 23),
GATE_MM0(CLK_MM_DISP_CCORR, "mm_disp_ccorr", "mm_sel", 24),
GATE_MM0(CLK_MM_DISP_AAL, "mm_disp_aal", "mm_sel", 25),
GATE_MM0(CLK_MM_DISP_GAMMA, "mm_disp_gamma", "mm_sel", 26),
GATE_MM0(CLK_MM_DISP_OD, "mm_disp_od", "mm_sel", 27),
GATE_MM0(CLK_MM_DISP_DITHER, "mm_disp_dither", "mm_sel", 28),
GATE_MM0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 29),
GATE_MM0(CLK_MM_DISP_DSC, "mm_disp_dsc", "mm_sel", 30),
GATE_MM0(CLK_MM_DISP_SPLIT, "mm_disp_split", "mm_sel", 31),
GATE_MM1(CLK_MM_DSI0_MM_CLOCK, "mm_dsi0_mm_clock", "mm_sel", 0),
GATE_MM1(CLK_MM_DSI1_MM_CLOCK, "mm_dsi1_mm_clock", "mm_sel", 2),
GATE_MM1(CLK_MM_DPI_MM_CLOCK, "mm_dpi_mm_clock", "mm_sel", 4),
GATE_MM1(CLK_MM_DPI_INTERFACE_CLOCK, "mm_dpi_interface_clock",
"dpi0_sel", 5),
GATE_MM1(CLK_MM_LARB4_AXI_ASIF_MM_CLOCK, "mm_larb4_axi_asif_mm_clock",
"mm_sel", 6),
GATE_MM1(CLK_MM_LARB4_AXI_ASIF_MJC_CLOCK, "mm_larb4_axi_asif_mjc_clock",
"mjc_sel", 7),
GATE_MM1(CLK_MM_DISP_OVL0_MOUT_CLOCK, "mm_disp_ovl0_mout_clock",
"mm_sel", 8),
GATE_MM1(CLK_MM_FAKE_ENG2, "mm_fake_eng2", "mm_sel", 9),
GATE_MM1(CLK_MM_DSI0_INTERFACE_CLOCK, "mm_dsi0_interface_clock",
"clk26m", 1),
GATE_MM1(CLK_MM_DSI1_INTERFACE_CLOCK, "mm_dsi1_interface_clock",
"clk26m", 3),
};
static const struct of_device_id of_match_clk_mt6797_mm[] = {
{ .compatible = "mediatek,mt6797-mmsys", },
{}
};
static int clk_mt6797_mm_probe(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
int r;
struct device_node *node = pdev->dev.of_node;
clk_data = mtk_alloc_clk_data(CLK_MM_NR);
mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt6797_mm_drv = {
.probe = clk_mt6797_mm_probe,
.driver = {
.name = "clk-mt6797-mm",
.of_match_table = of_match_clk_mt6797_mm,
},
};
builtin_platform_driver(clk_mt6797_mm_drv);
/*
* Copyright (c) 2017 MediaTek Inc.
* Author: Kevin-CW Chen <kevin-cw.chen@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include <dt-bindings/clock/mt6797-clk.h>
static const struct mtk_gate_regs vdec0_cg_regs = {
.set_ofs = 0x0000,
.clr_ofs = 0x0004,
.sta_ofs = 0x0000,
};
static const struct mtk_gate_regs vdec1_cg_regs = {
.set_ofs = 0x0008,
.clr_ofs = 0x000c,
.sta_ofs = 0x0008,
};
#define GATE_VDEC0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &vdec0_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr_inv, \
}
#define GATE_VDEC1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &vdec1_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr_inv, \
}
static const struct mtk_gate vdec_clks[] = {
GATE_VDEC0(CLK_VDEC_CKEN_ENG, "vdec_cken_eng", "vdec_sel", 8),
GATE_VDEC0(CLK_VDEC_ACTIVE, "vdec_active", "vdec_sel", 4),
GATE_VDEC0(CLK_VDEC_CKEN, "vdec_cken", "vdec_sel", 0),
GATE_VDEC1(CLK_VDEC_LARB1_CKEN, "vdec_larb1_cken", "mm_sel", 0),
};
static const struct of_device_id of_match_clk_mt6797_vdec[] = {
{ .compatible = "mediatek,mt6797-vdecsys", },
{}
};
static int clk_mt6797_vdec_probe(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
int r;
struct device_node *node = pdev->dev.of_node;
clk_data = mtk_alloc_clk_data(CLK_VDEC_NR);
mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt6797_vdec_drv = {
.probe = clk_mt6797_vdec_probe,
.driver = {
.name = "clk-mt6797-vdec",
.of_match_table = of_match_clk_mt6797_vdec,
},
};
builtin_platform_driver(clk_mt6797_vdec_drv);
/*
* Copyright (c) 2017 MediaTek Inc.
* Author: Kevin Chen <kevin-cw.chen@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include <dt-bindings/clock/mt6797-clk.h>
static const struct mtk_gate_regs venc_cg_regs = {
.set_ofs = 0x0004,
.clr_ofs = 0x0008,
.sta_ofs = 0x0000,
};
#define GATE_VENC(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &venc_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr_inv, \
}
static const struct mtk_gate venc_clks[] = {
GATE_VENC(CLK_VENC_0, "venc_0", "mm_sel", 0),
GATE_VENC(CLK_VENC_1, "venc_1", "venc_sel", 4),
GATE_VENC(CLK_VENC_2, "venc_2", "venc_sel", 8),
GATE_VENC(CLK_VENC_3, "venc_3", "venc_sel", 12),
};
static const struct of_device_id of_match_clk_mt6797_venc[] = {
{ .compatible = "mediatek,mt6797-vencsys", },
{}
};
static int clk_mt6797_venc_probe(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
int r;
struct device_node *node = pdev->dev.of_node;
clk_data = mtk_alloc_clk_data(CLK_VENC_NR);
mtk_clk_register_gates(node, venc_clks, ARRAY_SIZE(venc_clks),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt6797_venc_drv = {
.probe = clk_mt6797_venc_probe,
.driver = {
.name = "clk-mt6797-venc",
.of_match_table = of_match_clk_mt6797_venc,
},
};
builtin_platform_driver(clk_mt6797_venc_drv);
This diff is collapsed.
......@@ -2,6 +2,6 @@
# Makefile for Meson specific clk
#
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
/*
* Copyright (c) 2017 AmLogic, Inc.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* i2s master clock divider: The algorithm of the generic clk-divider used with
* a very precise clock parent such as the mpll tends to select a low divider
* factor. This gives poor results with this particular divider, especially with
* high frequencies (> 100 MHz)
*
* This driver try to select the maximum possible divider with the rate the
* upstream clock can provide.
*/
#include <linux/clk-provider.h>
#include "clkc.h"
#define to_meson_clk_audio_divider(_hw) container_of(_hw, \
struct meson_clk_audio_divider, hw)
static int _div_round(unsigned long parent_rate, unsigned long rate,
unsigned long flags)
{
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, rate);
return DIV_ROUND_UP_ULL((u64)parent_rate, rate);
}
static int _get_val(unsigned long parent_rate, unsigned long rate)
{
return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
}
static int _valid_divider(struct clk_hw *hw, int divider)
{
struct meson_clk_audio_divider *adiv =
to_meson_clk_audio_divider(hw);
int max_divider;
u8 width;
width = adiv->div.width;
max_divider = 1 << width;
return clamp(divider, 1, max_divider);
}
static unsigned long audio_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct meson_clk_audio_divider *adiv =
to_meson_clk_audio_divider(hw);
struct parm *p;
unsigned long reg, divider;
p = &adiv->div;
reg = readl(adiv->base + p->reg_off);
divider = PARM_GET(p->width, p->shift, reg) + 1;
return DIV_ROUND_UP_ULL((u64)parent_rate, divider);
}
static long audio_divider_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
struct meson_clk_audio_divider *adiv =
to_meson_clk_audio_divider(hw);
unsigned long max_prate;
int divider;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
divider = _div_round(*parent_rate, rate, adiv->flags);
divider = _valid_divider(hw, divider);
return DIV_ROUND_UP_ULL((u64)*parent_rate, divider);
}
/* Get the maximum parent rate */
max_prate = clk_hw_round_rate(clk_hw_get_parent(hw), ULONG_MAX);
/* Get the corresponding rounded down divider */
divider = max_prate / rate;
divider = _valid_divider(hw, divider);
/* Get actual rate of the parent */
*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
divider * rate);
return DIV_ROUND_UP_ULL((u64)*parent_rate, divider);
}
static int audio_divider_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct meson_clk_audio_divider *adiv =
to_meson_clk_audio_divider(hw);
struct parm *p;
unsigned long reg, flags = 0;
int val;
val = _get_val(parent_rate, rate);
if (adiv->lock)
spin_lock_irqsave(adiv->lock, flags);
else
__acquire(adiv->lock);
p = &adiv->div;
reg = readl(adiv->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, val);
writel(reg, adiv->base + p->reg_off);
if (adiv->lock)
spin_unlock_irqrestore(adiv->lock, flags);
else
__release(adiv->lock);
return 0;
}
const struct clk_ops meson_clk_audio_divider_ro_ops = {
.recalc_rate = audio_divider_recalc_rate,
.round_rate = audio_divider_round_rate,
};
const struct clk_ops meson_clk_audio_divider_ops = {
.recalc_rate = audio_divider_recalc_rate,
.round_rate = audio_divider_round_rate,
.set_rate = audio_divider_set_rate,
};
......@@ -64,17 +64,51 @@
#include <linux/clk-provider.h>
#include "clkc.h"
#define SDM_MAX 16384
#define SDM_DEN 16384
#define N2_MIN 4
#define N2_MAX 511
#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw)
static long rate_from_params(unsigned long parent_rate,
unsigned long sdm,
unsigned long n2)
{
unsigned long divisor = (SDM_DEN * n2) + sdm;
if (n2 < N2_MIN)
return -EINVAL;
return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
}
static void params_from_rate(unsigned long requested_rate,
unsigned long parent_rate,
unsigned long *sdm,
unsigned long *n2)
{
uint64_t div = parent_rate;
unsigned long rem = do_div(div, requested_rate);
if (div < N2_MIN) {
*n2 = N2_MIN;
*sdm = 0;
} else if (div > N2_MAX) {
*n2 = N2_MAX;
*sdm = SDM_DEN - 1;
} else {
*n2 = div;
*sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate);
}
}
static unsigned long mpll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long rate = 0;
unsigned long reg, sdm, n2;
long rate;
p = &mpll->sdm;
reg = readl(mpll->base + p->reg_off);
......@@ -84,11 +118,123 @@ static unsigned long mpll_recalc_rate(struct clk_hw *hw,
reg = readl(mpll->base + p->reg_off);
n2 = PARM_GET(p->width, p->shift, reg);
rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm);
rate = rate_from_params(parent_rate, sdm, n2);
if (rate < 0)
return 0;
return rate;
}
static long mpll_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
unsigned long sdm, n2;
params_from_rate(rate, *parent_rate, &sdm, &n2);
return rate_from_params(*parent_rate, sdm, n2);
}
static int mpll_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg, sdm, n2;
unsigned long flags = 0;
params_from_rate(rate, parent_rate, &sdm, &n2);
if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags);
else
__acquire(mpll->lock);
p = &mpll->sdm;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, sdm);
writel(reg, mpll->base + p->reg_off);
p = &mpll->sdm_en;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, 1);
writel(reg, mpll->base + p->reg_off);
p = &mpll->n2;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, n2);
writel(reg, mpll->base + p->reg_off);
if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags);
else
__release(mpll->lock);
return 0;
}
static void mpll_enable_core(struct clk_hw *hw, int enable)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg;
unsigned long flags = 0;
if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags);
else
__acquire(mpll->lock);
p = &mpll->en;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0);
writel(reg, mpll->base + p->reg_off);
if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags);
else
__release(mpll->lock);
}
static int mpll_enable(struct clk_hw *hw)
{
mpll_enable_core(hw, 1);
return 0;
}
static void mpll_disable(struct clk_hw *hw)
{
mpll_enable_core(hw, 0);
}
static int mpll_is_enabled(struct clk_hw *hw)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg;
int en;
p = &mpll->en;
reg = readl(mpll->base + p->reg_off);
en = PARM_GET(p->width, p->shift, reg);
return en;
}
const struct clk_ops meson_clk_mpll_ro_ops = {
.recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate,
.is_enabled = mpll_is_enabled,
};
const struct clk_ops meson_clk_mpll_ops = {
.recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate,
.set_rate = mpll_set_rate,
.enable = mpll_enable,
.disable = mpll_disable,
.is_enabled = mpll_is_enabled,
};
......@@ -116,6 +116,30 @@ static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_
return NULL;
}
/* Specific wait loop for GXL/GXM GP0 PLL */
static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll,
struct parm *p_n)
{
int delay = 100;
u32 reg;
while (delay > 0) {
reg = readl(pll->base + p_n->reg_off);
writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off);
udelay(10);
writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off);
/* This delay comes from AMLogic tree clk-gp0-gxl driver */
mdelay(1);
reg = readl(pll->base + p_n->reg_off);
if (reg & MESON_PLL_LOCK)
return 0;
delay--;
}
return -ETIMEDOUT;
}
static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
struct parm *p_n)
{
......@@ -132,6 +156,15 @@ static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
return -ETIMEDOUT;
}
static void meson_clk_pll_init_params(struct meson_clk_pll *pll)
{
int i;
for (i = 0 ; i < pll->params.params_count ; ++i)
writel(pll->params.params_table[i].value,
pll->base + pll->params.params_table[i].reg_off);
}
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
......@@ -151,9 +184,15 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
if (!rate_set)
return -EINVAL;
/* Initialize the PLL in a clean state if specified */
if (pll->params.params_count)
meson_clk_pll_init_params(pll);
/* PLL reset */
p = &pll->n;
reg = readl(pll->base + p->reg_off);
/* If no_init_reset is provided, avoid resetting at this point */
if (!pll->params.no_init_reset)
writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
......@@ -184,6 +223,16 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}
p = &pll->n;
/* If clear_reset_for_lock is provided, remove the reset bit here */
if (pll->params.clear_reset_for_lock) {
reg = readl(pll->base + p->reg_off);
writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off);
}
/* If reset_lock_loop, use a special loop including resetting */
if (pll->params.reset_lock_loop)
ret = meson_clk_pll_wait_lock_reset(pll, p);
else
ret = meson_clk_pll_wait_lock(pll, p);
if (ret) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
......
......@@ -25,7 +25,7 @@
#define PARM_GET(width, shift, reg) \
(((reg) & SETPMASK(width, shift)) >> (shift))
#define PARM_SET(width, shift, reg, val) \
(((reg) & CLRPMASK(width, shift)) | (val << (shift)))
(((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))
#define MESON_PARM_APPLICABLE(p) (!!((p)->width))
......@@ -62,6 +62,28 @@ struct pll_rate_table {
.frac = (_frac), \
} \
struct pll_params_table {
unsigned int reg_off;
unsigned int value;
};
#define PLL_PARAM(_reg, _val) \
{ \
.reg_off = (_reg), \
.value = (_val), \
}
struct pll_setup_params {
struct pll_params_table *params_table;
unsigned int params_count;
/* Workaround for GP0, do not reset before configuring */
bool no_init_reset;
/* Workaround for GP0, unreset right before checking for lock */
bool clear_reset_for_lock;
/* Workaround for GXL GP0, reset in the lock checking loop */
bool reset_lock_loop;
};
struct meson_clk_pll {
struct clk_hw hw;
void __iomem *base;
......@@ -70,6 +92,7 @@ struct meson_clk_pll {
struct parm frac;
struct parm od;
struct parm od2;
const struct pll_setup_params params;
const struct pll_rate_table *rate_table;
unsigned int rate_count;
spinlock_t *lock;
......@@ -92,8 +115,17 @@ struct meson_clk_mpll {
struct clk_hw hw;
void __iomem *base;
struct parm sdm;
struct parm sdm_en;
struct parm n2;
/* FIXME ssen gate control? */
struct parm en;
spinlock_t *lock;
};
struct meson_clk_audio_divider {
struct clk_hw hw;
void __iomem *base;
struct parm div;
u8 flags;
spinlock_t *lock;
};
......@@ -116,5 +148,8 @@ extern const struct clk_ops meson_clk_pll_ro_ops;
extern const struct clk_ops meson_clk_pll_ops;
extern const struct clk_ops meson_clk_cpu_ops;
extern const struct clk_ops meson_clk_mpll_ro_ops;
extern const struct clk_ops meson_clk_mpll_ops;
extern const struct clk_ops meson_clk_audio_divider_ro_ops;
extern const struct clk_ops meson_clk_audio_divider_ops;
#endif /* __CLKC_H */
This diff is collapsed.
......@@ -71,6 +71,8 @@
#define HHI_GP0_PLL_CNTL2 0x44 /* 0x11 offset in data sheet */
#define HHI_GP0_PLL_CNTL3 0x48 /* 0x12 offset in data sheet */
#define HHI_GP0_PLL_CNTL4 0x4c /* 0x13 offset in data sheet */
#define HHI_GP0_PLL_CNTL5 0x50 /* 0x14 offset in data sheet */
#define HHI_GP0_PLL_CNTL1 0x58 /* 0x16 offset in data sheet */
#define HHI_XTAL_DIVN_CNTL 0xbc /* 0x2f offset in data sheet */
#define HHI_TIMER90K 0xec /* 0x3b offset in data sheet */
......@@ -275,8 +277,15 @@
#define CLKID_MALI_1_DIV 104
/* CLKID_MALI_1 */
/* CLKID_MALI */
#define CLKID_CTS_AMCLK 107
#define CLKID_CTS_AMCLK_SEL 108
#define CLKID_CTS_AMCLK_DIV 109
#define CLKID_CTS_MCLK_I958 110
#define CLKID_CTS_MCLK_I958_SEL 111
#define CLKID_CTS_MCLK_I958_DIV 112
#define CLKID_CTS_I958 113
#define NR_CLKS 107
#define NR_CLKS 114
/* include the CLKIDs that have been made part of the stable DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>
......
......@@ -245,6 +245,96 @@ static struct clk_fixed_factor meson8b_fclk_div7 = {
},
};
static struct meson_clk_mpll meson8b_mpll0 = {
.sdm = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 16,
.width = 9,
},
.en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 14,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll0",
.ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
};
static struct meson_clk_mpll meson8b_mpll1 = {
.sdm = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 16,
.width = 9,
},
.en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 14,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll1",
.ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
};
static struct meson_clk_mpll meson8b_mpll2 = {
.sdm = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 16,
.width = 9,
},
.en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 14,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll2",
.ops = &meson_clk_mpll_ops,
.parent_names = (const char *[]){ "fixed_pll" },
.num_parents = 1,
},
};
/*
* FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL
* post-dividers and should be modeled with their respective PLLs via the
......@@ -491,6 +581,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
[CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw,
[CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw,
[CLKID_AO_IFACE] = &meson8b_ao_iface.hw,
[CLKID_MPLL0] = &meson8b_mpll0.hw,
[CLKID_MPLL1] = &meson8b_mpll1.hw,
[CLKID_MPLL2] = &meson8b_mpll2.hw,
},
.num = CLK_NR_CLKS,
};
......@@ -501,7 +594,13 @@ static struct meson_clk_pll *const meson8b_clk_plls[] = {
&meson8b_sys_pll,
};
static struct clk_gate *meson8b_clk_gates[] = {
static struct meson_clk_mpll *const meson8b_clk_mplls[] = {
&meson8b_mpll0,
&meson8b_mpll1,
&meson8b_mpll2,
};
static struct clk_gate *const meson8b_clk_gates[] = {
&meson8b_clk81,
&meson8b_ddr,
&meson8b_dos,
......@@ -582,6 +681,14 @@ static struct clk_gate *meson8b_clk_gates[] = {
&meson8b_ao_iface,
};
static struct clk_mux *const meson8b_clk_muxes[] = {
&meson8b_mpeg_clk_sel,
};
static struct clk_divider *const meson8b_clk_dividers[] = {
&meson8b_mpeg_clk_div,
};
static int meson8b_clkc_probe(struct platform_device *pdev)
{
void __iomem *clk_base;
......@@ -601,18 +708,28 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++)
meson8b_clk_plls[i]->base = clk_base;
/* Populate base address for MPLLs */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++)
meson8b_clk_mplls[i]->base = clk_base;
/* Populate the base address for CPU clk */
meson8b_cpu_clk.base = clk_base;
/* Populate the base address for the MPEG clks */
meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg;
meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg;
/* Populate base address for gates */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++)
meson8b_clk_gates[i]->reg = clk_base +
(u32)meson8b_clk_gates[i]->reg;
/* Populate base address for muxes */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++)
meson8b_clk_muxes[i]->reg = clk_base +
(u32)meson8b_clk_muxes[i]->reg;
/* Populate base address for dividers */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_dividers); i++)
meson8b_clk_dividers[i]->reg = clk_base +
(u32)meson8b_clk_dividers[i]->reg;
/*
* register all clks
* CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1
......
......@@ -41,6 +41,21 @@
#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */
#define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
/*
* MPLL register offeset taken from the S905 datasheet. Vendor kernel source
* confirm these are the same for the S805.
*/
#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */
#define HHI_MPLL_CNTL2 0x284 /* 0xa1 offset in data sheet */
#define HHI_MPLL_CNTL3 0x288 /* 0xa2 offset in data sheet */
#define HHI_MPLL_CNTL4 0x28C /* 0xa3 offset in data sheet */
#define HHI_MPLL_CNTL5 0x290 /* 0xa4 offset in data sheet */
#define HHI_MPLL_CNTL6 0x294 /* 0xa5 offset in data sheet */
#define HHI_MPLL_CNTL7 0x298 /* 0xa6 offset in data sheet */
#define HHI_MPLL_CNTL8 0x29C /* 0xa7 offset in data sheet */
#define HHI_MPLL_CNTL9 0x2A0 /* 0xa8 offset in data sheet */
#define HHI_MPLL_CNTL10 0x2A4 /* 0xa9 offset in data sheet */
/*
* CLKID index values
*
......@@ -142,8 +157,11 @@
#define CLKID_AO_AHB_SRAM 90
#define CLKID_AO_AHB_BUS 91
#define CLKID_AO_IFACE 92
#define CLKID_MPLL0 93
#define CLKID_MPLL1 94
#define CLKID_MPLL2 95
#define CLK_NR_CLKS 93
#define CLK_NR_CLKS 96
/* include the CLKIDs that have been made part of the stable DT binding */
#include <dt-bindings/clock/meson8b-clkc.h>
......
......@@ -186,11 +186,11 @@ static void __init of_cpu_clk_setup(struct device_node *node)
for_each_node_by_type(dn, "cpu")
ncpus++;
cpuclk = kzalloc(ncpus * sizeof(*cpuclk), GFP_KERNEL);
cpuclk = kcalloc(ncpus, sizeof(*cpuclk), GFP_KERNEL);
if (WARN_ON(!cpuclk))
goto cpuclk_out;
clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL);
clks = kcalloc(ncpus, sizeof(*clks), GFP_KERNEL);
if (WARN_ON(!clks))
goto clks_out;
......
......@@ -126,7 +126,7 @@ void __init mvebu_coreclk_setup(struct device_node *np,
if (desc->get_refclk_freq)
clk_data.clk_num += 1;
clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
clk_data.clks = kcalloc(clk_data.clk_num, sizeof(*clk_data.clks),
GFP_KERNEL);
if (WARN_ON(!clk_data.clks)) {
iounmap(base);
......@@ -270,7 +270,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
n++;
ctrl->num_gates = n;
ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *),
ctrl->gates = kcalloc(ctrl->num_gates, sizeof(*ctrl->gates),
GFP_KERNEL);
if (WARN_ON(!ctrl->gates))
goto gates_out;
......
......@@ -165,7 +165,7 @@ static int clk_smd_rpm_handoff(struct clk_smd_rpm *r)
struct clk_smd_rpm_req req = {
.key = cpu_to_le32(r->rpm_key),
.nbytes = cpu_to_le32(sizeof(u32)),
.value = cpu_to_le32(INT_MAX),
.value = cpu_to_le32(r->branch ? 1 : INT_MAX),
};
ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
......
......@@ -2944,6 +2944,7 @@ static struct gdsc venus_core0_gdsc = {
.pd = {
.name = "venus_core0",
},
.parent = &venus_gdsc.pd,
.pwrsts = PWRSTS_OFF_ON,
.flags = HW_CTRL,
};
......@@ -2955,6 +2956,7 @@ static struct gdsc venus_core1_gdsc = {
.pd = {
.name = "venus_core1",
},
.parent = &venus_gdsc.pd,
.pwrsts = PWRSTS_OFF_ON,
.flags = HW_CTRL,
};
......@@ -2986,7 +2988,7 @@ static struct gdsc vfe1_gdsc = {
.cxcs = (unsigned int []){ 0x36ac },
.cxc_count = 1,
.pd = {
.name = "vfe0",
.name = "vfe1",
},
.parent = &camss_gdsc.pd,
.pwrsts = PWRSTS_OFF_ON,
......
This diff is collapsed.
......@@ -95,10 +95,10 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A7796_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A7796_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A7796_CLK_SD0, CLK_SDSRC, 0x0074),
DEF_GEN3_SD("sd1", R8A7796_CLK_SD1, CLK_SDSRC, 0x0078),
DEF_GEN3_SD("sd2", R8A7796_CLK_SD2, CLK_SDSRC, 0x0268),
DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x026c),
DEF_GEN3_SD("sd0", R8A7796_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A7796_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A7796_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1),
......@@ -135,7 +135,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
DEF_MOD("sdif2", 312, R8A7796_CLK_SD2),
DEF_MOD("sdif1", 313, R8A7796_CLK_SD1),
DEF_MOD("sdif0", 314, R8A7796_CLK_SD0),
DEF_MOD("rwdt0", 402, R8A7796_CLK_R),
DEF_MOD("rwdt", 402, R8A7796_CLK_R),
DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1),
DEF_MOD("drif7", 508, R8A7796_CLK_S3D2),
DEF_MOD("drif6", 509, R8A7796_CLK_S3D2),
......@@ -179,6 +179,8 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
DEF_MOD("vin1", 810, R8A7796_CLK_S0D2),
DEF_MOD("vin0", 811, R8A7796_CLK_S0D2),
DEF_MOD("etheravb", 812, R8A7796_CLK_S0D6),
DEF_MOD("imr1", 822, R8A7796_CLK_S0D2),
DEF_MOD("imr0", 823, R8A7796_CLK_S0D2),
DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4),
DEF_MOD("gpio6", 906, R8A7796_CLK_S3D4),
DEF_MOD("gpio5", 907, R8A7796_CLK_S3D4),
......@@ -271,7 +273,7 @@ static int __init r8a7796_cpg_mssr_init(struct device *dev)
return -EINVAL;
}
return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR);
return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode);
}
const struct cpg_mssr_info r8a7796_cpg_mssr_info __initconst = {
......
......@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
#include "renesas-cpg-mssr.h"
#include "rcar-gen3-cpg.h"
......@@ -247,6 +248,27 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
static const struct rcar_gen3_cpg_pll_config *cpg_pll_config __initdata;
static unsigned int cpg_clk_extalr __initdata;
static u32 cpg_mode __initdata;
static u32 cpg_quirks __initdata;
#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */
#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */
static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
{
.soc_id = "r8a7795", .revision = "ES1.0",
.data = (void *)(PLL_ERRATA | RCKCR_CKSEL),
},
{
.soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)RCKCR_CKSEL,
},
{
.soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)RCKCR_CKSEL,
},
{ /* sentinel */ }
};
struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
......@@ -275,6 +297,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
*/
value = readl(base + CPG_PLL0CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
if (cpg_quirks & PLL_ERRATA)
mult *= 2;
break;
case CLK_TYPE_GEN3_PLL1:
......@@ -290,6 +314,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
*/
value = readl(base + CPG_PLL2CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
if (cpg_quirks & PLL_ERRATA)
mult *= 2;
break;
case CLK_TYPE_GEN3_PLL3:
......@@ -305,12 +331,15 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
*/
value = readl(base + CPG_PLL4CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
if (cpg_quirks & PLL_ERRATA)
mult *= 2;
break;
case CLK_TYPE_GEN3_SD:
return cpg_sd_clk_register(core, base, __clk_get_name(parent));
case CLK_TYPE_GEN3_R:
if (cpg_quirks & RCKCR_CKSEL) {
/*
* RINT is default.
* Only if EXTALR is populated, we switch to it.
......@@ -324,6 +353,12 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
writel(value, base + CPG_RCKCR);
break;
}
/* Select parent clock of RCLK by MD28 */
if (cpg_mode & BIT(28))
parent = clks[cpg_clk_extalr];
break;
default:
return ERR_PTR(-EINVAL);
......@@ -334,9 +369,16 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
}
int __init rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config,
unsigned int clk_extalr)
unsigned int clk_extalr, u32 mode)
{
const struct soc_device_attribute *attr;
cpg_pll_config = config;
cpg_clk_extalr = clk_extalr;
cpg_mode = mode;
attr = soc_device_match(cpg_quirks_match);
if (attr)
cpg_quirks = (uintptr_t)attr->data;
pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks);
return 0;
}
......@@ -37,6 +37,6 @@ struct clk *rcar_gen3_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base);
int rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config,
unsigned int clk_extalr);
unsigned int clk_extalr, u32 mode);
#endif
......@@ -265,6 +265,11 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
WARN_DEBUG(id >= priv->num_core_clks);
WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
if (!core->name) {
/* Skip NULLified clock */
return;
}
switch (core->type) {
case CLK_TYPE_IN:
clk = of_clk_get_by_name(priv->dev->of_node, core->name);
......@@ -335,6 +340,11 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
if (!mod->name) {
/* Skip NULLified clock */
return;
}
parent = priv->clks[mod->parent];
if (IS_ERR(parent)) {
clk = parent;
......@@ -734,5 +744,45 @@ static int __init cpg_mssr_init(void)
subsys_initcall(cpg_mssr_init);
void __init cpg_core_nullify_range(struct cpg_core_clk *core_clks,
unsigned int num_core_clks,
unsigned int first_clk,
unsigned int last_clk)
{
unsigned int i;
for (i = 0; i < num_core_clks; i++)
if (core_clks[i].id >= first_clk &&
core_clks[i].id <= last_clk)
core_clks[i].name = NULL;
}
void __init mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const unsigned int *clks, unsigned int n)
{
unsigned int i, j;
for (i = 0, j = 0; i < num_mod_clks && j < n; i++)
if (mod_clks[i].id == clks[j]) {
mod_clks[i].name = NULL;
j++;
}
}
void __init mssr_mod_reparent(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const struct mssr_mod_reparent *clks,
unsigned int n)
{
unsigned int i, j;
for (i = 0, j = 0; i < num_mod_clks && j < n; i++)
if (mod_clks[i].id == clks[j].clk) {
mod_clks[i].parent = clks[j].parent;
j++;
}
}
MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
MODULE_LICENSE("GPL v2");
......@@ -134,4 +134,26 @@ extern const struct cpg_mssr_info r8a7743_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7745_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7796_cpg_mssr_info;
/*
* Helpers for fixing up clock tables depending on SoC revision
*/
struct mssr_mod_reparent {
unsigned int clk, parent;
};
extern void cpg_core_nullify_range(struct cpg_core_clk *core_clks,
unsigned int num_core_clks,
unsigned int first_clk,
unsigned int last_clk);
extern void mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const unsigned int *clks, unsigned int n);
extern void mssr_mod_reparent(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const struct mssr_mod_reparent *clks,
unsigned int n);
#endif
......@@ -12,7 +12,7 @@ obj-y += clk-muxgrf.o
obj-y += clk-ddr.o
obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
obj-y += clk-rk1108.o
obj-y += clk-rv1108.o
obj-y += clk-rk3036.o
obj-y += clk-rk3188.o
obj-y += clk-rk3228.o
......
......@@ -269,6 +269,7 @@ static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
pll->reg_base + RK3036_PLLCON(1));
rockchip_pll_wait_lock(pll);
return 0;
}
......@@ -501,6 +502,7 @@ static int rockchip_rk3066_pll_enable(struct clk_hw *hw)
writel(HIWORD_UPDATE(0, RK3066_PLLCON3_PWRDOWN, 0),
pll->reg_base + RK3066_PLLCON(3));
rockchip_pll_wait_lock(pll);
return 0;
}
......@@ -746,6 +748,7 @@ static int rockchip_rk3399_pll_enable(struct clk_hw *hw)
writel(HIWORD_UPDATE(0, RK3399_PLLCON3_PWRDOWN, 0),
pll->reg_base + RK3399_PLLCON(3));
rockchip_rk3399_pll_wait_lock(pll);
return 0;
}
......
......@@ -20,6 +20,7 @@
#include <dt-bindings/clock/rk3328-cru.h>
#include "clk.h"
#define RK3328_GRF_SOC_CON4 0x410
#define RK3328_GRF_SOC_STATUS0 0x480
#define RK3328_GRF_MAC_CON1 0x904
#define RK3328_GRF_MAC_CON2 0x908
......@@ -214,6 +215,8 @@ PNAME(mux_mac2io_src_p) = { "clk_mac2io_src",
"gmac_clkin" };
PNAME(mux_mac2phy_src_p) = { "clk_mac2phy_src",
"phy_50m_out" };
PNAME(mux_mac2io_ext_p) = { "clk_mac2io",
"gmac_clkin" };
static struct rockchip_pll_clock rk3328_pll_clks[] __initdata = {
[apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p,
......@@ -680,6 +683,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
COMPOSITE(SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_p, 0,
RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS,
RK3328_CLKGATE_CON(3), 5, GFLAGS),
MUXGRF(SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_p, CLK_SET_RATE_NO_REPARENT,
RK3328_GRF_MAC_CON1, 10, 1, MFLAGS),
MUXGRF(SCLK_MAC2IO_EXT, "clk_mac2io_ext", mux_mac2io_ext_p, CLK_SET_RATE_NO_REPARENT,
RK3328_GRF_SOC_CON4, 14, 1, MFLAGS),
COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0,
RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS,
......@@ -691,6 +698,8 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
COMPOSITE_NOMUX(SCLK_MAC2PHY_OUT, "clk_mac2phy_out", "clk_mac2phy", 0,
RK3328_CLKSEL_CON(26), 8, 2, DFLAGS,
RK3328_CLKGATE_CON(9), 2, GFLAGS),
MUXGRF(SCLK_MAC2PHY, "clk_mac2phy", mux_mac2phy_src_p, CLK_SET_RATE_NO_REPARENT,
RK3328_GRF_MAC_CON2, 10, 1, MFLAGS),
FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
......
......@@ -835,18 +835,18 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 0, GFLAGS),
/* timer gates */
GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS),
GATE(0, "sclk_timer14", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 10, GFLAGS),
GATE(0, "sclk_timer13", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 9, GFLAGS),
GATE(0, "sclk_timer12", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 8, GFLAGS),
GATE(0, "sclk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 7, GFLAGS),
GATE(0, "sclk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 6, GFLAGS),
GATE(0, "sclk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 5, GFLAGS),
GATE(0, "sclk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 4, GFLAGS),
GATE(0, "sclk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 3, GFLAGS),
GATE(0, "sclk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 2, GFLAGS),
GATE(0, "sclk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 1, GFLAGS),
GATE(0, "sclk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 0, GFLAGS),
GATE(SCLK_TIMER15, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS),
GATE(SCLK_TIMER14, "sclk_timer14", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 10, GFLAGS),
GATE(SCLK_TIMER13, "sclk_timer13", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 9, GFLAGS),
GATE(SCLK_TIMER12, "sclk_timer12", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 8, GFLAGS),
GATE(SCLK_TIMER11, "sclk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 7, GFLAGS),
GATE(SCLK_TIMER10, "sclk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 6, GFLAGS),
GATE(SCLK_TIMER05, "sclk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 5, GFLAGS),
GATE(SCLK_TIMER04, "sclk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 4, GFLAGS),
GATE(SCLK_TIMER03, "sclk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 3, GFLAGS),
GATE(SCLK_TIMER02, "sclk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 2, GFLAGS),
GATE(SCLK_TIMER01, "sclk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 1, GFLAGS),
GATE(SCLK_TIMER00, "sclk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 0, GFLAGS),
};
static const char *const rk3368_critical_clocks[] __initconst = {
......@@ -858,6 +858,9 @@ static const char *const rk3368_critical_clocks[] __initconst = {
*/
"pclk_pwm1",
"pclk_pd_pmu",
"pclk_pd_alive",
"pclk_peri",
"hclk_peri",
};
static void __init rk3368_clk_init(struct device_node *np)
......
......@@ -1477,10 +1477,10 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS),
GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS),
GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS),
GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS),
GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS),
GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", 0, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS),
GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS),
GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS),
GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS),
GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS),
GATE(HCLK_NOC_PMU, "hclk_noc_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 5, GFLAGS),
};
......
......@@ -34,20 +34,20 @@ struct clk;
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
/* register positions shared by RK1108, RK2928, RK3036, RK3066, RK3188 and RK3228 */
#define RK1108_PLL_CON(x) ((x) * 0x4)
#define RK1108_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
#define RK1108_CLKGATE_CON(x) ((x) * 0x4 + 0x120)
#define RK1108_SOFTRST_CON(x) ((x) * 0x4 + 0x180)
#define RK1108_GLB_SRST_FST 0x1c0
#define RK1108_GLB_SRST_SND 0x1c4
#define RK1108_MISC_CON 0x1cc
#define RK1108_SDMMC_CON0 0x1d8
#define RK1108_SDMMC_CON1 0x1dc
#define RK1108_SDIO_CON0 0x1e0
#define RK1108_SDIO_CON1 0x1e4
#define RK1108_EMMC_CON0 0x1e8
#define RK1108_EMMC_CON1 0x1ec
/* register positions shared by RV1108, RK2928, RK3036, RK3066, RK3188 and RK3228 */
#define RV1108_PLL_CON(x) ((x) * 0x4)
#define RV1108_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
#define RV1108_CLKGATE_CON(x) ((x) * 0x4 + 0x120)
#define RV1108_SOFTRST_CON(x) ((x) * 0x4 + 0x180)
#define RV1108_GLB_SRST_FST 0x1c0
#define RV1108_GLB_SRST_SND 0x1c4
#define RV1108_MISC_CON 0x1cc
#define RV1108_SDMMC_CON0 0x1d8
#define RV1108_SDMMC_CON1 0x1dc
#define RV1108_SDIO_CON0 0x1e0
#define RV1108_SDIO_CON1 0x1e4
#define RV1108_EMMC_CON0 0x1e8
#define RV1108_EMMC_CON1 0x1ec
#define RK2928_PLL_CON(x) ((x) * 0x4)
#define RK2928_MODE_CON 0x40
......
......@@ -313,7 +313,7 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB,
ADC_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "adc");
clk_register_clkdev(clk, NULL, "d820b000.adc");
clk = clk_register_fixed_factor(NULL, "gpio0_clk", "apb_clk", 0, 1, 1);
clk_register_clkdev(clk, NULL, "f0100000.gpio");
......
......@@ -64,6 +64,7 @@ config SUN50I_A64_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default ARM64 && ARCH_SUNXI
depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
config SUN5I_CCU
bool "Support for the Allwinner sun5i family CCM"
......@@ -75,6 +76,7 @@ config SUN5I_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN5I
depends on MACH_SUN5I || COMPILE_TEST
config SUN6I_A31_CCU
bool "Support for the Allwinner A31/A31s CCU"
......@@ -86,6 +88,7 @@ config SUN6I_A31_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN6I
depends on MACH_SUN6I || COMPILE_TEST
config SUN8I_A23_CCU
bool "Support for the Allwinner A23 CCU"
......@@ -98,6 +101,7 @@ config SUN8I_A23_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN8I
depends on MACH_SUN8I || COMPILE_TEST
config SUN8I_A33_CCU
bool "Support for the Allwinner A33 CCU"
......@@ -110,6 +114,7 @@ config SUN8I_A33_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN8I
depends on MACH_SUN8I || COMPILE_TEST
config SUN8I_H3_CCU
bool "Support for the Allwinner H3 CCU"
......@@ -120,7 +125,8 @@ config SUN8I_H3_CCU
select SUNXI_CCU_NM
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN8I
default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
config SUN8I_V3S_CCU
bool "Support for the Allwinner V3s CCU"
......@@ -132,6 +138,7 @@ config SUN8I_V3S_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN8I
depends on MACH_SUN8I || COMPILE_TEST
config SUN9I_A80_CCU
bool "Support for the Allwinner A80 CCU"
......@@ -143,5 +150,12 @@ config SUN9I_A80_CCU
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default MACH_SUN9I
depends on MACH_SUN9I || COMPILE_TEST
config SUN8I_R_CCU
bool "Support for Allwinner SoCs' PRCM CCUs"
select SUNXI_CCU_DIV
select SUNXI_CCU_GATE
default MACH_SUN8I || (ARCH_SUNXI && ARM64)
endif
......@@ -25,6 +25,7 @@ obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o
obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o
obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o
obj-$(CONFIG_SUN8I_R_CCU) += ccu-sun8i-r.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-de.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-usb.o
......@@ -469,7 +469,7 @@ static const char * const csi_parents[] = { "hosc", "pll-video0", "pll-video1",
static const u8 csi_table[] = { 0, 1, 2, 5, 6 };
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_clk, "csi",
csi_parents, csi_table,
0x134, 0, 5, 24, 2, BIT(31), 0);
0x134, 0, 5, 24, 3, BIT(31), 0);
static SUNXI_CCU_GATE(ve_clk, "ve", "pll-ve",
0x13c, BIT(31), CLK_SET_RATE_PARENT);
......
......@@ -159,13 +159,17 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de",
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
/* TODO: Fix N */
static SUNXI_CCU_N_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1",
"osc24M", 0x04c,
8, 6, /* N */
BIT(31), /* gate */
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
static struct ccu_mult pll_ddr1_clk = {
.enable = BIT(31),
.lock = BIT(28),
.mult = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 6, 0, 12, 0),
.common = {
.reg = 0x04c,
.hw.init = CLK_HW_INIT("pll-ddr1", "osc24M",
&ccu_mult_ops,
CLK_SET_RATE_UNGATE),
},
};
static const char * const cpux_parents[] = { "osc32k", "osc24M",
"pll-cpux" , "pll-cpux" };
......
This diff is collapsed.
......@@ -57,6 +57,7 @@
/* And the GPU module clock is exported */
#define CLK_NUMBER (CLK_GPU + 1)
#define CLK_NUMBER_H3 (CLK_GPU + 1)
#define CLK_NUMBER_H5 (CLK_BUS_SCR1 + 1)
#endif /* _CCU_SUN8I_H3_H_ */
/*
* Copyright (c) 2016 Icenowy Zheng <icenowy@aosc.xyz>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include "ccu_common.h"
#include "ccu_reset.h"
#include "ccu_div.h"
#include "ccu_gate.h"
#include "ccu_mp.h"
#include "ccu_nm.h"
#include "ccu-sun8i-r.h"
static const char * const ar100_parents[] = { "osc32k", "osc24M",
"pll-periph0", "iosc" };
static struct ccu_div ar100_clk = {
.div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
.mux = {
.shift = 16,
.width = 2,
.variable_prediv = {
.index = 2,
.shift = 8,
.width = 5,
},
},
.common = {
.reg = 0x00,
.features = CCU_FEATURE_VARIABLE_PREDIV,
.hw.init = CLK_HW_INIT_PARENTS("ar100",
ar100_parents,
&ccu_div_ops,
0),
},
};
static CLK_FIXED_FACTOR(ahb0_clk, "ahb0", "ar100", 1, 1, 0);
static struct ccu_div apb0_clk = {
.div = _SUNXI_CCU_DIV_FLAGS(0, 2, CLK_DIVIDER_POWER_OF_TWO),
.common = {
.reg = 0x0c,
.hw.init = CLK_HW_INIT("apb0",
"ahb0",
&ccu_div_ops,
0),
},
};
static SUNXI_CCU_GATE(apb0_pio_clk, "apb0-pio", "apb0",
0x28, BIT(0), 0);
static SUNXI_CCU_GATE(apb0_ir_clk, "apb0-ir", "apb0",
0x28, BIT(1), 0);
static SUNXI_CCU_GATE(apb0_timer_clk, "apb0-timer", "apb0",
0x28, BIT(2), 0);
static SUNXI_CCU_GATE(apb0_rsb_clk, "apb0-rsb", "apb0",
0x28, BIT(3), 0);
static SUNXI_CCU_GATE(apb0_uart_clk, "apb0-uart", "apb0",
0x28, BIT(4), 0);
static SUNXI_CCU_GATE(apb0_i2c_clk, "apb0-i2c", "apb0",
0x28, BIT(6), 0);
static SUNXI_CCU_GATE(apb0_twd_clk, "apb0-twd", "apb0",
0x28, BIT(7), 0);
static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
r_mod0_default_parents, 0x54,
0, 4, /* M */
16, 2, /* P */
24, 2, /* mux */
BIT(31), /* gate */
0);
static struct ccu_common *sun8i_h3_r_ccu_clks[] = {
&ar100_clk.common,
&apb0_clk.common,
&apb0_pio_clk.common,
&apb0_ir_clk.common,
&apb0_timer_clk.common,
&apb0_uart_clk.common,
&apb0_i2c_clk.common,
&apb0_twd_clk.common,
&ir_clk.common,
};
static struct ccu_common *sun50i_a64_r_ccu_clks[] = {
&ar100_clk.common,
&apb0_clk.common,
&apb0_pio_clk.common,
&apb0_ir_clk.common,
&apb0_timer_clk.common,
&apb0_rsb_clk.common,
&apb0_uart_clk.common,
&apb0_i2c_clk.common,
&apb0_twd_clk.common,
&ir_clk.common,
};
static struct clk_hw_onecell_data sun8i_h3_r_hw_clks = {
.hws = {
[CLK_AR100] = &ar100_clk.common.hw,
[CLK_AHB0] = &ahb0_clk.hw,
[CLK_APB0] = &apb0_clk.common.hw,
[CLK_APB0_PIO] = &apb0_pio_clk.common.hw,
[CLK_APB0_IR] = &apb0_ir_clk.common.hw,
[CLK_APB0_TIMER] = &apb0_timer_clk.common.hw,
[CLK_APB0_UART] = &apb0_uart_clk.common.hw,
[CLK_APB0_I2C] = &apb0_i2c_clk.common.hw,
[CLK_APB0_TWD] = &apb0_twd_clk.common.hw,
[CLK_IR] = &ir_clk.common.hw,
},
.num = CLK_NUMBER,
};
static struct clk_hw_onecell_data sun50i_a64_r_hw_clks = {
.hws = {
[CLK_AR100] = &ar100_clk.common.hw,
[CLK_AHB0] = &ahb0_clk.hw,
[CLK_APB0] = &apb0_clk.common.hw,
[CLK_APB0_PIO] = &apb0_pio_clk.common.hw,
[CLK_APB0_IR] = &apb0_ir_clk.common.hw,
[CLK_APB0_TIMER] = &apb0_timer_clk.common.hw,
[CLK_APB0_RSB] = &apb0_rsb_clk.common.hw,
[CLK_APB0_UART] = &apb0_uart_clk.common.hw,
[CLK_APB0_I2C] = &apb0_i2c_clk.common.hw,
[CLK_APB0_TWD] = &apb0_twd_clk.common.hw,
[CLK_IR] = &ir_clk.common.hw,
},
.num = CLK_NUMBER,
};
static struct ccu_reset_map sun8i_h3_r_ccu_resets[] = {
[RST_APB0_IR] = { 0xb0, BIT(1) },
[RST_APB0_TIMER] = { 0xb0, BIT(2) },
[RST_APB0_UART] = { 0xb0, BIT(4) },
[RST_APB0_I2C] = { 0xb0, BIT(6) },
};
static struct ccu_reset_map sun50i_a64_r_ccu_resets[] = {
[RST_APB0_IR] = { 0xb0, BIT(1) },
[RST_APB0_TIMER] = { 0xb0, BIT(2) },
[RST_APB0_RSB] = { 0xb0, BIT(3) },
[RST_APB0_UART] = { 0xb0, BIT(4) },
[RST_APB0_I2C] = { 0xb0, BIT(6) },
};
static const struct sunxi_ccu_desc sun8i_h3_r_ccu_desc = {
.ccu_clks = sun8i_h3_r_ccu_clks,
.num_ccu_clks = ARRAY_SIZE(sun8i_h3_r_ccu_clks),
.hw_clks = &sun8i_h3_r_hw_clks,
.resets = sun8i_h3_r_ccu_resets,
.num_resets = ARRAY_SIZE(sun8i_h3_r_ccu_resets),
};
static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = {
.ccu_clks = sun50i_a64_r_ccu_clks,
.num_ccu_clks = ARRAY_SIZE(sun50i_a64_r_ccu_clks),
.hw_clks = &sun50i_a64_r_hw_clks,
.resets = sun50i_a64_r_ccu_resets,
.num_resets = ARRAY_SIZE(sun50i_a64_r_ccu_resets),
};
static void __init sunxi_r_ccu_init(struct device_node *node,
const struct sunxi_ccu_desc *desc)
{
void __iomem *reg;
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
pr_err("%s: Could not map the clock registers\n",
of_node_full_name(node));
return;
}
sunxi_ccu_probe(node, reg, desc);
}
static void __init sun8i_h3_r_ccu_setup(struct device_node *node)
{
sunxi_r_ccu_init(node, &sun8i_h3_r_ccu_desc);
}
CLK_OF_DECLARE(sun8i_h3_r_ccu, "allwinner,sun8i-h3-r-ccu",
sun8i_h3_r_ccu_setup);
static void __init sun50i_a64_r_ccu_setup(struct device_node *node)
{
sunxi_r_ccu_init(node, &sun50i_a64_r_ccu_desc);
}
CLK_OF_DECLARE(sun50i_a64_r_ccu, "allwinner,sun50i-a64-r-ccu",
sun50i_a64_r_ccu_setup);
/*
* Copyright 2016 Icenowy <icenowy@aosc.xyz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN8I_R_H
#define _CCU_SUN8I_R_H_
#include <dt-bindings/clock/sun8i-r-ccu.h>
#include <dt-bindings/reset/sun8i-r-ccu.h>
/* AHB/APB bus clocks are not exported */
#define CLK_AHB0 1
#define CLK_APB0 2
#define CLK_NUMBER (CLK_IR + 1)
#endif /* _CCU_SUN8I_R_H */
This diff is collapsed.
......@@ -112,8 +112,8 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
ret = clk_hw_register(NULL, hw);
if (ret) {
pr_err("Couldn't register clock %s\n",
clk_hw_get_name(hw));
pr_err("Couldn't register clock %d - %s\n",
i, clk_hw_get_name(hw));
goto err_clk_unreg;
}
}
......
......@@ -75,8 +75,55 @@ static int ccu_gate_is_enabled(struct clk_hw *hw)
return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
}
static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct ccu_gate *cg = hw_to_ccu_gate(hw);
unsigned long rate = parent_rate;
if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
rate /= cg->common.prediv;
return rate;
}
static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct ccu_gate *cg = hw_to_ccu_gate(hw);
int div = 1;
if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
div = cg->common.prediv;
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
unsigned long best_parent = rate;
if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
best_parent *= div;
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
}
return *prate / div;
}
static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
/*
* We must report success but we can do so unconditionally because
* clk_factor_round_rate returns values that ensure this call is a
* nop.
*/
return 0;
}
const struct clk_ops ccu_gate_ops = {
.disable = ccu_gate_disable,
.enable = ccu_gate_enable,
.is_enabled = ccu_gate_is_enabled,
.round_rate = ccu_gate_round_rate,
.set_rate = ccu_gate_set_rate,
.recalc_rate = ccu_gate_recalc_rate,
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment