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