807 lines
19 KiB
C
807 lines
19 KiB
C
/*
|
|
* Copyright 2017-2018 NXP
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
#include <common.h>
|
|
#include <malloc.h>
|
|
#include <errno.h>
|
|
#include <netdev.h>
|
|
#include <fsl_ifc.h>
|
|
#include <fdt_support.h>
|
|
#include <linux/libfdt.h>
|
|
#include <environment.h>
|
|
#include <fsl_esdhc.h>
|
|
#include <i2c.h>
|
|
#include "pca953x.h"
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/gpio.h>
|
|
#include <asm/arch/clock.h>
|
|
#include <asm/mach-imx/sci/sci.h>
|
|
#include <asm/arch/imx8-pins.h>
|
|
#include <dm.h>
|
|
#include <imx8_hsio.h>
|
|
#include <usb.h>
|
|
#include <asm/arch/iomux.h>
|
|
#include <asm/arch/sys_proto.h>
|
|
#include <asm/mach-imx/video.h>
|
|
#include <asm/arch/video_common.h>
|
|
#include <power-domain.h>
|
|
#include "../../freescale/common/tcpc.h"
|
|
#include <cdns3-uboot.h>
|
|
#include <asm/arch/lpcg.h>
|
|
#include "../nm-common/board_descriptor.h"
|
|
#include "../nm-common/da9063.h"
|
|
#include "../nm-common/reset_reason.h"
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
#define BD_EEPROM_ADDR (0x50)
|
|
#define BD_ADDRESS (0x0000)
|
|
#define PD_ADDRESS (0x0200)
|
|
|
|
#define RESET_REASON_SHM_LOCATION 0x95000000
|
|
|
|
static uint32_t sys_start_event = 0x0;
|
|
static BD_Context bdctx[3];
|
|
|
|
#define ESDHC_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
#define ESDHC_CLK_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
|
|
#define ENET_INPUT_PAD_CTRL ((SC_PAD_CONFIG_OD_IN << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_18V_10MA << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
#define ENET_NORMAL_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_18V_10MA << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
#define FSPI_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
#define GPIO_PAD_CTRL ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
#define I2C_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_DV_LOW << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
#define UART_PAD_CTRL ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) \
|
|
| (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
|
|
|
|
static iomux_cfg_t uart0_pads[] = {
|
|
SC_P_UART0_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
|
|
SC_P_UART0_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
|
|
};
|
|
|
|
static void setup_iomux_uart(void)
|
|
{
|
|
imx8_iomux_setup_multiple_pads(uart0_pads, ARRAY_SIZE(uart0_pads));
|
|
}
|
|
|
|
int board_early_init_f(void)
|
|
{
|
|
sc_ipc_t ipcHndl = 0;
|
|
sc_err_t sciErr = 0;
|
|
|
|
ipcHndl = gd->arch.ipc_channel_handle;
|
|
|
|
/* Power up UART0 */
|
|
sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_UART_0, SC_PM_PW_MODE_ON);
|
|
if (sciErr != SC_ERR_NONE)
|
|
return 0;
|
|
|
|
/* Set UART0 clock root to 80 MHz */
|
|
sc_pm_clock_rate_t rate = 80000000;
|
|
sciErr = sc_pm_set_clock_rate(ipcHndl, SC_R_UART_0, 2, &rate);
|
|
if (sciErr != SC_ERR_NONE)
|
|
return 0;
|
|
|
|
/* Enable UART0 clock root */
|
|
sciErr = sc_pm_clock_enable(ipcHndl, SC_R_UART_0, 2, true, false);
|
|
if (sciErr != SC_ERR_NONE)
|
|
return 0;
|
|
|
|
LPCG_AllClockOn(LPUART_0_LPCG);
|
|
|
|
setup_iomux_uart();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_FSL_ESDHC
|
|
#ifndef CONFIG_SPL_BUILD
|
|
|
|
static struct fsl_esdhc_cfg usdhc_cfg = { USDHC1_BASE_ADDR, 0, 8 };
|
|
|
|
static iomux_cfg_t emmc0[] = {
|
|
SC_P_EMMC0_CLK | MUX_PAD_CTRL(ESDHC_CLK_PAD_CTRL),
|
|
SC_P_EMMC0_CMD | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA0 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA1 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA2 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA3 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA4 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA5 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA6 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_DATA7 | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
SC_P_EMMC0_STROBE | MUX_PAD_CTRL(ESDHC_PAD_CTRL),
|
|
};
|
|
|
|
int board_mmc_init(bd_t *bis)
|
|
{
|
|
int ret;
|
|
struct power_domain pd;
|
|
|
|
if (!power_domain_lookup_name("conn_sdhc0", &pd))
|
|
{
|
|
power_domain_on(&pd);
|
|
}
|
|
imx8_iomux_setup_multiple_pads(emmc0, ARRAY_SIZE(emmc0));
|
|
init_clk_usdhc(0);
|
|
usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
|
|
|
|
ret = fsl_esdhc_initialize(bis, &usdhc_cfg);
|
|
if (ret)
|
|
{
|
|
printf("Warning: failed to initialize mmc\n");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int board_mmc_getcd(struct mmc *mmc)
|
|
{
|
|
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
|
|
int ret = 0;
|
|
|
|
/* eMMC */
|
|
if (cfg->esdhc_base == USDHC1_BASE_ADDR)
|
|
{
|
|
ret = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* CONFIG_SPL_BUILD */
|
|
#endif /* CONFIG_FSL_ESDHC */
|
|
|
|
#ifdef CONFIG_BOOTP_VENDOREX
|
|
u8 *dhcp_vendorex_prep(u8 *e)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
u8 *dhcp_vendorex_proc(u8 *e)
|
|
{
|
|
/* Suppress NETBIOS related unhandled option warnings */
|
|
if (*e == 46)
|
|
{
|
|
return e;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_FEC_MXC
|
|
#include <miiphy.h>
|
|
int board_phy_config(struct phy_device *phydev)
|
|
{
|
|
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
|
|
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8);
|
|
|
|
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x00);
|
|
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x82ee);
|
|
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
|
|
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
|
|
|
|
if (phydev->drv->config)
|
|
phydev->drv->config(phydev);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static void set_mac_address(int index, uchar mac[6])
|
|
{
|
|
/* Then take mac from bd */
|
|
if (is_valid_ethaddr(mac)) {
|
|
eth_env_set_enetaddr_by_index("eth", index, mac);
|
|
}
|
|
else {
|
|
printf("Trying to set invalid MAC address");
|
|
}
|
|
}
|
|
|
|
int board_eth_init(bd_t *bis)
|
|
{
|
|
uint8_t mac_addr0[6] = {02,00,00,00,00,01};
|
|
|
|
bd_get_mac(0, mac_addr0, sizeof(mac_addr0));
|
|
set_mac_address(0, mac_addr0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int checkboard(void)
|
|
{
|
|
puts("Board: iMX8QXP MEK\n");
|
|
|
|
print_bootinfo();
|
|
|
|
/* Note: After reloc, ipcHndl will no longer be valid. If handle
|
|
* returned by sc_ipc_open matches SC_IPC_CH, use this
|
|
* macro (valid after reloc) for subsequent SCI calls.
|
|
*/
|
|
if (gd->arch.ipc_channel_handle != SC_IPC_CH)
|
|
printf("\nSCI error! Invalid handle\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_FSL_HSIO
|
|
|
|
#define PCIE_PAD_CTRL ((SC_PAD_CONFIG_OD_IN << PADRING_CONFIG_SHIFT))
|
|
static iomux_cfg_t board_pcie_pins[] = {
|
|
SC_P_PCIE_CTRL0_CLKREQ_B | MUX_MODE_ALT(0) | MUX_PAD_CTRL(PCIE_PAD_CTRL),
|
|
SC_P_PCIE_CTRL0_WAKE_B | MUX_MODE_ALT(0) | MUX_PAD_CTRL(PCIE_PAD_CTRL),
|
|
SC_P_PCIE_CTRL0_PERST_B | MUX_MODE_ALT(0) | MUX_PAD_CTRL(PCIE_PAD_CTRL),
|
|
};
|
|
|
|
static void imx8qxp_hsio_initialize(void)
|
|
{
|
|
struct power_domain pd;
|
|
int ret;
|
|
|
|
if (!power_domain_lookup_name("hsio_pcie1", &pd)) {
|
|
ret = power_domain_on(&pd);
|
|
if (ret)
|
|
printf("hsio_pcie1 Power up failed! (error = %d)\n", ret);
|
|
}
|
|
|
|
if (!power_domain_lookup_name("hsio_gpio", &pd)) {
|
|
ret = power_domain_on(&pd);
|
|
if (ret)
|
|
printf("hsio_gpio Power up failed! (error = %d)\n", ret);
|
|
}
|
|
|
|
LPCG_AllClockOn(HSIO_PCIE_X1_LPCG);
|
|
LPCG_AllClockOn(HSIO_PHY_X1_LPCG);
|
|
LPCG_AllClockOn(HSIO_PHY_X1_CRR1_LPCG);
|
|
LPCG_AllClockOn(HSIO_PCIE_X1_CRR3_LPCG);
|
|
LPCG_AllClockOn(HSIO_MISC_LPCG);
|
|
LPCG_AllClockOn(HSIO_GPIO_LPCG);
|
|
|
|
imx8_iomux_setup_multiple_pads(board_pcie_pins, ARRAY_SIZE(board_pcie_pins));
|
|
}
|
|
|
|
void pci_init_board(void)
|
|
{
|
|
imx8qxp_hsio_initialize();
|
|
|
|
/* test the 1 lane mode of the PCIe A controller */
|
|
mx8qxp_pcie_init();
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_USB
|
|
|
|
#ifdef CONFIG_USB_TCPC
|
|
#define USB_TYPEC_SEL IMX_GPIO_NR(5, 9)
|
|
static iomux_cfg_t ss_mux_gpio[] = {
|
|
SC_P_ENET0_REFCLK_125M_25M | MUX_MODE_ALT(4) | MUX_PAD_CTRL(GPIO_PAD_CTRL),
|
|
};
|
|
|
|
struct tcpc_port port;
|
|
struct tcpc_port_config port_config = {
|
|
.i2c_bus = 1,
|
|
.addr = 0x50,
|
|
.port_type = TYPEC_PORT_DFP,
|
|
};
|
|
|
|
void ss_mux_select(enum typec_cc_polarity pol)
|
|
{
|
|
if (pol == TYPEC_POLARITY_CC1)
|
|
gpio_direction_output(USB_TYPEC_SEL, 0);
|
|
else
|
|
gpio_direction_output(USB_TYPEC_SEL, 1);
|
|
}
|
|
|
|
static void setup_typec(void)
|
|
{
|
|
int ret;
|
|
struct gpio_desc typec_en_desc;
|
|
|
|
imx8_iomux_setup_multiple_pads(ss_mux_gpio, ARRAY_SIZE(ss_mux_gpio));
|
|
gpio_request(USB_TYPEC_SEL, "typec_sel");
|
|
|
|
ret = dm_gpio_lookup_name("gpio@1a_7", &typec_en_desc);
|
|
if (ret) {
|
|
printf("%s lookup gpio@1a_7 failed ret = %d\n", __func__, ret);
|
|
return;
|
|
}
|
|
|
|
ret = dm_gpio_request(&typec_en_desc, "typec_en");
|
|
if (ret) {
|
|
printf("%s request typec_en failed ret = %d\n", __func__, ret);
|
|
return;
|
|
}
|
|
|
|
/* Enable SS MUX */
|
|
dm_gpio_set_dir_flags(&typec_en_desc, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
|
|
|
tcpc_init(&port, port_config, &ss_mux_select);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_USB_CDNS3_GADGET
|
|
static struct cdns3_device cdns3_device_data = {
|
|
.none_core_base = 0x5B110000,
|
|
.xhci_base = 0x5B130000,
|
|
.dev_base = 0x5B140000,
|
|
.phy_base = 0x5B160000,
|
|
.otg_base = 0x5B120000,
|
|
.dr_mode = USB_DR_MODE_PERIPHERAL,
|
|
.index = 1,
|
|
};
|
|
|
|
int usb_gadget_handle_interrupts(int index)
|
|
{
|
|
cdns3_uboot_handle_interrupt(index);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int board_usb_init(int index, enum usb_init_type init)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (index == 1) {
|
|
if (init == USB_INIT_HOST) {
|
|
#ifdef CONFIG_USB_TCPC
|
|
ret = tcpc_setup_dfp_mode(&port);
|
|
#endif
|
|
#ifdef CONFIG_USB_CDNS3_GADGET
|
|
} else {
|
|
#ifdef CONFIG_SPL_BUILD
|
|
sc_ipc_t ipcHndl = 0;
|
|
|
|
ipcHndl = gd->arch.ipc_channel_handle;
|
|
|
|
ret = sc_pm_set_resource_power_mode(ipcHndl, SC_R_USB_2, SC_PM_PW_MODE_ON);
|
|
if (ret != SC_ERR_NONE)
|
|
printf("conn_usb2 Power up failed! (error = %d)\n", ret);
|
|
|
|
ret = sc_pm_set_resource_power_mode(ipcHndl, SC_R_USB_2_PHY, SC_PM_PW_MODE_ON);
|
|
if (ret != SC_ERR_NONE)
|
|
printf("conn_usb2_phy Power up failed! (error = %d)\n", ret);
|
|
#else
|
|
struct power_domain pd;
|
|
int ret;
|
|
|
|
/* Power on usb */
|
|
if (!power_domain_lookup_name("conn_usb2", &pd)) {
|
|
ret = power_domain_on(&pd);
|
|
if (ret)
|
|
printf("conn_usb2 Power up failed! (error = %d)\n", ret);
|
|
}
|
|
|
|
if (!power_domain_lookup_name("conn_usb2_phy", &pd)) {
|
|
ret = power_domain_on(&pd);
|
|
if (ret)
|
|
printf("conn_usb2_phy Power up failed! (error = %d)\n", ret);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_USB_TCPC
|
|
ret = tcpc_setup_ufp_mode(&port);
|
|
printf("%d setufp mode %d\n", index, ret);
|
|
#endif
|
|
|
|
ret = cdns3_uboot_init(&cdns3_device_data);
|
|
printf("%d cdns3_uboot_initmode %d\n", index, ret);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int board_usb_cleanup(int index, enum usb_init_type init)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (index == 1) {
|
|
if (init == USB_INIT_HOST) {
|
|
#ifdef CONFIG_USB_TCPC
|
|
ret = tcpc_disable_src_vbus(&port);
|
|
#endif
|
|
#ifdef CONFIG_USB_CDNS3_GADGET
|
|
} else {
|
|
cdns3_uboot_exit(1);
|
|
|
|
#ifdef CONFIG_SPL_BUILD
|
|
sc_ipc_t ipcHndl = 0;
|
|
|
|
ipcHndl = gd->arch.ipc_channel_handle;
|
|
|
|
ret = sc_pm_set_resource_power_mode(ipcHndl, SC_R_USB_2, SC_PM_PW_MODE_OFF);
|
|
if (ret != SC_ERR_NONE)
|
|
printf("conn_usb2 Power down failed! (error = %d)\n", ret);
|
|
|
|
ret = sc_pm_set_resource_power_mode(ipcHndl, SC_R_USB_2_PHY, SC_PM_PW_MODE_OFF);
|
|
if (ret != SC_ERR_NONE)
|
|
printf("conn_usb2_phy Power down failed! (error = %d)\n", ret);
|
|
#else
|
|
struct power_domain pd;
|
|
int ret;
|
|
|
|
/* Power off usb */
|
|
if (!power_domain_lookup_name("conn_usb2", &pd)) {
|
|
ret = power_domain_off(&pd);
|
|
if (ret)
|
|
printf("conn_usb2 Power down failed! (error = %d)\n", ret);
|
|
}
|
|
|
|
if (!power_domain_lookup_name("conn_usb2_phy", &pd)) {
|
|
ret = power_domain_off(&pd);
|
|
if (ret)
|
|
printf("conn_usb2_phy Power down failed! (error = %d)\n", ret);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
int board_init(void)
|
|
{
|
|
struct udevice *sja1105;
|
|
int ret;
|
|
|
|
ret = uclass_get_device_by_name(UCLASS_MISC, "sja1105", &sja1105);
|
|
if (ret)
|
|
{
|
|
printf("Net: No switch found.\n");
|
|
}
|
|
else
|
|
{
|
|
printf("Net: SJA1105 switch found.\n");
|
|
}
|
|
|
|
#if defined(CONFIG_USB) && defined(CONFIG_USB_TCPC)
|
|
setup_typec();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
void board_quiesce_devices()
|
|
{
|
|
const char *power_on_devices[] = {
|
|
"dma_lpuart0",
|
|
|
|
/* HIFI DSP boot */
|
|
"audio_sai0",
|
|
"audio_ocram",
|
|
};
|
|
|
|
power_off_pd_devices(power_on_devices, ARRAY_SIZE(power_on_devices));
|
|
}
|
|
|
|
void detail_board_ddr_info(void)
|
|
{
|
|
puts("\nDDR ");
|
|
}
|
|
|
|
/*
|
|
* Board specific reset that is system reset.
|
|
*/
|
|
void reset_cpu(ulong addr)
|
|
{
|
|
puts("SCI reboot request");
|
|
sc_pm_reboot(SC_IPC_CH, SC_PM_RESET_TYPE_COLD);
|
|
while (1)
|
|
putc('.');
|
|
}
|
|
|
|
static void ft_start_event(void *blob, uint64_t reset_reason_shm_location)
|
|
{
|
|
volatile struct reset_registers* reset_regs = (struct reset_registers*)reset_reason_shm_location;
|
|
if (rr_is_start_reason_valid(reset_regs)) {
|
|
int node_offset;
|
|
|
|
node_offset = fdt_path_offset(blob, "/sysstate-start/");
|
|
if (node_offset != -1) {
|
|
|
|
fdt_setprop_u32(blob, node_offset, "start-reason", reset_regs->sr_events);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_OF_BOARD_SETUP
|
|
int ft_board_setup(void *blob, bd_t *bd)
|
|
{
|
|
ft_start_event(blob, RESET_REASON_SHM_LOCATION);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static void get_variant_name(void)
|
|
{
|
|
char hw_variant_name[64];
|
|
bd_get_variantname(hw_variant_name, sizeof(hw_variant_name));
|
|
printf("SYS: %s\n", hw_variant_name);
|
|
}
|
|
|
|
static void get_hw_version(void)
|
|
{
|
|
int hw_ver = -1;
|
|
int hw_rev = -1;
|
|
|
|
bd_get_hw_version(&hw_ver, &hw_rev);
|
|
|
|
printf("MB: V%d.%d\n", hw_ver, hw_rev);
|
|
}
|
|
int board_mmc_get_env_dev(int devno)
|
|
{
|
|
return devno;
|
|
}
|
|
|
|
static void powerdown(void)
|
|
{
|
|
/* Final call, will not return */
|
|
(void)da9063_set_reg(PMIC_REG_CONTROL_A, 0x00);
|
|
|
|
puts("ERROR: PMIC power down failed\n");
|
|
for (;;) {}
|
|
}
|
|
|
|
static void stop_if_ignition_is_off(void)
|
|
{
|
|
uint8_t state = 0x00;
|
|
int ret;
|
|
|
|
ret = da9063_get_reg(PMIC_REG_STATUS_A, &state);
|
|
if (ret == 0) {
|
|
if ((state & PMIC_REG_STATUS_A_COMP1V2_MASK) == PMIC_REG_STATUS_A_COMP1V2_MASK) {
|
|
puts("Ignition : On\n");
|
|
}
|
|
else {
|
|
puts("Ignition : Off\n");
|
|
/*
|
|
* Ignition is off, if this is a power-on start, power down
|
|
* as this is considered an unwanted system start.
|
|
*/
|
|
|
|
/*
|
|
* There is a chance for a race condition, when ignition is enabled
|
|
* between the check above and here. In this case we should just reset
|
|
* not power down.
|
|
* Although the risk is minimal here due to the very short time interval
|
|
* we do the check. The same logic will have to be added in other
|
|
* components.
|
|
*/
|
|
ret = da9063_get_reg(PMIC_REG_EVENT_B, &state);
|
|
if ((ret == 0) && ((state & PMIC_REG_EVENT_COMP1V2_MASK) == 0)) {
|
|
powerdown();
|
|
}
|
|
else {
|
|
reset_cpu(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void check_reset_reason(uint64_t reset_reason_shm_location)
|
|
{
|
|
volatile struct reset_registers* reset_regs = (struct reset_registers*)reset_reason_shm_location;
|
|
uint32_t start_reason = 0;
|
|
uint32_t reset_reason = 0;
|
|
uint8_t state = 0x00;
|
|
uint8_t gpId1 = 0x00;
|
|
uint8_t eventA = 0x00;
|
|
int ret;
|
|
char strbuf[256];
|
|
|
|
uint32_t scu_init_cnt = da9063_get_init_count();
|
|
printf("SCU init count = 0x%X\n", scu_init_cnt);
|
|
|
|
/*
|
|
* Check/write boot marker to PMIC register GP_ID_1
|
|
* If this marker is not present, we have a power on reset
|
|
*/
|
|
ret = da9063_get_reg(PMIC_GP_ID_1, &gpId1);
|
|
if ((ret == 0) && (gpId1 != 0xC5)) {
|
|
(void)da9063_set_reg(PMIC_GP_ID_1, 0xC5);
|
|
start_reason |= SR_POR;
|
|
}
|
|
printf("PMIC_GP_ID_1 = 0x%X (return code = %d)\n", gpId1, ret);
|
|
|
|
/*
|
|
* Check Fault Log register for
|
|
* - Power On Reset: No Power, RTC Delivery -> requires removal of RTC battery
|
|
* - Watchdog
|
|
*/
|
|
ret = da9063_get_reg(PMIC_REG_FAULT_LOG, &state);
|
|
printf("PMIC_REG_FAULT_LOG = 0x%X (return code = %d)\n", state, ret);
|
|
if ((ret == 0) && (state != 0)) {
|
|
/* clear pmic fault log by writing back all bits currently set */
|
|
(void)da9063_set_reg(PMIC_REG_FAULT_LOG, state);
|
|
|
|
/* PMIC Power On Reset (only when RTC battery is removed) */
|
|
if (state & PMIC_FAULT_POR_MASK) {
|
|
start_reason |= SR_POR;
|
|
}
|
|
|
|
/* PMIC Watchdog */
|
|
if (state & PMIC_FAULT_TWD_ERROR_MASK) {
|
|
start_reason |= SR_WATCHDOG;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check Wakeup Events
|
|
* Event Register A holds:
|
|
* - Event B, C Activity
|
|
* - nONKEY: Button
|
|
* - RTC Alarm
|
|
* - RTC Tick
|
|
* Event Register B
|
|
* - COMP 1V2: Ignition
|
|
*/
|
|
ret = da9063_get_reg(PMIC_REG_EVENT_A, &eventA);
|
|
printf("EVENT_A = 0x%X (return code = %d)\n", eventA, ret);
|
|
if ((ret == 0) && (eventA != 0)) {
|
|
(void)da9063_set_reg(PMIC_REG_EVENT_A, eventA);
|
|
|
|
if (eventA & PMIC_REG_EVENT_ONKEY_MASK) {
|
|
start_reason |= (SR_WAKEUP | SR_EVT_BUTTON);
|
|
}
|
|
|
|
if (eventA & PMIC_REG_EVENT_RTC_ALARM_MASK) {
|
|
start_reason |= (SR_WAKEUP | SR_EVT_RTC_ALARM);
|
|
}
|
|
|
|
if (eventA & PMIC_REG_EVENT_RTC_TICK_MASK) {
|
|
start_reason |= (SR_WAKEUP | SR_EVT_RTC_TICK);
|
|
}
|
|
|
|
if (eventA & PMIC_REG_EVENT_EVENTS_B_MASK) {
|
|
uint8_t state_b;
|
|
|
|
ret = da9063_get_reg(PMIC_REG_EVENT_B, &state_b);
|
|
if ((ret == 0) && (state_b != 0)) {
|
|
(void)da9063_set_reg(PMIC_REG_EVENT_B, state_b);
|
|
|
|
if (state_b & PMIC_REG_EVENT_COMP1V2_MASK) {
|
|
start_reason |= (SR_WAKEUP | SR_EVT_IGNITION);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for software reboot indicated by OS via shared memory
|
|
* - checksum valid?
|
|
* - Reason == 'REBO' or 'OOPS'
|
|
*/
|
|
if (rr_is_reset_reason_valid(reset_regs))
|
|
{
|
|
if (reset_regs->rr_value == RR_REBOOT_PATTERN) {
|
|
start_reason |= SR_REBOOT;
|
|
}
|
|
else if (reset_regs->rr_value == RR_OOPS_PATTERN) {
|
|
/* Treat kernel oops as reboot */
|
|
start_reason |= SR_REBOOT;
|
|
}
|
|
else if (reset_regs->rr_value == RR_WAKE_PATTERN) {
|
|
start_reason |= SR_WAKEUP;
|
|
}
|
|
else {
|
|
/* Unknown reset reason */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Priority decoder for start and reset reason
|
|
*/
|
|
if (start_reason & SR_WATCHDOG) {
|
|
/* Watchdog has highest priority as it also sets POR and other events */
|
|
start_reason = SR_WATCHDOG;
|
|
reset_reason = RR_EXTERNAL_WATCHDOG_PATTERN;
|
|
}
|
|
else if (start_reason & SR_POR) {
|
|
start_reason = SR_POR;
|
|
reset_reason = RR_POWEROFF_PATTERN;
|
|
}
|
|
else if (start_reason & SR_WAKEUP) {
|
|
/* Include start events when wakeup is detected */
|
|
start_reason = SR_WAKEUP | (start_reason & SR_EVT_WAKE_MASK);
|
|
reset_reason = RR_WAKE_PATTERN;
|
|
}
|
|
else if (start_reason & SR_REBOOT) {
|
|
start_reason = SR_REBOOT;
|
|
reset_reason = reset_regs->rr_value;
|
|
}
|
|
else {
|
|
/* Unknown start reason, assume reboot */
|
|
start_reason = SR_REBOOT;
|
|
reset_reason = reset_regs->rr_value;
|
|
}
|
|
|
|
sys_start_event = start_reason;
|
|
|
|
rr_set_reset_reason(reset_regs, reset_reason);
|
|
rr_set_start_reason(reset_regs, start_reason);
|
|
|
|
rr_start_reason_to_str(reset_regs->sr_events, strbuf, sizeof(strbuf));
|
|
printf("\nStart Events: %s\n", strbuf);
|
|
|
|
if (sys_start_event & SR_POR) {
|
|
stop_if_ignition_is_off();
|
|
}
|
|
}
|
|
|
|
static int _bd_init(void)
|
|
{
|
|
if (bd_get_context(&bdctx[0], BD_EEPROM_ADDR, BD_ADDRESS) != 0) {
|
|
printf("%s() no valid bd found\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
if (bd_get_context(&bdctx[1], BD_EEPROM_ADDR, PD_ADDRESS) != 0) {
|
|
printf("%s() no valid pd found\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
bd_register_context_list(bdctx, ARRAY_SIZE(bdctx));
|
|
return 0;
|
|
}
|
|
|
|
static inline int read_eeprom(void)
|
|
{
|
|
return _bd_init();
|
|
}
|
|
|
|
int board_late_init(void)
|
|
{
|
|
#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
|
|
env_set("board_name", "NMHW23");
|
|
env_set("board_rev", "iMX8DX");
|
|
#endif
|
|
|
|
env_set("sec_boot", "no");
|
|
#ifdef CONFIG_AHAB_BOOT
|
|
env_set("sec_boot", "yes");
|
|
#endif
|
|
|
|
#ifdef CONFIG_ENV_IS_IN_MMC
|
|
board_late_mmc_env_init();
|
|
#endif
|
|
|
|
if (read_eeprom() < 0) {
|
|
puts("Could no get board ID.\n");
|
|
}
|
|
|
|
get_variant_name();
|
|
get_hw_version();
|
|
|
|
board_eth_init(NULL);
|
|
da9063_init();
|
|
check_reset_reason(RESET_REASON_SHM_LOCATION);
|
|
|
|
return 0;
|
|
}
|