]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
aff2523f SG |
2 | /* |
3 | * (C) Copyright 2014 Google, Inc | |
4 | * | |
aff2523f SG |
5 | * Memory Type Range Regsters - these are used to tell the CPU whether |
6 | * memory is cacheable and if so the cache write mode to use. | |
7 | * | |
8 | * These can speed up booting. See the mtrr command. | |
9 | * | |
10 | * Reference: Intel Architecture Software Developer's Manual, Volume 3: | |
11 | * System Programming | |
12 | */ | |
13 | ||
590cee83 SG |
14 | /* |
15 | * Note that any console output (e.g. debug()) in this file will likely fail | |
16 | * since the MTRR registers are sometimes in flux. | |
17 | */ | |
18 | ||
aff2523f | 19 | #include <common.h> |
9edefc27 | 20 | #include <cpu_func.h> |
90526e9f | 21 | #include <asm/cache.h> |
aff2523f SG |
22 | #include <asm/io.h> |
23 | #include <asm/msr.h> | |
24 | #include <asm/mtrr.h> | |
25 | ||
566d1754 BM |
26 | DECLARE_GLOBAL_DATA_PTR; |
27 | ||
aff2523f | 28 | /* Prepare to adjust MTRRs */ |
590cee83 | 29 | void mtrr_open(struct mtrr_state *state, bool do_caches) |
aff2523f | 30 | { |
3b621cca BM |
31 | if (!gd->arch.has_mtrr) |
32 | return; | |
33 | ||
590cee83 SG |
34 | if (do_caches) { |
35 | state->enable_cache = dcache_status(); | |
aff2523f | 36 | |
590cee83 SG |
37 | if (state->enable_cache) |
38 | disable_caches(); | |
39 | } | |
aff2523f SG |
40 | state->deftype = native_read_msr(MTRR_DEF_TYPE_MSR); |
41 | wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype & ~MTRR_DEF_TYPE_EN); | |
42 | } | |
43 | ||
44 | /* Clean up after adjusting MTRRs, and enable them */ | |
590cee83 | 45 | void mtrr_close(struct mtrr_state *state, bool do_caches) |
aff2523f | 46 | { |
3b621cca BM |
47 | if (!gd->arch.has_mtrr) |
48 | return; | |
49 | ||
aff2523f | 50 | wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN); |
590cee83 | 51 | if (do_caches && state->enable_cache) |
aff2523f SG |
52 | enable_caches(); |
53 | } | |
54 | ||
6ccb2f89 SG |
55 | static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size) |
56 | { | |
57 | u64 mask; | |
58 | ||
59 | wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type); | |
60 | mask = ~(size - 1); | |
61 | mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; | |
62 | wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID); | |
63 | } | |
64 | ||
aff2523f SG |
65 | int mtrr_commit(bool do_caches) |
66 | { | |
67 | struct mtrr_request *req = gd->arch.mtrr_req; | |
68 | struct mtrr_state state; | |
aff2523f SG |
69 | int i; |
70 | ||
590cee83 SG |
71 | debug("%s: enabled=%d, count=%d\n", __func__, gd->arch.has_mtrr, |
72 | gd->arch.mtrr_req_count); | |
3b621cca BM |
73 | if (!gd->arch.has_mtrr) |
74 | return -ENOSYS; | |
75 | ||
590cee83 SG |
76 | debug("open\n"); |
77 | mtrr_open(&state, do_caches); | |
78 | debug("open done\n"); | |
6ccb2f89 SG |
79 | for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) |
80 | set_var_mtrr(i, req->type, req->start, req->size); | |
aff2523f SG |
81 | |
82 | /* Clear the ones that are unused */ | |
590cee83 | 83 | debug("clear\n"); |
aff2523f SG |
84 | for (; i < MTRR_COUNT; i++) |
85 | wrmsrl(MTRR_PHYS_MASK_MSR(i), 0); | |
590cee83 SG |
86 | debug("close\n"); |
87 | mtrr_close(&state, do_caches); | |
88 | debug("mtrr done\n"); | |
aff2523f SG |
89 | |
90 | return 0; | |
91 | } | |
92 | ||
93 | int mtrr_add_request(int type, uint64_t start, uint64_t size) | |
94 | { | |
95 | struct mtrr_request *req; | |
96 | uint64_t mask; | |
97 | ||
590cee83 | 98 | debug("%s: count=%d\n", __func__, gd->arch.mtrr_req_count); |
3b621cca BM |
99 | if (!gd->arch.has_mtrr) |
100 | return -ENOSYS; | |
101 | ||
aff2523f SG |
102 | if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS) |
103 | return -ENOSPC; | |
104 | req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++]; | |
105 | req->type = type; | |
106 | req->start = start; | |
107 | req->size = size; | |
108 | debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1, | |
109 | req->type, req->start, req->size); | |
110 | mask = ~(req->size - 1); | |
111 | mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; | |
112 | mask |= MTRR_PHYS_MASK_VALID; | |
113 | debug(" %016llx %016llx\n", req->start | req->type, mask); | |
114 | ||
115 | return 0; | |
116 | } | |
add3f4c9 SG |
117 | |
118 | static int get_var_mtrr_count(void) | |
119 | { | |
120 | return msr_read(MSR_MTRR_CAP_MSR).lo & MSR_MTRR_CAP_VCNT; | |
121 | } | |
122 | ||
123 | static int get_free_var_mtrr(void) | |
124 | { | |
125 | struct msr_t maskm; | |
126 | int vcnt; | |
127 | int i; | |
128 | ||
129 | vcnt = get_var_mtrr_count(); | |
130 | ||
131 | /* Identify the first var mtrr which is not valid */ | |
132 | for (i = 0; i < vcnt; i++) { | |
133 | maskm = msr_read(MTRR_PHYS_MASK_MSR(i)); | |
134 | if ((maskm.lo & MTRR_PHYS_MASK_VALID) == 0) | |
135 | return i; | |
136 | } | |
137 | ||
138 | /* No free var mtrr */ | |
139 | return -ENOSPC; | |
140 | } | |
141 | ||
142 | int mtrr_set_next_var(uint type, uint64_t start, uint64_t size) | |
143 | { | |
144 | int mtrr; | |
145 | ||
146 | mtrr = get_free_var_mtrr(); | |
147 | if (mtrr < 0) | |
148 | return mtrr; | |
149 | ||
150 | set_var_mtrr(mtrr, type, start, size); | |
151 | debug("MTRR %x: start=%x, size=%x\n", mtrr, (uint)start, (uint)size); | |
152 | ||
153 | return 0; | |
154 | } |