Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_ebiu_amc.c revision 1.1.1.1
      1 /* Blackfin External Bus Interface Unit (EBIU) Asynchronous Memory Controller
      2    (AMC) model.
      3 
      4    Copyright (C) 2010-2014 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       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
    125       bfin_ebiu_amc_write_amgctl (me, amc, value);
    126       break;
    127     case mmr_offset(bf50x.ambctl0):
    128       amc->bf50x.ambctl0 = value;
    129       break;
    130     case mmr_offset(bf50x.ambctl1):
    131       amc->bf50x.ambctl1 = value;
    132       break;
    133     case mmr_offset(bf50x.mode):
    134       /* XXX: implement this.  */
    135       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
    136       break;
    137     case mmr_offset(bf50x.fctl):
    138       /* XXX: implement this.  */
    139       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
    140       break;
    141     default:
    142       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    143       break;
    144     }
    145 
    146   return nr_bytes;
    147 }
    148 
    149 static unsigned
    150 bf53x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
    151 				address_word addr, unsigned nr_bytes,
    152 				struct bfin_ebiu_amc *amc, bu32 mmr_off,
    153 				bu32 value)
    154 {
    155   switch (mmr_off)
    156     {
    157     case mmr_offset(amgctl):
    158       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
    159       bfin_ebiu_amc_write_amgctl (me, amc, value);
    160       break;
    161     case mmr_offset(bf53x.ambctl0):
    162       amc->bf53x.ambctl0 = value;
    163       break;
    164     case mmr_offset(bf53x.ambctl1):
    165       amc->bf53x.ambctl1 = value;
    166       break;
    167     default:
    168       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    169       break;
    170     }
    171 
    172   return nr_bytes;
    173 }
    174 
    175 static unsigned
    176 bf54x_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
    177 				address_word addr, unsigned nr_bytes,
    178 				struct bfin_ebiu_amc *amc, bu32 mmr_off,
    179 				bu32 value)
    180 {
    181   switch (mmr_off)
    182     {
    183     case mmr_offset(amgctl):
    184       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
    185       bfin_ebiu_amc_write_amgctl (me, amc, value);
    186       break;
    187     case mmr_offset(bf54x.ambctl0):
    188       amc->bf54x.ambctl0 = value;
    189       break;
    190     case mmr_offset(bf54x.ambctl1):
    191       amc->bf54x.ambctl1 = value;
    192       break;
    193     case mmr_offset(bf54x.mbsctl):
    194       /* XXX: implement this.  */
    195       break;
    196     case mmr_offset(bf54x.arbstat):
    197       /* XXX: implement this.  */
    198       break;
    199     case mmr_offset(bf54x.mode):
    200       /* XXX: implement this.  */
    201       break;
    202     case mmr_offset(bf54x.fctl):
    203       /* XXX: implement this.  */
    204       break;
    205     default:
    206       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    207       break;
    208     }
    209 
    210   return nr_bytes;
    211 }
    212 
    213 static unsigned
    214 bfin_ebiu_amc_io_write_buffer (struct hw *me, const void *source, int space,
    215 			       address_word addr, unsigned nr_bytes)
    216 {
    217   struct bfin_ebiu_amc *amc = hw_data (me);
    218   bu32 mmr_off;
    219   bu32 value;
    220 
    221   value = dv_load_4 (source);
    222   mmr_off = addr - amc->base;
    223 
    224   HW_TRACE_WRITE ();
    225 
    226   return amc->io_write (me, source, space, addr, nr_bytes,
    227 			amc, mmr_off, value);
    228 }
    229 
    230 static unsigned
    231 bf50x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
    232 			       address_word addr, unsigned nr_bytes,
    233 			       struct bfin_ebiu_amc *amc, bu32 mmr_off,
    234 			       void *valuep, bu16 *value16, bu32 *value32)
    235 {
    236   switch (mmr_off)
    237     {
    238     case mmr_offset(amgctl):
    239     case mmr_offset(bf50x.fctl):
    240       dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
    241       dv_store_2 (dest, *value16);
    242       break;
    243     case mmr_offset(bf50x.ambctl0):
    244     case mmr_offset(bf50x.ambctl1):
    245     case mmr_offset(bf50x.mode):
    246       dv_store_4 (dest, *value32);
    247       break;
    248     default:
    249       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    250       break;
    251     }
    252 
    253   return nr_bytes;
    254 }
    255 
    256 static unsigned
    257 bf53x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
    258 			       address_word addr, unsigned nr_bytes,
    259 			       struct bfin_ebiu_amc *amc, bu32 mmr_off,
    260 			       void *valuep, bu16 *value16, bu32 *value32)
    261 {
    262   switch (mmr_off)
    263     {
    264     case mmr_offset(amgctl):
    265       dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
    266       dv_store_2 (dest, *value16);
    267       break;
    268     case mmr_offset(bf53x.ambctl0):
    269     case mmr_offset(bf53x.ambctl1):
    270       dv_store_4 (dest, *value32);
    271       break;
    272     default:
    273       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    274       break;
    275     }
    276 
    277   return nr_bytes;
    278 }
    279 
    280 static unsigned
    281 bf54x_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
    282 			       address_word addr, unsigned nr_bytes,
    283 			       struct bfin_ebiu_amc *amc, bu32 mmr_off,
    284 			       void *valuep, bu16 *value16, bu32 *value32)
    285 {
    286   switch (mmr_off)
    287     {
    288     case mmr_offset(amgctl):
    289       dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
    290       dv_store_2 (dest, *value16);
    291       break;
    292     case mmr_offset(bf54x.ambctl0):
    293     case mmr_offset(bf54x.ambctl1):
    294     case mmr_offset(bf54x.mbsctl):
    295     case mmr_offset(bf54x.arbstat):
    296     case mmr_offset(bf54x.mode):
    297     case mmr_offset(bf54x.fctl):
    298       dv_store_4 (dest, *value32);
    299       break;
    300     default:
    301       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    302       break;
    303     }
    304 
    305   return nr_bytes;
    306 }
    307 
    308 static unsigned
    309 bfin_ebiu_amc_io_read_buffer (struct hw *me, void *dest, int space,
    310 			      address_word addr, unsigned nr_bytes)
    311 {
    312   struct bfin_ebiu_amc *amc = hw_data (me);
    313   bu32 mmr_off;
    314   void *valuep;
    315 
    316   mmr_off = addr - amc->base;
    317   valuep = (void *)((unsigned long)amc + mmr_base() + mmr_off);
    318 
    319   HW_TRACE_READ ();
    320 
    321   return amc->io_read (me, dest, space, addr, nr_bytes, amc,
    322 		       mmr_off, valuep, valuep, valuep);
    323 }
    324 
    325 static void
    326 bfin_ebiu_amc_attach_address_callback (struct hw *me,
    327 				       int level,
    328 				       int space,
    329 				       address_word addr,
    330 				       address_word nr_bytes,
    331 				       struct hw *client)
    332 {
    333   struct bfin_ebiu_amc *amc = hw_data (me);
    334 
    335   HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
    336 	     level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
    337 
    338   if (addr + nr_bytes > ARRAY_SIZE (amc->slaves))
    339     hw_abort (me, "ebiu amc attaches are done in terms of banks");
    340 
    341   while (nr_bytes--)
    342     amc->slaves[addr + nr_bytes] = client;
    343 
    344   bfin_ebiu_amc_write_amgctl (me, amc, amc->amgctl);
    345 }
    346 
    347 static void
    348 attach_bfin_ebiu_amc_regs (struct hw *me, struct bfin_ebiu_amc *amc,
    349 			   unsigned reg_size)
    350 {
    351   address_word attach_address;
    352   int attach_space;
    353   unsigned attach_size;
    354   reg_property_spec reg;
    355 
    356   if (hw_find_property (me, "reg") == NULL)
    357     hw_abort (me, "Missing \"reg\" property");
    358 
    359   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    360     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    361 
    362   if (hw_find_property (me, "type") == NULL)
    363     hw_abort (me, "Missing \"type\" property");
    364 
    365   hw_unit_address_to_attach_address (hw_parent (me),
    366 				     &reg.address,
    367 				     &attach_space, &attach_address, me);
    368   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    369 
    370   if (attach_size != reg_size)
    371     hw_abort (me, "\"reg\" size must be %#x", reg_size);
    372 
    373   hw_attach_address (hw_parent (me),
    374 		     0, attach_space, attach_address, attach_size, me);
    375 
    376   amc->base = attach_address;
    377 }
    378 
    379 static void
    380 bfin_ebiu_amc_finish (struct hw *me)
    381 {
    382   struct bfin_ebiu_amc *amc;
    383   bu32 amgctl;
    384   unsigned reg_size;
    385 
    386   amc = HW_ZALLOC (me, struct bfin_ebiu_amc);
    387 
    388   set_hw_data (me, amc);
    389   set_hw_io_read_buffer (me, bfin_ebiu_amc_io_read_buffer);
    390   set_hw_io_write_buffer (me, bfin_ebiu_amc_io_write_buffer);
    391   set_hw_attach_address (me, bfin_ebiu_amc_attach_address_callback);
    392 
    393   amc->type = hw_find_integer_property (me, "type");
    394 
    395   switch (amc->type)
    396     {
    397     case 500 ... 509:
    398       amc->io_write = bf50x_ebiu_amc_io_write_buffer;
    399       amc->io_read = bf50x_ebiu_amc_io_read_buffer;
    400       mmr_names = bf50x_mmr_names;
    401       reg_size = sizeof (amc->bf50x) + 4;
    402 
    403       /* Initialize the AMC.  */
    404       amc->bank_base     = BFIN_EBIU_AMC_BASE;
    405       amc->bank_size     = 1 * 1024 * 1024;
    406       amgctl             = 0x00F3;
    407       amc->bf50x.ambctl0 = 0x0000FFC2;
    408       amc->bf50x.ambctl1 = 0x0000FFC2;
    409       amc->bf50x.mode    = 0x0001;
    410       amc->bf50x.fctl    = 0x0002;
    411       break;
    412     case 540 ... 549:
    413       amc->io_write = bf54x_ebiu_amc_io_write_buffer;
    414       amc->io_read = bf54x_ebiu_amc_io_read_buffer;
    415       mmr_names = bf54x_mmr_names;
    416       reg_size = sizeof (amc->bf54x) + 4;
    417 
    418       /* Initialize the AMC.  */
    419       amc->bank_base     = BFIN_EBIU_AMC_BASE;
    420       amc->bank_size     = 64 * 1024 * 1024;
    421       amgctl             = 0x0002;
    422       amc->bf54x.ambctl0 = 0xFFC2FFC2;
    423       amc->bf54x.ambctl1 = 0xFFC2FFC2;
    424       amc->bf54x.fctl    = 0x0006;
    425       break;
    426     case 510 ... 519:
    427     case 522 ... 527:
    428     case 531 ... 533:
    429     case 534:
    430     case 536:
    431     case 537:
    432     case 538 ... 539:
    433     case 561:
    434       amc->io_write = bf53x_ebiu_amc_io_write_buffer;
    435       amc->io_read = bf53x_ebiu_amc_io_read_buffer;
    436       mmr_names = bf53x_mmr_names;
    437       reg_size = sizeof (amc->bf53x) + 4;
    438 
    439       /* Initialize the AMC.  */
    440       amc->bank_base     = BFIN_EBIU_AMC_BASE;
    441       if (amc->type == 561)
    442 	amc->bank_size   = 64 * 1024 * 1024;
    443       else
    444 	amc->bank_size   = 1 * 1024 * 1024;
    445       amgctl             = 0x00F2;
    446       amc->bf53x.ambctl0 = 0xFFC2FFC2;
    447       amc->bf53x.ambctl1 = 0xFFC2FFC2;
    448       break;
    449     case 590 ... 599: /* BF59x has no AMC.  */
    450     default:
    451       hw_abort (me, "no support for EBIU AMC on this Blackfin model yet");
    452     }
    453 
    454   attach_bfin_ebiu_amc_regs (me, amc, reg_size);
    455 
    456   bfin_ebiu_amc_write_amgctl (me, amc, amgctl);
    457 }
    458 
    459 const struct hw_descriptor dv_bfin_ebiu_amc_descriptor[] =
    460 {
    461   {"bfin_ebiu_amc", bfin_ebiu_amc_finish,},
    462   {NULL, NULL},
    463 };
    464