1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <arch/machine/hardware.h>
8
9static inline void cleanByWSL(word_t wsl)
10{
11    asm volatile("dc csw, %0" : : "r"(wsl));
12}
13
14static inline void cleanInvalidateByWSL(word_t wsl)
15{
16    asm volatile("dc cisw, %0" : : "r"(wsl));
17}
18
19static inline word_t readCLID(void)
20{
21    word_t CLID;
22    MRS("clidr_el1", CLID);
23    return CLID;
24}
25
26#define LOUU(x)    (((x) >> 27)        & MASK(3))
27#define LOC(x)     (((x) >> 24)        & MASK(3))
28#define LOUIS(x)   (((x) >> 21)        & MASK(3))
29#define CTYPE(x,n) (((x) >> (n*3))     & MASK(3))
30
31enum arm_cache_type {
32    ARMCacheI =    1,
33    ARMCacheD =    2,
34    ARMCacheID =   3,
35};
36
37static inline word_t readCacheSize(int level, bool_t instruction)
38{
39    word_t size, csselr_old;
40    /* Save CSSELR */
41    MRS("csselr_el1", csselr_old);
42    /* Select cache level */
43    MSR("csselr_el1", ((level << 1) | instruction));
44    /* Read 'size' */
45    MRS("ccsidr_el1", size);
46    /* Restore CSSELR */
47    MSR("csselr_el1", csselr_old);
48    return size;
49}
50
51#define LINEBITS(s)     (((s) & MASK(3)) + 4)
52#define ASSOC(s)        ((((s) >> 3) & MASK(10)) + 1)
53#define NSETS(s)        ((((s) >> 13) & MASK(15)) + 1)
54
55void clean_D_PoU(void)
56{
57    int clid = readCLID();
58    int lou = LOUU(clid);
59
60    for (int l = 0; l < lou; l++) {
61        if (CTYPE(clid, l) > ARMCacheI) {
62            word_t lsize = readCacheSize(l, 0);
63            int lbits = LINEBITS(lsize);
64            int assoc = ASSOC(lsize);
65            int assoc_bits = wordBits - clzl(assoc - 1);
66            int nsets = NSETS(lsize);
67            for (int w = 0; w < assoc; w++) {
68                for (int s = 0; s < nsets; s++) {
69                    cleanByWSL((w << (32 - assoc_bits)) |
70                               (s << lbits) | (l << 1));
71                }
72            }
73        }
74    }
75}
76
77static inline void cleanInvalidate_D_by_level(int l)
78{
79    word_t lsize = readCacheSize(l, 0);
80    int lbits = LINEBITS(lsize);
81    int assoc = ASSOC(lsize);
82    int assoc_bits = wordBits - clzl(assoc - 1);
83    int nsets = NSETS(lsize);
84
85    for (int w = 0; w < assoc; w++) {
86        for (int s = 0; s < nsets; s++) {
87            cleanInvalidateByWSL((w << (32 - assoc_bits)) |
88                                 (s << lbits) | (l << 1));
89        }
90    }
91}
92
93void cleanInvalidate_D_PoC(void)
94{
95    int clid = readCLID();
96    int loc = LOC(clid);
97
98    for (int l = 0; l < loc; l++) {
99        if (CTYPE(clid, l) > ARMCacheI) {
100            cleanInvalidate_D_by_level(l);
101        }
102    }
103}
104
105void cleanInvalidate_L1D(void)
106{
107    cleanInvalidate_D_by_level(0);
108}
109