Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c284a7ba authored by Stephen Boyd's avatar Stephen Boyd
Browse files

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

Merge tag 'imx-clk-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into clk-next

Pull i.MX clock updates from Shawn Guo:

 - A patch series to fix the long standing issue with glitchy parent
   mux of ldb_di_clk, which can hang up LVDS display when ipu_di_clk
   is sourced from ldb_di_clk.
 - A patch to add imx6ull clock support on top of imx6ul clock driver.

* tag 'imx-clk-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
  clk: imx: clk-imx6ul: add clk support for imx6ull
  clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK
  clk: imx6: Make the LDB_DI0 and LDB_DI1 clocks read-only
  clk: imx6: Mask mmdc_ch1 handshake for periph2_sel and mmdc_ch1_axi_podf
parents 977f0ab0 73cd5e53
Loading
Loading
Loading
Loading
+273 −10
Original line number Diff line number Diff line
@@ -156,10 +156,267 @@ static struct clk ** const uart_clks[] __initconst = {
	NULL
};

static int ldb_di_sel_by_clock_id(int clock_id)
{
	switch (clock_id) {
	case IMX6QDL_CLK_PLL5_VIDEO_DIV:
		if (clk_on_imx6q() &&
		    imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
			return -ENOENT;
		return 0;
	case IMX6QDL_CLK_PLL2_PFD0_352M:
		return 1;
	case IMX6QDL_CLK_PLL2_PFD2_396M:
		return 2;
	case IMX6QDL_CLK_MMDC_CH1_AXI:
		return 3;
	case IMX6QDL_CLK_PLL3_USB_OTG:
		return 4;
	default:
		return -ENOENT;
	}
}

static void of_assigned_ldb_sels(struct device_node *node,
				 unsigned int *ldb_di0_sel,
				 unsigned int *ldb_di1_sel)
{
	struct of_phandle_args clkspec;
	int index, rc, num_parents;
	int parent, child, sel;

	num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
						 "#clock-cells");
	for (index = 0; index < num_parents; index++) {
		rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
					"#clock-cells", index, &clkspec);
		if (rc < 0) {
			/* skip empty (null) phandles */
			if (rc == -ENOENT)
				continue;
			else
				return;
		}
		if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
			pr_err("ccm: parent clock %d not in ccm\n", index);
			return;
		}
		parent = clkspec.args[0];

		rc = of_parse_phandle_with_args(node, "assigned-clocks",
				"#clock-cells", index, &clkspec);
		if (rc < 0)
			return;
		if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
			pr_err("ccm: child clock %d not in ccm\n", index);
			return;
		}
		child = clkspec.args[0];

		if (child != IMX6QDL_CLK_LDB_DI0_SEL &&
		    child != IMX6QDL_CLK_LDB_DI1_SEL)
			continue;

		sel = ldb_di_sel_by_clock_id(parent);
		if (sel < 0) {
			pr_err("ccm: invalid ldb_di%d parent clock: %d\n",
			       child == IMX6QDL_CLK_LDB_DI1_SEL, parent);
			continue;
		}

		if (child == IMX6QDL_CLK_LDB_DI0_SEL)
			*ldb_di0_sel = sel;
		if (child == IMX6QDL_CLK_LDB_DI1_SEL)
			*ldb_di1_sel = sel;
	}
}

#define CCM_CCDR		0x04
#define CCM_CCSR		0x0c
#define CCM_CS2CDR		0x2c

#define CCDR_MMDC_CH1_MASK		BIT(16)
#define CCSR_PLL3_SW_CLK_SEL		BIT(0)

#define CS2CDR_LDB_DI0_CLK_SEL_SHIFT	9
#define CS2CDR_LDB_DI1_CLK_SEL_SHIFT	12

static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
{
	unsigned int reg;

	reg = readl_relaxed(ccm_base + CCM_CCDR);
	reg |= CCDR_MMDC_CH1_MASK;
	writel_relaxed(reg, ccm_base + CCM_CCDR);
}

