1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2014 Google, Inc
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Memory Type Range Regsters - these are used to tell the CPU whether
7*4882a593Smuzhiyun * memory is cacheable and if so the cache write mode to use.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * These can speed up booting. See the mtrr command.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Reference: Intel Architecture Software Developer's Manual, Volume 3:
12*4882a593Smuzhiyun * System Programming
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <common.h>
16*4882a593Smuzhiyun #include <asm/io.h>
17*4882a593Smuzhiyun #include <asm/msr.h>
18*4882a593Smuzhiyun #include <asm/mtrr.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /* Prepare to adjust MTRRs */
mtrr_open(struct mtrr_state * state)23*4882a593Smuzhiyun void mtrr_open(struct mtrr_state *state)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun if (!gd->arch.has_mtrr)
26*4882a593Smuzhiyun return;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun state->enable_cache = dcache_status();
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun if (state->enable_cache)
31*4882a593Smuzhiyun disable_caches();
32*4882a593Smuzhiyun state->deftype = native_read_msr(MTRR_DEF_TYPE_MSR);
33*4882a593Smuzhiyun wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype & ~MTRR_DEF_TYPE_EN);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /* Clean up after adjusting MTRRs, and enable them */
mtrr_close(struct mtrr_state * state)37*4882a593Smuzhiyun void mtrr_close(struct mtrr_state *state)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun if (!gd->arch.has_mtrr)
40*4882a593Smuzhiyun return;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN);
43*4882a593Smuzhiyun if (state->enable_cache)
44*4882a593Smuzhiyun enable_caches();
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
mtrr_commit(bool do_caches)47*4882a593Smuzhiyun int mtrr_commit(bool do_caches)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun struct mtrr_request *req = gd->arch.mtrr_req;
50*4882a593Smuzhiyun struct mtrr_state state;
51*4882a593Smuzhiyun uint64_t mask;
52*4882a593Smuzhiyun int i;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (!gd->arch.has_mtrr)
55*4882a593Smuzhiyun return -ENOSYS;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun mtrr_open(&state);
58*4882a593Smuzhiyun for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) {
59*4882a593Smuzhiyun mask = ~(req->size - 1);
60*4882a593Smuzhiyun mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
61*4882a593Smuzhiyun wrmsrl(MTRR_PHYS_BASE_MSR(i), req->start | req->type);
62*4882a593Smuzhiyun wrmsrl(MTRR_PHYS_MASK_MSR(i), mask | MTRR_PHYS_MASK_VALID);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* Clear the ones that are unused */
66*4882a593Smuzhiyun for (; i < MTRR_COUNT; i++)
67*4882a593Smuzhiyun wrmsrl(MTRR_PHYS_MASK_MSR(i), 0);
68*4882a593Smuzhiyun mtrr_close(&state);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun return 0;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
mtrr_add_request(int type,uint64_t start,uint64_t size)73*4882a593Smuzhiyun int mtrr_add_request(int type, uint64_t start, uint64_t size)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct mtrr_request *req;
76*4882a593Smuzhiyun uint64_t mask;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (!gd->arch.has_mtrr)
79*4882a593Smuzhiyun return -ENOSYS;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
82*4882a593Smuzhiyun return -ENOSPC;
83*4882a593Smuzhiyun req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
84*4882a593Smuzhiyun req->type = type;
85*4882a593Smuzhiyun req->start = start;
86*4882a593Smuzhiyun req->size = size;
87*4882a593Smuzhiyun debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1,
88*4882a593Smuzhiyun req->type, req->start, req->size);
89*4882a593Smuzhiyun mask = ~(req->size - 1);
90*4882a593Smuzhiyun mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
91*4882a593Smuzhiyun mask |= MTRR_PHYS_MASK_VALID;
92*4882a593Smuzhiyun debug(" %016llx %016llx\n", req->start | req->type, mask);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96