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