183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2aff2523fSSimon Glass /*
3aff2523fSSimon Glass * (C) Copyright 2014 Google, Inc
4aff2523fSSimon Glass *
5aff2523fSSimon Glass * Memory Type Range Regsters - these are used to tell the CPU whether
6aff2523fSSimon Glass * memory is cacheable and if so the cache write mode to use.
7aff2523fSSimon Glass *
8aff2523fSSimon Glass * These can speed up booting. See the mtrr command.
9aff2523fSSimon Glass *
10aff2523fSSimon Glass * Reference: Intel Architecture Software Developer's Manual, Volume 3:
11aff2523fSSimon Glass * System Programming
12aff2523fSSimon Glass */
13aff2523fSSimon Glass
14*590cee83SSimon Glass /*
15*590cee83SSimon Glass * Note that any console output (e.g. debug()) in this file will likely fail
16*590cee83SSimon Glass * since the MTRR registers are sometimes in flux.
17*590cee83SSimon Glass */
18*590cee83SSimon Glass
19aff2523fSSimon Glass #include <common.h>
20aff2523fSSimon Glass #include <asm/io.h>
21aff2523fSSimon Glass #include <asm/msr.h>
22aff2523fSSimon Glass #include <asm/mtrr.h>
23aff2523fSSimon Glass
24566d1754SBin Meng DECLARE_GLOBAL_DATA_PTR;
25566d1754SBin Meng
26aff2523fSSimon Glass /* Prepare to adjust MTRRs */
mtrr_open(struct mtrr_state * state,bool do_caches)27*590cee83SSimon Glass void mtrr_open(struct mtrr_state *state, bool do_caches)
28aff2523fSSimon Glass {
293b621ccaSBin Meng if (!gd->arch.has_mtrr)
303b621ccaSBin Meng return;
313b621ccaSBin Meng
32*590cee83SSimon Glass if (do_caches) {
33aff2523fSSimon Glass state->enable_cache = dcache_status();
34aff2523fSSimon Glass
35aff2523fSSimon Glass if (state->enable_cache)
36aff2523fSSimon Glass disable_caches();
37*590cee83SSimon Glass }
38aff2523fSSimon Glass state->deftype = native_read_msr(MTRR_DEF_TYPE_MSR);
39aff2523fSSimon Glass wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype & ~MTRR_DEF_TYPE_EN);
40aff2523fSSimon Glass }
41aff2523fSSimon Glass
42aff2523fSSimon Glass /* Clean up after adjusting MTRRs, and enable them */
mtrr_close(struct mtrr_state * state,bool do_caches)43*590cee83SSimon Glass void mtrr_close(struct mtrr_state *state, bool do_caches)
44aff2523fSSimon Glass {
453b621ccaSBin Meng if (!gd->arch.has_mtrr)
463b621ccaSBin Meng return;
473b621ccaSBin Meng
48aff2523fSSimon Glass wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN);
49*590cee83SSimon Glass if (do_caches && state->enable_cache)
50aff2523fSSimon Glass enable_caches();
51aff2523fSSimon Glass }
52aff2523fSSimon Glass
mtrr_commit(bool do_caches)53aff2523fSSimon Glass int mtrr_commit(bool do_caches)
54aff2523fSSimon Glass {
55aff2523fSSimon Glass struct mtrr_request *req = gd->arch.mtrr_req;
56aff2523fSSimon Glass struct mtrr_state state;
57aff2523fSSimon Glass uint64_t mask;
58aff2523fSSimon Glass int i;
59aff2523fSSimon Glass
60*590cee83SSimon Glass debug("%s: enabled=%d, count=%d\n", __func__, gd->arch.has_mtrr,
61*590cee83SSimon Glass gd->arch.mtrr_req_count);
623b621ccaSBin Meng if (!gd->arch.has_mtrr)
633b621ccaSBin Meng return -ENOSYS;
643b621ccaSBin Meng
65*590cee83SSimon Glass debug("open\n");
66*590cee83SSimon Glass mtrr_open(&state, do_caches);
67*590cee83SSimon Glass debug("open done\n");
68aff2523fSSimon Glass for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) {
69aff2523fSSimon Glass mask = ~(req->size - 1);
70aff2523fSSimon Glass mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
71aff2523fSSimon Glass wrmsrl(MTRR_PHYS_BASE_MSR(i), req->start | req->type);
72aff2523fSSimon Glass wrmsrl(MTRR_PHYS_MASK_MSR(i), mask | MTRR_PHYS_MASK_VALID);
73aff2523fSSimon Glass }
74aff2523fSSimon Glass
75aff2523fSSimon Glass /* Clear the ones that are unused */
76*590cee83SSimon Glass debug("clear\n");
77aff2523fSSimon Glass for (; i < MTRR_COUNT; i++)
78aff2523fSSimon Glass wrmsrl(MTRR_PHYS_MASK_MSR(i), 0);
79*590cee83SSimon Glass debug("close\n");
80*590cee83SSimon Glass mtrr_close(&state, do_caches);
81*590cee83SSimon Glass debug("mtrr done\n");
82aff2523fSSimon Glass
83aff2523fSSimon Glass return 0;
84aff2523fSSimon Glass }
85aff2523fSSimon Glass
mtrr_add_request(int type,uint64_t start,uint64_t size)86aff2523fSSimon Glass int mtrr_add_request(int type, uint64_t start, uint64_t size)
87aff2523fSSimon Glass {
88aff2523fSSimon Glass struct mtrr_request *req;
89aff2523fSSimon Glass uint64_t mask;
90aff2523fSSimon Glass
91*590cee83SSimon Glass debug("%s: count=%d\n", __func__, gd->arch.mtrr_req_count);
923b621ccaSBin Meng if (!gd->arch.has_mtrr)
933b621ccaSBin Meng return -ENOSYS;
943b621ccaSBin Meng
95aff2523fSSimon Glass if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
96aff2523fSSimon Glass return -ENOSPC;
97aff2523fSSimon Glass req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
98aff2523fSSimon Glass req->type = type;
99aff2523fSSimon Glass req->start = start;
100aff2523fSSimon Glass req->size = size;
101aff2523fSSimon Glass debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1,
102aff2523fSSimon Glass req->type, req->start, req->size);
103aff2523fSSimon Glass mask = ~(req->size - 1);
104aff2523fSSimon Glass mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
105aff2523fSSimon Glass mask |= MTRR_PHYS_MASK_VALID;
106aff2523fSSimon Glass debug(" %016llx %016llx\n", req->start | req->type, mask);
107aff2523fSSimon Glass
108aff2523fSSimon Glass return 0;
109aff2523fSSimon Glass }
110