Nathan Barrett-Morrison | 48a0b0b | 2024-04-24 20:04:00 -0400 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* |
| 3 | * (C) Copyright 2022 - Analog Devices, Inc. |
| 4 | * |
| 5 | * Written and/or maintained by Timesys Corporation |
| 6 | * |
| 7 | * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com> |
| 8 | * Contact: Greg Malysa <greg.malysa@timesys.com> |
| 9 | */ |
| 10 | |
| 11 | #include <asm/arch-adi/sc5xx/sc5xx.h> |
| 12 | #include <asm/arch-adi/sc5xx/soc.h> |
| 13 | #include <asm/global_data.h> |
| 14 | #include <asm/io.h> |
| 15 | #include <cpu_func.h> |
| 16 | |
| 17 | #ifdef CONFIG_SC58X |
| 18 | #define RCU0_CTL 0x3108B000 |
| 19 | #define RCU0_STAT 0x3108B004 |
| 20 | #define RCU0_CRCTL 0x3108B008 |
| 21 | #define RCU0_CRSTAT 0x3108B00C |
| 22 | #define RCU0_SIDIS 0x3108B010 |
| 23 | #define RCU0_MSG_SET 0x3108B064 |
| 24 | #elif defined(CONFIG_SC57X) || defined(CONFIG_SC59X) || defined(CONFIG_SC59X_64) |
| 25 | #define RCU0_CTL 0x3108C000 |
| 26 | #define RCU0_STAT 0x3108C004 |
| 27 | #define RCU0_CRCTL 0x3108C008 |
| 28 | #define RCU0_CRSTAT 0x3108C00C |
| 29 | #define RCU0_SIDIS 0x3108C01C |
| 30 | #define RCU0_MSG_SET 0x3108C070 |
| 31 | #else |
| 32 | #error "No SC5xx SoC CONFIG_ enabled" |
| 33 | #endif |
| 34 | |
| 35 | #define BITP_RCU_STAT_BMODE 8 |
| 36 | #define BITM_RCU_STAT_BMODE 0x00000F00 |
| 37 | |
| 38 | #define REG_ARMPMU0_PMCR 0x31121E04 |
| 39 | #define REG_ARMPMU0_PMUSERENR 0x31121E08 |
| 40 | #define REG_ARMPMU0_PMLAR 0x31121FB0 |
| 41 | |
| 42 | DECLARE_GLOBAL_DATA_PTR; |
| 43 | |
| 44 | void reset_cpu(void) |
| 45 | { |
| 46 | u32 val = readl(RCU0_CTL); |
| 47 | writel(val | 1, RCU0_CTL); |
| 48 | } |
| 49 | |
| 50 | void enable_caches(void) |
| 51 | { |
| 52 | if (!IS_ENABLED(CONFIG_SYS_DCACHE_OFF)) |
| 53 | dcache_enable(); |
| 54 | } |
| 55 | |
| 56 | void sc5xx_enable_ns_sharc_access(uintptr_t securec0_base) |
| 57 | { |
| 58 | writel(0, securec0_base); |
| 59 | writel(0, securec0_base + 0x4); |
| 60 | writel(0, securec0_base + 0x8); |
| 61 | } |
| 62 | |
| 63 | void sc5xx_disable_spu0(uintptr_t spu0_start, uintptr_t spu0_end) |
| 64 | { |
| 65 | for (uintptr_t i = spu0_start; i <= spu0_end; i += 4) |
| 66 | writel(0, i); |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * PMU is only available on armv7 platforms and all share the same location |
| 71 | */ |
| 72 | void sc5xx_enable_pmu(void) |
| 73 | { |
| 74 | if (!IS_ENABLED(CONFIG_SC59X_64)) { |
| 75 | writel(readl(REG_ARMPMU0_PMUSERENR) | 0x01, REG_ARMPMU0_PMUSERENR); |
| 76 | writel(0xc5acce55, REG_ARMPMU0_PMLAR); |
| 77 | writel(readl(REG_ARMPMU0_PMCR) | (1 << 1), REG_ARMPMU0_PMCR); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | const char *sc5xx_get_boot_mode(u32 *bmode) |
| 82 | { |
| 83 | static const char * const bmodes[] = { |
| 84 | "JTAG/BOOTROM", |
| 85 | "QSPI Master", |
| 86 | "QSPI Slave", |
| 87 | "UART", |
| 88 | "LP0 Slave", |
| 89 | "OSPI", |
| 90 | #ifdef CONFIG_SC59X_64 |
| 91 | "eMMC" |
| 92 | #endif |
| 93 | }; |
| 94 | u32 local_mode; |
| 95 | |
| 96 | local_mode = (readl(RCU0_STAT) & BITM_RCU_STAT_BMODE) >> BITP_RCU_STAT_BMODE; |
| 97 | |
| 98 | #if CONFIG_ADI_SPL_FORCE_BMODE != 0 |
| 99 | /* |
| 100 | * In case we want to force boot sequences such as: |
| 101 | * QSPI -> OSPI |
| 102 | * QSPI -> eMMC |
| 103 | * If this is not set, then we will always try to use the BMODE setting |
| 104 | * for both stages... i.e. |
| 105 | * QSPI -> QSPI |
| 106 | */ |
| 107 | |
| 108 | // (Don't allow skipping JTAG/UART BMODE settings) |
| 109 | if (local_mode != 0 && local_mode != 3) |
| 110 | local_mode = CONFIG_ADI_SPL_FORCE_BMODE; |
| 111 | #endif |
| 112 | |
| 113 | *bmode = local_mode; |
| 114 | |
| 115 | if (local_mode >= 0 && local_mode <= ARRAY_SIZE(bmodes)) |
| 116 | return bmodes[local_mode]; |
| 117 | return "unknown"; |
| 118 | } |
| 119 | |
| 120 | void print_cpu_id(void) |
| 121 | { |
| 122 | if (!IS_ENABLED(CONFIG_ARM64)) { |
| 123 | u32 cpuid = 0; |
| 124 | |
| 125 | __asm__ __volatile__("mrc p15, 0, %0, c0, c0, 0" : "=r"(cpuid)); |
| 126 | |
| 127 | printf("Detected Revision: %d.%d\n", cpuid & 0xf00000 >> 20, cpuid & 0xf); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | int print_cpuinfo(void) |
| 132 | { |
| 133 | u32 bmode; |
| 134 | |
| 135 | printf("CPU: ADSP %s (%s boot)\n", CONFIG_LDR_CPU, sc5xx_get_boot_mode(&bmode)); |
| 136 | print_cpu_id(); |
| 137 | |
| 138 | return 0; |
| 139 | } |
| 140 | |
| 141 | void fixup_dp83867_phy(struct phy_device *phydev) |
| 142 | { |
| 143 | int phy_data = 0; |
| 144 | |
| 145 | phy_data = phy_read(phydev, MDIO_DEVAD_NONE, 0x32); |
| 146 | phy_write(phydev, MDIO_DEVAD_NONE, 0x32, (1 << 7) | phy_data); |
| 147 | int cfg3 = 0; |
| 148 | #define MII_DP83867_CFG3 (0x1e) |
| 149 | /* |
| 150 | * Pin INT/PWDN on DP83867 should be configured as an Interrupt Output |
| 151 | * instead of a Power-Down Input on ADI SC5XX boards in order to |
| 152 | * prevent the signal interference from other peripherals during they |
| 153 | * are running at the same time. |
| 154 | */ |
| 155 | cfg3 = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG3); |
| 156 | cfg3 |= (1 << 7); |
| 157 | phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG3, cfg3); |
| 158 | |
| 159 | // Mystery second port fixup on ezkits with two PHYs |
| 160 | if (CONFIG_DW_PORTS & 2) |
| 161 | phy_write(phydev, MDIO_DEVAD_NONE, 0x11, 3); |
| 162 | |
| 163 | if (IS_ENABLED(CONFIG_ADI_BUG_EZKHW21)) { |
| 164 | phydev->advertising &= PHY_BASIC_FEATURES; |
| 165 | phydev->speed = SPEED_100; |
| 166 | } |
| 167 | |
| 168 | if (phydev->drv->config) |
| 169 | phydev->drv->config(phydev); |
| 170 | |
| 171 | if (IS_ENABLED(CONFIG_ADI_BUG_EZKHW21)) |
| 172 | phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x3100); |
| 173 | } |
| 174 | |
| 175 | int dram_init(void) |
| 176 | { |
| 177 | gd->ram_size = CFG_SYS_SDRAM_SIZE; |
| 178 | return 0; |
| 179 | } |