1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12
13#include <arch/machine/hardware.h>
14
15static inline void invalidateByWSL(word_t wsl)
16{
17    asm volatile("dc isw, %0" : : "r"(wsl));
18}
19
20static inline void cleanByWSL(word_t wsl)
21{
22    asm volatile("dc csw, %0" : : "r"(wsl));
23}
24
25static inline void cleanInvalidateByWSL(word_t wsl)
26{
27    asm volatile("dc cisw, %0" : : "r"(wsl));
28}
29
30static inline word_t readCLID(void)
31{
32    word_t CLID;
33    MRS("clidr_el1", CLID);
34    return CLID;
35}
36
37#define LOUU(x)    (((x) >> 27)        & MASK(3))
38#define LOC(x)     (((x) >> 24)        & MASK(3))
39#define LOUIS(x)   (((x) >> 21)        & MASK(3))
40#define CTYPE(x,n) (((x) >> (n*3))     & MASK(3))
41
42enum arm_cache_type {
43    ARMCacheI =    1,
44    ARMCacheD =    2,
45    ARMCacheID =   3,
46};
47
48static inline word_t readCacheSize(int level, bool_t instruction)
49{
50    word_t size, csselr_old;
51    /* Save CSSELR */
52    MRS("csselr_el1", csselr_old);
53    /* Select cache level */
54    MSR("csselr_el1", ((level << 1) | instruction));
55    /* Read 'size' */
56    MRS("ccsidr_el1", size);
57    /* Restore CSSELR */
58    MSR("csselr_el1", csselr_old);
59    return size;
60}
61
62#define LINEBITS(s)     (((s) & MASK(3)) + 4)
63#define ASSOC(s)        ((((s) >> 3) & MASK(10)) + 1)
64#define NSETS(s)        ((((s) >> 13) & MASK(15)) + 1)
65
66void
67clean_D_PoU(void)
68{
69    int clid = readCLID();
70    int lou = LOUU(clid);
71    int l;
72
73    for (l = 0; l < lou; l++) {
74        if (CTYPE(clid, l) > ARMCacheI) {
75            word_t s = readCacheSize(l, 0);
76            int lbits = LINEBITS(s);
77            int assoc = ASSOC(s);
78            int assoc_bits = wordBits - clzl(assoc - 1);
79            int nsets = NSETS(s);
80            int w;
81
82            for (w = 0; w < assoc; w++) {
83                int s;
84
85                for (s = 0; s < nsets; s++) {
86                    cleanByWSL((w << (32 - assoc_bits)) |
87                               (s << lbits) | (l << 1));
88                }
89            }
90        }
91    }
92}
93
94void
95cleanInvalidate_D_PoC(void)
96{
97    int clid = readCLID();
98    int loc = LOC(clid);
99    int l;
100
101    for (l = 0; l < loc; l++) {
102        if (CTYPE(clid, l) > ARMCacheI) {
103            word_t s = readCacheSize(l, 0);
104            int lbits = LINEBITS(s);
105            int assoc = ASSOC(s);
106            int assoc_bits = wordBits - clzl(assoc - 1);
107            int nsets = NSETS(s);
108            int w;
109
110            for (w = 0; w < assoc; w++) {
111                int s;
112
113                for (s = 0; s < nsets; s++) {
114                    cleanInvalidateByWSL((w << (32 - assoc_bits)) |
115                                         (s << lbits) | (l << 1));
116                }
117            }
118        }
119    }
120}
121