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