]>
Commit | Line | Data |
---|---|---|
2c1d9ecb | 1 | /* |
2 | * TI OMAP L4 interconnect emulation. | |
3 | * | |
4 | * Copyright (C) 2007-2009 Nokia Corporation | |
5 | * Written by Andrzej Zaborowski <[email protected]> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation; either version 2 or | |
10 | * (at your option) any later version of the License. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * with this program; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | #include "hw.h" | |
21 | #include "omap.h" | |
22 | ||
23 | #ifdef L4_MUX_HACK | |
24 | static int omap_l4_io_entries; | |
25 | static int omap_cpu_io_entry; | |
26 | static struct omap_l4_entry { | |
27 | CPUReadMemoryFunc * const *mem_read; | |
28 | CPUWriteMemoryFunc * const *mem_write; | |
29 | void *opaque; | |
30 | } *omap_l4_io_entry; | |
31 | static CPUReadMemoryFunc * const *omap_l4_io_readb_fn; | |
32 | static CPUReadMemoryFunc * const *omap_l4_io_readh_fn; | |
33 | static CPUReadMemoryFunc * const *omap_l4_io_readw_fn; | |
34 | static CPUWriteMemoryFunc * const *omap_l4_io_writeb_fn; | |
35 | static CPUWriteMemoryFunc * const *omap_l4_io_writeh_fn; | |
36 | static CPUWriteMemoryFunc * const *omap_l4_io_writew_fn; | |
37 | static void **omap_l4_io_opaque; | |
38 | ||
39 | int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read, | |
40 | CPUWriteMemoryFunc * const *mem_write, void *opaque) | |
41 | { | |
42 | omap_l4_io_entry[omap_l4_io_entries].mem_read = mem_read; | |
43 | omap_l4_io_entry[omap_l4_io_entries].mem_write = mem_write; | |
44 | omap_l4_io_entry[omap_l4_io_entries].opaque = opaque; | |
45 | ||
46 | return omap_l4_io_entries ++; | |
47 | } | |
48 | ||
49 | static uint32_t omap_l4_io_readb(void *opaque, target_phys_addr_t addr) | |
50 | { | |
51 | unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; | |
52 | ||
53 | return omap_l4_io_readb_fn[i](omap_l4_io_opaque[i], addr); | |
54 | } | |
55 | ||
56 | static uint32_t omap_l4_io_readh(void *opaque, target_phys_addr_t addr) | |
57 | { | |
58 | unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; | |
59 | ||
60 | return omap_l4_io_readh_fn[i](omap_l4_io_opaque[i], addr); | |
61 | } | |
62 | ||
63 | static uint32_t omap_l4_io_readw(void *opaque, target_phys_addr_t addr) | |
64 | { | |
65 | unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; | |
66 | ||
67 | return omap_l4_io_readw_fn[i](omap_l4_io_opaque[i], addr); | |
68 | } | |
69 | ||
70 | static void omap_l4_io_writeb(void *opaque, target_phys_addr_t addr, | |
71 | uint32_t value) | |
72 | { | |
73 | unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; | |
74 | ||
75 | return omap_l4_io_writeb_fn[i](omap_l4_io_opaque[i], addr, value); | |
76 | } | |
77 | ||
78 | static void omap_l4_io_writeh(void *opaque, target_phys_addr_t addr, | |
79 | uint32_t value) | |
80 | { | |
81 | unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; | |
82 | ||
83 | return omap_l4_io_writeh_fn[i](omap_l4_io_opaque[i], addr, value); | |
84 | } | |
85 | ||
86 | static void omap_l4_io_writew(void *opaque, target_phys_addr_t addr, | |
87 | uint32_t value) | |
88 | { | |
89 | unsigned int i = (addr - OMAP2_L4_BASE) >> TARGET_PAGE_BITS; | |
90 | ||
91 | return omap_l4_io_writew_fn[i](omap_l4_io_opaque[i], addr, value); | |
92 | } | |
93 | ||
94 | static CPUReadMemoryFunc * const omap_l4_io_readfn[] = { | |
95 | omap_l4_io_readb, | |
96 | omap_l4_io_readh, | |
97 | omap_l4_io_readw, | |
98 | }; | |
99 | ||
100 | static CPUWriteMemoryFunc * const omap_l4_io_writefn[] = { | |
101 | omap_l4_io_writeb, | |
102 | omap_l4_io_writeh, | |
103 | omap_l4_io_writew, | |
104 | }; | |
105 | #else | |
106 | int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read, | |
107 | CPUWriteMemoryFunc * const *mem_write, | |
108 | void *opaque) | |
109 | { | |
2507c12a AG |
110 | return cpu_register_io_memory(mem_read, mem_write, opaque, |
111 | DEVICE_NATIVE_ENDIAN); | |
2c1d9ecb | 112 | } |
113 | #endif | |
114 | ||
115 | struct omap_l4_s { | |
116 | target_phys_addr_t base; | |
117 | int ta_num; | |
118 | struct omap_target_agent_s ta[0]; | |
119 | }; | |
120 | ||
121 | struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num) | |
122 | { | |
7267c094 | 123 | struct omap_l4_s *bus = g_malloc0( |
2c1d9ecb | 124 | sizeof(*bus) + ta_num * sizeof(*bus->ta)); |
125 | ||
126 | bus->ta_num = ta_num; | |
127 | bus->base = base; | |
128 | ||
129 | #ifdef L4_MUX_HACK | |
130 | omap_l4_io_entries = 1; | |
7267c094 | 131 | omap_l4_io_entry = g_malloc0(125 * sizeof(*omap_l4_io_entry)); |
2c1d9ecb | 132 | |
133 | omap_cpu_io_entry = | |
134 | cpu_register_io_memory(omap_l4_io_readfn, | |
2507c12a | 135 | omap_l4_io_writefn, bus, DEVICE_NATIVE_ENDIAN); |
2c1d9ecb | 136 | # define L4_PAGES (0xb4000 / TARGET_PAGE_SIZE) |
7267c094 AL |
137 | omap_l4_io_readb_fn = g_malloc0(sizeof(void *) * L4_PAGES); |
138 | omap_l4_io_readh_fn = g_malloc0(sizeof(void *) * L4_PAGES); | |
139 | omap_l4_io_readw_fn = g_malloc0(sizeof(void *) * L4_PAGES); | |
140 | omap_l4_io_writeb_fn = g_malloc0(sizeof(void *) * L4_PAGES); | |
141 | omap_l4_io_writeh_fn = g_malloc0(sizeof(void *) * L4_PAGES); | |
142 | omap_l4_io_writew_fn = g_malloc0(sizeof(void *) * L4_PAGES); | |
143 | omap_l4_io_opaque = g_malloc0(sizeof(void *) * L4_PAGES); | |
2c1d9ecb | 144 | #endif |
145 | ||
146 | return bus; | |
147 | } | |
148 | ||
f9049203 JR |
149 | target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta, |
150 | int region) | |
151 | { | |
152 | return ta->bus->base + ta->start[region].offset; | |
153 | } | |
154 | ||
2c1d9ecb | 155 | static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr) |
156 | { | |
157 | struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; | |
158 | ||
159 | switch (addr) { | |
160 | case 0x00: /* COMPONENT */ | |
161 | return s->component; | |
162 | ||
163 | case 0x20: /* AGENT_CONTROL */ | |
164 | return s->control; | |
165 | ||
166 | case 0x28: /* AGENT_STATUS */ | |
167 | return s->status; | |
168 | } | |
169 | ||
170 | OMAP_BAD_REG(addr); | |
171 | return 0; | |
172 | } | |
173 | ||
174 | static void omap_l4ta_write(void *opaque, target_phys_addr_t addr, | |
175 | uint32_t value) | |
176 | { | |
177 | struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; | |
178 | ||
179 | switch (addr) { | |
180 | case 0x00: /* COMPONENT */ | |
181 | case 0x28: /* AGENT_STATUS */ | |
182 | OMAP_RO_REG(addr); | |
183 | break; | |
184 | ||
185 | case 0x20: /* AGENT_CONTROL */ | |
186 | s->control = value & 0x01000700; | |
187 | if (value & 1) /* OCP_RESET */ | |
188 | s->status &= ~1; /* REQ_TIMEOUT */ | |
189 | break; | |
190 | ||
191 | default: | |
192 | OMAP_BAD_REG(addr); | |
193 | } | |
194 | } | |
195 | ||
196 | static CPUReadMemoryFunc * const omap_l4ta_readfn[] = { | |
197 | omap_badwidth_read16, | |
198 | omap_l4ta_read, | |
199 | omap_badwidth_read16, | |
200 | }; | |
201 | ||
202 | static CPUWriteMemoryFunc * const omap_l4ta_writefn[] = { | |
203 | omap_badwidth_write32, | |
204 | omap_badwidth_write32, | |
205 | omap_l4ta_write, | |
206 | }; | |
207 | ||
208 | struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, | |
209 | const struct omap_l4_region_s *regions, | |
210 | const struct omap_l4_agent_info_s *agents, | |
211 | int cs) | |
212 | { | |
213 | int i, iomemtype; | |
214 | struct omap_target_agent_s *ta = NULL; | |
215 | const struct omap_l4_agent_info_s *info = NULL; | |
216 | ||
217 | for (i = 0; i < bus->ta_num; i ++) | |
218 | if (agents[i].ta == cs) { | |
219 | ta = &bus->ta[i]; | |
220 | info = &agents[i]; | |
221 | break; | |
222 | } | |
223 | if (!ta) { | |
224 | fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs); | |
225 | exit(-1); | |
226 | } | |
227 | ||
228 | ta->bus = bus; | |
229 | ta->start = ®ions[info->region]; | |
230 | ta->regions = info->regions; | |
231 | ||
232 | ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); | |
233 | ta->status = 0x00000000; | |
234 | ta->control = 0x00000200; /* XXX 01000200 for L4TAO */ | |
235 | ||
236 | iomemtype = l4_register_io_memory(omap_l4ta_readfn, | |
237 | omap_l4ta_writefn, ta); | |
238 | ta->base = omap_l4_attach(ta, info->ta_region, iomemtype); | |
239 | ||
240 | return ta; | |
241 | } | |
242 | ||
243 | target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region, | |
244 | int iotype) | |
245 | { | |
246 | target_phys_addr_t base; | |
247 | ssize_t size; | |
248 | #ifdef L4_MUX_HACK | |
249 | int i; | |
250 | #endif | |
251 | ||
252 | if (region < 0 || region >= ta->regions) { | |
253 | fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region); | |
254 | exit(-1); | |
255 | } | |
256 | ||
257 | base = ta->bus->base + ta->start[region].offset; | |
258 | size = ta->start[region].size; | |
259 | if (iotype) { | |
260 | #ifndef L4_MUX_HACK | |
261 | cpu_register_physical_memory(base, size, iotype); | |
262 | #else | |
263 | cpu_register_physical_memory(base, size, omap_cpu_io_entry); | |
264 | i = (base - ta->bus->base) / TARGET_PAGE_SIZE; | |
265 | for (; size > 0; size -= TARGET_PAGE_SIZE, i ++) { | |
266 | omap_l4_io_readb_fn[i] = omap_l4_io_entry[iotype].mem_read[0]; | |
267 | omap_l4_io_readh_fn[i] = omap_l4_io_entry[iotype].mem_read[1]; | |
268 | omap_l4_io_readw_fn[i] = omap_l4_io_entry[iotype].mem_read[2]; | |
269 | omap_l4_io_writeb_fn[i] = omap_l4_io_entry[iotype].mem_write[0]; | |
270 | omap_l4_io_writeh_fn[i] = omap_l4_io_entry[iotype].mem_write[1]; | |
271 | omap_l4_io_writew_fn[i] = omap_l4_io_entry[iotype].mem_write[2]; | |
272 | omap_l4_io_opaque[i] = omap_l4_io_entry[iotype].opaque; | |
273 | } | |
274 | #endif | |
275 | } | |
276 | ||
277 | return base; | |
278 | } |