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