u-boot-imx-20210809

- new SOC: add support for imx8ulp
- Toradex fixes for colibri (vf / imx6 / imx7 / imx8x)
- convert to DM for mx28evk
- Fixes for Gateworks ventana boards

CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/8639
This commit is contained in:
Tom Rini
2021-08-09 09:27:26 -04:00
128 changed files with 11842 additions and 831 deletions

View File

@@ -45,6 +45,7 @@ obj-$(CONFIG_ARMADA_38X) += ddr/marvell/a38x/
obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/
obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/
obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/
obj-$(CONFIG_IMX8ULP_DRAM) += ddr/imx/imx8ulp/
obj-$(CONFIG_SPL_POWER) += power/ power/pmic/
obj-$(CONFIG_SPL_POWER) += power/regulator/
obj-$(CONFIG_SPL_POWER_DOMAIN) += power/domain/

View File

@@ -1 +1,2 @@
source "drivers/ddr/imx/imx8m/Kconfig"
source "drivers/ddr/imx/imx8ulp/Kconfig"

View File

@@ -0,0 +1,11 @@
menu "i.MX8ULP DDR controllers"
depends on ARCH_IMX8ULP
config IMX8ULP_DRAM
bool "imx8m dram"
config IMX8ULP_DRAM_PHY_PLL_BYPASS
bool "Enable the DDR PHY PLL bypass mode, so PHY clock is from DDR_CLK "
depends on IMX8ULP_DRAM
endmenu

View File

@@ -0,0 +1,9 @@
#
# Copyright 2021 NXP
#
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_IMX8ULP_DRAM) += ddr_init.o
endif

View File

