1/*
2 * Copyright 2014, General Dynamics C4 Systems
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("mcr p15, 0, %0, c7, c10, 2" : : "r"(wsl));
12}
13
14static inline void cleanInvalidateByWSL(word_t wsl)
15{
16    asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r"(wsl));
17}
18
19
20static inline word_t readCLID(void)
21{
22    word_t CLID;
23    asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r"(CLID));
24    return CLID;
25}
26
27#define LOUU(x)    (((x) >> 27)        & MASK(3))
28#define LOC(x)     (((x) >> 24)        & MASK(3))
29#define LOUIS(x)   (((x) >> 21)        & MASK(3))
30#define CTYPE(x,n) (((x) >> (n*3))     & MASK(3))
31
32enum arm_cache_type {
33    ARMCacheNone = 0,
34    ARMCacheI =    1,
35    ARMCacheD =    2,
36    ARMCacheID =   3,
37    ARMCacheU =    4,
38};
39
40
41static inline word_t readCacheSize(int level, bool_t instruction)
42{
43    word_t size_unique_name, csselr_old;
44    /* Save CSSELR */
45    asm volatile("mrc p15, 2, %0, c0, c0, 0" : "=r"(csselr_old));
46    /* Select cache level */
47    asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r"((level << 1) | instruction));
48    /* Read 'size' */
49    asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r"(size_unique_name));
50    /* Restore CSSELR */
51    asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r"(csselr_old));
52    return size_unique_name;
53}
54
55/* Number of bits to index within a cache line.  The field is log2(nwords) - 2
56 * , and thus by adding 4 we get log2(nbytes). */
57#define LINEBITS(s) (( (s)        & MASK(3))  + 4)
58/* Associativity, field is assoc - 1. */
59#define ASSOC(s)    ((((s) >> 3)  & MASK(10)) + 1)
60/* Number of sets, field is nsets - 1. */
61#define NSETS(s)    ((((s) >> 13) & MASK(15)) + 1)
62
63
64void clean_D_PoU(void)
65{
66    int clid = readCLID();
67    int lou = LOUU(clid);
68    int l;
69
70    for (l = 0; l < lou; l++) {
71        if (CTYPE(clid, l) > ARMCacheI) {
72            word_t s = readCacheSize(l, 0);
73            int lbits = LINEBITS(s);
74            int assoc = ASSOC(s);
75            int assoc_bits = wordBits - clzl(assoc - 1);
76            int nsets = NSETS(s);
77            int w;
78
79            for (w = 0; w < assoc; w++) {
80                int v;
81
82                for (v = 0; v < nsets; v++) {
83                    cleanByWSL((w << (32 - assoc_bits)) |
84                               (v << lbits) | (l << 1));
85                }
86            }
87        }
88    }
89}
90
91static inline void cleanInvalidate_D_by_level(int l)
92{
93    word_t s = readCacheSize(l, 0);
94    int lbits = LINEBITS(s);
95    int assoc = ASSOC(s);
96    int assoc_bits = wordBits - clzl(assoc - 1);
97    int nsets = NSETS(s);
98    int w;
99
100    for (w = 0; w < assoc; w++) {
101        int v;
102
103        for (v = 0; v < nsets; v++) {
104            cleanInvalidateByWSL((w << (32 - assoc_bits)) |
105                                 (v << lbits) | (l << 1));
106        }
107    }
108}
109
110void cleanInvalidate_D_PoC(void)
111{
112    int clid = readCLID();
113    int loc = LOC(clid);
114    int l;
115
116    for (l = 0; l < loc; l++) {
117        if (CTYPE(clid, l) > ARMCacheI) {
118            cleanInvalidate_D_by_level(l);
119        }
120    }
121}
122
123void cleanInvalidate_L1D(void)
124{
125    cleanInvalidate_D_by_level(0);
126}
127