Fix changelog
[external/binutils.git] / sim / bfin / dv-bfin_ebiu_amc.c
1 /* Blackfin External Bus Interface Unit (EBIU) Asynchronous Memory Controller
2    (AMC) model.
3
4    Copyright (C) 2010-2016 Free Software Foundation, Inc.
5    Contributed by Analog Devices, Inc.
6
7    This file is part of simulators.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "config.h"
23
24 #include "sim-main.h"
25 #include "devices.h"
26 #include "dv-bfin_ebiu_amc.h"
27
28 struct bfin_ebiu_amc
29 {
30   bu32 base;
31   int type;
32   bu32 bank_base, bank_size;
33   unsigned (*io_write) (struct hw *, const void *, int, address_word,
34                         unsigned, struct bfin_ebiu_amc *, bu32, bu32);
35   unsigned (*io_read) (struct hw *, void *, int, address_word, unsigned,
36                        struct bfin_ebiu_amc *, bu32, void *, bu16 *, bu32 *);
37   struct hw *slaves[4];
38
39   /* Order after here is important -- matches hardware MMR layout.  */
40   bu16 BFIN_MMR_16(amgctl);
41   union {
42     struct {
43       bu32 ambctl0, ambctl1;
44       bu32 _pad0[5];
45       bu16 BFIN_MMR_16(mode);
46       bu16 BFIN_MMR_16(fctl);
47     } bf50x;
48     struct {
49       bu32 ambctl0, ambctl1;
50     } bf53x;
51     struct {
52       bu32 ambctl0, ambctl1;
53       bu32 mbsctl, arbstat, mode, fctl;
54     } bf54x;
55   };
56 };
57 #define mmr_base()      offsetof(struct bfin_ebiu_amc, amgctl)
58 #define mmr_offset(mmr) (offsetof(struct bfin_ebiu_amc, mmr) - mmr_base())
59 #define mmr_idx(mmr)    (mmr_offset (mmr) / 4)
60
61 static const char * const bf50x_mmr_names[] =
62 {
63   "EBIU_AMGCTL", "EBIU_AMBCTL0", "EBIU_AMBCTL1",
64   [mmr_idx (bf50x.mode)] = "EBIU_MODE", "EBIU_FCTL",
65 };
66 static const char * const bf53x_mmr_names[] =
67 {
68   "EBIU_AMGCTL", "EBIU_AMBCTL0", "EBIU_AMBCTL1",
69 };
70 static const char * const bf54x_mmr_names[] =
71 {
72   "EBIU_AMGCTL", "EBIU_AMBCTL0", "EBIU_AMBCTL1",
73   "EBIU_MSBCTL", "EBIU_ARBSTAT", "EBIU_MODE", "EBIU_FCTL",
74 };
75 static const char * const *mmr_names;
76 #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
77
78 static void
79 bfin_ebiu_amc_write_amgctl (struct hw *me, struct bfin_ebiu_amc *amc,
80                             bu16 amgctl)
81 {
82   bu32 amben_old, amben, addr, i;
83
84   amben_old = min ((amc->amgctl >> 1) & 0x7, 4);
85   amben = min ((amgctl >> 1) & 0x7, 4);
86
87   HW_TRACE ((me, "reattaching banks: AMGCTL 0x%04x[%u] -> 0x%04x[%u]",
88              amc->amgctl, amben_old, amgctl, amben));
89
90   for (i = 0; i < 4; ++i)
91     {
92       addr = amc->bank_base + i * amc->bank_size;
93
94       if (i < amben_old)
95         {
96           HW_TRACE ((me, "detaching bank %u (%#x base)", i, addr));
97           sim_core_detach (hw_system (me), NULL, 0, 0, addr);
98         }
99
100       if (i < amben)
101         {
102           struct hw *slave = amc->slaves[i];
103
104           HW_TRACE ((me, "attaching bank %u (%#x base) to %s", i, addr,
105                      slave ? hw_path (slave) : "<floating pins>"));
106
107           sim_core_attach (hw_system (me), NULL, 0, access_read_write_exec,
108                            0, addr, amc->bank_size, 0, slave, NULL);
109         }
110     }
111
112   amc->amgctl = amgctl;
113 }
114
115 static unsigned
116 bf50x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
117                                 address_word addr, unsigned nr_bytes,
118                                 struct bfin_ebiu_amc *amc, bu32 mmr_off,
119                                 bu32 value)
120 {
121   switch (mmr_off)
122     {
123     case mmr_offset(amgctl):
124       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
125         return 0;
126       bfin_ebiu_amc_write_amgctl (me, amc, value);
127       break;
128     case mmr_offset(bf50x.ambctl0):
129       amc->bf50x.ambctl0 = value;
130       break;
131     case mmr_offset(bf50x.ambctl1):
132       amc->bf50x.ambctl1 = value;
133       break;
134     case mmr_offset(bf50x.mode):
135       /* XXX: implement this.  */
136       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
137         return 0;
138       break;
139     case mmr_offset(bf50x.fctl):
140       /* XXX: implement this.  */
141       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
142         return 0;
143       break;
144     default:
145       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
146       return 0;
147     }
148
149   return nr_bytes;
150 }
151
152 static unsigned
153 bf53x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
154                                 address_word addr, unsigned nr_bytes,
155                                 struct bfin_ebiu_amc *amc, bu32 mmr_off,
156                                 bu32 value)
157 {
158   switch (mmr_off)
159     {
160     case mmr_offset(amgctl):
161       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
162         return 0;
163       bfin_ebiu_amc_write_amgctl (me, amc, value);
164       break;
165     case mmr_offset(bf53x.ambctl0):
166       amc->bf53x.ambctl0 = value;
167       break;
168     case mmr_offset(bf53x.ambctl1):
169       amc->bf53x.ambctl1 = value;
170       break;
171     default:
172       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
173       return 0;
174     }
175
176   return nr_bytes;
177 }
178
179 static unsigned
180 bf54x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
181                                 address_word addr, unsigned nr_bytes,
182                                 struct bfin_ebiu_amc *amc, bu32 mmr_off,
183                                 bu32 value)
184 {
185   switch (mmr_off)
186     {
187     case mmr_offset(amgctl):
188       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
189         return 0;
190       bfin_ebiu_amc_write_amgctl (me, amc, value);
191       break;
192     case mmr_offset(bf54x.ambctl0):
193       amc->bf54x.ambctl0 = value;
194       break;
195     case mmr_offset(bf54x.ambctl1):
196       amc->bf54x.ambctl1 = value;
197       break;
198     case mmr_offset(bf54x.mbsctl):
199       /* XXX: implement this.  */
200       break;
201     case mmr_offset(bf54x.arbstat):
202       /* XXX: implement this.  */
203       break;
204     case mmr_offset(bf54x.mode):
205       /* XXX: implement this.  */
206       break;
207     case mmr_offset(bf54x.fctl):
208       /* XXX: implement this.  */
209       break;
210     default:
211       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
212       return 0;
213     }
214
215   return nr_bytes;
216 }
217
218 static unsigned
219 bfin_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
220                                address_word addr, unsigned nr_bytes)
221 {
222   struct bfin_ebiu_amc *amc = hw_data (me);
223   bu32 mmr_off;
224   bu32 value;
225
226   /* Invalid access mode is higher priority than missing register.  */
227   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
228     return 0;
229
230   value = dv_load_4 (source);
231   mmr_off = addr - amc->base;
232
233   HW_TRACE_WRITE ();
234
235   return amc->io_write (me, source, space, addr, nr_bytes,
236                         amc, mmr_off, value);
237 }
238
239 static unsigned
240 bf50x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
241                                address_word addr, unsigned nr_bytes,
242                                struct bfin_ebiu_amc *amc, bu32 mmr_off,
243                                void *valuep, bu16 *value16, bu32 *value32)
244 {
245   switch (mmr_off)
246     {
247     case mmr_offset(amgctl):
248     case mmr_offset(bf50x.fctl):
249       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
250         return 0;
251       dv_store_2 (dest, *value16);
252       break;
253     case mmr_offset(bf50x.ambctl0):
254     case mmr_offset(bf50x.ambctl1):
255     case mmr_offset(bf50x.mode):
256       dv_store_4 (dest, *value32);
257       break;
258     default:
259       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
260       return 0;
261     }
262
263   return nr_bytes;
264 }
265
266 static unsigned
267 bf53x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
268                                address_word addr, unsigned nr_bytes,
269                                struct bfin_ebiu_amc *amc, bu32 mmr_off,
270                                void *valuep, bu16 *value16, bu32 *value32)
271 {
272   switch (mmr_off)
273     {
274     case mmr_offset(amgctl):
275       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
276         return 0;
277       dv_store_2 (dest, *value16);
278       break;
279     case mmr_offset(bf53x.ambctl0):
280     case mmr_offset(bf53x.ambctl1):
281       dv_store_4 (dest, *value32);
282       break;
283     default:
284       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
285       return 0;
286     }
287
288   return nr_bytes;
289 }
290
291 static unsigned
292 bf54x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
293                                address_word addr, unsigned nr_bytes,
294                                struct bfin_ebiu_amc *amc, bu32 mmr_off,
295                                void *valuep, bu16 *value16, bu32 *value32)
296 {
297   switch (mmr_off)
298     {
299     case mmr_offset(amgctl):
300       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
301         return 0;
302       dv_store_2 (dest, *value16);
303       break;
304     case mmr_offset(bf54x.ambctl0):
305     case mmr_offset(bf54x.ambctl1):
306     case mmr_offset(bf54x.mbsctl):
307     case mmr_offset(bf54x.arbstat):
308     case mmr_offset(bf54x.mode):
309     case mmr_offset(bf54x.fctl):
310       dv_store_4 (dest, *value32);
311       break;
312     default:
313       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
314       return 0;
315     }
316
317   return nr_bytes;
318 }
319
320 static unsigned
321 bfin_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
322                               address_word addr, unsigned nr_bytes)
323 {
324   struct bfin_ebiu_amc *amc = hw_data (me);
325   bu32 mmr_off;
326   void *valuep;
327
328   /* Invalid access mode is higher priority than missing register.  */
329   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, false))
330     return 0;
331
332   mmr_off = addr - amc->base;
333   valuep = (void *)((unsigned long)amc + mmr_base() + mmr_off);
334
335   HW_TRACE_READ ();
336
337   return amc->io_read (me, dest, space, addr, nr_bytes, amc,
338                        mmr_off, valuep, valuep, valuep);
339 }
340
341 static void
342 bfin_ebiu_amc_attach_address_callback (struct hw *me,
343                                        int level,
344                                        int space,
345                                        address_word addr,
346                                        address_word nr_bytes,
347                                        struct hw *client)
348 {
349   struct bfin_ebiu_amc *amc = hw_data (me);
350
351   HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
352              level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
353
354   if (addr + nr_bytes > ARRAY_SIZE (amc->slaves))
355     hw_abort (me, "ebiu amc attaches are done in terms of banks");
356
357   while (nr_bytes--)
358     amc->slaves[addr + nr_bytes] = client;
359
360   bfin_ebiu_amc_write_amgctl (me, amc, amc->amgctl);
361 }
362
363 static void
364 attach_bfin_ebiu_amc_regs (struct hw *me, struct bfin_ebiu_amc *amc,
365                            unsigned reg_size)
366 {
367   address_word attach_address;
368   int attach_space;
369   unsigned attach_size;
370   reg_property_spec reg;
371
372   if (hw_find_property (me, "reg") == NULL)
373     hw_abort (me, "Missing \"reg\" property");
374
375   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
376     hw_abort (me, "\"reg\" property must contain three addr/size entries");
377
378   if (hw_find_property (me, "type") == NULL)
379     hw_abort (me, "Missing \"type\" property");
380
381   hw_unit_address_to_attach_address (hw_parent (me),
382                                      &reg.address,
383                                      &attach_space, &attach_address, me);
384   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
385
386   if (attach_size != reg_size)
387     hw_abort (me, "\"reg\" size must be %#x", reg_size);
388
389   hw_attach_address (hw_parent (me),
390                      0, attach_space, attach_address, attach_size, me);
391
392   amc->base = attach_address;
393 }
394
395 static void
396 bfin_ebiu_amc_finish (struct hw *me)
397 {
398   struct bfin_ebiu_amc *amc;
399   bu32 amgctl;
400   unsigned reg_size;
401
402   amc = HW_ZALLOC (me, struct bfin_ebiu_amc);
403
404   set_hw_data (me, amc);
405   set_hw_io_read_buffer (me, bfin_ebiu_amc_io_read_buffer);
406   set_hw_io_write_buffer (me, bfin_ebiu_amc_io_write_buffer);
407   set_hw_attach_address (me, bfin_ebiu_amc_attach_address_callback);
408
409   amc->type = hw_find_integer_property (me, "type");
410
411   switch (amc->type)
412     {
413     case 500 ... 509:
414       amc->io_write = bf50x_ebiu_amc_io_write_buffer;
415       amc->io_read = bf50x_ebiu_amc_io_read_buffer;
416       mmr_names = bf50x_mmr_names;
417       reg_size = sizeof (amc->bf50x) + 4;
418
419       /* Initialize the AMC.  */
420       amc->bank_base     = BFIN_EBIU_AMC_BASE;
421       amc->bank_size     = 1 * 1024 * 1024;
422       amgctl             = 0x00F3;
423       amc->bf50x.ambctl0 = 0x0000FFC2;
424       amc->bf50x.ambctl1 = 0x0000FFC2;
425       amc->bf50x.mode    = 0x0001;
426       amc->bf50x.fctl    = 0x0002;
427       break;
428     case 540 ... 549:
429       amc->io_write = bf54x_ebiu_amc_io_write_buffer;
430       amc->io_read = bf54x_ebiu_amc_io_read_buffer;
431       mmr_names = bf54x_mmr_names;
432       reg_size = sizeof (amc->bf54x) + 4;
433
434       /* Initialize the AMC.  */
435       amc->bank_base     = BFIN_EBIU_AMC_BASE;
436       amc->bank_size     = 64 * 1024 * 1024;
437       amgctl             = 0x0002;
438       amc->bf54x.ambctl0 = 0xFFC2FFC2;
439       amc->bf54x.ambctl1 = 0xFFC2FFC2;
440       amc->bf54x.fctl    = 0x0006;
441       break;
442     case 510 ... 519:
443     case 522 ... 527:
444     case 531 ... 533:
445     case 534:
446     case 536:
447     case 537:
448     case 538 ... 539:
449     case 561:
450       amc->io_write = bf53x_ebiu_amc_io_write_buffer;
451       amc->io_read = bf53x_ebiu_amc_io_read_buffer;
452       mmr_names = bf53x_mmr_names;
453       reg_size = sizeof (amc->bf53x) + 4;
454
455       /* Initialize the AMC.  */
456       amc->bank_base     = BFIN_EBIU_AMC_BASE;
457       if (amc->type == 561)
458         amc->bank_size   = 64 * 1024 * 1024;
459       else
460         amc->bank_size   = 1 * 1024 * 1024;
461       amgctl             = 0x00F2;
462       amc->bf53x.ambctl0 = 0xFFC2FFC2;
463       amc->bf53x.ambctl1 = 0xFFC2FFC2;
464       break;
465     case 590 ... 599: /* BF59x has no AMC.  */
466     default:
467       hw_abort (me, "no support for EBIU AMC on this Blackfin model yet");
468     }
469
470   attach_bfin_ebiu_amc_regs (me, amc, reg_size);
471
472   bfin_ebiu_amc_write_amgctl (me, amc, amgctl);
473 }
474
475 const struct hw_descriptor dv_bfin_ebiu_amc_descriptor[] =
476 {
477   {"bfin_ebiu_amc", bfin_ebiu_amc_finish,},
478   {NULL, NULL},
479 };