@@ -0,0 +1,217 @@
// SPDX-License-Identifier: GPL-2.0+ OR MIT
/*
* Copyright 2021 NXP
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/ddr.h>
#include <asm/arch/imx-regs.h>
#define DENALI_CTL_00 (DDR_CTL_BASE_ADDR + 4 * 0)
#define CTL_START 0x1
#define DENALI_CTL_03 (DDR_CTL_BASE_ADDR + 4 * 3)
#define DENALI_CTL_197 (DDR_CTL_BASE_ADDR + 4 * 197)
#define DENALI_CTL_250 (DDR_CTL_BASE_ADDR + 4 * 250)
#define DENALI_CTL_251 (DDR_CTL_BASE_ADDR + 4 * 251)
#define DENALI_CTL_266 (DDR_CTL_BASE_ADDR + 4 * 266)
#define DFI_INIT_COMPLETE 0x2
#define DENALI_CTL_614 (DDR_CTL_BASE_ADDR + 4 * 614)
#define DENALI_CTL_615 (DDR_CTL_BASE_ADDR + 4 * 615)
#define DENALI_PI_00 (DDR_PI_BASE_ADDR + 4 * 0)
#define PI_START 0x1
#define DENALI_PI_04 (DDR_PI_BASE_ADDR + 4 * 4)
#define DENALI_PI_11 (DDR_PI_BASE_ADDR + 4 * 11)
#define DENALI_PI_12 (DDR_PI_BASE_ADDR + 4 * 12)
#define DENALI_CTL_23 (DDR_CTL_BASE_ADDR + 4 * 23)
#define DENALI_CTL_25 (DDR_CTL_BASE_ADDR + 4 * 25)
#define DENALI_PHY_1624 (DDR_PHY_BASE_ADDR + 4 * 1624)
#define DENALI_PHY_1537 (DDR_PHY_BASE_ADDR + 4 * 1537)
#define PHY_FREQ_SEL_MULTICAST_EN(X) ((X) << 8)
#define PHY_FREQ_SEL_INDEX(X) ((X) << 16)
#define DENALI_PHY_1547 (DDR_PHY_BASE_ADDR + 4 * 1547)
#define DENALI_PHY_1555 (DDR_PHY_BASE_ADDR + 4 * 1555)
#define DENALI_PHY_1564 (DDR_PHY_BASE_ADDR + 4 * 1564)
#define DENALI_PHY_1565 (DDR_PHY_BASE_ADDR + 4 * 1565)
static void ddr_enable_pll_bypass(void)
{
u32 reg_val;
/* PI_INIT_LVL_EN=0x0 (DENALI_PI_04) */
reg_val = readl(DENALI_PI_04) & ~0x1;
writel(reg_val, DENALI_PI_04);
/* PI_FREQ_MAP=0x1 (DENALI_PI_12) */
writel(0x1, DENALI_PI_12);
/* PI_INIT_WORK_FREQ=0x0 (DENALI_PI_11) */
reg_val = readl(DENALI_PI_11) & ~(0x1f << 8);
writel(reg_val, DENALI_PI_11);
/* DFIBUS_FREQ_INIT=0x0 (DENALI_CTL_23) */
reg_val = readl(DENALI_CTL_23) & ~(0x3 << 24);
writel(reg_val, DENALI_CTL_23);
/* PHY_LP4_BOOT_DISABLE=0x0 (DENALI_PHY_1547) */
reg_val = readl(DENALI_PHY_1547) & ~(0x1 << 8);
writel(reg_val, DENALI_PHY_1547);
/* PHY_PLL_BYPASS=0x1 (DENALI_PHY_1624) */
reg_val = readl(DENALI_PHY_1624) | 0x1;
writel(reg_val, DENALI_PHY_1624);
/* PHY_LP4_BOOT_PLL_BYPASS to 0x1 (DENALI_PHY_1555) */
reg_val = readl(DENALI_PHY_1555) | 0x1;
writel(reg_val, DENALI_PHY_1555);
/* FREQ_CHANGE_TYPE_F0 = 0x0/FREQ_CHANGE_TYPE_F1 = 0x1/FREQ_CHANGE_TYPE_F2 = 0x2 */
reg_val = 0x020100;
writel(reg_val, DENALI_CTL_25);
}
int ddr_calibration(unsigned int fsp_table[3])
{
u32 reg_val;
u32 int_status_init, phy_freq_req, phy_freq_type;
u32 lock_0, lock_1, lock_2;
u32 freq_chg_pt, freq_chg_cnt;
if (IS_ENABLED(CONFIG_IMX8ULP_DRAM_PHY_PLL_BYPASS)) {
ddr_enable_pll_bypass();
freq_chg_cnt = 0;
freq_chg_pt = 0;
} else {
reg_val = readl(DENALI_CTL_250);
if (((reg_val >> 16) & 0x3) == 1)
freq_chg_cnt = 2;
else
freq_chg_cnt = 3;
reg_val = readl(DENALI_PI_12);
if (reg_val == 0x3) {
freq_chg_pt = 1;
} else if (reg_val == 0x7) {
freq_chg_pt = 2;
} else {
printf("frequency map(0x%x) is wrong, please check!\r\n", reg_val);
return -1;
}
}
/* Assert PI_START parameter and then assert START parameter in Controller. */
reg_val = readl(DENALI_PI_00) | PI_START;
writel(reg_val, DENALI_PI_00);
reg_val = readl(DENALI_CTL_00) | CTL_START;
writel(reg_val, DENALI_CTL_00);
/* Poll for init_done_bit in Controller interrupt status register (INT_STATUS_INIT) */
do {
if (!freq_chg_cnt) {
int_status_init = (readl(DENALI_CTL_266) >> 8) & 0xff;
/* DDR subsystem is ready for traffic. */
if (int_status_init & DFI_INIT_COMPLETE) {
debug("complete\n");
break;
}
}
/*
* During leveling, PHY will request for freq change and SoC clock logic
* should provide requested frequency
* Polling SIM LPDDR_CTRL2 Bit phy_freq_chg_req until be 1'b1
*/
reg_val = readl(AVD_SIM_LPDDR_CTRL2);
phy_freq_req = (reg_val >> 7) & 0x1;
if (phy_freq_req) {
phy_freq_type = reg_val & 0x1F;
if (phy_freq_type == 0x00) {
debug("Poll for freq_chg_req on SIM register and change to F0 frequency.\n");
set_ddr_clk(fsp_table[phy_freq_type] >> 1);
/* Write 1'b1 at LPDDR_CTRL2 bit phy_freq_cfg_ack */
reg_val = readl(AVD_SIM_LPDDR_CTRL2);
writel(reg_val | (0x1 << 6), AVD_SIM_LPDDR_CTRL2);
} else if (phy_freq_type == 0x01) {
debug("Poll for freq_chg_req on SIM register and change to F1 frequency.\n");
set_ddr_clk(fsp_table[phy_freq_type] >> 1);
/* Write 1'b1 at LPDDR_CTRL2 bit phy_freq_cfg_ack */
reg_val = readl(AVD_SIM_LPDDR_CTRL2);
writel(reg_val | (0x1 << 6), AVD_SIM_LPDDR_CTRL2);
if (freq_chg_pt == 1)
freq_chg_cnt--;
} else if (phy_freq_type == 0x02) {
debug("Poll for freq_chg_req on SIM register and change to F2 frequency.\n");
set_ddr_clk(fsp_table[phy_freq_type] >> 1);
/* Write 1'b1 at LPDDR_CTRL2 bit phy_freq_cfg_ack */
reg_val = readl(AVD_SIM_LPDDR_CTRL2);
writel(reg_val | (0x1 << 6), AVD_SIM_LPDDR_CTRL2);
if (freq_chg_pt == 2)
freq_chg_cnt--;
}
reg_val = readl(AVD_SIM_LPDDR_CTRL2);
}
} while (1);
/* Check PLL lock status */
lock_0 = readl(DENALI_PHY_1564) & 0xffff;
lock_1 = (readl(DENALI_PHY_1564) >> 16) & 0xffff;
lock_2 = readl(DENALI_PHY_1565) & 0xffff;
if ((lock_0 & 0x3) != 0x3 || (lock_1 & 0x3) != 0x3 || (lock_2 & 0x3) != 0x3) {
debug("De-Skew PLL failed to lock\n");
debug("lock_0=0x%x, lock_1=0x%x, lock_2=0x%x\n", lock_0, lock_1, lock_2);
return -1;
}
debug("De-Skew PLL is locked and ready\n");
return 0;
}
int ddr_init(struct dram_timing_info2 *dram_timing)
{
int i;
if (IS_ENABLED(CONFIG_IMX8ULP_DRAM_PHY_PLL_BYPASS)) {
/* Use PLL bypass for boot freq */
/* Since PLL can't generate the double freq, Need ddr clock to generate it. */
set_ddr_clk(dram_timing->fsp_table[0]); /* Set to boot freq */
setbits_le32(AVD_SIM_BASE_ADDR, 0x1); /* SIM_DDR_CTRL_DIV2_EN */
} else {
set_ddr_clk(dram_timing->fsp_table[0] >> 1); /* Set to boot freq */
clrbits_le32(AVD_SIM_BASE_ADDR, 0x1); /* SIM_DDR_CTRL_DIV2_EN */
}
/* Initialize CTL registers */
for (i = 0; i < dram_timing->ctl_cfg_num; i++)
writel(dram_timing->ctl_cfg[i].val, (ulong)dram_timing->ctl_cfg[i].reg);
/* Initialize PI registers */
for (i = 0; i < dram_timing->pi_cfg_num; i++)
writel(dram_timing->pi_cfg[i].val, (ulong)dram_timing->pi_cfg[i].reg);
/* Write PHY regiters for all 3 frequency points (48Mhz/384Mhz/528Mhz): f1_index=0 */
writel(PHY_FREQ_SEL_MULTICAST_EN(1) | PHY_FREQ_SEL_INDEX(0), DENALI_PHY_1537);
for (i = 0; i < dram_timing->phy_f1_cfg_num; i++)
writel(dram_timing->phy_f1_cfg[i].val, (ulong)dram_timing->phy_f1_cfg[i].reg);
/* Write PHY regiters for freqency point 2 (528Mhz): f2_index=1 */
writel(PHY_FREQ_SEL_MULTICAST_EN(0) | PHY_FREQ_SEL_INDEX(1), DENALI_PHY_1537);
for (i = 0; i < dram_timing->phy_f2_cfg_num; i++)
writel(dram_timing->phy_f2_cfg[i].val, (ulong)dram_timing->phy_f2_cfg[i].reg);
/* Re-enable MULTICAST mode */
writel(PHY_FREQ_SEL_MULTICAST_EN(1) | PHY_FREQ_SEL_INDEX(0), DENALI_PHY_1537);
return ddr_calibration(dram_timing->fsp_table);
}

