Commit 379c9a24 authored by Adam Ford's avatar Adam Ford Committed by Abel Vesa
Browse files

clk: imx: Fix reparenting of UARTs not associated with stdout



Most if not all i.MX SoC's call a function which enables all UARTS.
This is a problem for users who need to re-parent the clock source,
because any attempt to change the parent results in an busy error
due to the fact that the clocks have been enabled already.

  clk: failed to reparent uart1 to sys_pll1_80m: -16

Instead of pre-initializing all UARTS, scan the device tree to see
which UART clocks are associated to stdout, and only enable those
UART clocks if it's needed early.  This will move initialization of
the remaining clocks until after the parenting of the clocks.

When the clocks are shutdown, this mechanism will also disable any
clocks that were pre-initialized.

Fixes: 9461f7b3 ("clk: fix CLK_SET_RATE_GATE with clock rate protection")
Suggested-by: default avatarAisheng Dong <aisheng.dong@nxp.com>
Signed-off-by: default avatarAdam Ford <aford173@gmail.com>
Reviewed-by: default avatarAbel Vesa <abel.vesa@nxp.com>
Tested-by: default avatarAhmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: default avatarAbel Vesa <abel.vesa@nxp.com>
parent a38fd874
Loading
Loading
Loading
Loading
+1 −11
Original line number Original line Diff line number Diff line
@@ -73,16 +73,6 @@ enum mx25_clks {


static struct clk *clk[clk_max];
static struct clk *clk[clk_max];


static struct clk ** const uart_clks[] __initconst = {
	&clk[uart_ipg_per],
	&clk[uart1_ipg],
	&clk[uart2_ipg],
	&clk[uart3_ipg],
	&clk[uart4_ipg],
	&clk[uart5_ipg],
	NULL
};

static int __init __mx25_clocks_init(void __iomem *ccm_base)
static int __init __mx25_clocks_init(void __iomem *ccm_base)
{
{
	BUG_ON(!ccm_base);
	BUG_ON(!ccm_base);
@@ -228,7 +218,7 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base)
	 */
	 */
	clk_set_parent(clk[cko_sel], clk[ipg]);
	clk_set_parent(clk[cko_sel], clk[ipg]);


	imx_register_uart_clocks(uart_clks);
	imx_register_uart_clocks(6);


	return 0;
	return 0;
}
}
+1 −12
Original line number Original line Diff line number Diff line
@@ -49,17 +49,6 @@ static const char *ssi_sel_clks[] = { "spll_gate", "mpll", };
static struct clk *clk[IMX27_CLK_MAX];
static struct clk *clk[IMX27_CLK_MAX];
static struct clk_onecell_data clk_data;
static struct clk_onecell_data clk_data;


static struct clk ** const uart_clks[] __initconst = {
	&clk[IMX27_CLK_PER1_GATE],
	&clk[IMX27_CLK_UART1_IPG_GATE],
	&clk[IMX27_CLK_UART2_IPG_GATE],
	&clk[IMX27_CLK_UART3_IPG_GATE],
	&clk[IMX27_CLK_UART4_IPG_GATE],
	&clk[IMX27_CLK_UART5_IPG_GATE],
	&clk[IMX27_CLK_UART6_IPG_GATE],
	NULL
};