/*
 * The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk
 * via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the
 * bypass clock source, since there is no CG bit for mmdc_ch1.
 */
static void mmdc_ch1_disable(void __iomem *ccm_base)
{
	unsigned int reg;

	clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL],
		       clk[IMX6QDL_CLK_PLL3_USB_OTG]);

	/*
	 * Handshake with mmdc_ch1 module must be masked when changing
	 * periph2_clk_sel.
	 */
	clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]);

	/* Disable pll3_sw_clk by selecting the bypass clock source */
	reg = readl_relaxed(ccm_base + CCM_CCSR);
	reg |= CCSR_PLL3_SW_CLK_SEL;
	writel_relaxed(reg, ccm_base + CCM_CCSR);
}

static void mmdc_ch1_reenable(void __iomem *ccm_base)
{
	unsigned int reg;

	/* Enable pll3_sw_clk by disabling the bypass */
	reg = readl_relaxed(ccm_base + CCM_CCSR);
	reg &= ~CCSR_PLL3_SW_CLK_SEL;
	writel_relaxed(reg, ccm_base + CCM_CCSR);

	clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]);
}

/*
 * We have to follow a strict procedure when changing the LDB clock source,
 * otherwise we risk introducing a glitch that can lock up the LDB divider.
 * Things to keep in mind:
 *
 * 1. The current and new parent clock inputs to the mux must be disabled.
 * 2. The default clock input for ldb_di0/1_clk_sel is mmdc_ch1_axi, which
 *    has no CG bit.
 * 3. pll2_pfd2_396m can not be gated if it is used as memory clock.
 * 4. In the RTL implementation of the LDB_DI_CLK_SEL muxes the top four
 *    options are in one mux and the PLL3 option along with three unused
 *    inputs is in a second mux. There is a third mux with two inputs used
 *    to decide between the first and second 4-port mux:
 *
 *    pll5_video_div 0 --|\
 *    pll2_pfd0_352m 1 --| |_
 *    pll2_pfd2_396m 2 --| | `-|\
 *    mmdc_ch1_axi   3 --|/    | |
 *                             | |--
 *    pll3_usb_otg   4 --|\    | |
 *                   5 --| |_,-|/
 *                   6 --| |
 *                   7 --|/
 *
 * The ldb_di0/1_clk_sel[1:0] bits control both 4-port muxes at the same time.
 * The ldb_di0/1_clk_sel[2] bit controls the 2-port mux. The code below
 * switches the parent to the bottom mux first and then manipulates the top
 * mux to ensure that no glitch will enter the divider.
 */
static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
{
	unsigned int reg;
	unsigned int sel[2][4];
	int i;

	reg = readl_relaxed(ccm_base + CCM_CS2CDR);
	sel[0][0] = (reg >> CS2CDR_LDB_DI0_CLK_SEL_SHIFT) & 7;
	sel[1][0] = (reg >> CS2CDR_LDB_DI1_CLK_SEL_SHIFT) & 7;

	sel[0][3] = sel[0][2] = sel[0][1] = sel[0][0];
	sel[1][3] = sel[1][2] = sel[1][1] = sel[1][0];

	of_assigned_ldb_sels(np, &sel[0][3], &sel[1][3]);

	for (i = 0; i < 2; i++) {
		/* Warn if a glitch might have been introduced already */
		if (sel[i][0] != 3) {
			pr_warn("ccm: ldb_di%d_sel already changed from reset value: %d\n",
				i, sel[i][0]);
		}

		if (sel[i][0] == sel[i][3])
			continue;

		/* Only switch to or from pll2_pfd2_396m if it is disabled */
		if ((sel[i][0] == 2 || sel[i][3] == 2) &&
		    (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
		     clk[IMX6QDL_CLK_PLL2_PFD2_396M])) {
			pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n",
			       i);
			sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0];
			continue;
		}

		/* First switch to the bottom mux */
		sel[i][1] = sel[i][0] | 4;

		/* Then configure the top mux before switching back to it */
		sel[i][2] = sel[i][3] | 4;

		pr_debug("ccm: switching ldb_di%d_sel: %d->%d->%d->%d\n", i,
			 sel[i][0], sel[i][1], sel[i][2], sel[i][3]);
	}

	if (sel[0][0] == sel[0][3] && sel[1][0] == sel[1][3])
		return;

	mmdc_ch1_disable(ccm_base);

	for (i = 1; i < 4; i++) {
		reg = readl_relaxed(ccm_base + CCM_CS2CDR);
		reg &= ~((7 << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) |
			 (7 << CS2CDR_LDB_DI1_CLK_SEL_SHIFT));
		reg |= ((sel[0][i] << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) |
			(sel[1][i] << CS2CDR_LDB_DI1_CLK_SEL_SHIFT));
		writel_relaxed(reg, ccm_base + CCM_CS2CDR);
	}

	mmdc_ch1_reenable(ccm_base);
}

