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