static void __init _mx27_clocks_init(unsigned long fref)
static void __init _mx27_clocks_init(unsigned long fref)
{
{
	BUG_ON(!ccm);
	BUG_ON(!ccm);
@@ -176,7 +165,7 @@ static void __init _mx27_clocks_init(unsigned long fref)


	clk_prepare_enable(clk[IMX27_CLK_EMI_AHB_GATE]);
	clk_prepare_enable(clk[IMX27_CLK_EMI_AHB_GATE]);


	imx_register_uart_clocks(uart_clks);
	imx_register_uart_clocks(7);


	imx_print_silicon_rev("i.MX27", mx27_revision());
	imx_print_silicon_rev("i.MX27", mx27_revision());
}
}
+1 −9
Original line number Original line Diff line number Diff line
@@ -82,14 +82,6 @@ enum mx35_clks {


static struct clk *clk[clk_max];
static struct clk *clk[clk_max];


static struct clk ** const uart_clks[] __initconst = {
	&clk[ipg],
	&clk[uart1_gate],
	&clk[uart2_gate],
	&clk[uart3_gate],
	NULL
};

static void __init _mx35_clocks_init(void)
static void __init _mx35_clocks_init(void)
{
{
	void __iomem *base;
	void __iomem *base;
@@ -243,7 +235,7 @@ static void __init _mx35_clocks_init(void)
	 */
	 */
	clk_prepare_enable(clk[scc_gate]);
	clk_prepare_enable(clk[scc_gate]);


	imx_register_uart_clocks(uart_clks);
	imx_register_uart_clocks(4);


	imx_print_silicon_rev("i.MX35", mx35_revision());
	imx_print_silicon_rev("i.MX35", mx35_revision());
}
}
+3 −27
Original line number Original line Diff line number Diff line
@@ -128,30 +128,6 @@ static const char *ieee1588_sels[] = { "pll3_sw", "pll4_sw", "dummy" /* usbphy2_
static struct clk *clk[IMX5_CLK_END];
static struct clk *clk[IMX5_CLK_END];
static struct clk_onecell_data clk_data;
static struct clk_onecell_data clk_data;


static struct clk ** const uart_clks_mx51[] __initconst = {
	&clk[IMX5_CLK_UART1_IPG_GATE],
	&clk[IMX5_CLK_UART1_PER_GATE],
	&clk[IMX5_CLK_UART2_IPG_GATE],
	&clk[IMX5_CLK_UART2_PER_GATE],
	&clk[IMX5_CLK_UART3_IPG_GATE],
	&clk[IMX5_CLK_UART3_PER_GATE],
	NULL
};

static struct clk ** const uart_clks_mx50_mx53[] __initconst = {
	&clk[IMX5_CLK_UART1_IPG_GATE],
	&clk[IMX5_CLK_UART1_PER_GATE],
	&clk[IMX5_CLK_UART2_IPG_GATE],
	&clk[IMX5_CLK_UART2_PER_GATE],
	&clk[IMX5_CLK_UART3_IPG_GATE],
	&clk[IMX5_CLK_UART3_PER_GATE],
	&clk[IMX5_CLK_UART4_IPG_GATE],
	&clk[IMX5_CLK_UART4_PER_GATE],
	&clk[IMX5_CLK_UART5_IPG_GATE],
	&clk[IMX5_CLK_UART5_PER_GATE],
	NULL
};

static void __init mx5_clocks_common_init(void __iomem *ccm_base)
static void __init mx5_clocks_common_init(void __iomem *ccm_base)
{
{
	clk[IMX5_CLK_DUMMY]		= imx_clk_fixed("dummy", 0);
	clk[IMX5_CLK_DUMMY]		= imx_clk_fixed("dummy", 0);
@@ -382,7 +358,7 @@ static void __init mx50_clocks_init(struct device_node *np)
	r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
	r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
	clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
	clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);


	imx_register_uart_clocks(uart_clks_mx50_mx53);
	imx_register_uart_clocks(5);
}
}
CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);
CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);


@@ -488,7 +464,7 @@ static void __init mx51_clocks_init(struct device_node *np)
	val |= 1 << 23;
	val |= 1 << 23;
	writel(val, MXC_CCM_CLPCR);
	writel(val, MXC_CCM_CLPCR);


	imx_register_uart_clocks(uart_clks_mx51);
	imx_register_uart_clocks(3);
}
}
CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init);
CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init);


@@ -633,6 +609,6 @@ static void __init mx53_clocks_init(struct device_node *np)
	r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
	r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
	clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
	clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);


	imx_register_uart_clocks(uart_clks_mx50_mx53);
	imx_register_uart_clocks(5);
}
}
CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
+1 −15
Original line number Original line Diff line number Diff line
@@ -140,13 +140,6 @@ static inline int clk_on_imx6dl(void)
	return of_machine_is_compatible("fsl,imx6dl");
	return of_machine_is_compatible("fsl,imx6dl");
}
}


static const int uart_clk_ids[] __initconst = {
	IMX6QDL_CLK_UART_IPG,
	IMX6QDL_CLK_UART_SERIAL,
};

static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;

static int ldb_di_sel_by_clock_id(int clock_id)
static int ldb_di_sel_by_clock_id(int clock_id)
{
{
	switch (clock_id) {
	switch (clock_id) {
@@ -440,7 +433,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
	struct device_node *np;
	struct device_node *np;
	void __iomem *anatop_base, *base;
	void __iomem *anatop_base, *base;
	int ret;
	int ret;
	int i;


	clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
	clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
					  IMX6QDL_CLK_END), GFP_KERNEL);
					  IMX6QDL_CLK_END), GFP_KERNEL);
@@ -982,12 +974,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
			       hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
			       hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
	}
	}


	for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
	imx_register_uart_clocks(1);
		int index = uart_clk_ids[i];

		uart_clks[i] = &hws[index]->clk;
	}

	imx_register_uart_clocks(uart_clks);
}
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
Loading