#define CCM_ANALOG_PLL_VIDEO	0xa0
#define CCM_ANALOG_PFD_480	0xf0
#define CCM_ANALOG_PFD_528	0x100

#define PLL_ENABLE		BIT(13)

#define PFD0_CLKGATE		BIT(7)
#define PFD1_CLKGATE		BIT(15)
#define PFD2_CLKGATE		BIT(23)
#define PFD3_CLKGATE		BIT(31)

static void disable_anatop_clocks(void __iomem *anatop_base)
{
	unsigned int reg;

	/* Make sure PLL2 PFDs 0-2 are gated */
	reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528);
	/* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */
	if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
	    clk[IMX6QDL_CLK_PLL2_PFD2_396M])
		reg |= PFD0_CLKGATE | PFD1_CLKGATE;
	else
		reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE;
	writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_528);

	/* Make sure PLL3 PFDs 0-3 are gated */
	reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_480);
	reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE | PFD3_CLKGATE;
	writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_480);

	/* Make sure PLL5 is disabled */
	reg = readl_relaxed(anatop_base + CCM_ANALOG_PLL_VIDEO);
	reg &= ~PLL_ENABLE;
	writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO);
}

static void __init imx6q_clocks_init(struct device_node *ccm_node)
{
	struct device_node *np;
	void __iomem *base;
	void __iomem *anatop_base, *base;
	int i;
	int ret;

@@ -172,7 +429,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
	clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);

	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
	base = of_iomap(np, 0);
	anatop_base = base = of_iomap(np, 0);
	WARN_ON(!base);

	/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
@@ -330,8 +587,20 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
		clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
	clk[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
	clk[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
	clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
	clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);

	disable_anatop_clocks(anatop_base);

	imx6q_mmdc_ch1_mask_handshake(base);

	/*
	 * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware
	 * bug. Set the muxes to the requested values before registering the
	 * ldb_di_sel clocks.
	 */
	init_ldb_clks(np, base);

	clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
	clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
	clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
	clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
	clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
@@ -582,12 +851,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)

	clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);

	if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) ||
	    clk_on_imx6dl()) {
		clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
		clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
	}

	clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
	if (clk_on_imx6dl())
		clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+61 −11
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@ static const char *perclk_sels[] = { "ipg", "osc", };
static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
/* epdc_pre_sels, epdc_sels, esai_sels only exists on i.MX6ULL */
static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
static const char *esai_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };

static struct clk *clks[IMX6UL_CLK_END];
static struct clk_onecell_data clk_data;
@@ -102,6 +106,17 @@ static u32 share_count_audio;
static u32 share_count_sai1;
static u32 share_count_sai2;
static u32 share_count_sai3;
static u32 share_count_esai;

static inline int clk_on_imx6ul(void)
{
	return of_machine_is_compatible("fsl,imx6ul");
}

static inline int clk_on_imx6ull(void)
{
	return of_machine_is_compatible("fsl,imx6ull");
}

