1 /* Blackfin General Purpose Ports (GPIO) model 2 3 Copyright (C) 2010-2020 Free Software Foundation, Inc. 4 Contributed by Analog Devices, Inc. 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_gpio.h" 26 27 struct bfin_gpio 28 { 29 bu32 base; 30 31 bu16 int_state; 32 33 /* Order after here is important -- matches hardware MMR layout. */ 34 bu16 BFIN_MMR_16(data); 35 bu16 BFIN_MMR_16(clear); 36 bu16 BFIN_MMR_16(set); 37 bu16 BFIN_MMR_16(toggle); 38 bu16 BFIN_MMR_16(maska); 39 bu16 BFIN_MMR_16(maska_clear); 40 bu16 BFIN_MMR_16(maska_set); 41 bu16 BFIN_MMR_16(maska_toggle); 42 bu16 BFIN_MMR_16(maskb); 43 bu16 BFIN_MMR_16(maskb_clear); 44 bu16 BFIN_MMR_16(maskb_set); 45 bu16 BFIN_MMR_16(maskb_toggle); 46 bu16 BFIN_MMR_16(dir); 47 bu16 BFIN_MMR_16(polar); 48 bu16 BFIN_MMR_16(edge); 49 bu16 BFIN_MMR_16(both); 50 bu16 BFIN_MMR_16(inen); 51 }; 52 #define mmr_base() offsetof(struct bfin_gpio, data) 53 #define mmr_offset(mmr) (offsetof(struct bfin_gpio, mmr) - mmr_base()) 54 55 static const char * const mmr_names[] = 56 { 57 "PORTIO", "PORTIO_CLEAR", "PORTIO_SET", "PORTIO_TOGGLE", "PORTIO_MASKA", 58 "PORTIO_MASKA_CLEAR", "PORTIO_MASKA_SET", "PORTIO_MASKA_TOGGLE", 59 "PORTIO_MASKB", "PORTIO_MASKB_CLEAR", "PORTIO_MASKB_SET", 60 "PORTIO_MASKB_TOGGLE", "PORTIO_DIR", "PORTIO_POLAR", "PORTIO_EDGE", 61 "PORTIO_BOTH", "PORTIO_INEN", 62 }; 63 #define mmr_name(off) mmr_names[(off) / 4] 64 65 static void 66 bfin_gpio_forward_int (struct hw *me, struct bfin_gpio *port, bu32 mask, 67 int dst_port) 68 { 69 HW_TRACE ((me, "resending levels on port %c", 'a' + dst_port)); 70 hw_port_event (me, dst_port, !!(port->int_state & mask)); 71 } 72 static void 73 bfin_gpio_forward_ints (struct hw *me, struct bfin_gpio *port) 74 { 75 bfin_gpio_forward_int (me, port, port->maska, 0); 76 bfin_gpio_forward_int (me, port, port->maskb, 1); 77 } 78 79 static void 80 bfin_gpio_forward_ouput (struct hw *me, struct bfin_gpio *port, bu32 odata) 81 { 82 int pin, value, ovalue, bit; 83 84 for (pin = 0; pin < 16; ++pin) 85 { 86 bit = 1 << pin; 87 88 /* Make sure this is an output pin. */ 89 if (!(port->dir & bit)) 90 continue; 91 92 /* Only signal port if the pin changes value. */ 93 value = !!(port->data & bit); 94 ovalue = !!(odata & bit); 95 if (value == ovalue) 96 continue; 97 98 HW_TRACE ((me, "outputting gpio %i changed to %i", pin, value)); 99 hw_port_event (me, pin, value); 100 } 101 } 102 103 static unsigned 104 bfin_gpio_io_write_buffer (struct hw *me, const void *source, int space, 105 address_word addr, unsigned nr_bytes) 106 { 107 struct bfin_gpio *port = hw_data (me); 108 bu32 mmr_off; 109 bu16 value; 110 bu16 *valuep; 111 bu32 data = port->data; 112 113 /* Invalid access mode is higher priority than missing register. */ 114 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true)) 115 return 0; 116 117 value = dv_load_2 (source); 118 mmr_off = addr - port->base; 119 valuep = (void *)((unsigned long)port + mmr_base() + mmr_off); 120 121 HW_TRACE_WRITE (); 122 123 switch (mmr_off) 124 { 125 case mmr_offset(data): 126 case mmr_offset(maska): 127 case mmr_offset(maskb): 128 case mmr_offset(dir): 129 case mmr_offset(polar): 130 case mmr_offset(edge): 131 case mmr_offset(both): 132 case mmr_offset(inen): 133 *valuep = value; 134 break; 135 case mmr_offset(clear): 136 case mmr_offset(maska_clear): 137 case mmr_offset(maskb_clear): 138 /* We want to clear the related data MMR. */ 139 valuep -= 2; 140 dv_w1c_2 (valuep, value, -1); 141 break; 142 case mmr_offset(set): 143 case mmr_offset(maska_set): 144 case mmr_offset(maskb_set): 145 /* We want to set the related data MMR. */ 146 valuep -= 4; 147 *valuep |= value; 148 break; 149 case mmr_offset(toggle): 150 case mmr_offset(maska_toggle): 151 case mmr_offset(maskb_toggle): 152 /* We want to toggle the related data MMR. */ 153 valuep -= 6; 154 *valuep ^= value; 155 break; 156 default: 157 dv_bfin_mmr_invalid (me, addr, nr_bytes, true); 158 return 0; 159 } 160 161 /* If updating masks, make sure we send updated port info. */ 162 switch (mmr_off) 163 { 164 case mmr_offset(dir): 165 case mmr_offset(data) ... mmr_offset(toggle): 166 bfin_gpio_forward_ouput (me, port, data); 167 break; 168 case mmr_offset(maska) ... mmr_offset(maska_toggle): 169 bfin_gpio_forward_int (me, port, port->maska, 0); 170 break; 171 case mmr_offset(maskb) ... mmr_offset(maskb_toggle): 172 bfin_gpio_forward_int (me, port, port->maskb, 1); 173 break; 174 } 175 176 return nr_bytes; 177 } 178 179 static unsigned 180 bfin_gpio_io_read_buffer (struct hw *me, void *dest, int space, 181 address_word addr, unsigned nr_bytes) 182 { 183 struct bfin_gpio *port = hw_data (me); 184 bu32 mmr_off; 185 bu16 *valuep; 186 187 /* Invalid access mode is higher priority than missing register. */ 188 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false)) 189 return 0; 190 191 mmr_off = addr - port->base; 192 valuep = (void *)((unsigned long)port + mmr_base() + mmr_off); 193 194 HW_TRACE_READ (); 195 196 switch (mmr_off) 197 { 198 case mmr_offset(data): 199 case mmr_offset(clear): 200 case mmr_offset(set): 201 case mmr_offset(toggle): 202 dv_store_2 (dest, port->data); 203 break; 204 case mmr_offset(maska): 205 case mmr_offset(maska_clear): 206 case mmr_offset(maska_set): 207 case mmr_offset(maska_toggle): 208 dv_store_2 (dest, port->maska); 209 break; 210 case mmr_offset(maskb): 211 case mmr_offset(maskb_clear): 212 case mmr_offset(maskb_set): 213 case mmr_offset(maskb_toggle): 214 dv_store_2 (dest, port->maskb); 215 break; 216 case mmr_offset(dir): 217 case mmr_offset(polar): 218 case mmr_offset(edge): 219 case mmr_offset(both): 220 case mmr_offset(inen): 221 dv_store_2 (dest, *valuep); 222 break; 223 default: 224 dv_bfin_mmr_invalid (me, addr, nr_bytes, false); 225 return 0; 226 } 227 228 return nr_bytes; 229 } 230 231 static const struct hw_port_descriptor bfin_gpio_ports[] = 232 { 233 { "mask_a", 0, 0, output_port, }, 234 { "mask_b", 1, 0, output_port, }, 235 { "p0", 0, 0, bidirect_port, }, 236 { "p1", 1, 0, bidirect_port, }, 237 { "p2", 2, 0, bidirect_port, }, 238 { "p3", 3, 0, bidirect_port, }, 239 { "p4", 4, 0, bidirect_port, }, 240 { "p5", 5, 0, bidirect_port, }, 241 { "p6", 6, 0, bidirect_port, }, 242 { "p7", 7, 0, bidirect_port, }, 243 { "p8", 8, 0, bidirect_port, }, 244 { "p9", 9, 0, bidirect_port, }, 245 { "p10", 10, 0, bidirect_port, }, 246 { "p11", 11, 0, bidirect_port, }, 247 { "p12", 12, 0, bidirect_port, }, 248 { "p13", 13, 0, bidirect_port, }, 249 { "p14", 14, 0, bidirect_port, }, 250 { "p15", 15, 0, bidirect_port, }, 251 { NULL, 0, 0, 0, }, 252 }; 253 254 static void 255 bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source, 256 int source_port, int level) 257 { 258 struct bfin_gpio *port = hw_data (me); 259 bool olvl, nlvl; 260 bu32 bit = (1 << my_port); 261 262 /* Normalize the level value. A simulated device can send any value 263 it likes to us, but in reality we only care about 0 and 1. This 264 lets us assume only those two values below. */ 265 level = !!level; 266 267 HW_TRACE ((me, "pin %i set to %i", my_port, level)); 268 269 /* Only screw with state if this pin is set as an input, and the 270 input is actually enabled. */ 271 if ((port->dir & bit) || !(port->inen & bit)) 272 { 273 HW_TRACE ((me, "ignoring level/int due to DIR=%i INEN=%i", 274 !!(port->dir & bit), !!(port->inen & bit))); 275 return; 276 } 277 278 /* Get the old pin state for calculating an interrupt. */ 279 olvl = !!(port->data & bit); 280 281 /* Update the new pin state. */ 282 port->data = (port->data & ~bit) | (level << my_port); 283 284 /* See if this state transition will generate an interrupt. */ 285 nlvl = !!(port->data & bit); 286 287 if (port->edge & bit) 288 { 289 /* Pin is edge triggered. */ 290 if (port->both & bit) 291 { 292 /* Both edges. */ 293 if (olvl == nlvl) 294 { 295 HW_TRACE ((me, "ignoring int due to EDGE=%i BOTH=%i lvl=%i->%i", 296 !!(port->edge & bit), !!(port->both & bit), 297 olvl, nlvl)); 298 return; 299 } 300 } 301 else 302 { 303 /* Just one edge. */ 304 if (!(((port->polar & bit) && olvl > nlvl) 305 || (!(port->polar & bit) && olvl < nlvl))) 306 { 307 HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i->%i", 308 !!(port->edge & bit), !!(port->polar & bit), 309 olvl, nlvl)); 310 return; 311 } 312 } 313 314 /* Send the signal up, and then fall through to clear it. */ 315 port->int_state |= bit; 316 bfin_gpio_forward_ints (me, port); 317 port->int_state &= ~bit; 318 } 319 else 320 { 321 /* Pin is level triggered. */ 322 if (nlvl == !!(port->polar & bit)) 323 { 324 HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i", 325 !!(port->edge & bit), !!(port->polar & bit), nlvl)); 326 /* We still need to signal SIC to clear the int, so don't return. */ 327 port->int_state &= ~bit; 328 } 329 else 330 port->int_state |= bit; 331 } 332 333 bfin_gpio_forward_ints (me, port); 334 } 335 336 static void 337 attach_bfin_gpio_regs (struct hw *me, struct bfin_gpio *port) 338 { 339 address_word attach_address; 340 int attach_space; 341 unsigned attach_size; 342 reg_property_spec reg; 343 344 if (hw_find_property (me, "reg") == NULL) 345 hw_abort (me, "Missing \"reg\" property"); 346 347 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 348 hw_abort (me, "\"reg\" property must contain three addr/size entries"); 349 350 hw_unit_address_to_attach_address (hw_parent (me), 351 ®.address, 352 &attach_space, &attach_address, me); 353 hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 354 355 if (attach_size != BFIN_MMR_GPIO_SIZE) 356 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_GPIO_SIZE); 357 358 hw_attach_address (hw_parent (me), 359 0, attach_space, attach_address, attach_size, me); 360 361 port->base = attach_address; 362 } 363 364 static void 365 bfin_gpio_finish (struct hw *me) 366 { 367 struct bfin_gpio *port; 368 369 port = HW_ZALLOC (me, struct bfin_gpio); 370 371 set_hw_data (me, port); 372 set_hw_io_read_buffer (me, bfin_gpio_io_read_buffer); 373 set_hw_io_write_buffer (me, bfin_gpio_io_write_buffer); 374 set_hw_ports (me, bfin_gpio_ports); 375 set_hw_port_event (me, bfin_gpio_port_event); 376 377 attach_bfin_gpio_regs (me, port); 378 } 379 380 const struct hw_descriptor dv_bfin_gpio_descriptor[] = 381 { 382 {"bfin_gpio", bfin_gpio_finish,}, 383 {NULL, NULL}, 384 }; 385