// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2018 Microsemi Corporation */ #include <common.h> #include <image.h> #include <init.h> #include <asm/io.h> #include <led.h> #include <miiphy.h> #include <linux/bitops.h> #include <linux/delay.h> #include <asm/global_data.h> enum { BOARD_TYPE_PCB110 = 0xAABBCE00, BOARD_TYPE_PCB111, BOARD_TYPE_PCB112, }; int board_early_init_r(void) { /* Prepare SPI controller to be used in master mode */ writel(0, BASE_CFG + ICPU_SW_MODE); clrsetbits_le32(BASE_CFG + ICPU_GENERAL_CTRL, ICPU_GENERAL_CTRL_IF_SI_OWNER_M, ICPU_GENERAL_CTRL_IF_SI_OWNER(2)); /* Address of boot parameters */ gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE; return 0; } static void vcoreiii_gpio_set_alternate(int gpio, int mode) { u32 mask; u32 val0, val1; void __iomem *reg0, *reg1; if (gpio < 32) { mask = BIT(gpio); reg0 = BASE_DEVCPU_GCB + GPIO_GPIO_ALT(0); reg1 = BASE_DEVCPU_GCB + GPIO_GPIO_ALT(1); } else { gpio -= 32; mask = BIT(gpio); reg0 = BASE_DEVCPU_GCB + GPIO_GPIO_ALT1(0); reg1 = BASE_DEVCPU_GCB + GPIO_GPIO_ALT1(1); } val0 = readl(reg0); val1 = readl(reg1); if (mode == 1) { writel(val0 | mask, reg0); writel(val1 & ~mask, reg1); } else if (mode == 2) { writel(val0 & ~mask, reg0); writel(val1 | mask, reg1); } else if (mode == 3) { writel(val0 | mask, reg0); writel(val1 | mask, reg1); } else { writel(val0 & ~mask, reg0); writel(val1 & ~mask, reg1); } } int board_phy_config(struct phy_device *phydev) { if (gd->board_type == BOARD_TYPE_PCB110 || gd->board_type == BOARD_TYPE_PCB112) { phy_write(phydev, 0, 31, 0x10); phy_write(phydev, 0, 18, 0x80F0); while (phy_read(phydev, 0, 18) & 0x8000) ; phy_write(phydev, 0, 31, 0); } if (gd->board_type == BOARD_TYPE_PCB111) { phy_write(phydev, 0, 31, 0x10); phy_write(phydev, 0, 18, 0x80A0); while (phy_read(phydev, 0, 18) & 0x8000) ; phy_write(phydev, 0, 14, 0x800); phy_write(phydev, 0, 31, 0); } return 0; } void board_debug_uart_init(void) { /* too early for the pinctrl driver, so configure the UART pins here */ vcoreiii_gpio_set_alternate(10, 1); vcoreiii_gpio_set_alternate(11, 1); } static void do_board_detect(void) { int i; u16 pval; /* MIIM 1 + 2 MDC/MDIO */ for (i = 56; i < 60; i++) vcoreiii_gpio_set_alternate(i, 1); /* small delay for settling the pins */ mdelay(30); if (mscc_phy_rd(0, 0x10, 0x3, &pval) == 0 && ((pval >> 4) & 0x3F) == 0x3c) { gd->board_type = BOARD_TYPE_PCB112; /* Serval2-NID */ } else if (mscc_phy_rd(1, 0x0, 0x3, &pval) == 0 && ((pval >> 4) & 0x3F) == 0x3c) { gd->board_type = BOARD_TYPE_PCB110; /* Jr2-24 */ } else { /* Fall-back */ gd->board_type = BOARD_TYPE_PCB111; /* Jr2-48 */ } } #if defined(CONFIG_MULTI_DTB_FIT) int board_fit_config_name_match(const char *name) { if (gd->board_type == BOARD_TYPE_PCB110 && strcmp(name, "jr2_pcb110") == 0) return 0; if (gd->board_type == BOARD_TYPE_PCB111 && strcmp(name, "jr2_pcb111") == 0) return 0; if (gd->board_type == BOARD_TYPE_PCB112 && strcmp(name, "serval2_pcb112") == 0) return 0; return -1; } #endif #if defined(CONFIG_DTB_RESELECT) int embedded_dtb_select(void) { do_board_detect(); fdtdec_setup(); return 0; } #endif