1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2014 Google, Inc
4 */
5
6#include <common.h>
7#include <command.h>
8#include <log.h>
9#include <asm/msr.h>
10#include <asm/mp.h>
11#include <asm/mtrr.h>
12
13static int do_mtrr_set(int cpu_select, uint reg, int argc, char *const argv[])
14{
15	const char *typename = argv[0];
16	uint32_t start, size;
17	uint64_t base, mask;
18	int type = -1;
19	bool valid;
20	int ret;
21
22	if (argc < 3)
23		return CMD_RET_USAGE;
24	type = mtrr_get_type_by_name(typename);
25	if (type < 0) {
26		printf("Invalid type name %s\n", typename);
27		return CMD_RET_USAGE;
28	}
29	start = hextoul(argv[1], NULL);
30	size = hextoul(argv[2], NULL);
31
32	base = start | type;
33	valid = native_read_msr(MTRR_PHYS_MASK_MSR(reg)) & MTRR_PHYS_MASK_VALID;
34	mask = ~((uint64_t)size - 1);
35	mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
36	if (valid)
37		mask |= MTRR_PHYS_MASK_VALID;
38
39	ret = mtrr_set(cpu_select, reg, base, mask);
40	if (ret)
41		return CMD_RET_FAILURE;
42
43	return 0;
44}
45
46static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc,
47		   char *const argv[])
48{
49	int reg_count = mtrr_get_var_count();
50	int cmd;
51	int cpu_select;
52	uint reg;
53	int ret;
54
55	cpu_select = MP_SELECT_BSP;
56	if (argc >= 3 && !strcmp("-c", argv[1])) {
57		const char *cpustr;
58
59		cpustr = argv[2];
60		if (*cpustr == 'a')
61			cpu_select = MP_SELECT_ALL;
62		else
63			cpu_select = simple_strtol(cpustr, NULL, 16);
64		argc -= 2;
65		argv += 2;
66	}
67	argc--;
68	argv++;
69	cmd = argv[0] ? *argv[0] : 0;
70	if (argc < 1 || !cmd) {
71		cmd = 'l';
72		reg = 0;
73	}
74	if (cmd != 'l') {
75		if (argc < 2)
76			return CMD_RET_USAGE;
77		reg = hextoul(argv[1], NULL);
78		if (reg >= reg_count) {
79			printf("Invalid register number\n");
80			return CMD_RET_USAGE;
81		}
82	}
83	if (cmd == 'l') {
84		bool first;
85		int i;
86
87		i = mp_first_cpu(cpu_select);
88		if (i < 0) {
89			printf("Invalid CPU (err=%d)\n", i);
90			return CMD_RET_FAILURE;
91		}
92		first = true;
93		for (; i >= 0; i = mp_next_cpu(cpu_select, i)) {
94			if (!first)
95				printf("\n");
96			printf("CPU %d:\n", i);
97			ret = mtrr_list(reg_count, i);
98			if (ret) {
99				printf("Failed to read CPU %s (err=%d)\n",
100				       i < MP_SELECT_ALL ? simple_itoa(i) : "",
101				       ret);
102				return CMD_RET_FAILURE;
103			}
104			first = false;
105		}
106	} else {
107		switch (cmd) {
108		case 'e':
109			ret = mtrr_set_valid(cpu_select, reg, true);
110			break;
111		case 'd':
112			ret = mtrr_set_valid(cpu_select, reg, false);
113			break;
114		case 's':
115			ret = do_mtrr_set(cpu_select, reg, argc - 2, argv + 2);
116			break;
117		default:
118			return CMD_RET_USAGE;
119		}
120		if (ret) {
121			printf("Operation failed (err=%d)\n", ret);
122			return CMD_RET_FAILURE;
123		}
124	}
125
126	return 0;
127}
128
129U_BOOT_CMD(
130	mtrr,	8,	1,	do_mtrr,
131	"Use x86 memory type range registers (32-bit only)",
132	"[list]        - list current registers\n"
133	"set <reg> <type> <start> <size>   - set a register\n"
134	"\t<type> is Uncacheable, Combine, Through, Protect, Back\n"
135	"disable <reg>      - disable a register\n"
136	"enable <reg>       - enable a register\n"
137	"\n"
138	"Precede command with '-c <n>|all' to access a particular hex CPU, e.g.\n"
139	"   mtrr -c all list; mtrr -c 2e list"
140);
141