Suneel Garapati | d9e7246 | 2019-10-19 18:47:37 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Copyright (C) 2018 Marvell International Ltd. |
| 4 | * |
| 5 | * https://spdx.org/licenses |
| 6 | */ |
| 7 | |
| 8 | #include <command.h> |
| 9 | #include <console.h> |
| 10 | #include <cpu_func.h> |
| 11 | #include <dm.h> |
| 12 | #include <dm/uclass-internal.h> |
| 13 | #include <env.h> |
| 14 | #include <init.h> |
| 15 | #include <malloc.h> |
| 16 | #include <net.h> |
| 17 | #include <pci_ids.h> |
| 18 | #include <errno.h> |
| 19 | #include <asm/io.h> |
| 20 | #include <linux/compiler.h> |
| 21 | #include <linux/delay.h> |
| 22 | #include <linux/libfdt.h> |
| 23 | #include <fdt_support.h> |
| 24 | #include <asm/arch/smc.h> |
| 25 | #include <asm/arch/soc.h> |
| 26 | #include <asm/arch/board.h> |
| 27 | #include <dm/util.h> |
| 28 | |
| 29 | DECLARE_GLOBAL_DATA_PTR; |
| 30 | |
| 31 | void cleanup_env_ethaddr(void) |
| 32 | { |
| 33 | char ename[32]; |
| 34 | |
| 35 | for (int i = 0; i < 20; i++) { |
| 36 | sprintf(ename, i ? "eth%daddr" : "ethaddr", i); |
| 37 | if (env_get(ename)) |
| 38 | env_set(ename, NULL); |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | void octeontx2_board_get_mac_addr(u8 index, u8 *mac_addr) |
| 43 | { |
| 44 | u64 tmp_mac, board_mac_addr = fdt_get_board_mac_addr(); |
| 45 | static int board_mac_num; |
| 46 | |
| 47 | board_mac_num = fdt_get_board_mac_cnt(); |
| 48 | if ((!is_zero_ethaddr((u8 *)&board_mac_addr)) && board_mac_num) { |
| 49 | tmp_mac = board_mac_addr; |
| 50 | tmp_mac += index; |
| 51 | tmp_mac = swab64(tmp_mac) >> 16; |
| 52 | memcpy(mac_addr, (u8 *)&tmp_mac, ARP_HLEN); |
| 53 | board_mac_num--; |
| 54 | } else { |
| 55 | memset(mac_addr, 0, ARP_HLEN); |
| 56 | } |
| 57 | debug("%s mac %pM\n", __func__, mac_addr); |
| 58 | } |
| 59 | |
| 60 | void board_quiesce_devices(void) |
| 61 | { |
| 62 | struct uclass *uc_dev; |
| 63 | int ret; |
| 64 | |
| 65 | /* Removes all RVU PF devices */ |
| 66 | ret = uclass_get(UCLASS_ETH, &uc_dev); |
| 67 | if (uc_dev) |
| 68 | ret = uclass_destroy(uc_dev); |
| 69 | if (ret) |
| 70 | printf("couldn't remove rvu pf devices\n"); |
| 71 | |
| 72 | if (IS_ENABLED(CONFIG_OCTEONTX2_CGX_INTF)) { |
| 73 | /* Bring down all cgx lmac links */ |
| 74 | cgx_intf_shutdown(); |
| 75 | } |
| 76 | |
| 77 | /* Removes all CGX and RVU AF devices */ |
| 78 | ret = uclass_get(UCLASS_MISC, &uc_dev); |
| 79 | if (uc_dev) |
| 80 | ret = uclass_destroy(uc_dev); |
| 81 | if (ret) |
| 82 | printf("couldn't remove misc (cgx/rvu_af) devices\n"); |
| 83 | |
| 84 | /* SMC call - removes all LF<->PF mappings */ |
| 85 | smc_disable_rvu_lfs(0); |
| 86 | } |
| 87 | |
| 88 | int board_early_init_r(void) |
| 89 | { |
| 90 | pci_init(); |
| 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | int board_init(void) |
| 95 | { |
| 96 | return 0; |
| 97 | } |
| 98 | |
| 99 | int timer_init(void) |
| 100 | { |
| 101 | return 0; |
| 102 | } |
| 103 | |
| 104 | int dram_init(void) |
| 105 | { |
| 106 | gd->ram_size = smc_dram_size(0); |
| 107 | gd->ram_size -= CONFIG_SYS_SDRAM_BASE; |
| 108 | |
| 109 | mem_map_fill(); |
| 110 | |
| 111 | return 0; |
| 112 | } |
| 113 | |
| 114 | void board_late_probe_devices(void) |
| 115 | { |
| 116 | struct udevice *dev; |
| 117 | int err, cgx_cnt = 3, i; |
| 118 | |
| 119 | /* Probe MAC(CGX) and NIC AF devices before Network stack init */ |
| 120 | for (i = 0; i < cgx_cnt; i++) { |
| 121 | err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, |
| 122 | PCI_DEVICE_ID_CAVIUM_CGX, i, &dev); |
| 123 | if (err) |
| 124 | debug("%s CGX%d device not found\n", __func__, i); |
| 125 | } |
| 126 | err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, |
| 127 | PCI_DEVICE_ID_CAVIUM_RVU_AF, 0, &dev); |
| 128 | if (err) |
| 129 | debug("NIC AF device not found\n"); |
| 130 | } |
| 131 | |
| 132 | /** |
| 133 | * Board late initialization routine. |
| 134 | */ |
| 135 | int board_late_init(void) |
| 136 | { |
| 137 | char boardname[32]; |
| 138 | char boardserial[150], boardrev[150]; |
| 139 | long val; |
| 140 | bool save_env = false; |
| 141 | const char *str; |
| 142 | |
| 143 | debug("%s()\n", __func__); |
| 144 | |
| 145 | /* |
| 146 | * Now that pci_init initializes env device. |
| 147 | * Try to cleanup ethaddr env variables, this is needed |
| 148 | * as with each boot, configuration of QLM can change. |
| 149 | */ |
| 150 | cleanup_env_ethaddr(); |
| 151 | |
| 152 | snprintf(boardname, sizeof(boardname), "%s> ", fdt_get_board_model()); |
| 153 | env_set("prompt", boardname); |
| 154 | set_working_fdt_addr(env_get_hex("fdtcontroladdr", fdt_base_addr)); |
| 155 | |
| 156 | str = fdt_get_board_revision(); |
| 157 | if (str) { |
| 158 | snprintf(boardrev, sizeof(boardrev), "%s", str); |
| 159 | if (env_get("boardrev") && |
| 160 | strcmp(boardrev, env_get("boardrev"))) |
| 161 | save_env = true; |
| 162 | env_set("boardrev", boardrev); |
| 163 | } |
| 164 | |
| 165 | str = fdt_get_board_serial(); |
| 166 | if (str) { |
| 167 | snprintf(boardserial, sizeof(boardserial), "%s", str); |
| 168 | if (env_get("serial#") && |
| 169 | strcmp(boardserial, env_get("serial#"))) |
| 170 | save_env = true; |
| 171 | env_set("serial#", boardserial); |
| 172 | } |
| 173 | |
| 174 | val = env_get_hex("disable_ooo", 0); |
| 175 | smc_configure_ooo(val); |
| 176 | |
| 177 | if (IS_ENABLED(CONFIG_NET_OCTEONTX2)) |
| 178 | board_late_probe_devices(); |
| 179 | |
| 180 | if (save_env) |
| 181 | env_save(); |
| 182 | |
| 183 | return 0; |
| 184 | } |
| 185 | |
| 186 | /* |
| 187 | * Invoked before relocation, so limit to stack variables. |
| 188 | */ |
| 189 | int checkboard(void) |
| 190 | { |
| 191 | printf("Board: %s\n", fdt_get_board_model()); |
| 192 | |
| 193 | return 0; |
| 194 | } |
| 195 | |
| 196 | void board_acquire_flash_arb(bool acquire) |
| 197 | { |
| 198 | union cpc_boot_ownerx ownerx; |
| 199 | |
| 200 | if (!acquire) { |
| 201 | ownerx.u = readl(CPC_BOOT_OWNERX(3)); |
| 202 | ownerx.s.boot_req = 0; |
| 203 | writel(ownerx.u, CPC_BOOT_OWNERX(3)); |
| 204 | } else { |
| 205 | ownerx.u = 0; |
| 206 | ownerx.s.boot_req = 1; |
| 207 | writel(ownerx.u, CPC_BOOT_OWNERX(3)); |
| 208 | udelay(1); |
| 209 | do { |
| 210 | ownerx.u = readl(CPC_BOOT_OWNERX(3)); |
| 211 | } while (ownerx.s.boot_wait); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | int last_stage_init(void) |
| 216 | { |
| 217 | (void)smc_flsf_fw_booted(); |
| 218 | return 0; |
| 219 | } |
| 220 | |
| 221 | static int do_go_uboot(struct cmd_tbl *cmdtp, int flag, int argc, |
| 222 | char *const argv[]) |
| 223 | { |
| 224 | typedef void __noreturn (*uboot_entry_t)(ulong, void *); |
| 225 | uboot_entry_t entry; |
| 226 | ulong addr; |
| 227 | void *fdt; |
| 228 | |
| 229 | if (argc < 2) |
| 230 | return CMD_RET_USAGE; |
| 231 | |
| 232 | addr = simple_strtoul(argv[1], NULL, 16); |
| 233 | fdt = board_fdt_blob_setup(); |
| 234 | entry = (uboot_entry_t)addr; |
| 235 | flush_cache((ulong)addr, 1 << 20); /* 1MiB should be enough */ |
| 236 | dcache_disable(); |
| 237 | |
| 238 | printf("## Starting U-Boot at %p (FDT at %p)...\n", entry, fdt); |
| 239 | |
| 240 | entry(0, fdt); |
| 241 | |
| 242 | return 0; |
| 243 | } |
| 244 | |
| 245 | U_BOOT_CMD(go_uboot, 2, 0, do_go_uboot, |
| 246 | "Start U-Boot from RAM (pass FDT via x1 register)", |
| 247 | ""); |