Commit 3f2b4d72 authored by Peng Fan's avatar Peng Fan Committed by Stefano Babic
Browse files

arm: imx: add i.MX8ULP EVK support



Add i.MX8ULP EVK basic support, support SD/I2C/ENET/LPUART

Log as below: I would keep some debug info for now, and after we move
to be stable and production launch, we could drop that.

U-Boot SPL 2021.07-rc4-00164-gb800e19a6b (Jun 29 2021 - 10:23:30 +0800)
Normal Boot
upower_init: soc_id=48
upower_init: version:11.11.6
upower_init: start uPower RAM service
user_upwr_rdy_callb: soc=b
user_upwr_rdy_callb: RAM version:12.6
Turn on switches ok
Turn on memories ok
Clear DDR retention ok
Poll for freq_chg_req on SIM register and change to F1 frequency.
Poll for freq_chg_req on SIM register and change to F0 frequency.
Poll for freq_chg_req on SIM register and change to F1 frequency.
Poll for freq_chg_req on SIM register and change to F2 frequency.
Poll for freq_chg_req on SIM register and change to F1 frequency.
Poll for freq_chg_req on SIM register and change to F2 frequency.
complete
De-Skew PLL is locked and ready
WDT:   Not found!
Trying to boot from BOOTROM
image offset 0x8000, pagesize 0x200, ivt offset 0x0
Load image from 0x3a800 by ROM_API
NOTICE:  BL31: v2.4(release):imx_5.10.35_2.0.0_imx8ulp_er-10-gf37e59b94
NOTICE:  BL31: Built : 01:56:58, Jun 29 2021
NOTICE:  upower_init: start uPower RAM service
NOTICE:  user_upwr_rdy_callb: soc=b
NOTICE:  user_upwr_rdy_callb: RAM version:12.6

U-Boot 2021.07-rc4-00164-gb800e19a6b (Jun 29 2021 - 10:23:30 +0800)

CPU:   Freescale i.MX8ULP rev1.0 at 744 MHz
Reset cause: POR
Boot mode: Single boot
Model: FSL i.MX8ULP EVK
DRAM:  2 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 2
Loading Environment from MMC... ***
Warning - bad CRC, using default environment

