Merge branch 'master' of git://git.denx.de/u-boot-video
[oweals/u-boot.git] / arch / arm / mach-uniphier / arm32 / cache-uniphier.c
1 /*
2  * Copyright (C) 2012-2014 Panasonic Corporation
3  * Copyright (C) 2015-2016 Socionext Inc.
4  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <common.h>
10 #include <linux/io.h>
11 #include <asm/armv7.h>
12
13 #include "ssc-regs.h"
14
15 #ifdef CONFIG_UNIPHIER_L2CACHE_ON
16 static void uniphier_cache_sync(void)
17 {
18         /* drain internal buffers */
19         writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
20         /* need a read back to confirm */
21         readl(UNIPHIER_SSCOPE);
22 }
23
24 static void uniphier_cache_maint_all(u32 operation)
25 {
26         /* clear the complete notification flag */
27         writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
28
29         /* try until the command is successfully set */
30         do {
31                 writel(UNIPHIER_SSCOQM_S_ALL | UNIPHIER_SSCOQM_CE | operation,
32                        UNIPHIER_SSCOQM);
33         } while (readl(UNIPHIER_SSCOPPQSEF) &
34                  (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE));
35
36         /* wait until the operation is completed */
37         while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF)
38                 ;
39
40         uniphier_cache_sync();
41 }
42
43 void v7_outer_cache_flush_all(void)
44 {
45         uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
46 }
47
48 void v7_outer_cache_inval_all(void)
49 {
50         uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
51 }
52
53 static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation)
54 {
55         /* clear the complete notification flag */
56         writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
57
58         /* try until the command is successfully set */
59         do {
60                 writel(UNIPHIER_SSCOQM_S_RANGE | UNIPHIER_SSCOQM_CE | operation,
61                        UNIPHIER_SSCOQM);
62                 writel(start, UNIPHIER_SSCOQAD);
63                 writel(size, UNIPHIER_SSCOQSZ);
64
65         } while (readl(UNIPHIER_SSCOPPQSEF) &
66                  (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE));
67
68         /* wait until the operation is completed */
69         while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF)
70                 ;
71 }
72
73 static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
74 {
75         u32 size;
76
77         /*
78          * If start address is not aligned to cache-line,
79          * do cache operation for the first cache-line
80          */
81         start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
82
83         size = end - start;
84
85         if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
86                 /* this means cache operation for all range */
87                 uniphier_cache_maint_all(operation);
88                 return;
89         }
90
91         /*
92          * If end address is not aligned to cache-line,
93          * do cache operation for the last cache-line
94          */
95         size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
96
97         while (size) {
98                 u32 chunk_size = size > UNIPHIER_SSC_RANGE_OP_MAX_SIZE ?
99                                         UNIPHIER_SSC_RANGE_OP_MAX_SIZE : size;
100                 __uniphier_cache_maint_range(start, chunk_size, operation);
101
102                 start += chunk_size;
103                 size -= chunk_size;
104         }
105
106         uniphier_cache_sync();
107 }
108
109 void v7_outer_cache_flush_range(u32 start, u32 end)
110 {
111         uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
112 }
113
114 void v7_outer_cache_inval_range(u32 start, u32 end)
115 {
116         if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
117                 start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
118                 __uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE,
119                                              UNIPHIER_SSCOQM_CM_FLUSH);
120                 start += UNIPHIER_SSC_LINE_SIZE;
121         }
122
123         if (start >= end) {
124                 uniphier_cache_sync();
125                 return;
126         }
127
128         if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
129                 end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
130                 __uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE,
131                                              UNIPHIER_SSCOQM_CM_FLUSH);
132         }
133
134         if (start >= end) {
135                 uniphier_cache_sync();
136                 return;
137         }
138
139         uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV);
140 }
141
142 void v7_outer_cache_enable(void)
143 {
144         u32 tmp;
145
146         writel(U32_MAX, UNIPHIER_SSCLPDAWCR);   /* activate all ways */
147         tmp = readl(UNIPHIER_SSCC);
148         tmp |= UNIPHIER_SSCC_ON;
149         writel(tmp, UNIPHIER_SSCC);
150 }
151 #endif
152
153 void v7_outer_cache_disable(void)
154 {
155         u32 tmp;
156
157         tmp = readl(UNIPHIER_SSCC);
158         tmp &= ~UNIPHIER_SSCC_ON;
159         writel(tmp, UNIPHIER_SSCC);
160 }
161
162 void enable_caches(void)
163 {
164         dcache_enable();
165 }