Commit 80e9552e authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'clk-imx-6.4' of...

Merge tag 'clk-imx-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux into clk-imx

Pull i.MX clk driver updates from Abel Vesa:

 - Add clock generic devm_clk_hw_register_gate_parent_data.
 - Add audiomix block control for i.MX8MP.
 - Add support for determine_rate to composite-8m.
 - Add new macro for composite-8m to allow custom flags.
 - Let the LCDIF Pixel clock of i.MX8MM and i.MX8MN set parent rate.
 - Provide clock name in error message for clk-gpr-mux on get parent
   failure.
 - Drop duplicate imx_clk_mux_flags macro.
 - Register the i.MX8MP Media Disp2 Pix clock as bus clock.
 - Add Media LDB root clock to i.MX8MP.
 - Make i.MX8MP nand_usdhc_bus clock as non-critical.
 - Fix the rate table for fracn-gppll.
 - Disable HW control for the fracn-gppll in order to be controlled by
   register write.
 - Add support for interger PLL in fracn-gppll.
 - Add mcore_booted module parameter to i.MX93 provider.
 - Add NIC, A55 and ARM PLL clocks to i.MX93.
 - Fix i.MX8ULP XBAR_DIVBUS and AD_SLOW clock parents.
 - Use "divider closest" clock type for PLL4_PFD dividers on i.MX8ULP to
   get more accurate clock rates.
 - Mark the MU0_Bi and TPM5 clocks on i.MX8ULP as critical.
 - Update some of the critical clocks flags to allow glitchless
   on-the-fly rate change.

* tag 'clk-imx-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux: (25 commits)
  clk: imx: imx8ulp: update clk flag for system critical clock
  clk: imx: imx8ulp: Add tpm5 clock as critical gate clock
  clk: imx: imx8ulp: keep MU0_B clock enabled always
  clk: imx: imx8ulp: Add divider closest support to get more accurate clock rate
  clk: imx: imx8ulp: Fix XBAR_DIVBUS and AD_SLOW clock parents
  clk: imx: imx93: Add nic and A55 clk
  dt-bindings: clock: imx93: add NIC, A55 and ARM PLL CLK
  clk: imx: imx93: add mcore_booted module paratemter
  clk: imx: fracn-gppll: Add 300MHz freq support for imx9
  clk: imx: fracn-gppll: support integer pll
  clk: imx: fracn-gppll: disable hardware select control
  clk: imx: fracn-gppll: fix the rate table
  clk: imx: imx8mp: change the 'nand_usdhc_bus' clock to non-critical
  clk: imx: imx8mp: Add LDB root clock
  dt-bindings: clock: imx8mp: Add LDB clock entry
  clk: imx: imx8mp: correct DISP2 pixel clock type
  clk: imx: drop duplicated macro
  clk: imx: clk-gpr-mux: Provide clock name in error message
  clk: imx: Let IMX8MN_CLK_DISP_PIXEL set parent rate
  clk: imx8mm: Let IMX8MM_CLK_LCDIF_PIXEL set parent rate
  ...
parents fe15c26e 8a05f5cc
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/imx8mp-audiomix.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: NXP i.MX8MP AudioMIX Block Control Binding

maintainers:
  - Marek Vasut <marex@denx.de>

description: |
  NXP i.MX8M Plus AudioMIX is dedicated clock muxing and gating IP
  used to control Audio related clock on the SoC.

properties:
  compatible:
    const: fsl,imx8mp-audio-blk-ctrl

  reg:
    maxItems: 1

  power-domains:
    maxItems: 1

  clocks:
    minItems: 7
    maxItems: 7

  clock-names:
    items:
      - const: ahb
      - const: sai1
      - const: sai2
      - const: sai3
      - const: sai5
      - const: sai6
      - const: sai7

  '#clock-cells':
    const: 1
    description:
      The clock consumer should specify the desired clock by having the clock
      ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h
      for the full list of i.MX8MP IMX8MP_CLK_AUDIOMIX_ clock IDs.