In:    serial@293a0000
Out:   serial@293a0000
Err:   serial@293a0000
Net:
Warning: ethernet@29950000 (eth0) using random MAC address -
96:35:88:62:e0:44
eth0: ethernet@29950000
Hit any key to stop autoboot:  0
Signed-off-by: Peng Fan's avatarPeng Fan <peng.fan@nxp.com>
parent 6beec0e7
......@@ -862,6 +862,9 @@ dtb-$(CONFIG_ARCH_IMX8) += \
imx8-deneb.dtb \
imx8-giedi.dtb
dtb-$(CONFIG_ARCH_IMX8ULP) += \
imx8ulp-evk.dtb
dtb-$(CONFIG_ARCH_IMX8M) += \
imx8mm-evk.dtb \
imx8mm-icore-mx8mm-ctouch2.dtb \
......
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright 2021 NXP
*/
&{/soc@0} {
u-boot,dm-spl;
};
&per_bridge3 {
u-boot,dm-spl;
};
&per_bridge4 {
u-boot,dm-spl;
};
&iomuxc1 {
u-boot,dm-spl;
};
&pinctrl_lpuart5 {
u-boot,dm-spl;
};
&s400_mu {
u-boot,dm-spl;
};
&lpuart5 {
u-boot,dm-spl;
};
&usdhc0 {
u-boot,dm-spl;
};
&pinctrl_usdhc0 {
u-boot,dm-spl;
};
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright 2021 NXP
*/
/dts-v1/;
#include "imx8ulp.dtsi"
/ {
model = "FSL i.MX8ULP EVK";
compatible = "fsl,imx8ulp-evk", "fsl,imx8ulp";
chosen {
stdout-path = &lpuart5;
bootargs = "console=ttyLP1,115200 earlycon";
};
usdhc2_pwrseq: usdhc2_pwrseq {
compatible = "mmc-pwrseq-simple";
reset-gpios = <&pcal6408 2 GPIO_ACTIVE_LOW>;
};
};
&lpuart5 {
/* console */
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_lpuart5>;
pinctrl-1 = <&pinctrl_lpuart5>;
status = "okay";
};
&iomuxc1 {
pinctrl_lpuart5: lpuart5grp {
fsl,pins = <
MX8ULP_PAD_PTF14__LPUART5_TX 0x03
MX8ULP_PAD_PTF15__LPUART5_RX 0x03
>;
};
pinctrl_lpi2c7: lpi2c7grp {
fsl,pins = <
MX8ULP_PAD_PTE12__LPI2C7_SCL 0x27
MX8ULP_PAD_PTE13__LPI2C7_SDA 0x27
>;
};
pinctrl_usdhc0: usdhc0grp {
fsl,pins = <
MX8ULP_PAD_PTD0__SDHC0_RESET_B 0x43
MX8ULP_PAD_PTD1__SDHC0_CMD 0x43
MX8ULP_PAD_PTD2__SDHC0_CLK 0x10042
MX8ULP_PAD_PTD10__SDHC0_D0 0x43
MX8ULP_PAD_PTD9__SDHC0_D1 0x43
MX8ULP_PAD_PTD8__SDHC0_D2 0x43
MX8ULP_PAD_PTD7__SDHC0_D3 0x43
MX8ULP_PAD_PTD6__SDHC0_D4 0x43
MX8ULP_PAD_PTD5__SDHC0_D5 0x43
MX8ULP_PAD_PTD4__SDHC0_D6 0x43
MX8ULP_PAD_PTD3__SDHC0_D7 0x43
MX8ULP_PAD_PTD11__SDHC0_DQS 0x10042
>;
};
pinctrl_usdhc2_pte: usdhc2ptegrp {
fsl,pins = <
MX8ULP_PAD_PTE1__SDHC2_D0 0x43
MX8ULP_PAD_PTE0__SDHC2_D1 0x43
MX8ULP_PAD_PTE5__SDHC2_D2 0x43
MX8ULP_PAD_PTE4__SDHC2_D3 0x43
MX8ULP_PAD_PTE2__SDHC2_CLK 0x10042
MX8ULP_PAD_PTE3__SDHC2_CMD 0x43
MX8ULP_PAD_PTE7__PTE7 0x10003
>;
};
pinctrl_fec: fecgrp {
fsl,pins = <
MX8ULP_PAD_PTE14__ENET0_MDIO 0x43
MX8ULP_PAD_PTE15__ENET0_MDC 0x43
MX8ULP_PAD_PTE18__ENET0_CRS_DV 0x43
MX8ULP_PAD_PTE17__ENET0_RXER 0x43
MX8ULP_PAD_PTF1__ENET0_RXD0 0x43
MX8ULP_PAD_PTE20__ENET0_RXD1 0x43
MX8ULP_PAD_PTE16__ENET0_TXEN 0x43
MX8ULP_PAD_PTE23__ENET0_TXD0 0x43
MX8ULP_PAD_PTE22__ENET0_TXD1 0x43
MX8ULP_PAD_PTE19__ENET0_REFCLK 0x10043
MX8ULP_PAD_PTF10__ENET0_1588_CLKIN 0x10043
>;
};
pinctrl_usbotg0_id: otg0idgrp {
fsl,pins = <
MX8ULP_PAD_PTF2__USB0_ID 0x10003
>;
};
pinctrl_usbotg1_id: otg1idgrp {
fsl,pins = <
MX8ULP_PAD_PTD23__USB1_ID 0x10003
>;
};
};
&usdhc0 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc0>;
pinctrl-1 = <&pinctrl_usdhc0>;
pinctrl-2 = <&pinctrl_usdhc0>;
bus-width = <8>;
non-removable;
status = "okay";
};
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
pinctrl-0 = <&pinctrl_usdhc2_pte>;
pinctrl-1 = <&pinctrl_usdhc2_pte>;
pinctrl-2 = <&pinctrl_usdhc2_pte>;
pinctrl-3 = <&pinctrl_usdhc2_pte>;
mmc-pwrseq = <&usdhc2_pwrseq>;
max-frequency = <100000000>;
bus-width = <4>;
keep-power-in-suspend;
non-removable;
wakeup-source;
status = "okay";
wifi_wake_host {
compatible = "nxp,wifi-wake-host";
interrupt-parent = <&gpioe>;
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
interrupt-names = "host-wake";
};
};
&lpi2c7 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpi2c7>;
status = "okay";
pcal6408: gpio@21 {
compatible = "ti,tca6408";
reg = <0x21>;
gpio-controller;
#gpio-cells = <2>;
};
};
&flexspi0 {
status = "okay";
flash0: atxp032@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
compatible = "jedec,spi-nor";
spi-max-frequency = <66000000>;
};
};
&flexspi2 {
status = "okay";
flash1: mt35xu512aba@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
compatible = "jedec,spi-nor";
spi-max-frequency = <29000000>;
spi-nor,ddr-quad-read-dummy = <8>;
};
};
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fec>;
phy-mode = "rmii";
phy-handle = <&ethphy>;
status = "okay";
phy-reset-gpios = <&pcal6408 4 GPIO_ACTIVE_LOW>;
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy: ethernet-phy@1 {
reg = <1>;
micrel,led-mode = <1>;
};
};
};
&usbotg0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usbotg0_id>;
srp-disable;
hnp-disable;
adp-disable;
status = "okay";
};
&usbphy0 {
fsl,tx-d-cal = <88>;
};
&usbotg1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usbotg1_id>;
srp-disable;
hnp-disable;
adp-disable;
status = "okay";
};
&usbphy1 {
fsl,tx-d-cal = <88>;
};
......@@ -11,6 +11,13 @@ choice
prompt "i.MX8ULP board select"
optional
config TARGET_IMX8ULP_EVK
bool "imx8ulp_evk"
select IMX8ULP
select SUPPORT_SPL
endchoice
source "board/freescale/imx8ulp_evk/Kconfig"
endif
if TARGET_IMX8ULP_EVK
config SYS_BOARD
default "imx8ulp_evk"
config SYS_VENDOR
default "freescale"
config SYS_CONFIG_NAME
default "imx8ulp_evk"
source "board/freescale/common/Kconfig"
endif
i.MX8ULP EVK BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/imx8ulp_evk/
F: include/configs/imx8ulp_evk.h
F: configs/imx8ulp_evk_defconfig
# SPDX-License-Identifier: GPL-2.0+
obj-y += imx8ulp_evk.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o ddr_init.o lpddr4_timing.o
endif
// 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)
#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)
#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)
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;
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;
}
debug("%s\n", __func__);
/* 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) {
printf("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) {
printf("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) {
printf("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) {
printf("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) {
printf("De-Skew PLL failed to lock\n");
printf("lock_0=0x%x, lock_1=0x%x, lock_2=0x%x\n", lock_0, lock_1, lock_2);
return -1;
}
printf("De-Skew PLL is locked and ready\n");
return 0;
}
int ddr_init(struct dram_timing_info2 *dram_timing)
{
int i;
debug("%s\n", __func__);
set_ddr_clk(dram_timing->fsp_table[0] >> 1); /* Set to boot freq */
/* 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);
}
void enable_bypass_mode(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);
}
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020 NXP
*/
#include <common.h>
#include <miiphy.h>
#include <netdev.h>
#include <asm/arch/imx8ulp-pins.h>
#include <asm/arch/clock.h>
#include <asm/arch/pcc.h>
#include <asm/arch/sys_proto.h>
#include <miiphy.h>
#include <netdev.h>
DECLARE_GLOBAL_DATA_PTR;
#if IS_ENABLED(CONFIG_FEC_MXC)
#define ENET_CLK_PAD_CTRL (PAD_CTL_PUS_UP | PAD_CTL_DSE | PAD_CTL_IBE_ENABLE)
static iomux_cfg_t const enet_clk_pads[] = {
IMX8ULP_PAD_PTE19__ENET0_REFCLK | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
IMX8ULP_PAD_PTF10__ENET0_1588_CLKIN | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
};
static int setup_fec(void)
{
/*
* Since ref clock and timestamp clock are from external,
* set the iomux prior the clock enablement
*/
imx8ulp_iomux_setup_multiple_pads(enet_clk_pads, ARRAY_SIZE(enet_clk_pads));
/* Select enet time stamp clock: 001 - External Timestamp Clock */
cgc1_enet_stamp_sel(1);
/* enable FEC PCC */
pcc_clock_enable(4, ENET_PCC4_SLOT, true);
pcc_reset_peripheral(4, ENET_PCC4_SLOT, false);
return 0;
}
int board_phy_config(struct phy_device *phydev)
{
if (phydev->drv->config)
phydev->drv->config(phydev);
return 0;
}
#endif
int board_init(void)
{
if (IS_ENABLED(CONFIG_FEC_MXC))
setup_fec();
return 0;
}
int board_early_init_f(void)
{
return 0;
}
int board_late_init(void)
{
return 0;
}
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2021 NXP
*/
#include <common.h>
#include <init.h>
#include <spl.h>
#include <asm/io.h>
#include <errno.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx8ulp-pins.h>
#include <dm/uclass.h>
#include <dm/device.h>
#include <dm/uclass-internal.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <asm/arch/ddr.h>
#include <asm/arch/rdc.h>
#include <asm/arch/upower.h>