static void __init imx6ul_clocks_init(struct device_node *ccm_node)
{
@@ -238,12 +253,19 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	clks[IMX6UL_CLK_QSPI1_SEL]	  = imx_clk_mux("qspi1_sel",    base + 0x1c, 7,  3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
	clks[IMX6UL_CLK_PERCLK_SEL]	  = imx_clk_mux("perclk_sel",	base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
	clks[IMX6UL_CLK_CAN_SEL]	  = imx_clk_mux("can_sel",	base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
	if (clk_on_imx6ull())
		clks[IMX6ULL_CLK_ESAI_SEL]	  = imx_clk_mux("esai_sel",	base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
	clks[IMX6UL_CLK_UART_SEL]	  = imx_clk_mux("uart_sel",	base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
	clks[IMX6UL_CLK_ENFC_SEL]	  = imx_clk_mux("enfc_sel",	base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
	clks[IMX6UL_CLK_LDB_DI0_SEL]	  = imx_clk_mux("ldb_di0_sel",	base + 0x2c, 9,  3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
	clks[IMX6UL_CLK_SPDIF_SEL]	  = imx_clk_mux("spdif_sel",	base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
	if (clk_on_imx6ul()) {
		clks[IMX6UL_CLK_SIM_PRE_SEL] 	  = imx_clk_mux("sim_pre_sel",	base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
		clks[IMX6UL_CLK_SIM_SEL]	  = imx_clk_mux("sim_sel", 	base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
	} else if (clk_on_imx6ull()) {
		clks[IMX6ULL_CLK_EPDC_PRE_SEL]	  = imx_clk_mux("epdc_pre_sel",	base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
		clks[IMX6ULL_CLK_EPDC_SEL]	  = imx_clk_mux("epdc_sel",	base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
	}
	clks[IMX6UL_CLK_ECSPI_SEL]	  = imx_clk_mux("ecspi_sel",	base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
	clks[IMX6UL_CLK_LCDIF_PRE_SEL]	  = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
	clks[IMX6UL_CLK_LCDIF_SEL]	  = imx_clk_mux("lcdif_sel",	base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
@@ -276,6 +298,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	clks[IMX6UL_CLK_SAI3_PODF]	= imx_clk_divider("sai3_podf",	   "sai3_pred",		base + 0x28, 16, 6);
	clks[IMX6UL_CLK_SAI1_PRED]	= imx_clk_divider("sai1_pred",	   "sai1_sel",		base + 0x28, 6,	 3);
	clks[IMX6UL_CLK_SAI1_PODF]	= imx_clk_divider("sai1_podf",	   "sai1_pred",		base + 0x28, 0,	 6);
	if (clk_on_imx6ull()) {
		clks[IMX6ULL_CLK_ESAI_PRED]	= imx_clk_divider("esai_pred",     "esai_sel",		base + 0x28, 9,  3);
		clks[IMX6ULL_CLK_ESAI_PODF]	= imx_clk_divider("esai_podf",     "esai_pred",		base + 0x28, 25, 3);
	}
	clks[IMX6UL_CLK_ENFC_PRED]	= imx_clk_divider("enfc_pred",	   "enfc_sel",		base + 0x2c, 18, 3);
	clks[IMX6UL_CLK_ENFC_PODF]	= imx_clk_divider("enfc_podf",	   "enfc_pred",		base + 0x2c, 21, 6);
	clks[IMX6UL_CLK_SAI2_PRED]	= imx_clk_divider("sai2_pred",	   "sai2_sel",		base + 0x2c, 6,	 3);
@@ -298,9 +324,15 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	clks[IMX6UL_CLK_APBHDMA]	= imx_clk_gate2("apbh_dma",	"bch_podf",	base + 0x68,	4);
	clks[IMX6UL_CLK_ASRC_IPG]	= imx_clk_gate2_shared("asrc_ipg",	"ahb",	base + 0x68,	6, &share_count_asrc);
	clks[IMX6UL_CLK_ASRC_MEM]	= imx_clk_gate2_shared("asrc_mem",	"ahb",	base + 0x68,	6, &share_count_asrc);
	if (clk_on_imx6ul()) {
		clks[IMX6UL_CLK_CAAM_MEM]	= imx_clk_gate2("caam_mem",	"ahb",		base + 0x68,	8);
		clks[IMX6UL_CLK_CAAM_ACLK]	= imx_clk_gate2("caam_aclk",	"ahb",		base + 0x68,	10);
		clks[IMX6UL_CLK_CAAM_IPG]	= imx_clk_gate2("caam_ipg",	"ipg",		base + 0x68,	12);
	} else if (clk_on_imx6ull()) {
		clks[IMX6ULL_CLK_DCP_CLK]	= imx_clk_gate2("dcp",		"ahb",		base + 0x68,	10);
		clks[IMX6UL_CLK_ENET]		= imx_clk_gate2("enet",		"ipg",		base + 0x68,	12);
		clks[IMX6UL_CLK_ENET_AHB]	= imx_clk_gate2("enet_ahb",	"ahb",		base + 0x68,	12);
	}
	clks[IMX6UL_CLK_CAN1_IPG]	= imx_clk_gate2("can1_ipg",	"ipg",		base + 0x68,	14);
	clks[IMX6UL_CLK_CAN1_SERIAL]	= imx_clk_gate2("can1_serial",	"can_podf",	base + 0x68,	16);
	clks[IMX6UL_CLK_CAN2_IPG]	= imx_clk_gate2("can2_ipg",	"ipg",		base + 0x68,	18);
@@ -309,7 +341,10 @@ 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())
		clks[IMX6UL_CLK_AIPSTZ3]	= imx_clk_gate2("aips_tz3",	"ahb",		 base + 0x80,	18);

	/* CCGR1 */
	clks[IMX6UL_CLK_ECSPI1]		= imx_clk_gate2("ecspi1",	"ecspi_podf",	base + 0x6c,	0);
@@ -328,6 +363,11 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	clks[IMX6UL_CLK_UART4_SERIAL]	= imx_clk_gate2("uart4_serail",	"uart_podf",	base + 0x6c,	24);

	/* CCGR2 */
	if (clk_on_imx6ull()) {
		clks[IMX6ULL_CLK_ESAI_EXTAL]	= imx_clk_gate2_shared("esai_extal",	"esai_podf",	base + 0x70,	0, &share_count_esai);
		clks[IMX6ULL_CLK_ESAI_IPG]	= imx_clk_gate2_shared("esai_ipg",	"ahb",		base + 0x70,	0, &share_count_esai);
		clks[IMX6ULL_CLK_ESAI_MEM]	= imx_clk_gate2_shared("esai_mem",	"ahb",		base + 0x70,	0, &share_count_esai);
	}
	clks[IMX6UL_CLK_CSI]		= imx_clk_gate2("csi",		"csi_podf",		base + 0x70,	2);
	clks[IMX6UL_CLK_I2C1]		= imx_clk_gate2("i2c1",		"perclk",	base + 0x70,	6);
	clks[IMX6UL_CLK_I2C2]		= imx_clk_gate2("i2c2",		"perclk",	base + 0x70,	8);
@@ -340,8 +380,13 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	/* CCGR3 */
	clks[IMX6UL_CLK_UART5_IPG]	= imx_clk_gate2("uart5_ipg",	"ipg",		base + 0x74,	2);
	clks[IMX6UL_CLK_UART5_SERIAL]	= imx_clk_gate2("uart5_serial",	"uart_podf",	base + 0x74,	2);
	if (clk_on_imx6ul()) {
		clks[IMX6UL_CLK_ENET]		= imx_clk_gate2("enet",		"ipg",		base + 0x74,	4);
		clks[IMX6UL_CLK_ENET_AHB]	= imx_clk_gate2("enet_ahb",	"ahb",		base + 0x74,	4);
	} else if (clk_on_imx6ull()) {
		clks[IMX6ULL_CLK_EPDC_ACLK]	= imx_clk_gate2("epdc_aclk",	"axi",		base + 0x74,	4);
		clks[IMX6ULL_CLK_EPDC_PIX]	= imx_clk_gate2("epdc_pix",	"epdc_podf",	base + 0x74,	4);
	}
	clks[IMX6UL_CLK_UART6_IPG]	= imx_clk_gate2("uart6_ipg",	"ipg",		base + 0x74,	6);
	clks[IMX6UL_CLK_UART6_SERIAL]	= imx_clk_gate2("uart6_serial",	"uart_podf",	base + 0x74,	6);
	clks[IMX6UL_CLK_LCDIF_PIX]	= imx_clk_gate2("lcdif_pix",	"lcdif_podf",	base + 0x74,	10);
@@ -385,8 +430,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	clks[IMX6UL_CLK_USBOH3]		= imx_clk_gate2("usboh3",	"ipg",		 base + 0x80,	0);
	clks[IMX6UL_CLK_USDHC1]		= imx_clk_gate2("usdhc1",	"usdhc1_podf",	 base + 0x80,	2);
	clks[IMX6UL_CLK_USDHC2]		= imx_clk_gate2("usdhc2",	"usdhc2_podf",	 base + 0x80,	4);
	if (clk_on_imx6ul()) {
		clks[IMX6UL_CLK_SIM1]		= imx_clk_gate2("sim1",		"sim_sel",	 base + 0x80,	6);
		clks[IMX6UL_CLK_SIM2]		= imx_clk_gate2("sim2",		"sim_sel",	 base + 0x80,	8);
	}
	clks[IMX6UL_CLK_EIM]		= imx_clk_gate2("eim",		"eim_slow_podf", base + 0x80,	10);
	clks[IMX6UL_CLK_PWM8]		= imx_clk_gate2("pwm8",		"perclk",	 base + 0x80,	16);
	clks[IMX6UL_CLK_UART8_IPG]	= imx_clk_gate2("uart8_ipg",	"ipg",		 base + 0x80,	14);
@@ -441,7 +488,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
	}

	clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
	if (clk_on_imx6ul())
		clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
	else if (clk_on_imx6ull())
		clk_set_parent(clks[IMX6ULL_CLK_EPDC_PRE_SEL], clks[IMX6UL_CLK_PLL3_PFD2]);

	clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
}
+8 −0
Original line number Diff line number Diff line
@@ -75,6 +75,14 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate)
	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
}

static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
		u8 shift, u8 width, const char **parents, int num_parents)
{
	return clk_register_mux(NULL, name, parents, num_parents,
			CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
			shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock);
}

static inline struct clk *imx_clk_fixed_factor(const char *name,
		const char *parent, unsigned int mult, unsigned int div)
{
+14 −1
Original line number Diff line number Diff line
@@ -236,6 +236,19 @@
#define IMX6UL_CLK_PLL3_120M		223
#define IMX6UL_CLK_KPP			224

#define IMX6UL_CLK_END			225
/* For i.MX6ULL */
#define IMX6ULL_CLK_ESAI_PRED		225
#define IMX6ULL_CLK_ESAI_PODF		226
#define IMX6ULL_CLK_ESAI_EXTAL		227
#define IMX6ULL_CLK_ESAI_MEM		228
#define IMX6ULL_CLK_ESAI_IPG		229
#define IMX6ULL_CLK_DCP_CLK		230
#define IMX6ULL_CLK_EPDC_PRE_SEL	231
#define IMX6ULL_CLK_EPDC_SEL		232
#define IMX6ULL_CLK_EPDC_PODF		233
#define IMX6ULL_CLK_EPDC_ACLK		234
#define IMX6ULL_CLK_EPDC_PIX		235
#define IMX6ULL_CLK_ESAI_SEL		236
#define IMX6UL_CLK_END			237

#endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */