mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	With the newly added headers and their restructuring (which macro is defined where), some changes in the already existing Octeon files are necessary. This patch makes the necessary changes. Signed-off-by: Stefan Roese <sr@denx.de>
		
			
				
	
	
		
			368 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * Copyright (C) 2018-2020 Marvell International Ltd.
 | 
						|
 */
 | 
						|
 | 
						|
#include <env.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#include <linux/compat.h>
 | 
						|
#include <linux/ctype.h>
 | 
						|
 | 
						|
#include <mach/cvmx-regs.h>
 | 
						|
#include <mach/cvmx-coremask.h>
 | 
						|
#include <mach/cvmx-fuse.h>
 | 
						|
#include <mach/octeon-model.h>
 | 
						|
#include <mach/octeon-feature.h>
 | 
						|
#include <mach/cvmx-ciu-defs.h>
 | 
						|
 | 
						|
struct cvmx_coremask *get_coremask_override(struct cvmx_coremask *pcm)
 | 
						|
{
 | 
						|
	struct cvmx_coremask pcm_override = CVMX_COREMASK_MAX;
 | 
						|
	char *cptr;
 | 
						|
 | 
						|
	/* The old code sets the number of cores to be to 16 in this case. */
 | 
						|
	cvmx_coremask_set_cores(pcm, 0, 16);
 | 
						|
 | 
						|
	if (OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3())
 | 
						|
		cvmx_coremask_copy(pcm, &pcm_override);
 | 
						|
 | 
						|
	cptr = env_get("coremask_override");
 | 
						|
	if (cptr) {
 | 
						|
		if (cvmx_coremask_str2bmp(pcm, cptr) < 0)
 | 
						|
			return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return pcm;
 | 
						|
}
 | 
						|
 | 
						|
/* Validate the coremask that is passed to a boot* function. */
 | 
						|
int validate_coremask(struct cvmx_coremask *pcm)
 | 
						|
{
 | 
						|
	struct cvmx_coremask coremask_override;
 | 
						|
	struct cvmx_coremask fuse_coremask;
 | 
						|
 | 
						|
	if (!get_coremask_override(&coremask_override))
 | 
						|
		return -1;
 | 
						|
 | 
						|
	octeon_get_available_coremask(&fuse_coremask);
 | 
						|
 | 
						|
	if (!cvmx_coremask_is_subset(&fuse_coremask, pcm)) {
 | 
						|
		puts("ERROR: Can't boot cores that don't exist!\n");
 | 
						|
		puts("Available coremask:\n");
 | 
						|
		cvmx_coremask_print(&fuse_coremask);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!cvmx_coremask_is_subset(&coremask_override, pcm)) {
 | 
						|
		struct cvmx_coremask print_cm;
 | 
						|
 | 
						|
		puts("Notice: coremask changed from:\n");
 | 
						|
		cvmx_coremask_print(pcm);
 | 
						|
		puts("based on coremask_override of:\n");
 | 
						|
		cvmx_coremask_print(&coremask_override);
 | 
						|
		cvmx_coremask_and(&print_cm, pcm, &coremask_override);
 | 
						|
		puts("to:\n");
 | 
						|
		cvmx_coremask_print(&print_cm);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * In CIU_FUSE for the 78XX, odd and even cores are separated out.
 | 
						|
 * For example, a CIU_FUSE value of 0xfffffefffffe indicates that bits 0 and 1
 | 
						|
 * are set.
 | 
						|
 * This function converts the bit number in the CIU_FUSE register to a
 | 
						|
 * physical core number.
 | 
						|
 */
 | 
						|
static int convert_ciu_fuse_to_physical_core(int core, int max_cores)
 | 
						|
{
 | 
						|
	if (!octeon_has_feature(OCTEON_FEATURE_CIU3))
 | 
						|
		return core;
 | 
						|
	else if (!OCTEON_IS_MODEL(OCTEON_CN78XX))
 | 
						|
		return core;
 | 
						|
	else if (core < (max_cores / 2))
 | 
						|
		return core * 2;
 | 
						|
	else
 | 
						|
		return ((core - (max_cores / 2)) * 2) + 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Get the total number of fuses blown as well as the number blown per tad.
 | 
						|
 *
 | 
						|
 * @param	coremask	fuse coremask
 | 
						|
 * @param[out]	tad_blown_count	number of cores blown for each tad
 | 
						|
 * @param	num_tads	number of tads
 | 
						|
 * @param	max_cores	maximum number of cores
 | 
						|
 *
 | 
						|
 * @return	void
 | 
						|
 */
 | 
						|
void fill_tad_corecount(u64 coremask, int tad_blown_count[], int num_tads,
 | 
						|
			int max_cores)
 | 
						|
{
 | 
						|
	int core, physical_core;
 | 
						|
 | 
						|
	for (core = 0; core < max_cores; core++) {
 | 
						|
		if (!(coremask & (1ULL << core))) {
 | 
						|
			int tad;
 | 
						|
 | 
						|
			physical_core =
 | 
						|
				convert_ciu_fuse_to_physical_core(core,
 | 
						|
								  max_cores);
 | 
						|
			tad = physical_core % num_tads;
 | 
						|
			tad_blown_count[tad]++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
u64 get_core_pattern(int num_tads, int max_cores)
 | 
						|
{
 | 
						|
	u64 pattern = 1ULL;
 | 
						|
	int cnt;
 | 
						|
 | 
						|
	for (cnt = 1; cnt < (max_cores / num_tads); cnt++)
 | 
						|
		pattern |= pattern << num_tads;
 | 
						|
 | 
						|
	return pattern;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * For CN78XX and CN68XX this function returns the logical coremask from the
 | 
						|
 * CIU_FUSE register value. For other models there is no difference.
 | 
						|
 *
 | 
						|
 * @param ciu_fuse_value	fuse value from CIU_FUSE register
 | 
						|
 * @return logical coremask of CIU_FUSE value.
 | 
						|
 */
 | 
						|
u64 get_logical_coremask(u64 ciu_fuse_value)
 | 
						|
{
 | 
						|
	int tad_blown_count[MAX_CORE_TADS] = {0};
 | 
						|
	int tad;
 | 
						|
	u64 logical_coremask = 0;
 | 
						|
	u64 tad_mask, pattern;
 | 
						|
	int num_tads, max_cores;
 | 
						|
 | 
						|
	if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
 | 
						|
		num_tads = 8;
 | 
						|
		max_cores = 48;
 | 
						|
	} else if (OCTEON_IS_MODEL(OCTEON_CN73XX) ||
 | 
						|
		   OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
 | 
						|
		num_tads = 4;
 | 
						|
		max_cores = 16;
 | 
						|
	} else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
 | 
						|
		num_tads = 4;
 | 
						|
		max_cores = 32;
 | 
						|
	} else {
 | 
						|
		/* Most Octeon devices don't need any mapping. */
 | 
						|
		return ciu_fuse_value;
 | 
						|
	}
 | 
						|
 | 
						|
	pattern = get_core_pattern(num_tads, max_cores);
 | 
						|
	fill_tad_corecount(ciu_fuse_value, tad_blown_count,
 | 
						|
			   num_tads, max_cores);
 | 
						|
 | 
						|
	for (tad = 0; tad < num_tads; tad++) {
 | 
						|
		tad_mask = pattern << tad;
 | 
						|
		logical_coremask |= tad_mask >> (tad_blown_count[tad] * num_tads);
 | 
						|
	}
 | 
						|
	return logical_coremask;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the available coremask either from env or fuses.
 | 
						|
 * If the fuses are blown and locked, they are the definitive coremask.
 | 
						|
 *
 | 
						|
 * @param pcm	pointer to coremask to fill in
 | 
						|
 * @return pointer to coremask
 | 
						|
 */
 | 
						|
struct cvmx_coremask *octeon_get_available_coremask(struct cvmx_coremask *pcm)
 | 
						|
{
 | 
						|
	u8 node_mask = 0x01;	/* ToDo: Currently only one node is supported */
 | 
						|
	u64 ciu_fuse;
 | 
						|
	u64 cores;
 | 
						|
 | 
						|
	cvmx_coremask_clear_all(pcm);
 | 
						|
 | 
						|
	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
 | 
						|
		int node;
 | 
						|
 | 
						|
		cvmx_coremask_for_each_node(node, node_mask) {
 | 
						|
			ciu_fuse = (csr_rd(CVMX_CIU_FUSE) &
 | 
						|
				    0x0000FFFFFFFFFFFFULL);
 | 
						|
 | 
						|
			ciu_fuse = get_logical_coremask(ciu_fuse);
 | 
						|
			cvmx_coremask_set64_node(pcm, node, ciu_fuse);
 | 
						|
		}
 | 
						|
 | 
						|
		return pcm;
 | 
						|
	}
 | 
						|
 | 
						|
	ciu_fuse = (csr_rd(CVMX_CIU_FUSE) & 0x0000FFFFFFFFFFFFULL);
 | 
						|
	ciu_fuse = get_logical_coremask(ciu_fuse);
 | 
						|
 | 
						|
	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
 | 
						|
		cvmx_coremask_set64(pcm, ciu_fuse);
 | 
						|
 | 
						|
	/* Get number of cores from fuse register, convert to coremask */
 | 
						|
	cores = __builtin_popcountll(ciu_fuse);
 | 
						|
 | 
						|
	cvmx_coremask_set_cores(pcm, 0, cores);
 | 
						|
 | 
						|
	return pcm;
 | 
						|
}
 | 
						|
 | 
						|
int cvmx_coremask_str2bmp(struct cvmx_coremask *pcm, char *hexstr)
 | 
						|
{
 | 
						|
	int i, j;
 | 
						|
	int l;		/* length of the hexstr in characters */
 | 
						|
	int lb;		/* number of bits taken by hexstr */
 | 
						|
	int hldr_offset;/* holder's offset within the coremask */
 | 
						|
	int hldr_xsz;	/* holder's size in the number of hex digits */
 | 
						|
	u64 h;
 | 
						|
	char c;
 | 
						|
 | 
						|
#define MINUS_ONE (hexstr[0] == '-' && hexstr[1] == '1' && hexstr[2] == 0)
 | 
						|
	if (MINUS_ONE) {
 | 
						|
		cvmx_coremask_set_all(pcm);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Skip '0x' from hexstr */
 | 
						|
	if (hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] == 'X'))
 | 
						|
		hexstr += 2;
 | 
						|
 | 
						|
	if (!strlen(hexstr)) {
 | 
						|
		printf("%s: Error: hex string is empty\n", __func__);
 | 
						|
		return -2;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Trim leading zeros */
 | 
						|
	while (*hexstr == '0')
 | 
						|
		hexstr++;
 | 
						|
 | 
						|
	cvmx_coremask_clear_all(pcm);
 | 
						|
	l = strlen(hexstr);
 | 
						|
 | 
						|
	/* If length is 0 then the hex string must be all zeros */
 | 
						|
	if (l == 0)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	for (i = 0; i < l; i++) {
 | 
						|
		if (isxdigit((int)hexstr[i]) == 0) {
 | 
						|
			printf("%s: Non-hex digit within hexstr\n", __func__);
 | 
						|
			return -2;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	lb = (l - 1) * 4;
 | 
						|
	if (hexstr[0] > '7')
 | 
						|
		lb += 4;
 | 
						|
	else if (hexstr[0] > '3')
 | 
						|
		lb += 3;
 | 
						|
	else if (hexstr[0] > '1')
 | 
						|
		lb += 2;
 | 
						|
	else
 | 
						|
		lb += 1;
 | 
						|
	if (lb > CVMX_MIPS_MAX_CORES) {
 | 
						|
		printf("%s: hexstr (%s) is too long\n", __func__, hexstr);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	hldr_offset = 0;
 | 
						|
	hldr_xsz = 2 * sizeof(u64);
 | 
						|
	for (i = l; i > 0; i -= hldr_xsz) {
 | 
						|
		c = hexstr[i];
 | 
						|
		hexstr[i] = 0;
 | 
						|
		j = i - hldr_xsz;
 | 
						|
		if (j < 0)
 | 
						|
			j = 0;
 | 
						|
		h = simple_strtoull(&hexstr[j], NULL, 16);
 | 
						|
		if (errno == EINVAL) {
 | 
						|
			printf("%s: strtou returns w/ EINVAL\n", __func__);
 | 
						|
			return -2;
 | 
						|
		}
 | 
						|
		pcm->coremask_bitmap[hldr_offset] = h;
 | 
						|
		hexstr[i] = c;
 | 
						|
		hldr_offset++;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void cvmx_coremask_print(const struct cvmx_coremask *pcm)
 | 
						|
{
 | 
						|
	int i, j;
 | 
						|
	int start;
 | 
						|
	int found = 0;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Print one node per line. Since the bitmap is stored LSB to MSB
 | 
						|
	 * we reverse the order when printing.
 | 
						|
	 */
 | 
						|
	if (!octeon_has_feature(OCTEON_FEATURE_MULTINODE)) {
 | 
						|
		start = 0;
 | 
						|
		for (j = CVMX_COREMASK_MAX_CORES_PER_NODE -
 | 
						|
			     CVMX_COREMASK_HLDRSZ;
 | 
						|
		     j >= 0; j -= CVMX_COREMASK_HLDRSZ) {
 | 
						|
			if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0)
 | 
						|
				start = 1;
 | 
						|
			if (start) {
 | 
						|
				printf(" 0x%llx",
 | 
						|
				       (u64)pcm->coremask_bitmap[j /
 | 
						|
						CVMX_COREMASK_HLDRSZ]);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (start)
 | 
						|
			found = 1;
 | 
						|
 | 
						|
		/*
 | 
						|
		 * If the coremask is empty print <EMPTY> so it is not
 | 
						|
		 * confusing
 | 
						|
		 */
 | 
						|
		if (!found)
 | 
						|
			printf("<EMPTY>");
 | 
						|
		printf("\n");
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < CVMX_MAX_USED_CORES_BMP;
 | 
						|
	     i += CVMX_COREMASK_MAX_CORES_PER_NODE) {
 | 
						|
		printf("%s  node %d:", i > 0 ? "\n" : "",
 | 
						|
		       cvmx_coremask_core_to_node(i));
 | 
						|
		start = 0;
 | 
						|
 | 
						|
		for (j = i + CVMX_COREMASK_MAX_CORES_PER_NODE -
 | 
						|
			     CVMX_COREMASK_HLDRSZ;
 | 
						|
		     j >= i;
 | 
						|
		     j -= CVMX_COREMASK_HLDRSZ) {
 | 
						|
			/* Don't start printing until we get a non-zero word. */
 | 
						|
			if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0)
 | 
						|
				start = 1;
 | 
						|
 | 
						|
			if (start) {
 | 
						|
				printf(" 0x%llx", (u64)pcm->coremask_bitmap[j /
 | 
						|
							CVMX_COREMASK_HLDRSZ]);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (start)
 | 
						|
			found = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	i /= CVMX_COREMASK_HLDRSZ;
 | 
						|
	for (; i < CVMX_COREMASK_BMPSZ; i++) {
 | 
						|
		if (pcm->coremask_bitmap[i]) {
 | 
						|
			printf("  EXTRA GARBAGE[%i]: %016llx\n", i,
 | 
						|
			       (u64)pcm->coremask_bitmap[i]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* If the coremask is empty print <EMPTY> so it is not confusing */
 | 
						|
	if (!found)
 | 
						|
		printf("<EMPTY>");
 | 
						|
 | 
						|
	printf("\n");
 | 
						|
}
 |