blob: 76fe5ebe096e734c5f8b72d093122fb74aecb899 [file] [log] [blame]
Masahiro Yamadaa7c901f2016-07-22 13:38:31 +09001/*
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
16static 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
24static 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
43void v7_outer_cache_flush_all(void)
44{
45 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
46}
47
48void v7_outer_cache_inval_all(void)
49{
50 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
51}
52
53static 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
73static 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
109void v7_outer_cache_flush_range(u32 start, u32 end)
110{
111 uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
112}
113
114void 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
142void 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
153void 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
162void enable_caches(void)
163{
164 dcache_enable();
165}