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