blob: b5705f7a4d166f1aac4e2d82d6eb816e1a72ab4d [file] [log] [blame]
Konstantin Porotchkin62a76462018-02-26 15:51:11 +02001/*
2 * Copyright (C) 2018 Marvell International Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
8/* GWIN unit device driver for Marvell AP810 SoC */
9
10#include <a8k_common.h>
11#include <debug.h>
12#include <gwin.h>
13#include <mmio.h>
14#include <mvebu.h>
15#include <mvebu_def.h>
16
17#if LOG_LEVEL >= LOG_LEVEL_INFO
18#define DEBUG_ADDR_MAP
19#endif
20
21/* common defines */
22#define WIN_ENABLE_BIT (0x1)
23#define WIN_TARGET_MASK (0xF)
24#define WIN_TARGET_SHIFT (0x8)
25#define WIN_TARGET(tgt) (((tgt) & WIN_TARGET_MASK) \
26 << WIN_TARGET_SHIFT)
27
28/* Bits[43:26] of the physical address are the window base,
29 * which is aligned to 64MB
30 */
31#define ADDRESS_RSHIFT (26)
32#define ADDRESS_LSHIFT (10)
33#define GWIN_ALIGNMENT_64M (0x4000000)
34
35/* AP registers */
36#define GWIN_CR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x0 + \
37 (0x10 * (win)))
38#define GWIN_ALR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x8 + \
39 (0x10 * (win)))
40#define GWIN_AHR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0xc + \
41 (0x10 * (win)))
42
43#define CCU_GRU_CR_OFFSET(ap) (MVEBU_CCU_GRU_BASE(ap))
44#define CCR_GRU_CR_GWIN_MBYPASS (1 << 1)
45
46static void gwin_check(struct addr_map_win *win)
47{
48 /* The base is always 64M aligned */
49 if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) {
50 win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1);
51 NOTICE("%s: Align the base address to 0x%llx\n",
52 __func__, win->base_addr);
53 }
54
55 /* size parameter validity check */
56 if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) {
57 win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M);
58 NOTICE("%s: Aligning window size to 0x%llx\n",
59 __func__, win->win_size);
60 }
61}
62
63static void gwin_enable_window(int ap_index, struct addr_map_win *win,
64 uint32_t win_num)
65{
66 uint32_t alr, ahr;
67 uint64_t end_addr;
68
69 if ((win->target_id & WIN_TARGET_MASK) != win->target_id) {
70 ERROR("target ID = %d, is invalid\n", win->target_id);
71 return;
72 }
73
74 /* calculate 64bit end-address */
75 end_addr = (win->base_addr + win->win_size - 1);
76
77 alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
78 ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
79
80 /* write start address and end address for GWIN */
81 mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr);
82 mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr);
83
84 /* write the target ID and enable the window */
85 mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num),
86 WIN_TARGET(win->target_id) | WIN_ENABLE_BIT);
87}
88
89static void gwin_disable_window(int ap_index, uint32_t win_num)
90{
91 uint32_t win_reg;
92
93 win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
94 win_reg &= ~WIN_ENABLE_BIT;
95 mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg);
96}
97
98/* Insert/Remove temporary window for using the out-of reset default
99 * CPx base address to access the CP configuration space prior to
100 * the further base address update in accordance with address mapping
101 * design.
102 *
103 * NOTE: Use the same window array for insertion and removal of
104 * temporary windows.
105 */
106void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
107{
108 uint32_t win_id;
109
110 for (int i = 0; i < size; i++) {
111 win_id = MVEBU_GWIN_MAX_WINS - i - 1;
112 gwin_check(win);
113 gwin_enable_window(ap_index, win, win_id);
114 win++;
115 }
116}
117
118/*
119 * NOTE: Use the same window array for insertion and removal of
120 * temporary windows.
121 */
122void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
123{
124 uint32_t win_id;
125
126 for (int i = 0; i < size; i++) {
127 uint64_t base;
128 uint32_t target;
129
130 win_id = MVEBU_GWIN_MAX_WINS - i - 1;
131
132 target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id));
133 target >>= WIN_TARGET_SHIFT;
134 target &= WIN_TARGET_MASK;
135
136 base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id));
137 base >>= ADDRESS_LSHIFT;
138 base <<= ADDRESS_RSHIFT;
139
140 if (win->target_id != target) {
141 ERROR("%s: Trying to remove bad window-%d!\n",
142 __func__, win_id);
143 continue;
144 }
145 gwin_disable_window(ap_index, win_id);
146 win++;
147 }
148}
149
150#ifdef DEBUG_ADDR_MAP
151static void dump_gwin(int ap_index)
152{
153 uint32_t win_num;
154
155 /* Dump all GWIN windows */
Antonio Nino Diaz00086e32018-08-16 16:46:06 +0100156 printf("\tbank target start end\n");
157 printf("\t----------------------------------------------------\n");
Konstantin Porotchkin62a76462018-02-26 15:51:11 +0200158 for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) {
159 uint32_t cr;
160 uint64_t alr, ahr;
161
162 cr = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
163 /* Window enabled */
164 if (cr & WIN_ENABLE_BIT) {
165 alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num));
166 alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
167 ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num));
168 ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
Antonio Nino Diaz00086e32018-08-16 16:46:06 +0100169 printf("\tgwin %d 0x%016llx 0x%016llx\n",
170 (cr >> 8) & 0xF, alr, ahr);
Konstantin Porotchkin62a76462018-02-26 15:51:11 +0200171 }
172 }
173}
174#endif
175
176int init_gwin(int ap_index)
177{
178 struct addr_map_win *win;
179 uint32_t win_id;
180 uint32_t win_count;
181 uint32_t win_reg;
182
183 INFO("Initializing GWIN Address decoding\n");
184
185 /* Get the array of the windows and its size */
186 marvell_get_gwin_memory_map(ap_index, &win, &win_count);
187 if (win_count <= 0) {
188 INFO("no windows configurations found\n");
189 return 0;
190 }
191
192 if (win_count > MVEBU_GWIN_MAX_WINS) {
193 ERROR("number of windows is bigger than %d\n",
194 MVEBU_GWIN_MAX_WINS);
195 return 0;
196 }
197
198 /* disable all windows */
199 for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++)
200 gwin_disable_window(ap_index, win_id);
201
202 /* enable relevant windows */
203 for (win_id = 0; win_id < win_count; win_id++, win++) {
204 gwin_check(win);
205 gwin_enable_window(ap_index, win, win_id);
206 }
207
208 /* GWIN Miss feature has not verified, therefore any access towards
209 * remote AP should be accompanied with proper configuration to
210 * GWIN registers group and therefore the GWIN Miss feature
211 * should be set into Bypass mode, need to make sure all GWIN regions
212 * are defined correctly that will assure no GWIN miss occurrance
213 * JIRA-AURORA2-1630
214 */
215 INFO("Update GWIN miss bypass\n");
216 win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index));
217 win_reg |= CCR_GRU_CR_GWIN_MBYPASS;
218 mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg);
219
220#ifdef DEBUG_ADDR_MAP
221 dump_gwin(ap_index);
222#endif
223
224 INFO("Done GWIN Address decoding Initializing\n");
225
226 return 0;
227}