Merge tag 'u-boot-imx-20190426' of git://git.denx.de/u-boot-imx
Porting to DM and i.MX8 ------------------------ - warp7 to DM - kp_imx53 to DM - Warnings in DT - MX8QM support - colibri-imx6ull to DM - imx7d-pico to DM - ocotp for MX8
This commit is contained in:
@@ -3,3 +3,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_CLK_IMX8) += clk-imx8.o
|
||||
|
||||
ifdef CONFIG_CLK_IMX8
|
||||
obj-$(CONFIG_IMX8QXP) += clk-imx8qxp.o
|
||||
obj-$(CONFIG_IMX8QM) += clk-imx8qm.o
|
||||
endif
|
||||
|
||||
@@ -13,304 +13,23 @@
|
||||
#include <dt-bindings/soc/imx_rsrc.h>
|
||||
#include <misc.h>
|
||||
|
||||
struct imx8_clks {
|
||||
ulong id;
|
||||
const char *name;
|
||||
};
|
||||
#include "clk-imx8.h"
|
||||
|
||||
#if CONFIG_IS_ENABLED(CMD_CLK)
|
||||
static struct imx8_clks imx8_clk_names[] = {
|
||||
{ IMX8QXP_A35_DIV, "A35_DIV" },
|
||||
{ IMX8QXP_I2C0_CLK, "I2C0" },
|
||||
{ IMX8QXP_I2C1_CLK, "I2C1" },
|
||||
{ IMX8QXP_I2C2_CLK, "I2C2" },
|
||||
{ IMX8QXP_I2C3_CLK, "I2C3" },
|
||||
{ IMX8QXP_UART0_CLK, "UART0" },
|
||||
{ IMX8QXP_UART1_CLK, "UART1" },
|
||||
{ IMX8QXP_UART2_CLK, "UART2" },
|
||||
{ IMX8QXP_UART3_CLK, "UART3" },
|
||||
{ IMX8QXP_SDHC0_CLK, "SDHC0" },
|
||||
{ IMX8QXP_SDHC1_CLK, "SDHC1" },
|
||||
{ IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
|
||||
{ IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
|
||||
{ IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
|
||||
{ IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
|
||||
{ IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
|
||||
{ IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
|
||||
{ IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
|
||||
{ IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
|
||||
};
|
||||
#endif
|
||||
|
||||
static ulong imx8_clk_get_rate(struct clk *clk)
|
||||
__weak ulong imx8_clk_get_rate(struct clk *clk)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
ulong rate;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QXP_A35_DIV:
|
||||
resource = SC_R_A35;
|
||||
pm_clk = SC_PM_CLK_CPU;
|
||||
break;
|
||||
case IMX8QXP_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC0_IPG_CLK:
|
||||
case IMX8QXP_SDHC0_CLK:
|
||||
case IMX8QXP_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC1_IPG_CLK:
|
||||
case IMX8QXP_SDHC1_CLK:
|
||||
case IMX8QXP_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART0_IPG_CLK:
|
||||
case IMX8QXP_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET0_IPG_CLK:
|
||||
case IMX8QXP_ENET0_AHB_CLK:
|
||||
case IMX8QXP_ENET0_REF_DIV:
|
||||
case IMX8QXP_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET1_IPG_CLK:
|
||||
case IMX8QXP_ENET1_AHB_CLK:
|
||||
case IMX8QXP_ENET1_REF_DIV:
|
||||
case IMX8QXP_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QXP_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QXP_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
|
||||
(sc_pm_clock_rate_t *)&rate);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
u32 new_rate = rate;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QXP_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC0_IPG_CLK:
|
||||
case IMX8QXP_SDHC0_CLK:
|
||||
case IMX8QXP_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC1_SEL:
|
||||
case IMX8QXP_SDHC0_SEL:
|
||||
return 0;
|
||||
case IMX8QXP_SDHC1_IPG_CLK:
|
||||
case IMX8QXP_SDHC1_CLK:
|
||||
case IMX8QXP_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET0_IPG_CLK:
|
||||
case IMX8QXP_ENET0_AHB_CLK:
|
||||
case IMX8QXP_ENET0_REF_DIV:
|
||||
case IMX8QXP_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET1_IPG_CLK:
|
||||
case IMX8QXP_ENET1_AHB_CLK:
|
||||
case IMX8QXP_ENET1_REF_DIV:
|
||||
case IMX8QXP_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QXP_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QXP_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
}
|
||||
|
||||
static int __imx8_clk_enable(struct clk *clk, bool enable)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QXP_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC0_IPG_CLK:
|
||||
case IMX8QXP_SDHC0_CLK:
|
||||
case IMX8QXP_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC1_IPG_CLK:
|
||||
case IMX8QXP_SDHC1_CLK:
|
||||
case IMX8QXP_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET0_IPG_CLK:
|
||||
case IMX8QXP_ENET0_AHB_CLK:
|
||||
case IMX8QXP_ENET0_REF_DIV:
|
||||
case IMX8QXP_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET1_IPG_CLK:
|
||||
case IMX8QXP_ENET1_AHB_CLK:
|
||||
case IMX8QXP_ENET1_REF_DIV:
|
||||
case IMX8QXP_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QXP_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QXP_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int __imx8_clk_enable(struct clk *clk, bool enable)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int imx8_clk_disable(struct clk *clk)
|
||||
{
|
||||
return __imx8_clk_enable(clk, 0);
|
||||
@@ -336,7 +55,7 @@ int soc_clk_dump(void)
|
||||
|
||||
printf("Clk\t\tHz\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(imx8_clk_names); i++) {
|
||||
for (i = 0; i < num_clks; i++) {
|
||||
clk.id = imx8_clk_names[i].id;
|
||||
ret = clk_request(dev, &clk);
|
||||
if (ret < 0) {
|
||||
@@ -382,6 +101,7 @@ static int imx8_clk_probe(struct udevice *dev)
|
||||
|
||||
static const struct udevice_id imx8_clk_ids[] = {
|
||||
{ .compatible = "fsl,imx8qxp-clk" },
|
||||
{ .compatible = "fsl,imx8qm-clk" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
19
drivers/clk/imx/clk-imx8.h
Normal file
19
drivers/clk/imx/clk-imx8.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
* Peng Fan <peng.fan@nxp.com>
|
||||
*/
|
||||
|
||||
struct imx8_clks {
|
||||
ulong id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(CMD_CLK)
|
||||
extern struct imx8_clks imx8_clk_names[];
|
||||
extern int num_clks;
|
||||
#endif
|
||||
|
||||
ulong imx8_clk_get_rate(struct clk *clk);
|
||||
ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate);
|
||||
int __imx8_clk_enable(struct clk *clk, bool enable);
|
||||
307
drivers/clk/imx/clk-imx8qm.c
Normal file
307
drivers/clk/imx/clk-imx8qm.c
Normal file
@@ -0,0 +1,307 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
* Peng Fan <peng.fan@nxp.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <asm/arch/sci/sci.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <dt-bindings/clock/imx8qm-clock.h>
|
||||
#include <dt-bindings/soc/imx_rsrc.h>
|
||||
#include <misc.h>
|
||||
|
||||
#include "clk-imx8.h"
|
||||
|
||||
#if CONFIG_IS_ENABLED(CMD_CLK)
|
||||
struct imx8_clks imx8_clk_names[] = {
|
||||
{ IMX8QM_A53_DIV, "A53_DIV" },
|
||||
{ IMX8QM_UART0_CLK, "UART0" },
|
||||
{ IMX8QM_UART1_CLK, "UART1" },
|
||||
{ IMX8QM_UART2_CLK, "UART2" },
|
||||
{ IMX8QM_UART3_CLK, "UART3" },
|
||||
{ IMX8QM_SDHC0_CLK, "SDHC0" },
|
||||
{ IMX8QM_SDHC1_CLK, "SDHC1" },
|
||||
{ IMX8QM_SDHC2_CLK, "SDHC2" },
|
||||
{ IMX8QM_ENET0_AHB_CLK, "ENET0_AHB" },
|
||||
{ IMX8QM_ENET0_IPG_CLK, "ENET0_IPG" },
|
||||
{ IMX8QM_ENET0_REF_DIV, "ENET0_REF" },
|
||||
{ IMX8QM_ENET0_PTP_CLK, "ENET0_PTP" },
|
||||
{ IMX8QM_ENET1_AHB_CLK, "ENET1_AHB" },
|
||||
{ IMX8QM_ENET1_IPG_CLK, "ENET1_IPG" },
|
||||
{ IMX8QM_ENET1_REF_DIV, "ENET1_REF" },
|
||||
{ IMX8QM_ENET1_PTP_CLK, "ENET1_PTP" },
|
||||
};
|
||||
|
||||
int num_clks = ARRAY_SIZE(imx8_clk_names);
|
||||
#endif
|
||||
|
||||
ulong imx8_clk_get_rate(struct clk *clk)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
ulong rate;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QM_A53_DIV:
|
||||
resource = SC_R_A53;
|
||||
pm_clk = SC_PM_CLK_CPU;
|
||||
break;
|
||||
case IMX8QM_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_SDHC0_IPG_CLK:
|
||||
case IMX8QM_SDHC0_CLK:
|
||||
case IMX8QM_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_SDHC1_IPG_CLK:
|
||||
case IMX8QM_SDHC1_CLK:
|
||||
case IMX8QM_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART0_IPG_CLK:
|
||||
case IMX8QM_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_ENET0_IPG_CLK:
|
||||
case IMX8QM_ENET0_AHB_CLK:
|
||||
case IMX8QM_ENET0_REF_DIV:
|
||||
case IMX8QM_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_ENET1_IPG_CLK:
|
||||
case IMX8QM_ENET1_AHB_CLK:
|
||||
case IMX8QM_ENET1_REF_DIV:
|
||||
case IMX8QM_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QM_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QM_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
|
||||
(sc_pm_clock_rate_t *)&rate);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
u32 new_rate = rate;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QM_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_SDHC0_IPG_CLK:
|
||||
case IMX8QM_SDHC0_CLK:
|
||||
case IMX8QM_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_SDHC1_IPG_CLK:
|
||||
case IMX8QM_SDHC1_CLK:
|
||||
case IMX8QM_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_ENET0_IPG_CLK:
|
||||
case IMX8QM_ENET0_AHB_CLK:
|
||||
case IMX8QM_ENET0_REF_DIV:
|
||||
case IMX8QM_ENET0_PTP_CLK:
|
||||
case IMX8QM_ENET0_ROOT_DIV:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_ENET1_IPG_CLK:
|
||||
case IMX8QM_ENET1_AHB_CLK:
|
||||
case IMX8QM_ENET1_REF_DIV:
|
||||
case IMX8QM_ENET1_PTP_CLK:
|
||||
case IMX8QM_ENET1_ROOT_DIV:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QM_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QM_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
}
|
||||
|
||||
int __imx8_clk_enable(struct clk *clk, bool enable)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QM_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_SDHC0_IPG_CLK:
|
||||
case IMX8QM_SDHC0_CLK:
|
||||
case IMX8QM_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_SDHC1_IPG_CLK:
|
||||
case IMX8QM_SDHC1_CLK:
|
||||
case IMX8QM_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_ENET0_IPG_CLK:
|
||||
case IMX8QM_ENET0_AHB_CLK:
|
||||
case IMX8QM_ENET0_REF_DIV:
|
||||
case IMX8QM_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QM_ENET1_IPG_CLK:
|
||||
case IMX8QM_ENET1_AHB_CLK:
|
||||
case IMX8QM_ENET1_REF_DIV:
|
||||
case IMX8QM_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QM_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QM_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
311
drivers/clk/imx/clk-imx8qxp.c
Normal file
311
drivers/clk/imx/clk-imx8qxp.c
Normal file
@@ -0,0 +1,311 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2018 NXP
|
||||
* Peng Fan <peng.fan@nxp.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <asm/arch/sci/sci.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <dt-bindings/clock/imx8qxp-clock.h>
|
||||
#include <dt-bindings/soc/imx_rsrc.h>
|
||||
#include <misc.h>
|
||||
|
||||
#include "clk-imx8.h"
|
||||
|
||||
#if CONFIG_IS_ENABLED(CMD_CLK)
|
||||
struct imx8_clks imx8_clk_names[] = {
|
||||
{ IMX8QXP_A35_DIV, "A35_DIV" },
|
||||
{ IMX8QXP_I2C0_CLK, "I2C0" },
|
||||
{ IMX8QXP_I2C1_CLK, "I2C1" },
|
||||
{ IMX8QXP_I2C2_CLK, "I2C2" },
|
||||
{ IMX8QXP_I2C3_CLK, "I2C3" },
|
||||
{ IMX8QXP_UART0_CLK, "UART0" },
|
||||
{ IMX8QXP_UART1_CLK, "UART1" },
|
||||
{ IMX8QXP_UART2_CLK, "UART2" },
|
||||
{ IMX8QXP_UART3_CLK, "UART3" },
|
||||
{ IMX8QXP_SDHC0_CLK, "SDHC0" },
|
||||
{ IMX8QXP_SDHC1_CLK, "SDHC1" },
|
||||
{ IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
|
||||
{ IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
|
||||
{ IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
|
||||
{ IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
|
||||
{ IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
|
||||
{ IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
|
||||
{ IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
|
||||
{ IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
|
||||
};
|
||||
|
||||
int num_clks = ARRAY_SIZE(imx8_clk_names);
|
||||
#endif
|
||||
|
||||
ulong imx8_clk_get_rate(struct clk *clk)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
ulong rate;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QXP_A35_DIV:
|
||||
resource = SC_R_A35;
|
||||
pm_clk = SC_PM_CLK_CPU;
|
||||
break;
|
||||
case IMX8QXP_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC0_IPG_CLK:
|
||||
case IMX8QXP_SDHC0_CLK:
|
||||
case IMX8QXP_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC1_IPG_CLK:
|
||||
case IMX8QXP_SDHC1_CLK:
|
||||
case IMX8QXP_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART0_IPG_CLK:
|
||||
case IMX8QXP_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET0_IPG_CLK:
|
||||
case IMX8QXP_ENET0_AHB_CLK:
|
||||
case IMX8QXP_ENET0_REF_DIV:
|
||||
case IMX8QXP_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET1_IPG_CLK:
|
||||
case IMX8QXP_ENET1_AHB_CLK:
|
||||
case IMX8QXP_ENET1_REF_DIV:
|
||||
case IMX8QXP_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QXP_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QXP_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
|
||||
(sc_pm_clock_rate_t *)&rate);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
u32 new_rate = rate;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QXP_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC0_IPG_CLK:
|
||||
case IMX8QXP_SDHC0_CLK:
|
||||
case IMX8QXP_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC1_SEL:
|
||||
case IMX8QXP_SDHC0_SEL:
|
||||
return 0;
|
||||
case IMX8QXP_SDHC1_IPG_CLK:
|
||||
case IMX8QXP_SDHC1_CLK:
|
||||
case IMX8QXP_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET0_IPG_CLK:
|
||||
case IMX8QXP_ENET0_AHB_CLK:
|
||||
case IMX8QXP_ENET0_REF_DIV:
|
||||
case IMX8QXP_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET1_IPG_CLK:
|
||||
case IMX8QXP_ENET1_AHB_CLK:
|
||||
case IMX8QXP_ENET1_REF_DIV:
|
||||
case IMX8QXP_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QXP_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QXP_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
}
|
||||
|
||||
int __imx8_clk_enable(struct clk *clk, bool enable)
|
||||
{
|
||||
sc_pm_clk_t pm_clk;
|
||||
u16 resource;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
switch (clk->id) {
|
||||
case IMX8QXP_I2C0_CLK:
|
||||
resource = SC_R_I2C_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C1_CLK:
|
||||
resource = SC_R_I2C_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C2_CLK:
|
||||
resource = SC_R_I2C_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_I2C3_CLK:
|
||||
resource = SC_R_I2C_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART0_CLK:
|
||||
resource = SC_R_UART_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART1_CLK:
|
||||
resource = SC_R_UART_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART2_CLK:
|
||||
resource = SC_R_UART_2;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_UART3_CLK:
|
||||
resource = SC_R_UART_3;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC0_IPG_CLK:
|
||||
case IMX8QXP_SDHC0_CLK:
|
||||
case IMX8QXP_SDHC0_DIV:
|
||||
resource = SC_R_SDHC_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_SDHC1_IPG_CLK:
|
||||
case IMX8QXP_SDHC1_CLK:
|
||||
case IMX8QXP_SDHC1_DIV:
|
||||
resource = SC_R_SDHC_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET0_IPG_CLK:
|
||||
case IMX8QXP_ENET0_AHB_CLK:
|
||||
case IMX8QXP_ENET0_REF_DIV:
|
||||
case IMX8QXP_ENET0_PTP_CLK:
|
||||
resource = SC_R_ENET_0;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
case IMX8QXP_ENET1_IPG_CLK:
|
||||
case IMX8QXP_ENET1_AHB_CLK:
|
||||
case IMX8QXP_ENET1_REF_DIV:
|
||||
case IMX8QXP_ENET1_PTP_CLK:
|
||||
resource = SC_R_ENET_1;
|
||||
pm_clk = SC_PM_CLK_PER;
|
||||
break;
|
||||
default:
|
||||
if (clk->id < IMX8QXP_UART0_IPG_CLK ||
|
||||
clk->id >= IMX8QXP_CLK_END) {
|
||||
printf("%s(Invalid clk ID #%lu)\n",
|
||||
__func__, clk->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
|
||||
if (ret) {
|
||||
printf("%s err %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
menu "i.MX8M DDR controllers"
|
||||
depends on ARCH_IMX8M
|
||||
|
||||
config IMX8M_DRAM
|
||||
bool "imx8m dram"
|
||||
|
||||
@@ -20,3 +23,4 @@ config SAVED_DRAM_TIMING_BASE
|
||||
info into memory for low power use. OCRAM_S is used for this
|
||||
purpose on i.MX8MM.
|
||||
default 0x180000
|
||||
endmenu
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
obj-y += scu_api.o scu.o
|
||||
obj-$(CONFIG_CMD_FUSE) += fuse.o
|
||||
|
||||
86
drivers/misc/imx8/fuse.c
Normal file
86
drivers/misc/imx8/fuse.c
Normal file
@@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include <errno.h>
|
||||
#include <fuse.h>
|
||||
#include <asm/arch/sci/sci.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define FSL_ECC_WORD_START_1 0x10
|
||||
#define FSL_ECC_WORD_END_1 0x10F
|
||||
|
||||
#ifdef CONFIG_IMX8QXP
|
||||
#define FSL_ECC_WORD_START_2 0x220
|
||||
#define FSL_ECC_WORD_END_2 0x31F
|
||||
|
||||
#define FSL_QXP_FUSE_GAP_START 0x110
|
||||
#define FSL_QXP_FUSE_GAP_END 0x21F
|
||||
#endif
|
||||
|
||||
#define FSL_SIP_OTP_READ 0xc200000A
|
||||
#define FSL_SIP_OTP_WRITE 0xc200000B
|
||||
|
||||
int fuse_read(u32 bank, u32 word, u32 *val)
|
||||
{
|
||||
return fuse_sense(bank, word, val);
|
||||
}
|
||||
|
||||
int fuse_sense(u32 bank, u32 word, u32 *val)
|
||||
{
|
||||
unsigned long ret = 0, value = 0;
|
||||
|
||||
if (bank != 0) {
|
||||
printf("Invalid bank argument, ONLY bank 0 is supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = call_imx_sip_ret2(FSL_SIP_OTP_READ, (unsigned long)word, &value,
|
||||
0, 0);
|
||||
*val = (u32)value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fuse_prog(u32 bank, u32 word, u32 val)
|
||||
{
|
||||
if (bank != 0) {
|
||||
printf("Invalid bank argument, ONLY bank 0 is supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_IMX8QXP)) {
|
||||
if (word >= FSL_QXP_FUSE_GAP_START &&
|
||||
word <= FSL_QXP_FUSE_GAP_END) {
|
||||
printf("Invalid word argument for this SoC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((word >= FSL_ECC_WORD_START_1 && word <= FSL_ECC_WORD_END_1) ||
|
||||
(word >= FSL_ECC_WORD_START_2 && word <= FSL_ECC_WORD_END_2)) {
|
||||
puts("Warning: Words in this index range have ECC protection\n"
|
||||
"and can only be programmed once per word. Individual bit\n"
|
||||
"operations will be rejected after the first one.\n"
|
||||
"\n\n Really program this word? <y/N>\n");
|
||||
|
||||
if (!confirm_yesno()) {
|
||||
puts("Word programming aborted\n");
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
return call_imx_sip(FSL_SIP_OTP_WRITE, (unsigned long)word,
|
||||
(unsigned long)val, 0);
|
||||
}
|
||||
|
||||
int fuse_override(u32 bank, u32 word, u32 val)
|
||||
{
|
||||
printf("Override fuse to i.MX8 in u-boot is forbidden\n");
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -219,11 +219,21 @@ static int imx8_scu_bind(struct udevice *dev)
|
||||
int ret;
|
||||
struct udevice *child;
|
||||
int node;
|
||||
char *clk_compatible, *iomuxc_compatible;
|
||||
|
||||
if (IS_ENABLED(CONFIG_IMX8QXP)) {
|
||||
clk_compatible = "fsl,imx8qxp-clk";
|
||||
iomuxc_compatible = "fsl,imx8qxp-iomuxc";
|
||||
} else if (IS_ENABLED(CONFIG_IMX8QM)) {
|
||||
clk_compatible = "fsl,imx8qm-clk";
|
||||
iomuxc_compatible = "fsl,imx8qm-iomuxc";
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug("%s(dev=%p)\n", __func__, dev);
|
||||
|
||||
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
|
||||
"fsl,imx8qxp-clk");
|
||||
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, clk_compatible);
|
||||
if (node < 0)
|
||||
panic("No clk node found\n");
|
||||
|
||||
@@ -234,7 +244,7 @@ static int imx8_scu_bind(struct udevice *dev)
|
||||
plat->clk = child;
|
||||
|
||||
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
|
||||
"fsl,imx8qxp-iomuxc");
|
||||
iomuxc_compatible);
|
||||
if (node < 0)
|
||||
panic("No iomuxc node found\n");
|
||||
|
||||
|
||||
@@ -321,6 +321,11 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
|
||||
struct ocotp_regs *regs;
|
||||
int ret;
|
||||
|
||||
if (is_imx8mq() && is_soc_rev(CHIP_REV_2_1)) {
|
||||
printf("mxc_ocotp %s(): fuse sense is disabled\n", __func__);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = prepare_read(®s, bank, word, val, __func__);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -354,13 +359,17 @@ static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word,
|
||||
|
||||
/* Only bank 0 and 1 are redundancy mode, others are ECC mode */
|
||||
if (bank != 0 && bank != 1) {
|
||||
ret = fuse_sense(bank, word, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if ((soc_rev() < CHIP_REV_2_0) ||
|
||||
((soc_rev() >= CHIP_REV_2_0) &&
|
||||
bank != 9 && bank != 10 && bank != 28)) {
|
||||
ret = fuse_sense(bank, word, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val != 0) {
|
||||
printf("mxc_ocotp: The word has been programmed, no more write\n");
|
||||
return -EPERM;
|
||||
if (val != 0) {
|
||||
printf("mxc_ocotp: The word has been programmed, no more write\n");
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@ static int imx8_pinctrl_probe(struct udevice *dev)
|
||||
|
||||
static const struct udevice_id imx8_pinctrl_match[] = {
|
||||
{ .compatible = "fsl,imx8qxp-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
|
||||
{ .compatible = "fsl,imx8qm-iomuxc", .data = (ulong)&imx8_pinctrl_soc_info },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
||||
@@ -132,6 +132,13 @@ config USB_EHCI_MARVELL
|
||||
---help---
|
||||
Enables support for the on-chip EHCI controller on MVEBU SoCs.
|
||||
|
||||
config USB_EHCI_MX5
|
||||
bool "Support for i.MX5 on-chip EHCI USB controller"
|
||||
depends on ARCH_MX5
|
||||
default n
|
||||
help
|
||||
Enables support for the on-chip EHCI controller on i.MX5 SoCs.
|
||||
|
||||
config USB_EHCI_MX6
|
||||
bool "Support for i.MX6 on-chip EHCI USB controller"
|
||||
depends on ARCH_MX6
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <dm.h>
|
||||
#include <power/regulator.h>
|
||||
|
||||
#include "ehci.h"
|
||||
|
||||
@@ -223,6 +225,7 @@ __weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
|
||||
mdelay(50);
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(DM_USB)
|
||||
static const struct ehci_ops mx5_ehci_ops = {
|
||||
.powerup_fixup = mx5_ehci_powerup_fixup,
|
||||
};
|
||||
@@ -267,3 +270,103 @@ int ehci_hcd_stop(int index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_IS_ENABLED(DM_USB) */
|
||||
struct ehci_mx5_priv_data {
|
||||
struct ehci_ctrl ctrl;
|
||||
struct usb_ehci *ehci;
|
||||
struct udevice *vbus_supply;
|
||||
enum usb_init_type init_type;
|
||||
int portnr;
|
||||
};
|
||||
|
||||
static const struct ehci_ops mx5_ehci_ops = {
|
||||
.powerup_fixup = mx5_ehci_powerup_fixup,
|
||||
};
|
||||
|
||||
static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct usb_platdata *plat = dev_get_platdata(dev);
|
||||
const char *mode;
|
||||
|
||||
mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL);
|
||||
if (mode) {
|
||||
if (strcmp(mode, "peripheral") == 0)
|
||||
plat->init_type = USB_INIT_DEVICE;
|
||||
else if (strcmp(mode, "host") == 0)
|
||||
plat->init_type = USB_INIT_HOST;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehci_usb_probe(struct udevice *dev)
|
||||
{
|
||||
struct usb_platdata *plat = dev_get_platdata(dev);
|
||||
struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev);
|
||||
struct ehci_mx5_priv_data *priv = dev_get_priv(dev);
|
||||
enum usb_init_type type = plat->init_type;
|
||||
struct ehci_hccr *hccr;
|
||||
struct ehci_hcor *hcor;
|
||||
int ret;
|
||||
|
||||
set_usboh3_clk();
|
||||
enable_usboh3_clk(true);
|
||||
set_usb_phy_clk();
|
||||
enable_usb_phy1_clk(true);
|
||||
enable_usb_phy2_clk(true);
|
||||
mdelay(1);
|
||||
|
||||
priv->ehci = ehci;
|
||||
priv->portnr = dev->seq;
|
||||
priv->init_type = type;
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vbus-supply",
|
||||
&priv->vbus_supply);
|
||||
if (ret)
|
||||
debug("%s: No vbus supply\n", dev->name);
|
||||
|
||||
if (!ret && priv->vbus_supply) {
|
||||
ret = regulator_set_enable(priv->vbus_supply,
|
||||
(type == USB_INIT_DEVICE) ?
|
||||
false : true);
|
||||
if (ret) {
|
||||
puts("Error enabling VBUS supply\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
|
||||
hcor = (struct ehci_hcor *)((uint32_t)hccr +
|
||||
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
|
||||
setbits_le32(&ehci->usbmode, CM_HOST);
|
||||
|
||||
__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
|
||||
setbits_le32(&ehci->portsc, USB_EN);
|
||||
|
||||
mxc_set_usbcontrol(priv->portnr, CONFIG_MXC_USB_FLAGS);
|
||||
mdelay(10);
|
||||
|
||||
return ehci_register(dev, hccr, hcor, &mx5_ehci_ops, 0,
|
||||
priv->init_type);
|
||||
}
|
||||
|
||||
static const struct udevice_id mx5_usb_ids[] = {
|
||||
{ .compatible = "fsl,imx53-usb" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(usb_mx5) = {
|
||||
.name = "ehci_mx5",
|
||||
.id = UCLASS_USB,
|
||||
.of_match = mx5_usb_ids,
|
||||
.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
|
||||
.probe = ehci_usb_probe,
|
||||
.remove = ehci_deregister,
|
||||
.ops = &ehci_usb_ops,
|
||||
.platdata_auto_alloc_size = sizeof(struct usb_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct ehci_mx5_priv_data),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
||||
#endif /* !CONFIG_IS_ENABLED(DM_USB) */
|
||||
|
||||
Reference in New Issue
Block a user