u-boot/board/siemens/capricorn/board.c
Peng Fan 99ac6c769f imx: move imx8 sci header file to include/firmware/imx
Move imx8 sci header file to include/firmware/imx, then we could
use build macro to reuse some i.MX8 drivers for i.MX9, such as
drivers/cpu/imx8_cpu.c.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Stefano Babic <sbabic@denx.de>
2023-05-21 16:54:32 +02:00

449 lines
9.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2017-2019 NXP
*
* Copyright 2019 Siemens AG
*
*/
#include <common.h>
#include <command.h>
#include <dm.h>
#include <env.h>
#include <errno.h>
#include <init.h>
#include <log.h>
#include <netdev.h>
#include <env_internal.h>
#include <fsl_esdhc_imx.h>
#include <i2c.h>
#include <led.h>
#include <pca953x.h>
#include <power-domain.h>
#include <asm/gpio.h>
#include <asm/arch/imx8-pins.h>
#include <asm/arch/iomux.h>
#include <firmware/imx/sci/sci.h>
#include <asm/arch/sys_proto.h>
#ifndef CONFIG_SPL
#include <asm/arch-imx8/clock.h>
#endif
#include <linux/delay.h>
#include "../common/factoryset.h"
#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 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 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 uart2_pads[] = {
SC_P_UART2_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
SC_P_UART2_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
};
static void setup_iomux_uart(void)
{
imx8_iomux_setup_multiple_pads(uart2_pads, ARRAY_SIZE(uart2_pads));
}
int board_early_init_f(void)
{
/* Set UART clock root to 80 MHz */
sc_pm_clock_rate_t rate = SC_80MHZ;
int ret;
ret = sc_pm_setup_uart(SC_R_UART_0, rate);
ret |= sc_pm_setup_uart(SC_R_UART_2, rate);
if (ret)
return ret;
setup_iomux_uart();
return 0;
}
#define ENET_PHY_RESET IMX_GPIO_NR(0, 3)
#define ENET_TEST_1 IMX_GPIO_NR(0, 8)
#define ENET_TEST_2 IMX_GPIO_NR(0, 9)
/*#define ETH_IO_TEST*/
static iomux_cfg_t enet_reset[] = {
SC_P_ESAI0_SCKT | MUX_MODE_ALT(4) | MUX_PAD_CTRL(GPIO_PAD_CTRL),
#ifdef ETH_IO_TEST
/* GPIO0.IO08 MODE3: TXD0 */
SC_P_ESAI0_TX4_RX1 | MUX_MODE_ALT(4) |
MUX_PAD_CTRL(ENET_NORMAL_PAD_CTRL),
/* GPIO0.IO09 MODE3: TXD1 */
SC_P_ESAI0_TX5_RX0 | MUX_MODE_ALT(4) |
MUX_PAD_CTRL(ENET_NORMAL_PAD_CTRL),
#endif
};
static void enet_device_phy_reset(void)
{
int ret = 0;
imx8_iomux_setup_multiple_pads(enet_reset, ARRAY_SIZE(enet_reset));
ret = gpio_request(ENET_PHY_RESET, "enet_phy_reset");
if (!ret) {
gpio_direction_output(ENET_PHY_RESET, 1);
gpio_set_value(ENET_PHY_RESET, 0);
/* SMSC9303 TRM chapter 14.5.2 */
udelay(200);
gpio_set_value(ENET_PHY_RESET, 1);
} else {
printf("ENET RESET failed!\n");
}
#ifdef ETH_IO_TEST
ret = gpio_request(ENET_TEST_1, "enet_test1");
if (!ret) {
int i;
printf("ENET TEST 1!\n");
for (i = 0; i < 20; i++) {
gpio_direction_output(ENET_TEST_1, 1);
gpio_set_value(ENET_TEST_1, 0);
udelay(50);
gpio_set_value(ENET_TEST_1, 1);
udelay(50);
}
gpio_free(ENET_TEST_1);
} else {
printf("GPIO for ENET TEST 1 failed!\n");
}
ret = gpio_request(ENET_TEST_2, "enet_test2");
if (!ret) {
int i;
printf("ENET TEST 2!\n");
for (i = 0; i < 20; i++) {
gpio_direction_output(ENET_TEST_2, 1);
gpio_set_value(ENET_TEST_2, 0);
udelay(50);
gpio_set_value(ENET_TEST_2, 1);
udelay(50);
}
gpio_free(ENET_TEST_2);
} else {
printf("GPIO for ENET TEST 2 failed!\n");
}
#endif
}
int setup_gpr_fec(void)
{
sc_ipc_t ipc_handle = -1;
sc_err_t err = 0;
unsigned int test;
/*
* TX_CLK_SEL: it controls a mux between clock coming from the pad 50M
* input pin and clock generated internally to connectivity subsystem
* 0: internal clock
* 1: external clock ---> your choice for RMII
*
* CLKDIV_SEL: it controls a div by 2 on the internal clock path à
* it should be dont care when using external clock
* 0: non-divided clock
* 1: clock divided by 2
* 50_DISABLE or 125_DISABLE:
* its used to disable the clock tree going outside the chip
* when reference clock is generated internally.
* It should be dont care when reference clock is provided
* externally.
* 0: clock is enabled
* 1: clock is disabled
*
* SC_C_TXCLK = 24,
* SC_C_CLKDIV = 25,
* SC_C_DISABLE_50 = 26,
* SC_C_DISABLE_125 = 27,
*/
err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, 1);
if (err != SC_ERR_NONE)
printf("Error in setting up SC_C %d\n\r", SC_C_TXCLK);
sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
debug("TEST SC_C %d-->%d\n\r", SC_C_TXCLK, test);
err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, 0);
if (err != SC_ERR_NONE)
printf("Error in setting up SC_C %d\n\r", SC_C_CLKDIV);
sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, &test);
debug("TEST SC_C %d-->%d\n\r", SC_C_CLKDIV, test);
err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_50, 0);
if (err != SC_ERR_NONE)
printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_50);
sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_50, test);
err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_125, 1);
if (err != SC_ERR_NONE)
printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_125);
sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_125, test);
err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, 1);
if (err != SC_ERR_NONE)
printf("Error in setting up SC_C %d\n\r", SC_C_SEL_125);
sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, &test);
debug("TEST SC_C %d-->%d\n\r", SC_C_SEL_125, test);
return 0;
}
#if IS_ENABLED(CONFIG_FEC_MXC)
#include <miiphy.h>
int board_phy_config(struct phy_device *phydev)
{
if (phydev->drv->config)
phydev->drv->config(phydev);
return 0;
}
#endif
static int setup_fec(void)
{
setup_gpr_fec();
/* Reset ENET PHY */
enet_device_phy_reset();
return 0;
}
void reset_cpu(void)
{
}
#ifndef CONFIG_SPL_BUILD
/* LED's */
static int board_led_init(void)
{
struct udevice *bus, *dev;
u8 pca_led[2] = { 0x00, 0x00 };
int ret;
/* enable all leds on PCA9552 */
ret = uclass_get_device_by_seq(UCLASS_I2C, PCA9552_1_I2C_BUS, &bus);
if (ret) {
printf("ERROR: I2C get %d\n", ret);
return ret;
}
ret = dm_i2c_probe(bus, PCA9552_1_I2C_ADDR, 0, &dev);
if (ret) {
printf("ERROR: PCA9552 probe failed\n");
return ret;
}
ret = dm_i2c_write(dev, 0x16, pca_led, sizeof(pca_led));
if (ret) {
printf("ERROR: PCA9552 write failed\n");
return ret;
}
mdelay(1);
return ret;
}
#endif /* !CONFIG_SPL_BUILD */
int checkboard(void)
{
puts("Board: Capricorn\n");
/*
* Running build_info() doesn't work with current SCFW blob.
* Uncomment below call when new blob is available.
*/
/*build_info();*/
print_bootinfo();
return 0;
}
int board_init(void)
{
setup_fec();
return 0;
}
#ifdef CONFIG_OF_BOARD_SETUP
int ft_board_setup(void *blob, struct bd_info *bd)
{
return 0;
}
#endif
int board_mmc_get_env_dev(int devno)
{
return devno;
}
static int check_mmc_autodetect(void)
{
char *autodetect_str = env_get("mmcautodetect");
if (autodetect_str && (strcmp(autodetect_str, "yes") == 0))
return 1;
return 0;
}
/* This should be defined for each board */
__weak int mmc_map_to_kernel_blk(int dev_no)
{
return dev_no;
}
void board_late_mmc_env_init(void)
{
char cmd[32];
char mmcblk[32];
u32 dev_no = mmc_get_env_dev();
if (!check_mmc_autodetect())
return;
env_set_ulong("mmcdev", dev_no);
/* Set mmcblk env */
sprintf(mmcblk, "/dev/mmcblk%dp2 rootwait rw",
mmc_map_to_kernel_blk(dev_no));
env_set("mmcroot", mmcblk);
sprintf(cmd, "mmc dev %d", dev_no);
run_command(cmd, 0);
}
#ifndef CONFIG_SPL_BUILD
int factoryset_read_eeprom(int i2c_addr);
static int load_parameters_from_factoryset(void)
{
int ret;
ret = factoryset_read_eeprom(EEPROM_I2C_ADDR);
if (ret)
return ret;
return factoryset_env_set();
}
int board_late_init(void)
{
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
/* Init LEDs */
if (board_led_init())
printf("I2C LED init failed\n");
/* Set environment from factoryset */
if (load_parameters_from_factoryset())
printf("Loading factoryset parameters failed!\n");
return 0;
}
/* Service button */
#define MAX_PIN_NUMBER 128
#define BOARD_DEFAULT_BUTTON_GPIO IMX_GPIO_NR(1, 31)
unsigned char get_button_state(char * const envname, unsigned char def)
{
int button = 0;
int gpio;
char *ptr_env;
/* If button is not found we take default */
ptr_env = env_get(envname);
if (!ptr_env) {
printf("Using default: %u\n", def);
gpio = def;
} else {
gpio = (unsigned char)simple_strtoul(ptr_env, NULL, 0);
if (gpio > MAX_PIN_NUMBER)
gpio = def;
}
gpio_request(gpio, "");
gpio_direction_input(gpio);
if (gpio_get_value(gpio))
button = 1;
else
button = 0;
gpio_free(gpio);
return button;
}
/*
* This command returns the status of the user button on
* Input - none
* Returns - 1 if button is held down
* 0 if button is not held down
*/
static int
do_userbutton(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
int button = 0;
button = get_button_state("button_usr1", BOARD_DEFAULT_BUTTON_GPIO);
if (argc > 1)
printf("Button state: %u\n", button);
return button;
}
U_BOOT_CMD(
usrbutton, CONFIG_SYS_MAXARGS, 2, do_userbutton,
"Return the status of user button",
"[print]"
);
#define ERST IMX_GPIO_NR(0, 3)
static int
do_eth_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
gpio_request(ERST, "ERST");
gpio_direction_output(ERST, 0);
udelay(200);
gpio_set_value(ERST, 1);
return 0;
}
U_BOOT_CMD(
switch_rst, CONFIG_SYS_MAXARGS, 2, do_eth_reset,
"Reset eth phy",
"[print]"
);
#endif /* ! CONFIG_SPL_BUILD */