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