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:
Tom Rini
2019-04-30 23:21:27 -04:00
111 changed files with 6451 additions and 836 deletions

View File

@@ -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

View File

@@ -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" },
{ },
};

View 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);

View 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;
}

View 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;
}

View File

@@ -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

View File

@@ -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
View 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;
}

View File

@@ -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");

View File

@@ -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(&regs, 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

View File

@@ -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 */ }
};

View File

@@ -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

View File

@@ -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) */