View File

@@ -46,6 +46,7 @@ obj-$(CONFIG_SANDBOX) += irq_sandbox.o
obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
obj-$(CONFIG_IMX8) += imx8/
obj-$(CONFIG_IMX8ULP) += imx8ulp/
obj-$(CONFIG_LED_STATUS) += status_led.o
obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o

View File

@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += s400_api.o imx8ulp_mu.o
obj-$(CONFIG_CMD_FUSE) += fuse.o

198
drivers/misc/imx8ulp/fuse.c Normal file
View File

@@ -0,0 +1,198 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 NXP
*/
#include <common.h>
#include <console.h>
#include <errno.h>
#include <fuse.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/imx-regs.h>
#include <env.h>
#include <asm/arch/s400_api.h>
#include <asm/global_data.h>
DECLARE_GLOBAL_DATA_PTR;
#define FUSE_BANKS 64
#define WORDS_PER_BANKS 8
struct fsb_map_entry {
s32 fuse_bank;
u32 fuse_words;
bool redundancy;
};
struct s400_map_entry {
s32 fuse_bank;
u32 fuse_words;
u32 fuse_offset;
u32 s400_index;
};
struct fsb_map_entry fsb_mapping_table[] = {
{ 3, 8 },
{ 4, 8 },
{ 5, 8 },
{ 6, 8 },
{ -1, 48 }, /* Reserve 48 words */
{ 8, 4, true },
{ 24, 4, true },
{ 26, 4, true },
{ 27, 4, true },
{ 28, 8 },
{ 29, 8 },
{ 30, 8 },
{ 31, 8 },
{ 37, 8 },
{ 38, 8 },
{ 39, 8 },
{ 40, 8 },
{ 41, 8 },
{ 42, 8 },
{ 43, 8 },
{ 44, 8 },
{ 45, 8 },
{ 46, 8 },
};
struct s400_map_entry s400_api_mapping_table[] = {
{ 1, 8 }, /* LOCK */
{ 2, 8 }, /* ECID */
{ 7, 4, 0, 1 }, /* OTP_UNIQ_ID */
{ 23, 1, 4, 2 }, /* OTFAD */
};
static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy)
{
s32 size = ARRAY_SIZE(fsb_mapping_table);
s32 i, word_pos = 0;
/* map the fuse from ocotp fuse map to FSB*/
for (i = 0; i < size; i++) {
if (fsb_mapping_table[i].fuse_bank != -1 &&
fsb_mapping_table[i].fuse_bank == bank) {
break;
}
word_pos += fsb_mapping_table[i].fuse_words;
}
if (i == size)
return -1; /* Failed to find */
if (fsb_mapping_table[i].redundancy) {
*redundancy = true;
return (word >> 1) + word_pos;
}
*redundancy = false;
return word + word_pos;
}
static s32 map_s400_fuse_index(u32 bank, u32 word)
{
s32 size = ARRAY_SIZE(s400_api_mapping_table);
s32 i;
/* map the fuse from ocotp fuse map to FSB*/
for (i = 0; i < size; i++) {
if (s400_api_mapping_table[i].fuse_bank != -1 &&
s400_api_mapping_table[i].fuse_bank == bank) {
if (word >= s400_api_mapping_table[i].fuse_offset &&
word < (s400_api_mapping_table[i].fuse_offset +
s400_api_mapping_table[i].fuse_words))
break;
}
}
if (i == size)
return -1; /* Failed to find */
if (s400_api_mapping_table[i].s400_index != 0)
return s400_api_mapping_table[i].s400_index;
return s400_api_mapping_table[i].fuse_bank * 8 + word;
}
int fuse_sense(u32 bank, u32 word, u32 *val)
{
s32 word_index;
bool redundancy;
if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
return -EINVAL;
word_index = map_fsb_fuse_index(bank, word, &redundancy);
if (word_index >= 0) {
*val = readl((ulong)FSB_BASE_ADDR + 0x800 + (word_index << 2));
if (redundancy)
*val = (*val >> ((word % 2) * 16)) & 0xFFFF;
return 0;
}
word_index = map_s400_fuse_index(bank, word);
if (word_index >= 0) {
u32 data[4];
u32 res, size = 4;
int ret;
/* Only UID return 4 words */
if (word_index != 1)
size = 1;
ret = ahab_read_common_fuse(word_index, data, size, &res);
if (ret) {
printf("ahab read fuse failed %d, 0x%x\n", ret, res);
return ret;
}
if (word_index == 1) {
*val = data[word]; /* UID */
} else if (word_index == 2) {
/*
* OTFAD 3 bits as follow:
* bit 0: OTFAD_ENABLE
* bit 1: OTFAD_DISABLE_OVERRIDE
* bit 2: KEY_BLOB_EN
*/
*val = data[0] << 3;
} else {
*val = data[0];
}
return 0;
}
return -ENOENT;
}
int fuse_read(u32 bank, u32 word, u32 *val)
{
return fuse_sense(bank, word, val);
}
int fuse_prog(u32 bank, u32 word, u32 val)
{
u32 res;
int ret;
if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
return -EINVAL;
ret = ahab_write_fuse((bank * 8 + word), val, false, &res);
if (ret) {
printf("ahab write fuse failed %d, 0x%x\n", ret, res);
return ret;
}
return 0;
}
int fuse_override(u32 bank, u32 word, u32 val)
{
printf("Override fuse to i.MX8ULP in u-boot is forbidden\n");
return -EPERM;
}