required:
  - compatible
  - reg
  - clocks
  - clock-names
  - power-domains
  - '#clock-cells'

additionalProperties: false

examples:
  # Clock Control Module node:
  - |
    #include <dt-bindings/clock/imx8mp-clock.h>

    clock-controller@30e20000 {
        compatible = "fsl,imx8mp-audio-blk-ctrl";
        reg = <0x30e20000 0x10000>;
        #clock-cells = <1>;
        clocks = <&clk IMX8MP_CLK_AUDIO_ROOT>,
                 <&clk IMX8MP_CLK_SAI1>,
                 <&clk IMX8MP_CLK_SAI2>,
                 <&clk IMX8MP_CLK_SAI3>,
                 <&clk IMX8MP_CLK_SAI5>,
                 <&clk IMX8MP_CLK_SAI6>,
                 <&clk IMX8MP_CLK_SAI7>;
        clock-names = "ahb",
                      "sai1", "sai2", "sai3",
                      "sai5", "sai6", "sai7";
        power-domains = <&pgc_audio>;
    };

...
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ obj-$(CONFIG_MXC_CLK) += mxc-clk.o

obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o
obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o
obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-imx8mp-audiomix.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o

obj-$(CONFIG_CLK_IMX93) += clk-imx93.o
+7 −0
Original line number Diff line number Diff line
@@ -119,10 +119,17 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw,
	return ret;
}

static int imx8m_clk_divider_determine_rate(struct clk_hw *hw,
				      struct clk_rate_request *req)
{
	return clk_divider_ops.determine_rate(hw, req);
}

static const struct clk_ops imx8m_clk_composite_divider_ops = {
	.recalc_rate = imx8m_clk_composite_divider_recalc_rate,
	.round_rate = imx8m_clk_composite_divider_round_rate,
	.set_rate = imx8m_clk_composite_divider_set_rate,
	.determine_rate = imx8m_clk_divider_determine_rate,
};

static u8 imx8m_clk_composite_mux_get_parent(struct clk_hw *hw)
+7 −1
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p
		hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
					       mux_hw, &clk_mux_ro_ops, div_hw,
					       &clk_divider_ro_ops, NULL, NULL, flags);
	} else {
	} else if (!mcore_booted) {
		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
		if (!gate)
			goto fail;
@@ -238,6 +238,12 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p
					       &imx93_clk_composite_divider_ops, gate_hw,
					       &imx93_clk_composite_gate_ops,
					       flags | CLK_SET_RATE_NO_REPARENT);
	} else {
		hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
					       mux_hw, &imx93_clk_composite_mux_ops, div_hw,
					       &imx93_clk_composite_divider_ops, NULL,
					       &imx93_clk_composite_gate_ops,
					       flags | CLK_SET_RATE_NO_REPARENT);
	}

	if (IS_ERR(hw))
+77 −14
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "clk.h"

#define PLL_CTRL		0x0
#define HW_CTRL_SEL		BIT(16)
#define CLKMUX_BYPASS		BIT(2)
#define CLKMUX_EN		BIT(1)
#define POWERUP_MASK		BIT(0)
@@ -52,26 +53,40 @@
		.odiv	=	(_odiv),			\
	}

#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv)		\
	{							\
		.rate	=	(_rate),			\
		.mfi	=	(_mfi),				\
		.mfn	=	0,				\
		.mfd	=	0,				\
		.rdiv	=	(_rdiv),			\
		.odiv	=	(_odiv),			\
	}

struct clk_fracn_gppll {
	struct clk_hw			hw;
	void __iomem			*base;
	const struct imx_fracn_gppll_rate_table *rate_table;
	int rate_count;
	u32 flags;
};

/*
 * Fvco = Fref * (MFI + MFN / MFD)
 * Fout = Fvco / (rdiv * odiv)
 * Fvco = (Fref / rdiv) * (MFI + MFN / MFD)
 * Fout = Fvco / odiv
 * The (Fref / rdiv) should be in range 20MHz to 40MHz
 * The Fvco should be in range 2.5Ghz to 5Ghz
 */
