diff options
author | Tom Rini <trini@konsulko.com> | 2021-04-24 19:39:14 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-04-24 19:39:14 -0400 |
commit | 4dda435131251a94b29afd52f010cf1ec5a7ceb2 (patch) | |
tree | 16bda495e53e1e5d6afc58077f2ec8e6ca670d1c /board | |
parent | e1333435afbf0c6290b1d16bb446b57807f75502 (diff) | |
parent | b1d9554e058e5e8510a9d22183ae8321290ee87b (diff) | |
download | u-boot-4dda435131251a94b29afd52f010cf1ec5a7ceb2.tar.gz |
Merge tag 'mips-pull-2021-04-24' of https://source.denx.de/u-boot/custodians/u-boot-mipsWIP/24Apr2021
- MIPS: octeon: fix minor bugs of initial merge
- MIPS: octeon: add support for QLM and PCI-E controller
- MIPS: octeon: add support for AHCI and SATA
- MIPS: octeon: add E1000 ethernet support
- MIPS: octeon: add Octeon III NIC23 board
- ata/scsi: add support for Big Endian platforms
Diffstat (limited to 'board')
-rw-r--r-- | board/Marvell/octeon_ebb7304/board.c | 732 | ||||
-rw-r--r-- | board/Marvell/octeon_nic23/Kconfig | 19 | ||||
-rw-r--r-- | board/Marvell/octeon_nic23/MAINTAINERS | 7 | ||||
-rw-r--r-- | board/Marvell/octeon_nic23/Makefile | 8 | ||||
-rw-r--r-- | board/Marvell/octeon_nic23/board.c | 106 | ||||
-rw-r--r-- | board/Marvell/octeon_nic23/board_ddr.h | 269 |
6 files changed, 1139 insertions, 2 deletions
diff --git a/board/Marvell/octeon_ebb7304/board.c b/board/Marvell/octeon_ebb7304/board.c index 611b18fa6a..9aac5f0b09 100644 --- a/board/Marvell/octeon_ebb7304/board.c +++ b/board/Marvell/octeon_ebb7304/board.c @@ -3,20 +3,32 @@ * Copyright (C) 2020 Stefan Roese <sr@denx.de> */ -#include <common.h> #include <dm.h> +#include <fdt_support.h> #include <ram.h> +#include <asm/gpio.h> #include <mach/octeon_ddr.h> +#include <mach/cvmx-qlm.h> +#include <mach/octeon_qlm.h> +#include <mach/octeon_fdt.h> +#include <mach/cvmx-helper.h> +#include <mach/cvmx-helper-cfg.h> +#include <mach/cvmx-helper-util.h> +#include <mach/cvmx-bgxx-defs.h> #include "board_ddr.h" +#define MAX_MIX_ENV_VARS 4 + #define EBB7304_DEF_DRAM_FREQ 800 static struct ddr_conf board_ddr_conf[] = { - OCTEON_EBB7304_DDR_CONFIGURATION + OCTEON_EBB7304_DDR_CONFIGURATION }; +static int no_phy[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + struct ddr_conf *octeon_ddr_conf_table_get(int *count, int *def_ddr_freq) { *count = ARRAY_SIZE(board_ddr_conf); @@ -24,3 +36,719 @@ struct ddr_conf *octeon_ddr_conf_table_get(int *count, int *def_ddr_freq) return board_ddr_conf; } + +/* + * parse_env_var: Parse the environment variable ("bgx_for_mix%d") to + * extract the lmac it is set to. + * + * index: Index of environment variable to parse. + * environment variable. + * env_bgx: Updated with the bgx of the lmac in the environment + * variable. + * env_lmac: Updated with the index of lmac in the environment + * variable. + * + * returns: Zero on success, error otherwise. + */ +static int parse_env_var(int index, int *env_bgx, int *env_lmac) +{ + char env_var[20]; + ulong xipd_port; + + sprintf(env_var, "bgx_for_mix%d", index); + xipd_port = env_get_ulong(env_var, 0, 0xffff); + if (xipd_port != 0xffff) { + int xiface; + struct cvmx_xiface xi; + struct cvmx_xport xp; + + /* + * The environemt variable is set to the xipd port. Convert the + * xipd port to numa node, bgx, and lmac. + */ + xiface = cvmx_helper_get_interface_num(xipd_port); + xi = cvmx_helper_xiface_to_node_interface(xiface); + xp = cvmx_helper_ipd_port_to_xport(xipd_port); + *env_bgx = xi.interface; + *env_lmac = cvmx_helper_get_interface_index_num(xp.port); + return 0; + } + + return -1; +} + +/* + * get_lmac_fdt_node: Search the device tree for the node corresponding to + * a given bgx lmac. + * + * fdt: Pointer to flat device tree + * search_node: Numa node of the lmac to search for. + * search_bgx: Bgx of the lmac to search for. + * search_lmac: Lmac index to search for. + * compat: Compatible string to search for. + + * returns: The device tree node of the lmac if found, + * or -1 otherwise. + */ +static int get_lmac_fdt_node(const void *fdt, int search_node, int search_bgx, int search_lmac, + const char *compat) +{ + int node; + const fdt32_t *reg; + u64 addr; + int fdt_node = -1; + int fdt_bgx = -1; + int fdt_lmac = -1; + int len; + int parent; + + /* Iterate through all bgx ports */ + node = -1; + while ((node = fdt_node_offset_by_compatible((void *)fdt, node, + compat)) >= 0) { + /* Get the node and bgx from the physical address */ + parent = fdt_parent_offset(fdt, node); + reg = fdt_getprop(fdt, parent, "reg", &len); + if (parent < 0 || !reg) + continue; + + addr = fdt_translate_address((void *)fdt, parent, reg); + fdt_node = (addr >> 36) & 0x7; + fdt_bgx = (addr >> 24) & 0xf; + + /* Get the lmac index from the reg property */ + reg = fdt_getprop(fdt, node, "reg", &len); + if (reg) + fdt_lmac = *reg; + + /* Check for a match */ + if (search_node == fdt_node && search_bgx == fdt_bgx && + search_lmac == fdt_lmac) + return node; + } + + return -1; +} + +/* + * get_mix_fdt_node: Search the device tree for the node corresponding to + * a given mix. + * + * fdt: Pointer to flat device tree + * search_node: Mix numa node to search for. + * search_index: Mix index to search for. + * + * returns: The device tree node of the lmac if found, + * or -1 otherwise. + */ +static int get_mix_fdt_node(const void *fdt, int search_node, int search_index) +{ + int node; + + /* Iterate through all the mix fdt nodes */ + node = -1; + while ((node = fdt_node_offset_by_compatible((void *)fdt, node, + "cavium,octeon-7890-mix")) >= 0) { + int parent; + int len; + const char *name; + int mix_numa_node; + const fdt32_t *reg; + int mix_index = -1; + u64 addr; + + /* Get the numa node of the mix from the parent node name */ + parent = fdt_parent_offset(fdt, node); + if (parent < 0 || + ((name = fdt_get_name(fdt, parent, &len)) == NULL) || + ((name = strchr(name, '@')) == NULL)) + continue; + + name++; + mix_numa_node = simple_strtol(name, NULL, 0) ? 1 : 0; + + /* Get the mix index from the reg property */ + reg = fdt_getprop(fdt, node, "reg", &len); + if (reg) { + addr = fdt_translate_address((void *)fdt, parent, reg); + mix_index = (addr >> 11) & 1; + } + + /* Check for a match */ + if (mix_numa_node == search_node && mix_index == search_index) + return node; + } + + return -1; +} + +/* + * fdt_fix_mix: Fix the mix nodes in the device tree. Only the mix nodes + * configured by the user will be preserved. All other mix + * nodes will be trimmed. + * + * fdt: Pointer to flat device tree + * + * returns: Zero on success, error otherwise. + */ +static int fdt_fix_mix(const void *fdt) +{ + int node; + int next_node; + int len; + int i; + + /* Parse all the mix port environment variables */ + for (i = 0; i < MAX_MIX_ENV_VARS; i++) { + int env_node = 0; + int env_bgx = -1; + int env_lmac = -1; + int lmac_fdt_node = -1; + int mix_fdt_node = -1; + int lmac_phandle; + char *compat; + + /* Get the lmac for this environment variable */ + if (parse_env_var(i, &env_bgx, &env_lmac)) + continue; + + /* Get the fdt node for this lmac and add a phandle to it */ + compat = "cavium,octeon-7890-bgx-port"; + lmac_fdt_node = get_lmac_fdt_node(fdt, env_node, env_bgx, + env_lmac, compat); + if (lmac_fdt_node < 0) { + /* Must check for the xcv compatible string too */ + compat = "cavium,octeon-7360-xcv"; + lmac_fdt_node = get_lmac_fdt_node(fdt, env_node, + env_bgx, env_lmac, + compat); + if (lmac_fdt_node < 0) { + printf("WARNING: Failed to get lmac fdt node for %d%d%d\n", + env_node, env_bgx, env_lmac); + continue; + } + } + + lmac_phandle = fdt_alloc_phandle((void *)fdt); + fdt_set_phandle((void *)fdt, lmac_fdt_node, lmac_phandle); + + /* Get the fdt mix node corresponding to this lmac */ + mix_fdt_node = get_mix_fdt_node(fdt, env_node, env_lmac); + if (mix_fdt_node < 0) + continue; + + /* Point the mix to the lmac */ + fdt_getprop(fdt, mix_fdt_node, "cavium,mac-handle", &len); + fdt_setprop_inplace((void *)fdt, mix_fdt_node, + "cavium,mac-handle", &lmac_phandle, len); + } + + /* Trim unused mix'es from the device tree */ + for (node = fdt_next_node(fdt, -1, NULL); node >= 0; node = next_node) { + const char *compat; + const fdt32_t *reg; + + next_node = fdt_next_node(fdt, node, NULL); + + compat = fdt_getprop(fdt, node, "compatible", &len); + if (compat) { + if (strcmp(compat, "cavium,octeon-7890-mix")) + continue; + + reg = fdt_getprop(fdt, node, "cavium,mac-handle", &len); + if (reg) { + if (*reg == 0xffff) + fdt_nop_node((void *)fdt, node); + } + } + } + + return 0; +} + +static void kill_fdt_phy(void *fdt, int offset, void *arg) +{ + int len, phy_offset; + const fdt32_t *php; + u32 phandle; + + php = fdt_getprop(fdt, offset, "phy-handle", &len); + if (php && len == sizeof(*php)) { + phandle = fdt32_to_cpu(*php); + fdt_nop_property(fdt, offset, "phy-handle"); + phy_offset = fdt_node_offset_by_phandle(fdt, phandle); + if (phy_offset > 0) + fdt_nop_node(fdt, phy_offset); + } +} + +void __fixup_xcv(void) +{ + unsigned long bgx = env_get_ulong("bgx_for_rgmii", 10, + (unsigned long)-1); + char fdt_key[16]; + int i; + + debug("%s: BGX %d\n", __func__, (int)bgx); + + for (i = 0; i < 3; i++) { + snprintf(fdt_key, sizeof(fdt_key), + bgx == i ? "%d,xcv" : "%d,not-xcv", i); + debug("%s: trimming bgx %lu with key %s\n", + __func__, bgx, fdt_key); + + octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key, + "cavium,xcv-trim", true, NULL, NULL); + } +} + +/* QLM0 - QLM6 */ +void __fixup_fdt(void) +{ + int qlm; + int speed = 0; + + for (qlm = 0; qlm < 7; qlm++) { + enum cvmx_qlm_mode mode; + char fdt_key[16]; + const char *type_str = "none"; + + mode = cvmx_qlm_get_mode(qlm); + switch (mode) { + case CVMX_QLM_MODE_SGMII: + case CVMX_QLM_MODE_RGMII_SGMII: + case CVMX_QLM_MODE_RGMII_SGMII_1X1: + type_str = "sgmii"; + break; + case CVMX_QLM_MODE_XAUI: + case CVMX_QLM_MODE_RGMII_XAUI: + speed = (cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10) * 4; + if (speed == 10000) + type_str = "xaui"; + else + type_str = "dxaui"; + break; + case CVMX_QLM_MODE_RXAUI: + case CVMX_QLM_MODE_RGMII_RXAUI: + type_str = "rxaui"; + break; + case CVMX_QLM_MODE_XLAUI: + case CVMX_QLM_MODE_RGMII_XLAUI: + type_str = "xlaui"; + break; + case CVMX_QLM_MODE_XFI: + case CVMX_QLM_MODE_RGMII_XFI: + case CVMX_QLM_MODE_RGMII_XFI_1X1: + type_str = "xfi"; + break; + case CVMX_QLM_MODE_10G_KR: + case CVMX_QLM_MODE_RGMII_10G_KR: + type_str = "10G_KR"; + break; + case CVMX_QLM_MODE_40G_KR4: + case CVMX_QLM_MODE_RGMII_40G_KR4: + type_str = "40G_KR4"; + break; + case CVMX_QLM_MODE_SATA_2X1: + type_str = "sata"; + break; + case CVMX_QLM_MODE_SGMII_2X1: + case CVMX_QLM_MODE_XFI_1X2: + case CVMX_QLM_MODE_10G_KR_1X2: + case CVMX_QLM_MODE_RXAUI_1X2: + case CVMX_QLM_MODE_MIXED: // special for DLM5 & DLM6 + { + cvmx_bgxx_cmrx_config_t cmr_config; + cvmx_bgxx_spux_br_pmd_control_t pmd_control; + int mux = cvmx_qlm_mux_interface(2); + + if (mux == 2) { // only dlm6 + cmr_config.u64 = csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2)); + pmd_control.u64 = + csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2)); + } else { + if (qlm == 5) { + cmr_config.u64 = + csr_rd(CVMX_BGXX_CMRX_CONFIG(0, 2)); + pmd_control.u64 = + csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(0, 2)); + } else { + cmr_config.u64 = + csr_rd(CVMX_BGXX_CMRX_CONFIG(2, 2)); + pmd_control.u64 = + csr_rd(CVMX_BGXX_SPUX_BR_PMD_CONTROL(2, 2)); + } + } + switch (cmr_config.s.lmac_type) { + case 0: + type_str = "sgmii"; + break; + case 1: + type_str = "xaui"; + break; + case 2: + type_str = "rxaui"; + break; + case 3: + if (pmd_control.s.train_en) + type_str = "10G_KR"; + else + type_str = "xfi"; + break; + case 4: + if (pmd_control.s.train_en) + type_str = "40G_KR4"; + else + type_str = "xlaui"; + break; + default: + type_str = "none"; + break; + } + break; + } + default: + type_str = "none"; + break; + } + sprintf(fdt_key, "%d,%s", qlm, type_str); + debug("Patching qlm %d for %s for mode %d%s\n", qlm, fdt_key, mode, + no_phy[qlm] ? ", removing PHY" : ""); + octeon_fdt_patch_rename((void *)gd->fdt_blob, fdt_key, NULL, true, + no_phy[qlm] ? kill_fdt_phy : NULL, NULL); + } +} + +int board_fix_fdt(void) +{ + __fixup_fdt(); + __fixup_xcv(); + + /* Fix the mix ports */ + fdt_fix_mix(gd->fdt_blob); + + return 0; +} + +/* + * Here is the description of the parameters that are passed to QLM + * configuration: + * + * param0 : The QLM to configure + * param1 : Speed to configure the QLM at + * param2 : Mode the QLM to configure + * param3 : 1 = RC, 0 = EP + * param4 : 0 = GEN1, 1 = GEN2, 2 = GEN3 + * param5 : ref clock select, 0 = 100Mhz, 1 = 125MHz, 2 = 156MHz + * param6 : ref clock input to use: + * 0 - external reference (QLMx_REF_CLK) + * 1 = common clock 0 (QLMC_REF_CLK0) + * 2 = common_clock 1 (QLMC_REF_CLK1) + */ +static void board_configure_qlms(void) +{ + int speed[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int mode[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; + int pcie_rc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int pcie_gen[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int ref_clock_sel[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int ref_clock_input[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + struct gpio_desc desc; + int rbgx, rqlm; + char env_var[16]; + int qlm; + int ret; + + /* RGMII PHY reset GPIO */ + ret = dm_gpio_lookup_name("gpio-controllerA27", &desc); + if (ret) + debug("gpio ret=%d\n", ret); + ret = dm_gpio_request(&desc, "rgmii_phy_reset"); + if (ret) + debug("gpio_request ret=%d\n", ret); + ret = dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT); + if (ret) + debug("gpio dir ret=%d\n", ret); + + /* Put RGMII PHY in reset */ + dm_gpio_set_value(&desc, 0); + + octeon_init_qlm(0); + + rbgx = env_get_ulong("bgx_for_rgmii", 10, (unsigned long)-1); + switch (rbgx) { + case 0: + rqlm = 2; + break; + case 1: + rqlm = 3; + break; + case 2: + rqlm = 5; + break; + default: + rqlm = -1; + break; + } + + for (qlm = 0; qlm < 7; qlm++) { + const char *mode_str; + char spd_env[16]; + + mode[qlm] = CVMX_QLM_MODE_DISABLED; + sprintf(env_var, "qlm%d_mode", qlm); + mode_str = env_get(env_var); + if (!mode_str) + continue; + + if (qlm == 4 && mode[4] != -1 && + mode[4] != CVMX_QLM_MODE_SATA_2X1) { + printf("Error: DLM 4 can only be configured for SATA\n"); + continue; + } + + if (strstr(mode_str, ",no_phy")) + no_phy[qlm] = 1; + + if (!strncmp(mode_str, "sgmii", 5)) { + bool rgmii = false; + + speed[qlm] = 1250; + if (rqlm == qlm && qlm < 5) { + mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII; + rgmii = true; + } else if (qlm == 6 || qlm == 5) { + if (rqlm == qlm && qlm == 5) { + mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_1X1; + rgmii = true; + } else if (rqlm == 5 && qlm == 6 && + mode[5] != CVMX_QLM_MODE_RGMII_SGMII_1X1) { + mode[qlm] = CVMX_QLM_MODE_RGMII_SGMII_2X1; + rgmii = true; + } else { + mode[qlm] = CVMX_QLM_MODE_SGMII_2X1; + } + } else { + mode[qlm] = CVMX_QLM_MODE_SGMII; + } + ref_clock_sel[qlm] = 2; + + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + + if (no_phy[qlm]) { + int i; + int start = 0, stop = 2; + + rbgx = 0; + switch (qlm) { + case 3: + rbgx = 1; + case 2: + for (i = 0; i < 4; i++) { + printf("Ignoring PHY for interface: %d, port: %d\n", + rbgx, i); + cvmx_helper_set_port_force_link_up(rbgx, i, true); + } + break; + case 6: + start = 2; + stop = 4; + case 5: + for (i = start; i < stop; i++) { + printf("Ignoring PHY for interface: %d, port: %d\n", + 2, i); + cvmx_helper_set_port_force_link_up(2, i, true); + } + break; + default: + printf("SGMII not supported for QLM/DLM %d\n", + qlm); + break; + } + } + printf("QLM %d: SGMII%s\n", + qlm, rgmii ? ", RGMII" : ""); + } else if (!strncmp(mode_str, "xaui", 4)) { + speed[qlm] = 3125; + mode[qlm] = CVMX_QLM_MODE_XAUI; + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + printf("QLM %d: XAUI\n", qlm); + } else if (!strncmp(mode_str, "dxaui", 5)) { + speed[qlm] = 6250; + mode[qlm] = CVMX_QLM_MODE_XAUI; + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + printf("QLM %d: DXAUI\n", qlm); + } else if (!strncmp(mode_str, "rxaui", 5)) { + bool rgmii = false; + + speed[qlm] = 6250; + if (qlm == 5 || qlm == 6) { + if (rqlm == qlm && qlm == 5) { + mode[qlm] = CVMX_QLM_MODE_RGMII_RXAUI; + rgmii = true; + } else { + mode[qlm] = CVMX_QLM_MODE_RXAUI_1X2; + } + } else { + mode[qlm] = CVMX_QLM_MODE_RXAUI; + } + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + printf("QLM %d: RXAUI%s\n", + qlm, rgmii ? ", rgmii" : ""); + } else if (!strncmp(mode_str, "xlaui", 5)) { + speed[qlm] = 103125; + mode[qlm] = CVMX_QLM_MODE_XLAUI; + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + sprintf(spd_env, "qlm%d_speed", qlm); + if (env_get(spd_env)) { + int spd = env_get_ulong(spd_env, 0, 8); + + if (spd) + speed[qlm] = spd; + else + speed[qlm] = 103125; + } + printf("QLM %d: XLAUI\n", qlm); + } else if (!strncmp(mode_str, "xfi", 3)) { + bool rgmii = false; + + speed[qlm] = 103125; + if (rqlm == qlm) { + mode[qlm] = CVMX_QLM_MODE_RGMII_XFI; + rgmii = true; + } else if (qlm == 5 || qlm == 6) { + mode[qlm] = CVMX_QLM_MODE_XFI_1X2; + } else { + mode[qlm] = CVMX_QLM_MODE_XFI; + } + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + printf("QLM %d: XFI%s\n", qlm, rgmii ? ", RGMII" : ""); + } else if (!strncmp(mode_str, "10G_KR", 6)) { + speed[qlm] = 103125; + if (rqlm == qlm && qlm == 5) + mode[qlm] = CVMX_QLM_MODE_RGMII_10G_KR; + else if (qlm == 5 || qlm == 6) + mode[qlm] = CVMX_QLM_MODE_10G_KR_1X2; + else + mode[qlm] = CVMX_QLM_MODE_10G_KR; + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + printf("QLM %d: 10G_KR\n", qlm); + } else if (!strncmp(mode_str, "40G_KR4", 7)) { + speed[qlm] = 103125; + mode[qlm] = CVMX_QLM_MODE_40G_KR4; + ref_clock_sel[qlm] = 2; + if (qlm == 5 || qlm == 6) + ref_clock_input[qlm] = 2; // use QLMC_REF_CLK1 + printf("QLM %d: 40G_KR4\n", qlm); + } else if (!strcmp(mode_str, "pcie")) { + char *pmode; + int lanes = 0; + + sprintf(env_var, "pcie%d_mode", qlm); + pmode = env_get(env_var); + if (pmode && !strcmp(pmode, "ep")) + pcie_rc[qlm] = 0; + else + pcie_rc[qlm] = 1; + sprintf(env_var, "pcie%d_gen", qlm); + pcie_gen[qlm] = env_get_ulong(env_var, 0, 3); + sprintf(env_var, "pcie%d_lanes", qlm); + lanes = env_get_ulong(env_var, 0, 8); + if (lanes == 8) { + mode[qlm] = CVMX_QLM_MODE_PCIE_1X8; + } else if (qlm == 5 || qlm == 6) { + if (lanes != 2) { + printf("QLM%d: Invalid lanes selected, defaulting to 2 lanes\n", + qlm); + } + mode[qlm] = CVMX_QLM_MODE_PCIE_1X2; + ref_clock_input[qlm] = 1; // use QLMC_REF_CLK0 + } else { + mode[qlm] = CVMX_QLM_MODE_PCIE; + } + ref_clock_sel[qlm] = 0; + printf("QLM %d: PCIe gen%d %s, x%d lanes\n", + qlm, pcie_gen[qlm] + 1, + pcie_rc[qlm] ? "root complex" : "endpoint", + lanes); + } else if (!strcmp(mode_str, "sata")) { + mode[qlm] = CVMX_QLM_MODE_SATA_2X1; + ref_clock_sel[qlm] = 0; + ref_clock_input[qlm] = 1; + sprintf(spd_env, "qlm%d_speed", qlm); + if (env_get(spd_env)) { + int spd = env_get_ulong(spd_env, 0, 8); + + if (spd == 1500 || spd == 3000 || spd == 3000) + speed[qlm] = spd; + else + speed[qlm] = 6000; + } else { + speed[qlm] = 6000; + } + } else { + printf("QLM %d: disabled\n", qlm); + } + } + + for (qlm = 0; qlm < 7; qlm++) { + int rc; + + if (mode[qlm] == -1) + continue; + + debug("Configuring qlm%d with speed(%d), mode(%d), RC(%d), Gen(%d), REF_CLK(%d), CLK_SOURCE(%d)\n", + qlm, speed[qlm], mode[qlm], pcie_rc[qlm], + pcie_gen[qlm] + 1, + ref_clock_sel[qlm], ref_clock_input[qlm]); + rc = octeon_configure_qlm(qlm, speed[qlm], mode[qlm], + pcie_rc[qlm], pcie_gen[qlm], + ref_clock_sel[qlm], + ref_clock_input[qlm]); + + if (speed[qlm] == 6250) { + if (mode[qlm] == CVMX_QLM_MODE_RXAUI) { + octeon_qlm_tune_v3(0, qlm, speed[qlm], 0x12, + 0xa0, -1, -1); + } else { + octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xa, + 0xa0, -1, -1); + } + } else if (speed[qlm] == 103125) { + octeon_qlm_tune_v3(0, qlm, speed[qlm], 0xd, 0xd0, + -1, -1); + } + + if (qlm == 4 && rc != 0) + /* + * There is a bug with SATA with 73xx. Until it's + * fixed we need to strip it from the device tree. + */ + octeon_fdt_patch_rename((void *)gd->fdt_blob, "4,none", + NULL, true, NULL, NULL); + } + + dm_gpio_set_value(&desc, 0); /* Put RGMII PHY in reset */ + mdelay(10); + dm_gpio_set_value(&desc, 1); /* Take RGMII PHY out of reset */ +} + +int board_late_init(void) +{ + board_configure_qlms(); + + return 0; +} diff --git a/board/Marvell/octeon_nic23/Kconfig b/board/Marvell/octeon_nic23/Kconfig new file mode 100644 index 0000000000..3c42e8acda --- /dev/null +++ b/board/Marvell/octeon_nic23/Kconfig @@ -0,0 +1,19 @@ +if TARGET_OCTEON_NIC23 + +config SYS_BOARD + string + default "octeon_nic23" + +config SYS_VENDOR + string + default "Marvell" + +config SYS_CONFIG_NAME + string + default "octeon_nic23" + +config DEFAULT_DEVICE_TREE + string + default "mrvl,octeon-nic23" + +endif diff --git a/board/Marvell/octeon_nic23/MAINTAINERS b/board/Marvell/octeon_nic23/MAINTAINERS new file mode 100644 index 0000000000..cd5148dcfe --- /dev/null +++ b/board/Marvell/octeon_nic23/MAINTAINERS @@ -0,0 +1,7 @@ +OCTEON_NIC23 BOARD +M: Aaron Williams <awilliams@marvell.com> +S: Maintained +F: board/Marvell/octeon_nic23/* +F: configs/octeon_nic23_defconfig +F: include/configs/octeon_nic23.h +F: arch/mips/dts/mrvl,octeon-nic23.dts diff --git a/board/Marvell/octeon_nic23/Makefile b/board/Marvell/octeon_nic23/Makefile new file mode 100644 index 0000000000..a79b94ec6f --- /dev/null +++ b/board/Marvell/octeon_nic23/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2021 Stefan Roese <sr@denx.de> +# Copyright (C) 2019-2020 Marvell International Ltd. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := board.o diff --git a/board/Marvell/octeon_nic23/board.c b/board/Marvell/octeon_nic23/board.c new file mode 100644 index 0000000000..9f5eb2e2a1 --- /dev/null +++ b/board/Marvell/octeon_nic23/board.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Stefan Roese <sr@denx.de> + */ + +#include <dm.h> +#include <ram.h> + +#include <mach/octeon_ddr.h> +#include <mach/cvmx-qlm.h> +#include <mach/octeon_qlm.h> +#include <mach/octeon_fdt.h> +#include <mach/cvmx-helper.h> +#include <mach/cvmx-helper-cfg.h> +#include <mach/cvmx-helper-util.h> +#include <mach/cvmx-bgxx-defs.h> + +#include "board_ddr.h" + +#define NIC23_DEF_DRAM_FREQ 800 + +static u8 octeon_nic23_cfg0_spd_values[512] = { + OCTEON_NIC23_CFG0_SPD_VALUES +}; + +static struct ddr_conf board_ddr_conf[] = { + OCTEON_NIC23_DDR_CONFIGURATION +}; + +struct ddr_conf *octeon_ddr_conf_table_get(int *count, int *def_ddr_freq) +{ + *count = ARRAY_SIZE(board_ddr_conf); + *def_ddr_freq = NIC23_DEF_DRAM_FREQ; + + return board_ddr_conf; +} + +int board_fix_fdt(void *fdt) +{ + u32 range_data[5 * 8]; + bool rev4; + int node; + int rc; + + /* + * ToDo: + * Read rev4 info from EEPROM or where the original U-Boot does + * and don't hard-code it here. + */ + rev4 = true; + + debug("%s() rev4: %s\n", __func__, rev4 ? "true" : "false"); + /* Patch the PHY configuration based on board revision */ + rc = octeon_fdt_patch_rename(fdt, + rev4 ? "4,nor-flash" : "4,no-nor-flash", + "cavium,board-trim", false, NULL, NULL); + if (!rev4) { + /* Modify the ranges for CS 0 */ + node = fdt_node_offset_by_compatible(fdt, -1, + "cavium,octeon-3860-bootbus"); + if (node < 0) { + printf("%s: Error: cannot find boot bus in device tree!\n", + __func__); + return -1; + } + + rc = fdtdec_get_int_array(fdt, node, "ranges", + range_data, 5 * 8); + if (rc) { + printf("%s: Error reading ranges from boot bus FDT\n", + __func__); + return -1; + } + range_data[2] = cpu_to_fdt32(0x10000); + range_data[3] = 0; + range_data[4] = 0; + rc = fdt_setprop(fdt, node, "ranges", range_data, + sizeof(range_data)); + if (rc) { + printf("%s: Error updating boot bus ranges in fdt\n", + __func__); + } + } + return rc; +} + +void board_configure_qlms(void) +{ + octeon_configure_qlm(4, 3000, CVMX_QLM_MODE_SATA_2X1, 0, 0, 0, 0); + octeon_configure_qlm(5, 103125, CVMX_QLM_MODE_XFI_1X2, 0, 0, 2, 0); + /* Apply amplitude tuning to 10G interface */ + octeon_qlm_tune_v3(0, 4, 3000, -1, -1, 7, -1); + octeon_qlm_tune_v3(0, 5, 103125, 0x19, 0x0, -1, -1); + octeon_qlm_set_channel_v3(0, 5, 0); + octeon_qlm_dfe_disable(0, 5, -1, 103125, CVMX_QLM_MODE_XFI_1X2); + debug("QLM 4 reference clock: %d\n" + "DLM 5 reference clock: %d\n", + cvmx_qlm_measure_clock(4), cvmx_qlm_measure_clock(5)); +} + +int board_late_init(void) +{ + board_configure_qlms(); + + return 0; +} diff --git a/board/Marvell/octeon_nic23/board_ddr.h b/board/Marvell/octeon_nic23/board_ddr.h new file mode 100644 index 0000000000..eac877faf8 --- /dev/null +++ b/board/Marvell/octeon_nic23/board_ddr.h @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + * + * https://spdx.org/licenses + */ + +#ifndef __BOARD_DDR_H__ +#define __BOARD_DDR_H__ + +#define OCTEON_NIC23_DRAM_SOCKET_CONFIGURATION0 \ + { {0x0, 0x0}, {octeon_nic23_cfg0_spd_values, NULL} } + +#define NIC23_MTA8ATF51264AZ2G3_SPD_VALUES \ + 0x23, 0x10, 0x0c, 0x02, 0x84, 0x19, 0x00, 0x08, \ + 0x00, 0x00, 0x00, 0x03, 0x01, 0x0b, 0x80, 0x00, \ + 0x00, 0x00, 0x08, 0x0c, 0xf4, 0x1b, 0x00, 0x00, \ + 0x6c, 0x6c, 0x6c, 0x11, 0x08, 0x74, 0x20, 0x08, \ + 0x00, 0x05, 0x70, 0x03, 0x00, 0xa8, 0x1e, 0x2b, \ + 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2c, 0x15, 0x35, \ + 0x15, 0x35, 0x0b, 0x2c, 0x15, 0x35, 0x0b, 0x35, \ + 0x0b, 0x2c, 0x0b, 0x35, 0x15, 0x36, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xb5, 0xce, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x30, 0x0e, \ + 0x11, 0x11, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2e, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x80, 0x2c, 0x0f, 0x14, 0x50, 0x0e, 0x08, 0x18, \ + 0xc8, 0x31, 0x38, 0x41, 0x53, 0x46, 0x31, 0x47, \ + 0x37, 0x32, 0x41, 0x5a, 0x2d, 0x32, 0x47, 0x31, \ + 0x41, 0x31, 0x20, 0x20, 0x20, 0x31, 0x80, 0x2c, \ + 0x41, 0x44, 0x50, 0x41, 0x45, 0x4e, 0x43, 0x39, \ + 0x30, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +#define OCTEON_NIC23_CFG0_SPD_VALUES NIC23_MTA8ATF51264AZ2G3_SPD_VALUES + +#define OCTEON_NIC23_BOARD_EEPROM_TWSI_ADDR 0x56 + +#define OCTEON_NIC23_MODEREG_PARAMS1_1RANK_1SLOT \ +{ \ + .cn78xx = { \ + .pasr_00 = 0, \ + .asr_00 = 0, \ + .srt_00 = 0, \ + .rtt_wr_00 = ddr4_rttwr_80ohm & 3, \ + .rtt_wr_00_ext = (ddr4_rttwr_80ohm >> 2) & 1, \ + .dic_00 = ddr4_dic_34ohm, \ + .rtt_nom_00 = 0, \ + .pasr_01 = 0, \ + .asr_01 = 0, \ + .srt_01 = 0, \ + .rtt_wr_01 = 0, \ + .dic_01 = ddr4_dic_34ohm, \ + .rtt_nom_01 = 0, \ + .pasr_10 = 0, \ + .asr_10 = 0, \ + .srt_10 = 0, \ + .rtt_wr_10 = 0, \ + .dic_10 = ddr4_dic_34ohm, \ + .rtt_nom_10 = 0, \ + .pasr_11 = 0, \ + .asr_11 = 0, \ + .srt_11 = 0, \ + .rtt_wr_11 = 0, \ + .dic_11 = ddr4_dic_34ohm, \ + .rtt_nom_11 = 0, \ + } \ + } + +#define OCTEON_NIC23_MODEREG_PARAMS1_1RANK_2SLOT \ +{ \ + .cn78xx = { \ + .pasr_00 = 0, \ + .asr_00 = 0, \ + .srt_00 = 0, \ + .rtt_wr_00 = ddr4_rttwr_80ohm & 3, \ + .rtt_wr_00_ext = (ddr4_rttwr_80ohm >> 2) & 1, \ + .dic_00 = ddr4_dic_34ohm, \ + .rtt_nom_00 = 0, \ + .pasr_01 = 0, \ + .asr_01 = 0, \ + .srt_01 = 0, \ + .rtt_wr_01 = 0, \ + .dic_01 = ddr4_dic_34ohm, \ + .rtt_nom_01 = 0, \ + .pasr_10 = 0, \ + .asr_10 = 0, \ + .srt_10 = 0, \ + .rtt_wr_10 = ddr4_rttwr_80ohm & 3, \ + .rtt_wr_10_ext = (ddr4_rttwr_80ohm >> 2) & 1, \ + .dic_10 = ddr4_dic_34ohm, \ + .rtt_nom_10 = 0, \ + .pasr_11 = 0, \ + .asr_11 = 0, \ + .srt_11 = 0, \ + .rtt_wr_11 = 0, \ + .dic_11 = ddr4_dic_34ohm, \ + .rtt_nom_11 = 0 \ + } \ +} + +#define OCTEON_NIC23_MODEREG_PARAMS2_1RANK_1SLOT \ +{ \ + .cn78xx = { \ + .rtt_park_00 = ddr4_rttpark_60ohm, \ + .vref_value_00 = 0x22, \ + .vref_range_00 = 0, \ + .rtt_park_01 = 0, \ + .vref_value_01 = 0, \ + .vref_range_01 = 0, \ + .rtt_park_10 = 0, \ + .vref_value_10 = 0, \ + .vref_range_10 = 0, \ + .rtt_park_11 = 0, \ + .vref_value_11 = 0, \ + .vref_range_11 = 0 \ + } \ +} + +#define OCTEON_NIC23_MODEREG_PARAMS2_1RANK_2SLOT \ +{ \ + .cn78xx = { \ + .rtt_park_00 = ddr4_rttpark_48ohm, \ + .vref_value_00 = 0x1f, \ + .vref_range_00 = 0, \ + .rtt_park_01 = 0, \ + .vref_value_01 = 0, \ + .vref_range_01 = 0, \ + .rtt_park_10 = ddr4_rttpark_48ohm, \ + .vref_value_10 = 0x1f, \ + .vref_range_10 = 0, \ + .rtt_park_11 = 0, \ + .vref_value_11 = 0, \ + .vref_range_11 = 0 \ + } \ +} + +#define OCTEON_NIC23_CN73XX_DRAM_ODT_1RANK_CONFIGURATION \ + /* 1 */ \ + { \ + ddr4_dqx_driver_34_ohm, \ + 0x00000000ULL, \ + OCTEON_NIC23_MODEREG_PARAMS1_1RANK_1SLOT, \ + OCTEON_NIC23_MODEREG_PARAMS2_1RANK_1SLOT, \ + ddr4_rodt_ctl_48_ohm, \ + 0x00000000ULL, \ + 0 \ + }, \ + /* 2 */ \ + { \ + ddr4_dqx_driver_34_ohm, \ + 0x00000000ULL, \ + OCTEON_NIC23_MODEREG_PARAMS1_1RANK_2SLOT, \ + OCTEON_NIC23_MODEREG_PARAMS2_1RANK_2SLOT, \ + ddr4_rodt_ctl_80_ohm, \ + 0x00000000ULL, \ + 0 \ + } + +/* + * Construct a static initializer for the ddr_configuration_t variable that + * holds (almost) all of the information required for DDR initialization. + */ + +/* + * The parameters below make up the custom_lmc_config data structure. + * This structure is used to customize the way that the LMC DRAM + * Controller is configured for a particular board design. + * + * Refer to the file lib_octeon_board_table_entry.h for a description + * of the custom board settings. It is usually kept in the following + * location... arch/mips/include/asm/arch-octeon/ + * + */ + +#define OCTEON_NIC23_DDR_CONFIGURATION \ +/* Interface 0 */ \ +{ \ + .custom_lmc_config = { \ + .min_rtt_nom_idx = 2, \ + .max_rtt_nom_idx = 5, \ + .min_rodt_ctl = 2, \ + .max_rodt_ctl = 4, \ + .ck_ctl = ddr4_driver_34_ohm, \ + .cmd_ctl = ddr4_driver_34_ohm, \ + .ctl_ctl = ddr4_driver_34_ohm, \ + .min_cas_latency = 7, \ + .offset_en = 1, \ + .offset_udimm = 2, \ + .offset_rdimm = 2, \ + .ddr_rtt_nom_auto = 0, \ + .ddr_rodt_ctl_auto = 0, \ + .rlevel_compute = 0, \ + .ddr2t_udimm = 1, \ + .ddr2t_rdimm = 1, \ + .maximum_adjacent_rlevel_delay_increment = 2, \ + .fprch2 = 2, \ + .dll_write_offset = NULL, \ + .dll_read_offset = NULL, \ + .disable_sequential_delay_check = 1, \ + .parity = 0 \ + }, \ + .dimm_config_table = { \ + OCTEON_NIC23_DRAM_SOCKET_CONFIGURATION0, \ + DIMM_CONFIG_TERMINATOR \ + }, \ + .unbuffered = { \ + .ddr_board_delay = 0, \ + .lmc_delay_clk = 0, \ + .lmc_delay_cmd = 0, \ + .lmc_delay_dq = 0 \ + }, \ + .registered = { \ + .ddr_board_delay = 0, \ + .lmc_delay_clk = 0, \ + .lmc_delay_cmd = 0, \ + .lmc_delay_dq = 0 \ + }, \ + .odt_1rank_config = { \ + OCTEON_NIC23_CN73XX_DRAM_ODT_1RANK_CONFIGURATION \ + }, \ +}, + +#endif /* __BOARD_DDR_H__ */ |