View File

@@ -0,0 +1,234 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 NXP
*/
#include <common.h>
#include <asm/io.h>
#include <dm.h>
#include <dm/lists.h>
#include <dm/root.h>
#include <dm/device-internal.h>
#include <asm/arch/s400_api.h>
#include <asm/arch/imx-regs.h>
#include <linux/iopoll.h>
#include <misc.h>
DECLARE_GLOBAL_DATA_PTR;
struct imx8ulp_mu {
struct mu_type *base;
};
#define MU_SR_TE0_MASK BIT(0)
#define MU_SR_RF0_MASK BIT(0)
#define MU_TR_COUNT 4
#define MU_RR_COUNT 4
void mu_hal_init(ulong base)
{
struct mu_type *mu_base = (struct mu_type *)base;
writel(0, &mu_base->tcr);
writel(0, &mu_base->rcr);
}
int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg)
{
struct mu_type *mu_base = (struct mu_type *)base;
u32 mask = MU_SR_TE0_MASK << reg_index;
u32 val;
int ret;
assert(reg_index < MU_TR_COUNT);
debug("sendmsg sr 0x%x\n", readl(&mu_base->sr));
/* Wait TX register to be empty. */
ret = readl_poll_timeout(&mu_base->tsr, val, val & mask, 10000);
if (ret < 0) {
debug("%s timeout\n", __func__);
return -ETIMEDOUT;
}
debug("tr[%d] 0x%x\n", reg_index, msg);
writel(msg, &mu_base->tr[reg_index]);
return 0;
}
int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg)
{
struct mu_type *mu_base = (struct mu_type *)base;
u32 mask = MU_SR_RF0_MASK << reg_index;
u32 val;
int ret;
assert(reg_index < MU_TR_COUNT);
debug("receivemsg sr 0x%x\n", readl(&mu_base->sr));
/* Wait RX register to be full. */
ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 10000);
if (ret < 0) {
debug("%s timeout\n", __func__);
return -ETIMEDOUT;
}
*msg = readl(&mu_base->rr[reg_index]);
debug("rr[%d] 0x%x\n", reg_index, *msg);
return 0;
}
static int imx8ulp_mu_read(struct mu_type *base, void *data)
{
struct imx8ulp_s400_msg *msg = (struct imx8ulp_s400_msg *)data;
int ret;
u8 count = 0;
if (!msg)
return -EINVAL;
/* Read first word */
ret = mu_hal_receivemsg((ulong)base, 0, (u32 *)msg);
if (ret)
return ret;
count++;
/* Check size */
if (msg->size > S400_MAX_MSG) {
*((u32 *)msg) = 0;
return -EINVAL;
}
/* Read remaining words */
while (count < msg->size) {
ret = mu_hal_receivemsg((ulong)base, count % MU_RR_COUNT,
&msg->data[count - 1]);
if (ret)
return ret;
count++;
}
return 0;
}
static int imx8ulp_mu_write(struct mu_type *base, void *data)
{
struct imx8ulp_s400_msg *msg = (struct imx8ulp_s400_msg *)data;
int ret;
u8 count = 0;
if (!msg)
return -EINVAL;
/* Check size */
if (msg->size > S400_MAX_MSG)
return -EINVAL;
/* Write first word */
ret = mu_hal_sendmsg((ulong)base, 0, *((u32 *)msg));
if (ret)
return ret;
count++;
/* Write remaining words */
while (count < msg->size) {
ret = mu_hal_sendmsg((ulong)base, count % MU_TR_COUNT,
msg->data[count - 1]);
if (ret)
return ret;
count++;
}
return 0;
}
/*
* Note the function prototype use msgid as the 2nd parameter, here
* we take it as no_resp.
*/
static int imx8ulp_mu_call(struct udevice *dev, int no_resp, void *tx_msg,
int tx_size, void *rx_msg, int rx_size)
{
struct imx8ulp_mu *priv = dev_get_priv(dev);
u32 result;
int ret;
/* Expect tx_msg, rx_msg are the same value */
if (rx_msg && tx_msg != rx_msg)
printf("tx_msg %p, rx_msg %p\n", tx_msg, rx_msg);
ret = imx8ulp_mu_write(priv->base, tx_msg);
if (ret)
return ret;
if (!no_resp) {
ret = imx8ulp_mu_read(priv->base, rx_msg);
if (ret)
return ret;
}
result = ((struct imx8ulp_s400_msg *)rx_msg)->data[0];
if ((result & 0xff) == 0xd6)
return 0;
return -EIO;
}
static int imx8ulp_mu_probe(struct udevice *dev)
{
struct imx8ulp_mu *priv = dev_get_priv(dev);
fdt_addr_t addr;
debug("%s(dev=%p) (priv=%p)\n", __func__, dev, priv);
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->base = (struct mu_type *)addr;
debug("mu base 0x%lx\n", (ulong)priv->base);
/* U-Boot not enable interrupts, so need to enable RX interrupts */
mu_hal_init((ulong)priv->base);
gd->arch.s400_dev = dev;
return 0;
}
static int imx8ulp_mu_remove(struct udevice *dev)
{
return 0;
}
static int imx8ulp_mu_bind(struct udevice *dev)
{
debug("%s(dev=%p)\n", __func__, dev);
return 0;
}
static struct misc_ops imx8ulp_mu_ops = {
.call = imx8ulp_mu_call,
};
static const struct udevice_id imx8ulp_mu_ids[] = {
{ .compatible = "fsl,imx8ulp-mu" },
{ }
};
U_BOOT_DRIVER(imx8ulp_mu) = {
.name = "imx8ulp_mu",
.id = UCLASS_MISC,
.of_match = imx8ulp_mu_ids,
.probe = imx8ulp_mu_probe,
.bind = imx8ulp_mu_bind,
.remove = imx8ulp_mu_remove,
.ops = &imx8ulp_mu_ops,
.priv_auto = sizeof(struct imx8ulp_mu),
};

