1 1.1 christos /* Blackfin Pin Interrupt (PINT) model 2 1.1 christos 3 1.11 christos Copyright (C) 2010-2024 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