static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
	PLL_FRACN_GP(650000000U, 81, 0, 1, 0, 3),
	PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
	PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
	PLL_FRACN_GP(560000000U, 70, 0, 1, 0, 3),
	PLL_FRACN_GP(498000000U, 83, 0, 1, 0, 4),
	PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
	PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8),
	PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
	PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
	PLL_FRACN_GP(400000000U, 50, 0, 1, 0, 3),
	PLL_FRACN_GP(393216000U, 81, 92, 100, 0, 5)
	PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
	PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
	PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
};

struct imx_fracn_gppll_clk imx_fracn_gppll = {
@@ -80,6 +95,24 @@ struct imx_fracn_gppll_clk imx_fracn_gppll = {
};
EXPORT_SYMBOL_GPL(imx_fracn_gppll);

/*
 * Fvco = (Fref / rdiv) * MFI
 * Fout = Fvco / odiv
 * The (Fref / rdiv) should be in range 20MHz to 40MHz
 * The Fvco should be in range 2.5Ghz to 5Ghz
 */
static const struct imx_fracn_gppll_rate_table int_tbl[] = {
	PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2),
	PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3),
	PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4),
};

struct imx_fracn_gppll_clk imx_fracn_gppll_integer = {
	.rate_table = int_tbl,
	.rate_count = ARRAY_SIZE(int_tbl),
};
EXPORT_SYMBOL_GPL(imx_fracn_gppll_integer);

static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw)
{
	return container_of(hw, struct clk_fracn_gppll, hw);
@@ -166,9 +199,15 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon
		break;
	}

	/* Fvco = Fref * (MFI + MFN / MFD) */
	if (pll->flags & CLK_FRACN_GPPLL_INTEGER) {
		/* Fvco = (Fref / rdiv) * MFI */
		fvco = fvco * mfi;
		do_div(fvco, rdiv * odiv);
	} else {
		/* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */
		fvco = fvco * mfi * mfd + fvco * mfn;
		do_div(fvco, mfd * rdiv * odiv);
	}

	return (unsigned long)fvco;
}
@@ -191,6 +230,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,

	rate = imx_get_pll_settings(pll, drate);

	/* Hardware control select disable. PLL is control by register */
	tmp = readl_relaxed(pll->base + PLL_CTRL);
	tmp &= ~HW_CTRL_SEL;
	writel_relaxed(tmp, pll->base + PLL_CTRL);

	/* Disable output */
	tmp = readl_relaxed(pll->base + PLL_CTRL);
	tmp &= ~CLKMUX_EN;
@@ -207,8 +251,10 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
	pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
		FIELD_PREP(PLL_MFI_MASK, rate->mfi);
	writel_relaxed(pll_div, pll->base + PLL_DIV);
	if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
		writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
		writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
	}

	/* Wait for 5us according to fracn mode pll doc */
	udelay(5);
@@ -292,8 +338,10 @@ static const struct clk_ops clk_fracn_gppll_ops = {
	.set_rate	= clk_fracn_gppll_set_rate,
};

struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
				   const struct imx_fracn_gppll_clk *pll_clk)
static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name,
					   void __iomem *base,
					   const struct imx_fracn_gppll_clk *pll_clk,
					   u32 pll_flags)
{
	struct clk_fracn_gppll *pll;
	struct clk_hw *hw;
@@ -314,6 +362,7 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo
	pll->hw.init = &init;
	pll->rate_table = pll_clk->rate_table;
	pll->rate_count = pll_clk->rate_count;
	pll->flags = pll_flags;

	hw = &pll->hw;

@@ -326,4 +375,18 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo

	return hw;
}

struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
				   const struct imx_fracn_gppll_clk *pll_clk)
{
	return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN);
}
EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll);

struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
					   void __iomem *base,
					   const struct imx_fracn_gppll_clk *pll_clk)
{
	return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER);
}
EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer);
Loading