View File

@@ -0,0 +1,244 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 NXP
*
*/
#include <common.h>
#include <hang.h>
#include <malloc.h>
#include <asm/io.h>
#include <dm.h>
#include <asm/arch/s400_api.h>
#include <misc.h>
DECLARE_GLOBAL_DATA_PTR;
int ahab_release_rdc(u8 core_id, bool xrdc, u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 2;
msg.command = AHAB_RELEASE_RDC_REQ_CID;
if (xrdc)
msg.data[0] = (0x78 << 8) | core_id;
else
msg.data[0] = (0x74 << 8) | core_id;
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, core id %u, response 0x%x\n",
__func__, ret, core_id, msg.data[0]);
if (response)
*response = msg.data[0];
return ret;
}
int ahab_auth_oem_ctnr(ulong ctnr_addr, u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 3;
msg.command = AHAB_AUTH_OEM_CTNR_CID;
msg.data[0] = upper_32_bits(ctnr_addr);
msg.data[1] = lower_32_bits(ctnr_addr);
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, cntr_addr 0x%lx, response 0x%x\n",
__func__, ret, ctnr_addr, msg.data[0]);
if (response)
*response = msg.data[0];
return ret;
}
int ahab_release_container(u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 1;
msg.command = AHAB_RELEASE_CTNR_CID;
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, response 0x%x\n",
__func__, ret, msg.data[0]);
if (response)
*response = msg.data[0];
return ret;
}
int ahab_verify_image(u32 img_id, u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 2;
msg.command = AHAB_VERIFY_IMG_CID;
msg.data[0] = 1 << img_id;
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, img_id %u, response 0x%x\n",
__func__, ret, img_id, msg.data[0]);
if (response)
*response = msg.data[0];
return ret;
}
int ahab_forward_lifecycle(u16 life_cycle, u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 2;
msg.command = AHAB_FWD_LIFECYCLE_UP_REQ_CID;
msg.data[0] = life_cycle;
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, life_cycle 0x%x, response 0x%x\n",
__func__, ret, life_cycle, msg.data[0]);
if (response)
*response = msg.data[0];
return ret;
}
int ahab_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
if (!fuse_words) {
printf("Invalid parameters for fuse read\n");
return -EINVAL;
}
if ((fuse_id != 1 && fuse_num != 1) ||
(fuse_id == 1 && fuse_num != 4)) {
printf("Invalid fuse number parameter\n");
return -EINVAL;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 2;
msg.command = AHAB_READ_FUSE_REQ_CID;
msg.data[0] = fuse_id;
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
__func__, ret, fuse_id, msg.data[0]);
if (response)
*response = msg.data[0];
fuse_words[0] = msg.data[1];
if (fuse_id == 1) {
/* OTP_UNIQ_ID */
fuse_words[1] = msg.data[2];
fuse_words[2] = msg.data[3];
fuse_words[3] = msg.data[4];
}
return ret;
}
int ahab_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response)
{
struct udevice *dev = gd->arch.s400_dev;
int size = sizeof(struct imx8ulp_s400_msg);
struct imx8ulp_s400_msg msg;
int ret;
if (!dev) {
printf("s400 dev is not initialized\n");
return -ENODEV;
}
msg.version = AHAB_VERSION;
msg.tag = AHAB_CMD_TAG;
msg.size = 3;
msg.command = AHAB_WRITE_FUSE_REQ_CID;
msg.data[0] = (32 << 16) | (fuse_id << 5);
if (lock)
msg.data[0] |= (1 << 31);
msg.data[1] = fuse_val;
ret = misc_call(dev, false, &msg, size, &msg, size);
if (ret)
printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
__func__, ret, fuse_id, msg.data[0]);
if (response)
*response = msg.data[0];
return ret;
}

