sim: dv-sockser: push module init prototype down
[external/binutils.git] / sim / bfin / dv-bfin_gpio.c
1 /* Blackfin General Purpose Ports (GPIO) model
2
3    Copyright (C) 2010-2015 Free Software Foundation, Inc.
4    Contributed by Analog Devices, Inc.
5
6    This file is part of simulators.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22
23 #include "sim-main.h"
24 #include "devices.h"
25 #include "dv-bfin_gpio.h"
26
27 struct bfin_gpio
28 {
29   bu32 base;
30
31   bu16 int_state;
32
33   /* Order after here is important -- matches hardware MMR layout.  */
34   bu16 BFIN_MMR_16(data);
35   bu16 BFIN_MMR_16(clear);
36   bu16 BFIN_MMR_16(set);
37   bu16 BFIN_MMR_16(toggle);
38   bu16 BFIN_MMR_16(maska);
39   bu16 BFIN_MMR_16(maska_clear);
40   bu16 BFIN_MMR_16(maska_set);
41   bu16 BFIN_MMR_16(maska_toggle);
42   bu16 BFIN_MMR_16(maskb);
43   bu16 BFIN_MMR_16(maskb_clear);
44   bu16 BFIN_MMR_16(maskb_set);
45   bu16 BFIN_MMR_16(maskb_toggle);
46   bu16 BFIN_MMR_16(dir);
47   bu16 BFIN_MMR_16(polar);
48   bu16 BFIN_MMR_16(edge);
49   bu16 BFIN_MMR_16(both);
50   bu16 BFIN_MMR_16(inen);
51 };
52 #define mmr_base()      offsetof(struct bfin_gpio, data)
53 #define mmr_offset(mmr) (offsetof(struct bfin_gpio, mmr) - mmr_base())
54
55 static const char * const mmr_names[] =
56 {
57   "PORTIO", "PORTIO_CLEAR", "PORTIO_SET", "PORTIO_TOGGLE", "PORTIO_MASKA",
58   "PORTIO_MASKA_CLEAR", "PORTIO_MASKA_SET", "PORTIO_MASKA_TOGGLE",
59   "PORTIO_MASKB", "PORTIO_MASKB_CLEAR", "PORTIO_MASKB_SET",
60   "PORTIO_MASKB_TOGGLE", "PORTIO_DIR", "PORTIO_POLAR", "PORTIO_EDGE",
61   "PORTIO_BOTH", "PORTIO_INEN",
62 };
63 #define mmr_name(off) mmr_names[(off) / 4]
64
65 static void
66 bfin_gpio_forward_int (struct hw *me, struct bfin_gpio *port, bu32 mask,
67                        int dst_port)
68 {
69   HW_TRACE ((me, "resending levels on port %c", 'a' + dst_port));
70   hw_port_event (me, dst_port, !!(port->int_state & mask));
71 }
72 static void
73 bfin_gpio_forward_ints (struct hw *me, struct bfin_gpio *port)
74 {
75   bfin_gpio_forward_int (me, port, port->maska, 0);
76   bfin_gpio_forward_int (me, port, port->maskb, 1);
77 }
78
79 static void
80 bfin_gpio_forward_ouput (struct hw *me, struct bfin_gpio *port, bu32 odata)
81 {
82   int pin, value, ovalue, bit;
83
84   for (pin = 0; pin < 16; ++pin)
85     {
86       bit = 1 << pin;
87
88       /* Make sure this is an output pin.  */
89       if (!(port->dir & bit))
90         continue;
91
92       /* Only signal port if the pin changes value.  */
93       value = !!(port->data & bit);
94       ovalue = !!(odata & bit);
95       if (value == ovalue)
96         continue;
97
98       HW_TRACE ((me, "outputting gpio %i changed to %i", pin, value));
99       hw_port_event (me, pin, value);
100     }
101 }
102
103 static unsigned
104 bfin_gpio_io_write_buffer (struct hw *me, const void *source, int space,
105                            address_word addr, unsigned nr_bytes)
106 {
107   struct bfin_gpio *port = hw_data (me);
108   bu32 mmr_off;
109   bu16 value;
110   bu16 *valuep;
111   bu32 data = port->data;
112
113   value = dv_load_2 (source);
114   mmr_off = addr - port->base;
115   valuep = (void *)((unsigned long)port + mmr_base() + mmr_off);
116
117   HW_TRACE_WRITE ();
118
119   dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
120
121   switch (mmr_off)
122     {
123     case mmr_offset(data):
124     case mmr_offset(maska):
125     case mmr_offset(maskb):
126     case mmr_offset(dir):
127     case mmr_offset(polar):
128     case mmr_offset(edge):
129     case mmr_offset(both):
130     case mmr_offset(inen):
131       *valuep = value;
132       break;
133     case mmr_offset(clear):
134     case mmr_offset(maska_clear):
135     case mmr_offset(maskb_clear):
136       /* We want to clear the related data MMR.  */
137       valuep -= 2;
138       dv_w1c_2 (valuep, value, -1);
139       break;
140     case mmr_offset(set):
141     case mmr_offset(maska_set):
142     case mmr_offset(maskb_set):
143       /* We want to set the related data MMR.  */
144       valuep -= 4;
145       *valuep |= value;
146       break;
147     case mmr_offset(toggle):
148     case mmr_offset(maska_toggle):
149     case mmr_offset(maskb_toggle):
150       /* We want to toggle the related data MMR.  */
151       valuep -= 6;
152       *valuep ^= value;
153       break;
154     default:
155       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
156       break;
157     }
158
159   /* If updating masks, make sure we send updated port info.  */
160   switch (mmr_off)
161     {
162     case mmr_offset(dir):
163     case mmr_offset(data) ... mmr_offset(toggle):
164       bfin_gpio_forward_ouput (me, port, data);
165       break;
166     case mmr_offset(maska) ... mmr_offset(maska_toggle):
167       bfin_gpio_forward_int (me, port, port->maska, 0);
168       break;
169     case mmr_offset(maskb) ... mmr_offset(maskb_toggle):
170       bfin_gpio_forward_int (me, port, port->maskb, 1);
171       break;
172     }
173
174   return nr_bytes;
175 }
176
177 static unsigned
178 bfin_gpio_io_read_buffer (struct hw *me, void *dest, int space,
179                           address_word addr, unsigned nr_bytes)
180 {
181   struct bfin_gpio *port = hw_data (me);
182   bu32 mmr_off;
183   bu16 *valuep;
184
185   mmr_off = addr - port->base;
186   valuep = (void *)((unsigned long)port + mmr_base() + mmr_off);
187
188   HW_TRACE_READ ();
189
190   dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
191
192   switch (mmr_off)
193     {
194     case mmr_offset(data):
195     case mmr_offset(clear):
196     case mmr_offset(set):
197     case mmr_offset(toggle):
198       dv_store_2 (dest, port->data);
199       break;
200     case mmr_offset(maska):
201     case mmr_offset(maska_clear):
202     case mmr_offset(maska_set):
203     case mmr_offset(maska_toggle):
204       dv_store_2 (dest, port->maska);
205       break;
206     case mmr_offset(maskb):
207     case mmr_offset(maskb_clear):
208     case mmr_offset(maskb_set):
209     case mmr_offset(maskb_toggle):
210       dv_store_2 (dest, port->maskb);
211       break;
212     case mmr_offset(dir):
213     case mmr_offset(polar):
214     case mmr_offset(edge):
215     case mmr_offset(both):
216     case mmr_offset(inen):
217       dv_store_2 (dest, *valuep);
218       break;
219     default:
220       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
221       break;
222     }
223
224   return nr_bytes;
225 }
226
227 static const struct hw_port_descriptor bfin_gpio_ports[] =
228 {
229   { "mask_a", 0, 0, output_port, },
230   { "mask_b", 1, 0, output_port, },
231   { "p0",     0, 0, bidirect_port, },
232   { "p1",     1, 0, bidirect_port, },
233   { "p2",     2, 0, bidirect_port, },
234   { "p3",     3, 0, bidirect_port, },
235   { "p4",     4, 0, bidirect_port, },
236   { "p5",     5, 0, bidirect_port, },
237   { "p6",     6, 0, bidirect_port, },
238   { "p7",     7, 0, bidirect_port, },
239   { "p8",     8, 0, bidirect_port, },
240   { "p9",     9, 0, bidirect_port, },
241   { "p10",   10, 0, bidirect_port, },
242   { "p11",   11, 0, bidirect_port, },
243   { "p12",   12, 0, bidirect_port, },
244   { "p13",   13, 0, bidirect_port, },
245   { "p14",   14, 0, bidirect_port, },
246   { "p15",   15, 0, bidirect_port, },
247   { NULL, 0, 0, 0, },
248 };
249
250 static void
251 bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source,
252                       int source_port, int level)
253 {
254   struct bfin_gpio *port = hw_data (me);
255   bool olvl, nlvl;
256   bu32 bit = (1 << my_port);
257
258   /* Normalize the level value.  A simulated device can send any value
259      it likes to us, but in reality we only care about 0 and 1.  This
260      lets us assume only those two values below.  */
261   level = !!level;
262
263   HW_TRACE ((me, "pin %i set to %i", my_port, level));
264
265   /* Only screw with state if this pin is set as an input, and the
266      input is actually enabled.  */
267   if ((port->dir & bit) || !(port->inen & bit))
268     {
269       HW_TRACE ((me, "ignoring level/int due to DIR=%i INEN=%i",
270                  !!(port->dir & bit), !!(port->inen & bit)));
271       return;
272     }
273
274   /* Get the old pin state for calculating an interrupt.  */
275   olvl = !!(port->data & bit);
276
277   /* Update the new pin state.  */
278   port->data = (port->data & ~bit) | (level << my_port);
279
280   /* See if this state transition will generate an interrupt.  */
281   nlvl = !!(port->data & bit);
282
283   if (port->edge & bit)
284     {
285       /* Pin is edge triggered.  */
286       if (port->both & bit)
287         {
288           /* Both edges.  */
289           if (olvl == nlvl)
290             {
291               HW_TRACE ((me, "ignoring int due to EDGE=%i BOTH=%i lvl=%i->%i",
292                          !!(port->edge & bit), !!(port->both & bit),
293                          olvl, nlvl));
294               return;
295             }
296         }
297       else
298         {
299           /* Just one edge.  */
300           if (!(((port->polar & bit) && olvl > nlvl)
301                 || (!(port->polar & bit) && olvl < nlvl)))
302             {
303               HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i->%i",
304                          !!(port->edge & bit), !!(port->polar & bit),
305                          olvl, nlvl));
306               return;
307             }
308         }
309
310       /* Send the signal up, and then fall through to clear it.  */
311       port->int_state |= bit;
312       bfin_gpio_forward_ints (me, port);
313       port->int_state &= ~bit;
314     }
315   else
316     {
317       /* Pin is level triggered.  */
318       if (nlvl == !!(port->polar & bit))
319         {
320           HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i",
321                      !!(port->edge & bit), !!(port->polar & bit), nlvl));
322           /* We still need to signal SIC to clear the int, so don't return.  */
323           port->int_state &= ~bit;
324         }
325       else
326         port->int_state |= bit;
327     }
328
329   bfin_gpio_forward_ints (me, port);
330 }
331
332 static void
333 attach_bfin_gpio_regs (struct hw *me, struct bfin_gpio *port)
334 {
335   address_word attach_address;
336   int attach_space;
337   unsigned attach_size;
338   reg_property_spec reg;
339
340   if (hw_find_property (me, "reg") == NULL)
341     hw_abort (me, "Missing \"reg\" property");
342
343   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
344     hw_abort (me, "\"reg\" property must contain three addr/size entries");
345
346   hw_unit_address_to_attach_address (hw_parent (me),
347                                      &reg.address,
348                                      &attach_space, &attach_address, me);
349   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
350
351   if (attach_size != BFIN_MMR_GPIO_SIZE)
352     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_GPIO_SIZE);
353
354   hw_attach_address (hw_parent (me),
355                      0, attach_space, attach_address, attach_size, me);
356
357   port->base = attach_address;
358 }
359
360 static void
361 bfin_gpio_finish (struct hw *me)
362 {
363   struct bfin_gpio *port;
364
365   port = HW_ZALLOC (me, struct bfin_gpio);
366
367   set_hw_data (me, port);
368   set_hw_io_read_buffer (me, bfin_gpio_io_read_buffer);
369   set_hw_io_write_buffer (me, bfin_gpio_io_write_buffer);
370   set_hw_ports (me, bfin_gpio_ports);
371   set_hw_port_event (me, bfin_gpio_port_event);
372
373   attach_bfin_gpio_regs (me, port);
374 }
375
376 const struct hw_descriptor dv_bfin_gpio_descriptor[] =
377 {
378   {"bfin_gpio", bfin_gpio_finish,},
379   {NULL, NULL},
380 };