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