View File

@@ -832,7 +832,7 @@ config FSL_ESDHC_IMX
config FSL_USDHC
bool "Freescale/NXP i.MX uSDHC controller support"
depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMXRT
depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMX8ULP || IMXRT
select FSL_ESDHC_IMX
help
This enables the Ultra Secured Digital Host Controller enhancements

View File

@@ -291,7 +291,8 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
{
int timeout;
struct fsl_esdhc *regs = priv->esdhc_regs;
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M) || \
defined(CONFIG_IMX8ULP)
dma_addr_t addr;
#endif
uint wml_value;
@@ -304,7 +305,8 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M) || \
defined(CONFIG_IMX8ULP)
addr = virt_to_phys((void *)(data->dest));
if (upper_32_bits(addr))
printf("Error found for upper 32 bits\n");
@@ -341,7 +343,8 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
wml_value << 16);
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M) || \
defined(CONFIG_IMX8ULP)
addr = virt_to_phys((void *)(data->src));
if (upper_32_bits(addr))
printf("Error found for upper 32 bits\n");
@@ -406,7 +409,8 @@ static void check_and_invalidate_dcache_range
unsigned end = 0;
unsigned size = roundup(ARCH_DMA_MINALIGN,
data->blocks*data->blocksize);
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M)
#if defined(CONFIG_S32V234) || defined(CONFIG_IMX8) || defined(CONFIG_IMX8M) || \
defined(CONFIG_IMX8ULP)
dma_addr_t addr;
addr = virt_to_phys((void *)(data->dest));

