Skip to content

Commit

Permalink
clk: imx: Fix reparenting of UARTs not associated with stdout
Browse files Browse the repository at this point in the history
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: 9461f7b ("clk: fix CLK_SET_RATE_GATE with clock rate protection")
Suggested-by: Aisheng Dong <aisheng.dong@nxp.com>
Signed-off-by: Adam Ford <aford173@gmail.com>
Reviewed-by: Abel Vesa <abel.vesa@nxp.com>
Tested-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Abel Vesa <abel.vesa@nxp.com>
  • Loading branch information
Adam Ford authored and Abel Vesa committed Apr 4, 2021
1 parent a38fd87 commit 379c9a2
Show file tree
Hide file tree
Showing 16 changed files with 54 additions and 252 deletions.
12 changes: 1 addition & 11 deletions drivers/clk/imx/clk-imx25.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,6 @@ enum mx25_clks {

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)
{
BUG_ON(!ccm_base);
Expand Down Expand Up @@ -228,7 +218,7 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base)
*/
clk_set_parent(clk[cko_sel], clk[ipg]);

imx_register_uart_clocks(uart_clks);
imx_register_uart_clocks(6);

return 0;
}
Expand Down
13 changes: 1 addition & 12 deletions drivers/clk/imx/clk-imx27.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,6 @@ static const char *ssi_sel_clks[] = { "spll_gate", "mpll", };
static struct clk *clk[IMX27_CLK_MAX];
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)
{
BUG_ON(!ccm);
Expand Down Expand Up @@ -176,7 +165,7 @@ static void __init _mx27_clocks_init(unsigned long fref)

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());
}
Expand Down
10 changes: 1 addition & 9 deletions drivers/clk/imx/clk-imx35.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,6 @@ enum mx35_clks {

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)
{
void __iomem *base;
Expand Down Expand Up @@ -243,7 +235,7 @@ static void __init _mx35_clocks_init(void)
*/
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());
}
Expand Down
30 changes: 3 additions & 27 deletions drivers/clk/imx/clk-imx5.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_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)
{
clk[IMX5_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
Expand Down Expand Up @@ -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);
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);

Expand Down Expand Up @@ -488,7 +464,7 @@ static void __init mx51_clocks_init(struct device_node *np)
val |= 1 << 23;
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);

Expand Down Expand Up @@ -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);
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);
16 changes: 1 addition & 15 deletions drivers/clk/imx/clk-imx6q.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,6 @@ static inline int clk_on_imx6dl(void)
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)
{
switch (clock_id) {
Expand Down Expand Up @@ -440,7 +433,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
struct device_node *np;
void __iomem *anatop_base, *base;
int ret;
int i;

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

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

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

imx_register_uart_clocks(uart_clks);
imx_register_uart_clocks(1);
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
16 changes: 1 addition & 15 deletions drivers/clk/imx/clk-imx6sl.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,11 @@ void imx6sl_set_wait_clk(bool enter)
imx6sl_enable_pll_arm(false);
}

static const int uart_clk_ids[] __initconst = {
IMX6SL_CLK_UART,
IMX6SL_CLK_UART_SERIAL,
};

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

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

clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6SL_CLK_END), GFP_KERNEL);
Expand Down Expand Up @@ -448,12 +440,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
hws[IMX6SL_CLK_PLL2_PFD2]->clk);

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

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

imx_register_uart_clocks(uart_clks);
imx_register_uart_clocks(2);
}
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
24 changes: 1 addition & 23 deletions drivers/clk/imx/clk-imx6sll.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,26 +76,10 @@ static u32 share_count_ssi1;
static u32 share_count_ssi2;
static u32 share_count_ssi3;

static const int uart_clk_ids[] __initconst = {
IMX6SLL_CLK_UART1_IPG,
IMX6SLL_CLK_UART1_SERIAL,
IMX6SLL_CLK_UART2_IPG,
IMX6SLL_CLK_UART2_SERIAL,
IMX6SLL_CLK_UART3_IPG,
IMX6SLL_CLK_UART3_SERIAL,
IMX6SLL_CLK_UART4_IPG,
IMX6SLL_CLK_UART4_SERIAL,
IMX6SLL_CLK_UART5_IPG,
IMX6SLL_CLK_UART5_SERIAL,
};

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

static void __init imx6sll_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;

clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6SLL_CLK_END), GFP_KERNEL);
Expand Down Expand Up @@ -356,13 +340,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)

of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);

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

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

imx_register_uart_clocks(uart_clks);
imx_register_uart_clocks(5);

/* Lower the AHB clock rate before changing the clock source. */
clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000);
Expand Down
16 changes: 1 addition & 15 deletions drivers/clk/imx/clk-imx6sx.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,18 +117,10 @@ static u32 share_count_ssi3;
static u32 share_count_sai1;
static u32 share_count_sai2;

static const int uart_clk_ids[] __initconst = {
IMX6SX_CLK_UART_IPG,
IMX6SX_CLK_UART_SERIAL,
};

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

static void __init imx6sx_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;

clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX6SX_CLK_CLK_END), GFP_KERNEL);
Expand Down Expand Up @@ -556,12 +548,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);

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

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

imx_register_uart_clocks(uart_clks);
imx_register_uart_clocks(2);
}
CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
22 changes: 1 addition & 21 deletions drivers/clk/imx/clk-imx7d.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,23 +377,10 @@ static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_
static struct clk_hw **hws;
static struct clk_hw_onecell_data *clk_hw_data;

static const int uart_clk_ids[] __initconst = {
IMX7D_UART1_ROOT_CLK,
IMX7D_UART2_ROOT_CLK,
IMX7D_UART3_ROOT_CLK,
IMX7D_UART4_ROOT_CLK,
IMX7D_UART5_ROOT_CLK,
IMX7D_UART6_ROOT_CLK,
IMX7D_UART7_ROOT_CLK,
};

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

static void __init imx7d_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;

clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
IMX7D_CLK_END), GFP_KERNEL);
Expand Down Expand Up @@ -897,14 +884,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);

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

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


imx_register_uart_clocks(uart_clks);
imx_register_uart_clocks(7);

}
CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
31 changes: 2 additions & 29 deletions drivers/clk/imx/clk-imx7ulp.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,6 @@ static const struct clk_div_table ulp_div_table[] = {
{ /* sentinel */ },
};

static const int pcc2_uart_clk_ids[] __initconst = {
IMX7ULP_CLK_LPUART4,
IMX7ULP_CLK_LPUART5,
};

static const int pcc3_uart_clk_ids[] __initconst = {
IMX7ULP_CLK_LPUART6,
IMX7ULP_CLK_LPUART7,
};

static struct clk **pcc2_uart_clks[ARRAY_SIZE(pcc2_uart_clk_ids) + 1] __initdata;
static struct clk **pcc3_uart_clks[ARRAY_SIZE(pcc3_uart_clk_ids) + 1] __initdata;

static void __init imx7ulp_clk_scg1_init(struct device_node *np)
{
struct clk_hw_onecell_data *clk_data;
Expand Down Expand Up @@ -150,7 +137,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
struct clk_hw_onecell_data *clk_data;
struct clk_hw **hws;
void __iomem *base;
int i;

clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC2_END),
GFP_KERNEL);
Expand Down Expand Up @@ -190,13 +176,7 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)

of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);

for (i = 0; i < ARRAY_SIZE(pcc2_uart_clk_ids); i++) {
int index = pcc2_uart_clk_ids[i];

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

imx_register_uart_clocks(pcc2_uart_clks);
imx_register_uart_clocks(2);
}
CLK_OF_DECLARE(imx7ulp_clk_pcc2, "fsl,imx7ulp-pcc2", imx7ulp_clk_pcc2_init);

Expand All @@ -205,7 +185,6 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
struct clk_hw_onecell_data *clk_data;
struct clk_hw **hws;
void __iomem *base;
int i;

clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC3_END),
GFP_KERNEL);
Expand Down Expand Up @@ -244,13 +223,7 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)

of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);

for (i = 0; i < ARRAY_SIZE(pcc3_uart_clk_ids); i++) {
int index = pcc3_uart_clk_ids[i];

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

imx_register_uart_clocks(pcc3_uart_clks);
imx_register_uart_clocks(7);
}
CLK_OF_DECLARE(imx7ulp_clk_pcc3, "fsl,imx7ulp-pcc3", imx7ulp_clk_pcc3_init);

Expand Down
Loading

0 comments on commit 379c9a2

Please sign in to comment.