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