Merge tag 'u-boot-imx-20210809' of https://source.denx.de/u-boot/custodians/u-boot-imx
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:
@@ -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/
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
source "drivers/ddr/imx/imx8m/Kconfig"
|
||||
source "drivers/ddr/imx/imx8ulp/Kconfig"
|
||||
|
||||
11
drivers/ddr/imx/imx8ulp/Kconfig
Normal file
11
drivers/ddr/imx/imx8ulp/Kconfig
Normal 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
|
||||
9
drivers/ddr/imx/imx8ulp/Makefile
Normal file
9
drivers/ddr/imx/imx8ulp/Makefile
Normal 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
|
||||
217
drivers/ddr/imx/imx8ulp/ddr_init.c
Normal file
217
drivers/ddr/imx/imx8ulp/ddr_init.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
4
drivers/misc/imx8ulp/Makefile
Normal file
4
drivers/misc/imx8ulp/Makefile
Normal 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
198
drivers/misc/imx8ulp/fuse.c
Normal 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;
|
||||
}
|
||||
234
drivers/misc/imx8ulp/imx8ulp_mu.c
Normal file
234
drivers/misc/imx8ulp/imx8ulp_mu.c
Normal 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),
|
||||
};
|
||||
244
drivers/misc/imx8ulp/s400_api.c
Normal file
244
drivers/misc/imx8ulp/s400_api.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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(®s->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(®s->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));
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
44
drivers/pinctrl/nxp/pinctrl-imx8ulp.c
Normal file
44
drivers/pinctrl/nxp/pinctrl-imx8ulp.c
Normal 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,
|
||||
};
|
||||
Reference in New Issue
Block a user