View File

@@ -331,7 +331,7 @@ config FEC_MXC_MDIO_BASE
config FEC_MXC
bool "FEC Ethernet controller"
depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || VF610
depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || IMX8ULP || VF610
help
This driver supports the 10/100 Fast Ethernet controller for
NXP i.MX processors.

View File

@@ -631,7 +631,7 @@ static int fec_init(struct eth_device *dev, struct bd_info *bd)
writel(0x00000000, &fec->eth->gaddr2);
/* Do not access reserved register */
if (!is_mx6ul() && !is_mx6ull() && !is_imx8() && !is_imx8m()) {
if (!is_mx6ul() && !is_mx6ull() && !is_imx8() && !is_imx8m() && !is_imx8ulp()) {
/* clear MIB RAM */
for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4)
writel(0, i);

View File

@@ -60,6 +60,20 @@ config PINCTRL_IMX7ULP
only parses the 'fsl,pins' property and configure related
registers.
config PINCTRL_IMX8ULP
bool "IMX8ULP pinctrl driver"
depends on ARCH_IMX8ULP && PINCTRL_FULL
select DEVRES
select PINCTRL_IMX
help
Say Y here to enable the imx8ulp pinctrl driver
This provides a simple pinctrl driver for i.MX8ULP SoC familiy.
This feature depends on device tree configuration. This driver
is different from the linux one, this is a simple implementation,
only parses the 'fsl,pins' property and configure related
registers.
config PINCTRL_IMX8
bool "IMX8 pinctrl driver"
depends on ARCH_IMX8 && PINCTRL_FULL

View File

@@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_IMX5) += pinctrl-imx5.o
obj-$(CONFIG_PINCTRL_IMX6) += pinctrl-imx6.o
obj-$(CONFIG_PINCTRL_IMX7) += pinctrl-imx7.o
obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
obj-$(CONFIG_PINCTRL_IMX8ULP) += pinctrl-imx8ulp.o
obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o
obj-$(CONFIG_PINCTRL_IMX8) += pinctrl-imx8.o
obj-$(CONFIG_PINCTRL_IMX8M) += pinctrl-imx8m.o

View File

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020 NXP
*
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "pinctrl-imx.h"
static struct imx_pinctrl_soc_info imx8ulp_pinctrl_soc_info0 = {
.flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
};
static struct imx_pinctrl_soc_info imx8ulp_pinctrl_soc_info1 = {
.flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
};
static int imx8ulp_pinctrl_probe(struct udevice *dev)
{
struct imx_pinctrl_soc_info *info =
(struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
return imx_pinctrl_probe(dev, info);
}
static const struct udevice_id imx8ulp_pinctrl_match[] = {
{ .compatible = "fsl,imx8ulp-iomuxc0", .data = (ulong)&imx8ulp_pinctrl_soc_info0 },
{ .compatible = "fsl,imx8ulp-iomuxc1", .data = (ulong)&imx8ulp_pinctrl_soc_info1 },
{ /* sentinel */ }
};
U_BOOT_DRIVER(imx8ulp_pinctrl) = {
.name = "imx8ulp-pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(imx8ulp_pinctrl_match),
.probe = imx8ulp_pinctrl_probe,
.remove = imx_pinctrl_remove,
.priv_auto = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};