xref: /rk3399_ARM-atf/drivers/marvell/amb_adec.c (revision c0474d5843321392172356f79efb6ec6140c4e48)
1*c0474d58SKonstantin Porotchkin /*
2*c0474d58SKonstantin Porotchkin  * Copyright (C) 2018 Marvell International Ltd.
3*c0474d58SKonstantin Porotchkin  *
4*c0474d58SKonstantin Porotchkin  * SPDX-License-Identifier:     BSD-3-Clause
5*c0474d58SKonstantin Porotchkin  * https://spdx.org/licenses
6*c0474d58SKonstantin Porotchkin  */
7*c0474d58SKonstantin Porotchkin 
8*c0474d58SKonstantin Porotchkin /* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
9*c0474d58SKonstantin Porotchkin 
10*c0474d58SKonstantin Porotchkin #include <a8k_common.h>
11*c0474d58SKonstantin Porotchkin #include <debug.h>
12*c0474d58SKonstantin Porotchkin #include <mmio.h>
13*c0474d58SKonstantin Porotchkin #include <mvebu.h>
14*c0474d58SKonstantin Porotchkin #include <mvebu_def.h>
15*c0474d58SKonstantin Porotchkin 
16*c0474d58SKonstantin Porotchkin #if LOG_LEVEL >= LOG_LEVEL_INFO
17*c0474d58SKonstantin Porotchkin #define DEBUG_ADDR_MAP
18*c0474d58SKonstantin Porotchkin #endif
19*c0474d58SKonstantin Porotchkin 
20*c0474d58SKonstantin Porotchkin /* common defines */
21*c0474d58SKonstantin Porotchkin #define WIN_ENABLE_BIT			(0x1)
22*c0474d58SKonstantin Porotchkin 
23*c0474d58SKonstantin Porotchkin #define MVEBU_AMB_ADEC_OFFSET		(0x70ff00)
24*c0474d58SKonstantin Porotchkin 
25*c0474d58SKonstantin Porotchkin #define AMB_WIN_CR_OFFSET(win)		(amb_base + 0x0 + (0x8 * win))
26*c0474d58SKonstantin Porotchkin #define AMB_ATTR_OFFSET			8
27*c0474d58SKonstantin Porotchkin #define AMB_ATTR_MASK			0xFF
28*c0474d58SKonstantin Porotchkin #define AMB_SIZE_OFFSET			16
29*c0474d58SKonstantin Porotchkin #define AMB_SIZE_MASK			0xFF
30*c0474d58SKonstantin Porotchkin 
31*c0474d58SKonstantin Porotchkin #define AMB_WIN_BASE_OFFSET(win)	(amb_base + 0x4 + (0x8 * win))
32*c0474d58SKonstantin Porotchkin #define AMB_BASE_OFFSET			16
33*c0474d58SKonstantin Porotchkin #define AMB_BASE_ADDR_MASK		((1 << (32 - AMB_BASE_OFFSET)) - 1)
34*c0474d58SKonstantin Porotchkin 
35*c0474d58SKonstantin Porotchkin #define AMB_WIN_ALIGNMENT_64K		(0x10000)
36*c0474d58SKonstantin Porotchkin #define AMB_WIN_ALIGNMENT_1M		(0x100000)
37*c0474d58SKonstantin Porotchkin 
38*c0474d58SKonstantin Porotchkin uintptr_t amb_base;
39*c0474d58SKonstantin Porotchkin 
40*c0474d58SKonstantin Porotchkin static void amb_check_win(struct addr_map_win *win, uint32_t win_num)
41*c0474d58SKonstantin Porotchkin {
42*c0474d58SKonstantin Porotchkin 	uint32_t base_addr;
43*c0474d58SKonstantin Porotchkin 
44*c0474d58SKonstantin Porotchkin 	/* make sure the base address is in 16-bit range */
45*c0474d58SKonstantin Porotchkin 	if (win->base_addr > AMB_BASE_ADDR_MASK) {
46*c0474d58SKonstantin Porotchkin 		WARN("Window %d: base address is too big 0x%llx\n",
47*c0474d58SKonstantin Porotchkin 		       win_num, win->base_addr);
48*c0474d58SKonstantin Porotchkin 		win->base_addr = AMB_BASE_ADDR_MASK;
49*c0474d58SKonstantin Porotchkin 		WARN("Set the base address to 0x%llx\n", win->base_addr);
50*c0474d58SKonstantin Porotchkin 	}
51*c0474d58SKonstantin Porotchkin 
52*c0474d58SKonstantin Porotchkin 	base_addr  = win->base_addr << AMB_BASE_OFFSET;
53*c0474d58SKonstantin Porotchkin 	/* for AMB The base is always 1M aligned */
54*c0474d58SKonstantin Porotchkin 	/* check if address is aligned to 1M */
55*c0474d58SKonstantin Porotchkin 	if (IS_NOT_ALIGN(base_addr, AMB_WIN_ALIGNMENT_1M)) {
56*c0474d58SKonstantin Porotchkin 		win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M);
57*c0474d58SKonstantin Porotchkin 		WARN("Window %d: base address unaligned to 0x%x\n",
58*c0474d58SKonstantin Porotchkin 		       win_num, AMB_WIN_ALIGNMENT_1M);
59*c0474d58SKonstantin Porotchkin 		WARN("Align up the base address to 0x%llx\n", win->base_addr);
60*c0474d58SKonstantin Porotchkin 	}
61*c0474d58SKonstantin Porotchkin 
62*c0474d58SKonstantin Porotchkin 	/* size parameter validity check */
63*c0474d58SKonstantin Porotchkin 	if (!IS_POWER_OF_2(win->win_size)) {
64*c0474d58SKonstantin Porotchkin 		WARN("Window %d: window size is not power of 2 (0x%llx)\n",
65*c0474d58SKonstantin Porotchkin 		       win_num, win->win_size);
66*c0474d58SKonstantin Porotchkin 		win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size);
67*c0474d58SKonstantin Porotchkin 		WARN("Rounding size to 0x%llx\n", win->win_size);
68*c0474d58SKonstantin Porotchkin 	}
69*c0474d58SKonstantin Porotchkin }
70*c0474d58SKonstantin Porotchkin 
71*c0474d58SKonstantin Porotchkin static void amb_enable_win(struct addr_map_win *win, uint32_t win_num)
72*c0474d58SKonstantin Porotchkin {
73*c0474d58SKonstantin Porotchkin 	uint32_t ctrl, base, size;
74*c0474d58SKonstantin Porotchkin 
75*c0474d58SKonstantin Porotchkin 	/*
76*c0474d58SKonstantin Porotchkin 	 * size is 64KB granularity.
77*c0474d58SKonstantin Porotchkin 	 * The number of ones specifies the size of the
78*c0474d58SKonstantin Porotchkin 	 * window in 64 KB granularity. 0 is 64KB
79*c0474d58SKonstantin Porotchkin 	 */
80*c0474d58SKonstantin Porotchkin 	size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1;
81*c0474d58SKonstantin Porotchkin 	ctrl = (size << AMB_SIZE_OFFSET) | (win->target_id << AMB_ATTR_OFFSET);
82*c0474d58SKonstantin Porotchkin 	base = win->base_addr << AMB_BASE_OFFSET;
83*c0474d58SKonstantin Porotchkin 
84*c0474d58SKonstantin Porotchkin 	mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base);
85*c0474d58SKonstantin Porotchkin 	mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
86*c0474d58SKonstantin Porotchkin 
87*c0474d58SKonstantin Porotchkin 	/* enable window after configuring window size (and attributes) */
88*c0474d58SKonstantin Porotchkin 	ctrl |= WIN_ENABLE_BIT;
89*c0474d58SKonstantin Porotchkin 	mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
90*c0474d58SKonstantin Porotchkin }
91*c0474d58SKonstantin Porotchkin 
92*c0474d58SKonstantin Porotchkin #ifdef DEBUG_ADDR_MAP
93*c0474d58SKonstantin Porotchkin static void dump_amb_adec(void)
94*c0474d58SKonstantin Porotchkin {
95*c0474d58SKonstantin Porotchkin 	uint32_t ctrl, base, win_id, attr;
96*c0474d58SKonstantin Porotchkin 	uint32_t size, size_count;
97*c0474d58SKonstantin Porotchkin 
98*c0474d58SKonstantin Porotchkin 	/* Dump all AMB windows */
99*c0474d58SKonstantin Porotchkin 	tf_printf("bank  attribute     base          size\n");
100*c0474d58SKonstantin Porotchkin 	tf_printf("--------------------------------------------\n");
101*c0474d58SKonstantin Porotchkin 	for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
102*c0474d58SKonstantin Porotchkin 		ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
103*c0474d58SKonstantin Porotchkin 		if (ctrl & WIN_ENABLE_BIT) {
104*c0474d58SKonstantin Porotchkin 			base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id));
105*c0474d58SKonstantin Porotchkin 			attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK;
106*c0474d58SKonstantin Porotchkin 			size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK;
107*c0474d58SKonstantin Porotchkin 			size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K;
108*c0474d58SKonstantin Porotchkin 			tf_printf("amb   0x%04x        0x%08x    0x%08x\n",
109*c0474d58SKonstantin Porotchkin 				  attr, base, size);
110*c0474d58SKonstantin Porotchkin 		}
111*c0474d58SKonstantin Porotchkin 	}
112*c0474d58SKonstantin Porotchkin }
113*c0474d58SKonstantin Porotchkin #endif
114*c0474d58SKonstantin Porotchkin 
115*c0474d58SKonstantin Porotchkin int init_amb_adec(uintptr_t base)
116*c0474d58SKonstantin Porotchkin {
117*c0474d58SKonstantin Porotchkin 	struct addr_map_win *win;
118*c0474d58SKonstantin Porotchkin 	uint32_t win_id, win_reg;
119*c0474d58SKonstantin Porotchkin 	uint32_t win_count;
120*c0474d58SKonstantin Porotchkin 
121*c0474d58SKonstantin Porotchkin 	INFO("Initializing AXI to MBus Bridge Address decoding\n");
122*c0474d58SKonstantin Porotchkin 
123*c0474d58SKonstantin Porotchkin 	/* Get the base address of the AMB address decoding */
124*c0474d58SKonstantin Porotchkin 	amb_base = base + MVEBU_AMB_ADEC_OFFSET;
125*c0474d58SKonstantin Porotchkin 
126*c0474d58SKonstantin Porotchkin 	/* Get the array of the windows and its size */
127*c0474d58SKonstantin Porotchkin 	marvell_get_amb_memory_map(&win, &win_count, base);
128*c0474d58SKonstantin Porotchkin 	if (win_count <= 0)
129*c0474d58SKonstantin Porotchkin 		INFO("no windows configurations found\n");
130*c0474d58SKonstantin Porotchkin 
131*c0474d58SKonstantin Porotchkin 	if (win_count > AMB_MAX_WIN_ID) {
132*c0474d58SKonstantin Porotchkin 		INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID);
133*c0474d58SKonstantin Porotchkin 		return 0;
134*c0474d58SKonstantin Porotchkin 	}
135*c0474d58SKonstantin Porotchkin 
136*c0474d58SKonstantin Porotchkin 	/* disable all AMB windows */
137*c0474d58SKonstantin Porotchkin 	for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
138*c0474d58SKonstantin Porotchkin 		win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
139*c0474d58SKonstantin Porotchkin 		win_reg &= ~WIN_ENABLE_BIT;
140*c0474d58SKonstantin Porotchkin 		mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg);
141*c0474d58SKonstantin Porotchkin 	}
142*c0474d58SKonstantin Porotchkin 
143*c0474d58SKonstantin Porotchkin 	/* enable relevant windows */
144*c0474d58SKonstantin Porotchkin 	for (win_id = 0; win_id < win_count; win_id++, win++) {
145*c0474d58SKonstantin Porotchkin 		amb_check_win(win, win_id);
146*c0474d58SKonstantin Porotchkin 		amb_enable_win(win, win_id);
147*c0474d58SKonstantin Porotchkin 	}
148*c0474d58SKonstantin Porotchkin 
149*c0474d58SKonstantin Porotchkin #ifdef DEBUG_ADDR_MAP
150*c0474d58SKonstantin Porotchkin 	dump_amb_adec();
151*c0474d58SKonstantin Porotchkin #endif
152*c0474d58SKonstantin Porotchkin 
153*c0474d58SKonstantin Porotchkin 	INFO("Done AXI to MBus Bridge Address decoding Initializing\n");
154*c0474d58SKonstantin Porotchkin 
155*c0474d58SKonstantin Porotchkin 	return 0;
156*c0474d58SKonstantin Porotchkin }
157