Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/25370
Change subject: soc/cavium: Implement L2C functions without the need of BDK ......................................................................
soc/cavium: Implement L2C functions without the need of BDK
* Implement functions to handle L2C. * Don't use BDK functions any more. * Flush L2 cache after loading the payload using memmove. Fixes payload booting. TODO: Find out why L2 is not point of unification.
Change-Id: I697de35522af55fa8f40f4502e8245d31d07ba5f Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/soc/cavium/cn81xx/Makefile.inc A src/soc/cavium/cn81xx/include/soc/l2c.h A src/soc/cavium/cn81xx/l2c.c M src/soc/cavium/cn81xx/sdram.c 4 files changed, 426 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/70/25370/1
diff --git a/src/soc/cavium/cn81xx/Makefile.inc b/src/soc/cavium/cn81xx/Makefile.inc index ac4dee2..d4fc57d 100644 --- a/src/soc/cavium/cn81xx/Makefile.inc +++ b/src/soc/cavium/cn81xx/Makefile.inc @@ -38,7 +38,7 @@ romstage-y += spi.c romstage-y += uart.c romstage-$(CONFIG_DRIVERS_UART) += uart.c - +romstage-y += l2c.c romstage-y += sdram.c romstage-y += ../common/cbmem.c romstage-y += ../common/lame_string.c @@ -87,6 +87,7 @@ ramstage-y += uart.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c ramstage-y += sdram.c +ramstage-y += l2c.c
ramstage-y += bl31_plat_params.c #BL31_MAKEARGS += PLAT=qemu M0_CROSS_COMPILE="$(CROSS_COMPILE_arm)" diff --git a/src/soc/cavium/cn81xx/include/soc/l2c.h b/src/soc/cavium/cn81xx/include/soc/l2c.h new file mode 100644 index 0000000..f6e216e --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/l2c.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights + * reserved. + * Copyright 2017-present Facebook, Inc. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SOC_CAVIUM_CN81XX_L2C_H__ +#define __SOC_CAVIUM_CN81XX_L2C_H__ + +#include <arch/cache.h> +#include <inttypes.h> + +struct cn81xx_l2c_tad { + u64 prf; + u8 rsvd0[0xf8]; + u64 pfc; + u8 rsvd1[0xfef8]; + u64 tag; + u64 stat; + u8 rsvd2[0xfff0]; + u64 dll; + u8 rsvd3[0xfff8]; + u64 int_w1c; + u64 int_w1s; + u8 rsvd4[0x10]; + u64 int_ena_w1c; + u64 int_ena_w1s; + u8 rsvd5[0xffd0]; + u64 timetwo; + u8 rsvd6[0xf8]; + u64 timeout; + u8 rsvd7[0xfef8]; + u64 err; + u8 rsvd8[0xf8]; + u64 tqd_err; + u8 rsvd9[0xf8]; + u64 ttg_err; + u8 rsvd10[0xfdf8]; + u64 tbf_bist_status; + u8 rsvd11[0xf8]; + u64 tdt_bist_status; + u8 rsvd12[0xf8]; + u64 ttg_bist_status; +}; +check_member(cn81xx_l2c_tad, ttg_bist_status, 0x70200 - 0x10000); + +#define L2C_TAD_INT_W1C_L2DSBE (1 << 0) +#define L2C_TAD_INT_W1C_L2DDBE (1 << 1) +#define L2C_TAD_INT_W1C_SBFSBE (1 << 2) +#define L2C_TAD_INT_W1C_SBFDBE (1 << 3) +#define L2C_TAD_INT_W1C_FPFSBE (1 << 4) +#define L2C_TAD_INT_W1C_FPFDBE (1 << 5) +#define L2C_TAD_INT_W1C_TAGSBE (1 << 8) +#define L2C_TAD_INT_W1C_TAGDBE (1 << 9) +#define L2C_TAD_INT_W1C_NOWAY (1 << 10) +#define L2C_TAD_INT_W1C_WRNXM (1 << 13) +#define L2C_TAD_INT_W1C_RDNXM (1 << 14) +#define L2C_TAD_INT_W1C_RDDISLMC (1 << 15) +#define L2C_TAD_INT_W1C_WRDISLMC (1 << 16) +#define L2C_TAD_INT_W1C_LFBTO (1 << 17) +#define L2C_TAD_INT_W1C_GSYNCTO (1 << 18) +#define L2C_TAD_INT_W1C_TDDISOCI (1 << 34) +#define L2C_TAD_INT_W1C_WRDISOCI (1 << 35) + + +/* Flush L2 Cache */ +void l2c_flush(void); + +/* Unlock L2 Cache sets */ +size_t l2c_unlock_mem_region(uint64_t start, uint64_t len); + +/* Return the L2 Cache size in bytes */ +size_t l2c_get_cache_size_bytes(void); + +/* Return the number of sets in the L2 Cache */ +size_t l2c_get_num_sets(void); + +/* Return the number of associations in the L2 Cache */ +size_t l2c_get_num_assoc(void); + +#endif /* __SOC_CAVIUM_CN81XX_L2C_H__ */ diff --git a/src/soc/cavium/cn81xx/l2c.c b/src/soc/cavium/cn81xx/l2c.c new file mode 100644 index 0000000..75c106d --- /dev/null +++ b/src/soc/cavium/cn81xx/l2c.c @@ -0,0 +1,337 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights + * reserved. + * Copyright 2018-present Facebook, Inc. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch/cache.h> +#include <inttypes.h> +#include <soc/asm.h> +#include <soc/l2c.h> +#include <arch/io.h> + +#include <console/console.h> +#include <program_loading.h> +#include <libbdk-arch/bdk-asm.h> + +/* Flush L2 Cache */ +void l2c_flush(void) +{ + /* The number of ways can be reduced with fuses, but the equations below + assume the max number of ways */ + const size_t MAX_WAYS = 16; + const size_t num_sets = l2c_get_num_sets(); + const size_t num_ways = l2c_get_num_assoc(); + const size_t cache_line_size = dcache_line_bytes(); + + printk(BIOS_DEBUG, "L2C: flush\n"); + + int is_rtg = 1; /* Clear remote tags */ + for (int l2_way = 0; l2_way < num_ways; l2_way++) { + for (int l2_set = 0; l2_set < num_sets; l2_set++) { + const uint64_t encoded = cache_line_size * + (l2_set + num_sets * (l2_way + (is_rtg * MAX_WAYS))); + BDK_CACHE_WBI_L2_INDEXED(encoded); + } + } + + is_rtg = 0; /* Clear local tags */ + for (int l2_way = 0; l2_way < num_ways; l2_way++) { + for (int l2_set = 0; l2_set < num_sets; l2_set++) { + const uint64_t encoded = cache_line_size * + (l2_set + num_sets * (l2_way + (is_rtg * MAX_WAYS))); + BDK_CACHE_WBI_L2_INDEXED(encoded); + } + } +} + +void platform_segment_loaded(uintptr_t start, size_t size, int flags) +{ +#if ENV_RAMSTAGE + l2c_flush(); +#endif +} + +/* Unlock L2 Cache sets */ +size_t l2c_unlock_mem_region(uint64_t start, uint64_t len) +{ + const size_t cache_line_size = dcache_line_bytes(); + const size_t cache_line_mask = cache_line_size - 1; + + /* Round start/end to cache line boundaries */ + len += start & cache_line_mask; + start &= ~cache_line_mask; + len = (len + cache_line_mask) & ~cache_line_mask; + void *ptr = (void *)start; + + printk(BIOS_DEBUG, "L2C: unlock [%p, %p)\n", ptr, ptr + len); + + while (len > 0) { + /* Must use invalidate version to release lock */ + BDK_CACHE_WBI_L2(ptr); + ptr += cache_line_size; + len -= cache_line_size; + } + + return 0; +} + +/* Return the L2 Cache size in bytes */ +size_t l2c_get_cache_size_bytes(void) +{ + return l2c_get_num_sets() * l2c_get_num_assoc() * + dcache_line_bytes(); +} + +/** + * Register (SYSREG) ap_csselr_el1 + * + * AP Cache Size Selection Register + * Selects the current Cache Size ID Register, AP_CCSIDR_EL1, by specifying the + * required cache level and the cache type (either instruction or data cache). + */ +union bdk_ap_csselr_el1 +{ + uint32_t u; + struct bdk_ap_csselr_el1_s + { + /**< [ 0: 0](R/W) Instruction not Data bit. + * 0 = Data or unified cache. + * 1 = Instruction cache. */ + uint32_t ind : 1; + /**< [ 3: 1](R/W) Cache level of required cache. */ + uint32_t level : 3; + uint32_t reserved_4_31 : 28; + } s; +}; + +/** + * Register (SYSREG) ap_ccsidr_el1 + * + * AP Current Cache Size ID Register + * This register provides information about the architecture of the currently + * selected cache. AP_CSSELR_EL1 selects which Cache Size ID Register is + * accessible. + */ +union bdk_ap_ccsidr_el1 +{ + uint32_t u; + struct bdk_ap_ccsidr_el1_cn81xx + { +/**< [ 2: 0](RO) Cache-line size, in + * (Log2(Number of bytes in cache line)) - 4. + * For CNXXXX, 128 bytes. + */ + uint32_t linesize : 3; + +/**< [ 12: 3](RO) Associativity of cache minus 1, therefore a + * value of 0 indicates an associativity of 1. The associativity + * does not have to be a power of 2. + * For CNXXXX L1D (AP_CSSELR_EL1[LEVEL] = 0x0, AP_CSSELR_EL1[IND] = 0), is 31. + * For CNXXXX L1I (AP_CSSELR_EL1[LEVEL] = 0x0, AP_CSSELR_EL1[IND] = 1), is 38. + * For CN81XX L2 (AP_CSSELR_EL1[LEVEL] = 0x1, AP_CSSELR_EL1[IND] = 0), is 15. + * For CN80XX L2 (AP_CSSELR_EL1[LEVEL] = 0x1, AP_CSSELR_EL1[IND] = 0), is 7. + */ + + uint32_t associativity : 10; +/**< [ 27: 13](RO) Number of sets in cache minus 1, therefore a + * value of 0 indicates 1 set in the cache. The number of sets + * does not have to be a power of 2. + * For CNXXXX L1D (AP_CSSELR_EL1[LEVEL] = 0x0, AP_CSSELR_EL1[IND] = 0), is 7. + * For CNXXXX L1I (AP_CSSELR_EL1[LEVEL] = 0x0, AP_CSSELR_EL1[IND] = 1), is 15. + * For CN81XX L2 (AP_CSSELR_EL1[LEVEL] = 0x1, AP_CSSELR_EL1[IND] = 0), is 1023. + * For CN80XX L2 (AP_CSSELR_EL1[LEVEL] = 0x1, AP_CSSELR_EL1[IND] = 0), is 1023. + */ + uint32_t numsets : 15; + +/**< [ 28: 28](RO) Indicates whether the selected cache level supports + * write-allocation. + * 0 = Write-allocation not supported. + * 1 = Write-allocation supported. + * For CNXXXX does not apply as hardware managed coherence. + */ + uint32_t wa : 1; + +/**< [ 29: 29](RO) Indicates whether the selected cache level supports + * read-allocation. + * 0 = Read-allocation not supported. + * 1 = Read-allocation supported. + * For CNXXXX does not apply as hardware managed coherence. + */ + uint32_t ra : 1; + +/**< [ 30: 30](RO) Indicates whether the selected cache level supports + * write-back. + * 0 = Write-back not supported. + * 1 = Write-back supported. + * For CNXXXX does not apply as hardware managed coherence. + */ + uint32_t wb : 1; + +/**< [ 31: 31](RO) Indicates whether the selected cache level supports + * write-through. + * 0 = Write-through not supported. + * 1 = Write-through supported. + * For CNXXXX does not apply as hardware managed coherence. + */ + uint32_t wt : 1; + } s; +}; + + +/* Return the number of sets in the L2 Cache */ +size_t l2c_get_num_sets(void) +{ + /* Select the L2 cache */ + union bdk_ap_csselr_el1 csselr_el1; + csselr_el1.u = 0; + csselr_el1.s.ind = 0; + csselr_el1.s.level = 1; + BDK_MSR(CSSELR_EL1, csselr_el1.u); + /* Read its size */ + union bdk_ap_ccsidr_el1 ccsidr_el1; + BDK_MRS(CCSIDR_EL1, ccsidr_el1.u); + + printk(BIOS_DEBUG, "L2C: num sets %u\n", ccsidr_el1.s.numsets + 1); + + return ccsidr_el1.s.numsets + 1; +} + +// FIXME: Move to fuse.c +#define MIO_FUS_DAT3 0x87e003001418ll + +/** + * Register (RSL) mio_fus_dat3 + * + * MIO Fuse Data3 Register + */ +union cavm_mio_fus_dat3 +{ + uint64_t u; + struct cavm_mio_fus_dat3_cn81xx { +/**< [ 3: 0](RO) Coprocessor-clock PLL multiplier hardware limit. Indicates + * maximum value for PNR_MUL[5:1] straps. Any strap setting above this value + * will be ignored. A value of 0 indicates no hardware limit. + */ + uint64_t pnr_pll_mul : 4; +/**< [ 8: 4](RO) Core-clock PLL multiplier hardware limit. Indicates maximum + * value for PLL_MUL[5:1] straps. Any strap setting above this value will be + * ignored. A value of 0 indicates no hardware limit. + */ + uint64_t core_pll_mul : 5; +/**< [ 9: 9](RO) Reserved. + * Internal: + * When set to 1, TNS switching functionality is permanently disabled. + */ + uint64_t tns_cripple : 1; +/**< [ 13: 10](RO) Fuse information - HNA information (cluster mask). */ + uint64_t hna_info_clm : 4; +/**< [ 16: 14](RO) Fuse information - HNA information (DTE). */ + uint64_t hna_info_dte : 3; +/**< [ 17: 17](RO) Fuse information - HNA disable (DTE). */ + uint64_t nohna_dte : 1; +/**< [ 23: 18](RO) Fuse information - EMA1. + * Internal: + * Default value is 0x02. Soft or hard blow of these fuses will XOR with this + * value. + */ + uint64_t ema1 : 6; +/**< [ 24: 24](RO) Fuse information - HFA disable (HTE). */ + uint64_t nodfa_dte : 1; +/**< [ 25: 25](RO) Fuse information - ZIP disable. */ + uint64_t nozip : 1; +/**< [ 26: 26](RO) Fuse information - efuse ignore. */ + uint64_t efus_ign : 1; +/**< [ 27: 27](RO) Fuse information - efuse lockdown. */ + uint64_t efus_lck : 1; +/**< [ 28: 28](RO) Fuse information - When 0, BAR2 size conforms to PCIe + * specification. */ + uint64_t bar2_sz_conf : 1; +/**< [ 30: 29](RO) Fuse information - ZIP information. */ + uint64_t zip_info : 2; +/**< [ 31: 31](RO) If set, use the PLL output as the low-jitter reference clock + * to the rclk DLLs. Default is to use the internal input reference clock. */ + uint64_t use_int_refclk : 1; +/**< [ 34: 32](RO) Fuse information - L2C cripple: + * 0x0 = Full cache (16-way, 2 MB). + * 0x1 = 3/4 ways (12-way, 1.5 MB). + * 0x2 = 1/2 ways (8-way, 1 MB). + * 0x3 = 1/4 ways (4-way, 512 KB). + * 0x4-0x7 = Reserved. + */ + uint64_t l2c_crip : 3; +/**< [ 35: 35](RO/H) Fuse information - coprocessor-clock PLL control. */ + uint64_t pll_half_dis : 1; +/**< [ 36: 36](RO) Fuse information - efuse lockdown. */ + uint64_t efus_lck_man : 1; +/**< [ 37: 37](RO) Fuse information - efuse lockdown. */ + uint64_t efus_lck_rsv : 1; +/**< [ 39: 38](RO) Select CLKF denominator for BWADJ value. + * 0x0 = Selects CLKF/4. + * 0x1 = Selects CLKF/2. + * 0x2 = Selects CLKF/8. + */ + uint64_t pll_bwadj_denom : 2; +/**< [ 40: 40](RO) Fuse information - Select alternate PLL matrix. */ + uint64_t pll_alt_matrix : 1; +/**< [ 44: 41](RO) Fuse information - HFA information (cluster mask). */ + uint64_t dfa_info_clm : 4; +/**< [ 47: 45](RO) Fuse information - HFA information (HTE). */ + uint64_t dfa_info_dte : 3; +/**< [ 57: 48](RO) Reserved. */ + uint64_t pll_ctl : 10; +/**< [ 63: 58](RO) Fuse information - EMA0. + * Internal: + * Default value is 0x11. Soft or hard blow of these fuses will XOR with this + * value. + */ + uint64_t ema0 : 6; + } s; +}; + +/* Return the number of associations in the L2 Cache */ +size_t l2c_get_num_assoc(void) +{ + /* Select the L2 cache */ + union bdk_ap_csselr_el1 csselr_el1; + csselr_el1.u = 0; + csselr_el1.s.ind = 0; + csselr_el1.s.level = 1; + BDK_MSR(CSSELR_EL1, csselr_el1.u); + /* Read its size */ + union bdk_ap_ccsidr_el1 ccsidr_el1; + BDK_MRS(CCSIDR_EL1, ccsidr_el1.u); + /* Store it for use later */ + size_t ways = ccsidr_el1.s.associativity + 1; + + /* Early chips didn't update the number of ways based on fusing */ + if (ways == 16) { + /* The l2 can be reduced in 25% increments */ + union cavm_mio_fus_dat3 mio_fus_dat3; + mio_fus_dat3.u = read64((u64 *)MIO_FUS_DAT3); + switch (mio_fus_dat3.s.l2c_crip) { + case 3: /* 1/4 size */ + ways *= 1; + break; + case 2: /* 1/2 size */ + ways *= 2; + break; + case 1: /* 3/4 size */ + ways *= 3; + break; + default: /* Full size */ + ways *= 4; + break; + } + ways /= 4; + } + + printk(BIOS_DEBUG, "L2C: num ways %zu\n", ways); + + return ways; +} + diff --git a/src/soc/cavium/cn81xx/sdram.c b/src/soc/cavium/cn81xx/sdram.c index b6b42f7..420f1b0 100644 --- a/src/soc/cavium/cn81xx/sdram.c +++ b/src/soc/cavium/cn81xx/sdram.c @@ -15,6 +15,7 @@
#include <console/console.h> #include <soc/sdram.h> +#include <soc/l2c.h> #include <cbfs.h>
#include <soc/bdk/libbdk-arch/bdk-warn.h> @@ -89,13 +90,9 @@ }
/* Unlock L2 now that DRAM works */ - if (node == bdk_numa_master()) - { - uint64_t l2_size = bdk_l2c_get_cache_size_bytes(node); - BDK_TRACE(INIT, "Unlocking L2\n"); - bdk_l2c_unlock_mem_region(node, 0, l2_size); - bdk_watchdog_poke(); - } + size_t l2_size = l2c_get_cache_size_bytes(); + l2c_unlock_mem_region(0, l2_size); + bdk_watchdog_poke();
printk(BIOS_INFO, "SDRAM initialization finished.\n"); }