sim: bfin: new PINT model
[external/binutils.git] / sim / bfin / dv-bfin_pint.c
1 /* Blackfin Pin Interrupt (PINT) model
2
3    Copyright (C) 2010-2012 Free Software Foundation, Inc.
4    Contributed by Analog Devices, Inc. and Mike Frysinger.
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_pint.h"
26
27 struct bfin_pint
28 {
29   bu32 base;
30
31   /* Only accessed indirectly via the associated set/clear MMRs.  */
32   bu32 mask, edge, invert;
33
34   /* Order after here is important -- matches hardware MMR layout.  */
35   bu32 mask_set;
36   bu32 mask_clear;
37   bu32 request;
38   bu32 assign;
39   bu32 edge_set;
40   bu32 edge_clear;
41   bu32 invert_set;
42   bu32 invert_clear;
43   bu32 pinstate;
44   bu32 latch;
45 };
46 #define mmr_base()      offsetof(struct bfin_pint, mask_set)
47 #define mmr_offset(mmr) (offsetof(struct bfin_pint, mmr) - mmr_base())
48
49 static const char * const mmr_names[] =
50 {
51   "PINT_MASK_SET", "PINT_MASK_CLEAR", "PINT_REQUEST", "PINT_ASSIGN",
52   "PINT_EDGE_SET", "PINT_EDGE_CLEAR", "PINT_INVERT_SET",
53   "PINT_INVERT_CLEAR", "PINT_PINSTATE", "PINT_LATCH",
54 };
55 #define mmr_name(off) mmr_names[(off) / 4]
56
57 static unsigned
58 bfin_pint_io_write_buffer (struct hw *me, const void *source, int space,
59                            address_word addr, unsigned nr_bytes)
60 {
61   struct bfin_pint *pint = hw_data (me);
62   bu32 mmr_off;
63   bu32 value;
64   bu32 *valuep;
65
66   if (nr_bytes == 4)
67     value = dv_load_4 (source);
68   else
69     value = dv_load_2 (source);
70   mmr_off = addr - pint->base;
71   valuep = (void *)((unsigned long)pint + mmr_base() + mmr_off);
72
73   HW_TRACE_WRITE ();
74
75   /* XXX: The hardware allows 16 or 32 bit accesses ...  */
76   dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
77
78   switch (mmr_off)
79     {
80     case mmr_offset(request):
81     case mmr_offset(assign):
82     case mmr_offset(pinstate):
83     case mmr_offset(latch):
84       *valuep = value;
85       break;
86     case mmr_offset(mask_set):
87       dv_w1c_4 (&pint->mask, value, -1);
88       break;
89     case mmr_offset(mask_clear):
90       pint->mask |= value;
91       break;
92     case mmr_offset(edge_set):
93       dv_w1c_4 (&pint->edge, value, -1);
94       break;
95     case mmr_offset(edge_clear):
96       pint->edge |= value;
97       break;
98     case mmr_offset(invert_set):
99       dv_w1c_4 (&pint->invert, value, -1);
100       break;
101     case mmr_offset(invert_clear):
102       pint->invert |= value;
103       break;
104     default:
105       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
106       break;
107     }
108
109 #if 0
110   /* If updating masks, make sure we send updated port info.  */
111   switch (mmr_off)
112     {
113     case mmr_offset(dir):
114     case mmr_offset(data) ... mmr_offset(toggle):
115       bfin_pint_forward_ouput (me, pint, data);
116       break;
117     case mmr_offset(maska) ... mmr_offset(maska_toggle):
118       bfin_pint_forward_int (me, pint, pint->maska, 0);
119       break;
120     case mmr_offset(maskb) ... mmr_offset(maskb_toggle):
121       bfin_pint_forward_int (me, pint, pint->maskb, 1);
122       break;
123     }
124 #endif
125
126   return nr_bytes;
127 }
128
129 static unsigned
130 bfin_pint_io_read_buffer (struct hw *me, void *dest, int space,
131                           address_word addr, unsigned nr_bytes)
132 {
133   struct bfin_pint *pint = hw_data (me);
134   bu32 mmr_off;
135   bu32 *valuep;
136
137   mmr_off = addr - pint->base;
138   valuep = (void *)((unsigned long)pint + mmr_base() + mmr_off);
139
140   HW_TRACE_READ ();
141
142   /* XXX: The hardware allows 16 or 32 bit accesses ...  */
143   dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
144
145   switch (mmr_off)
146     {
147     case mmr_offset(request):
148     case mmr_offset(assign):
149     case mmr_offset(pinstate):
150     case mmr_offset(latch):
151       dv_store_4 (dest, *valuep);
152       break;
153     case mmr_offset(mask_set):
154     case mmr_offset(mask_clear):
155       dv_store_4 (dest, pint->mask);
156       break;
157     case mmr_offset(edge_set):
158     case mmr_offset(edge_clear):
159       dv_store_4 (dest, pint->edge);
160       break;
161     case mmr_offset(invert_set):
162     case mmr_offset(invert_clear):
163       dv_store_4 (dest, pint->invert);
164       break;
165     default:
166       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
167       break;
168     }
169
170   return nr_bytes;
171 }
172
173 #define ENC(bmap, piq) (((bmap) << 8) + (piq))
174
175 #define PIQ_PORTS(n) \
176   { "piq0@"#n,   ENC(n,  0), 0, input_port, }, \
177   { "piq1@"#n,   ENC(n,  1), 0, input_port, }, \
178   { "piq2@"#n,   ENC(n,  2), 0, input_port, }, \
179   { "piq3@"#n,   ENC(n,  3), 0, input_port, }, \
180   { "piq4@"#n,   ENC(n,  4), 0, input_port, }, \
181   { "piq5@"#n,   ENC(n,  5), 0, input_port, }, \
182   { "piq6@"#n,   ENC(n,  6), 0, input_port, }, \
183   { "piq7@"#n,   ENC(n,  7), 0, input_port, }, \
184   { "piq8@"#n,   ENC(n,  8), 0, input_port, }, \
185   { "piq9@"#n,   ENC(n,  9), 0, input_port, }, \
186   { "piq10@"#n,  ENC(n, 10), 0, input_port, }, \
187   { "piq11@"#n,  ENC(n, 11), 0, input_port, }, \
188   { "piq12@"#n,  ENC(n, 12), 0, input_port, }, \
189   { "piq13@"#n,  ENC(n, 13), 0, input_port, }, \
190   { "piq14@"#n,  ENC(n, 14), 0, input_port, }, \
191   { "piq15@"#n,  ENC(n, 15), 0, input_port, }, \
192   { "piq16@"#n,  ENC(n, 16), 0, input_port, }, \
193   { "piq17@"#n,  ENC(n, 17), 0, input_port, }, \
194   { "piq18@"#n,  ENC(n, 18), 0, input_port, }, \
195   { "piq19@"#n,  ENC(n, 19), 0, input_port, }, \
196   { "piq20@"#n,  ENC(n, 20), 0, input_port, }, \
197   { "piq21@"#n,  ENC(n, 21), 0, input_port, }, \
198   { "piq22@"#n,  ENC(n, 22), 0, input_port, }, \
199   { "piq23@"#n,  ENC(n, 23), 0, input_port, }, \
200   { "piq24@"#n,  ENC(n, 24), 0, input_port, }, \
201   { "piq25@"#n,  ENC(n, 25), 0, input_port, }, \
202   { "piq26@"#n,  ENC(n, 26), 0, input_port, }, \
203   { "piq27@"#n,  ENC(n, 27), 0, input_port, }, \
204   { "piq28@"#n,  ENC(n, 28), 0, input_port, }, \
205   { "piq29@"#n,  ENC(n, 29), 0, input_port, }, \
206   { "piq30@"#n,  ENC(n, 30), 0, input_port, }, \
207   { "piq31@"#n,  ENC(n, 31), 0, input_port, },
208
209 static const struct hw_port_descriptor bfin_pint_ports[] =
210 {
211   { "stat", 0, 0, output_port, },
212   PIQ_PORTS(0)
213   PIQ_PORTS(1)
214   PIQ_PORTS(2)
215   PIQ_PORTS(3)
216   PIQ_PORTS(4)
217   PIQ_PORTS(5)
218   PIQ_PORTS(6)
219   PIQ_PORTS(7)
220   { NULL, 0, 0, 0, },
221 };
222
223 static void
224 bfin_pint_port_event (struct hw *me, int my_port, struct hw *source,
225                       int source_port, int level)
226 {
227   /* XXX: TODO.  */
228 }
229
230 static void
231 attach_bfin_pint_regs (struct hw *me, struct bfin_pint *pint)
232 {
233   address_word attach_address;
234   int attach_space;
235   unsigned attach_size;
236   reg_property_spec reg;
237
238   if (hw_find_property (me, "reg") == NULL)
239     hw_abort (me, "Missing \"reg\" property");
240
241   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
242     hw_abort (me, "\"reg\" property must contain three addr/size entries");
243
244   hw_unit_address_to_attach_address (hw_parent (me),
245                                      &reg.address,
246                                      &attach_space, &attach_address, me);
247   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
248
249   if (attach_size != BFIN_MMR_PINT_SIZE)
250     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PINT_SIZE);
251
252   hw_attach_address (hw_parent (me),
253                      0, attach_space, attach_address, attach_size, me);
254
255   pint->base = attach_address;
256 }
257
258 static void
259 bfin_pint_finish (struct hw *me)
260 {
261   struct bfin_pint *pint;
262
263   pint = HW_ZALLOC (me, struct bfin_pint);
264
265   set_hw_data (me, pint);
266   set_hw_io_read_buffer (me, bfin_pint_io_read_buffer);
267   set_hw_io_write_buffer (me, bfin_pint_io_write_buffer);
268   set_hw_ports (me, bfin_pint_ports);
269   set_hw_port_event (me, bfin_pint_port_event);
270
271   /* Initialize the PINT.  */
272   switch (dv_get_bus_num (me))
273     {
274     case 0:
275       pint->assign = 0x00000101;
276       break;
277     case 1:
278       pint->assign = 0x01010000;
279       break;
280     case 2:
281       pint->assign = 0x00000101;
282       break;
283     case 3:
284       pint->assign = 0x02020303;
285       break;
286     default:
287       /* XXX: Should move this default into device tree.  */
288       hw_abort (me, "no support for PINT at this address yet");
289     }
290
291   attach_bfin_pint_regs (me, pint);
292 }
293
294 const struct hw_descriptor dv_bfin_pint_descriptor[] =
295 {
296   {"bfin_pint", bfin_pint_finish,},
297   {NULL, NULL},
298 };