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