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