1 /* Blackfin General Purpose Ports (GPIO) model 2 3 Copyright (C) 2010-2015 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 value = dv_load_2 (source); 114 mmr_off = addr - port->base; 115 valuep = (void *)((unsigned long)port + mmr_base() + mmr_off); 116 117 HW_TRACE_WRITE (); 118 119 dv_bfin_mmr_require_16 (me, addr, nr_bytes, true); 120 121 switch (mmr_off) 122 { 123 case mmr_offset(data): 124 case mmr_offset(maska): 125 case mmr_offset(maskb): 126 case mmr_offset(dir): 127 case mmr_offset(polar): 128 case mmr_offset(edge): 129 case mmr_offset(both): 130 case mmr_offset(inen): 131 *valuep = value; 132 break; 133 case mmr_offset(clear): 134 case mmr_offset(maska_clear): 135 case mmr_offset(maskb_clear): 136 /* We want to clear the related data MMR. */ 137 valuep -= 2; 138 dv_w1c_2 (valuep, value, -1); 139 break; 140 case mmr_offset(set): 141 case mmr_offset(maska_set): 142 case mmr_offset(maskb_set): 143 /* We want to set the related data MMR. */ 144 valuep -= 4; 145 *valuep |= value; 146 break; 147 case mmr_offset(toggle): 148 case mmr_offset(maska_toggle): 149 case mmr_offset(maskb_toggle): 150 /* We want to toggle the related data MMR. */ 151 valuep -= 6; 152 *valuep ^= value; 153 break; 154 default: 155 dv_bfin_mmr_invalid (me, addr, nr_bytes, true); 156 break; 157 } 158 159 /* If updating masks, make sure we send updated port info. */ 160 switch (mmr_off) 161 { 162 case mmr_offset(dir): 163 case mmr_offset(data) ... mmr_offset(toggle): 164 bfin_gpio_forward_ouput (me, port, data); 165 break; 166 case mmr_offset(maska) ... mmr_offset(maska_toggle): 167 bfin_gpio_forward_int (me, port, port->maska, 0); 168 break; 169 case mmr_offset(maskb) ... mmr_offset(maskb_toggle): 170 bfin_gpio_forward_int (me, port, port->maskb, 1); 171 break; 172 } 173 174 return nr_bytes; 175 } 176 177 static unsigned 178 bfin_gpio_io_read_buffer (struct hw *me, void *dest, int space, 179 address_word addr, unsigned nr_bytes) 180 { 181 struct bfin_gpio *port = hw_data (me); 182 bu32 mmr_off; 183 bu16 *valuep; 184 185 mmr_off = addr - port->base; 186 valuep = (void *)((unsigned long)port + mmr_base() + mmr_off); 187 188 HW_TRACE_READ (); 189 190 dv_bfin_mmr_require_16 (me, addr, nr_bytes, false); 191 192 switch (mmr_off) 193 { 194 case mmr_offset(data): 195 case mmr_offset(clear): 196 case mmr_offset(set): 197 case mmr_offset(toggle): 198 dv_store_2 (dest, port->data); 199 break; 200 case mmr_offset(maska): 201 case mmr_offset(maska_clear): 202 case mmr_offset(maska_set): 203 case mmr_offset(maska_toggle): 204 dv_store_2 (dest, port->maska); 205 break; 206 case mmr_offset(maskb): 207 case mmr_offset(maskb_clear): 208 case mmr_offset(maskb_set): 209 case mmr_offset(maskb_toggle): 210 dv_store_2 (dest, port->maskb); 211 break; 212 case mmr_offset(dir): 213 case mmr_offset(polar): 214 case mmr_offset(edge): 215 case mmr_offset(both): 216 case mmr_offset(inen): 217 dv_store_2 (dest, *valuep); 218 break; 219 default: 220 dv_bfin_mmr_invalid (me, addr, nr_bytes, false); 221 break; 222 } 223 224 return nr_bytes; 225 } 226 227 static const struct hw_port_descriptor bfin_gpio_ports[] = 228 { 229 { "mask_a", 0, 0, output_port, }, 230 { "mask_b", 1, 0, output_port, }, 231 { "p0", 0, 0, bidirect_port, }, 232 { "p1", 1, 0, bidirect_port, }, 233 { "p2", 2, 0, bidirect_port, }, 234 { "p3", 3, 0, bidirect_port, }, 235 { "p4", 4, 0, bidirect_port, }, 236 { "p5", 5, 0, bidirect_port, }, 237 { "p6", 6, 0, bidirect_port, }, 238 { "p7", 7, 0, bidirect_port, }, 239 { "p8", 8, 0, bidirect_port, }, 240 { "p9", 9, 0, bidirect_port, }, 241 { "p10", 10, 0, bidirect_port, }, 242 { "p11", 11, 0, bidirect_port, }, 243 { "p12", 12, 0, bidirect_port, }, 244 { "p13", 13, 0, bidirect_port, }, 245 { "p14", 14, 0, bidirect_port, }, 246 { "p15", 15, 0, bidirect_port, }, 247 { NULL, 0, 0, 0, }, 248 }; 249 250 static void 251 bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source, 252 int source_port, int level) 253 { 254 struct bfin_gpio *port = hw_data (me); 255 bool olvl, nlvl; 256 bu32 bit = (1 << my_port); 257 258 /* Normalize the level value. A simulated device can send any value 259 it likes to us, but in reality we only care about 0 and 1. This 260 lets us assume only those two values below. */ 261 level = !!level; 262 263 HW_TRACE ((me, "pin %i set to %i", my_port, level)); 264 265 /* Only screw with state if this pin is set as an input, and the 266 input is actually enabled. */ 267 if ((port->dir & bit) || !(port->inen & bit)) 268 { 269 HW_TRACE ((me, "ignoring level/int due to DIR=%i INEN=%i", 270 !!(port->dir & bit), !!(port->inen & bit))); 271 return; 272 } 273 274 /* Get the old pin state for calculating an interrupt. */ 275 olvl = !!(port->data & bit); 276 277 /* Update the new pin state. */ 278 port->data = (port->data & ~bit) | (level << my_port); 279 280 /* See if this state transition will generate an interrupt. */ 281 nlvl = !!(port->data & bit); 282 283 if (port->edge & bit) 284 { 285 /* Pin is edge triggered. */ 286 if (port->both & bit) 287 { 288 /* Both edges. */ 289 if (olvl == nlvl) 290 { 291 HW_TRACE ((me, "ignoring int due to EDGE=%i BOTH=%i lvl=%i->%i", 292 !!(port->edge & bit), !!(port->both & bit), 293 olvl, nlvl)); 294 return; 295 } 296 } 297 else 298 { 299 /* Just one edge. */ 300 if (!(((port->polar & bit) && olvl > nlvl) 301 || (!(port->polar & bit) && olvl < nlvl))) 302 { 303 HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i->%i", 304 !!(port->edge & bit), !!(port->polar & bit), 305 olvl, nlvl)); 306 return; 307 } 308 } 309 310 /* Send the signal up, and then fall through to clear it. */ 311 port->int_state |= bit; 312 bfin_gpio_forward_ints (me, port); 313 port->int_state &= ~bit; 314 } 315 else 316 { 317 /* Pin is level triggered. */ 318 if (nlvl == !!(port->polar & bit)) 319 { 320 HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i", 321 !!(port->edge & bit), !!(port->polar & bit), nlvl)); 322 /* We still need to signal SIC to clear the int, so don't return. */ 323 port->int_state &= ~bit; 324 } 325 else 326 port->int_state |= bit; 327 } 328 329 bfin_gpio_forward_ints (me, port); 330 } 331 332 static void 333 attach_bfin_gpio_regs (struct hw *me, struct bfin_gpio *port) 334 { 335 address_word attach_address; 336 int attach_space; 337 unsigned attach_size; 338 reg_property_spec reg; 339 340 if (hw_find_property (me, "reg") == NULL) 341 hw_abort (me, "Missing \"reg\" property"); 342 343 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 344 hw_abort (me, "\"reg\" property must contain three addr/size entries"); 345 346 hw_unit_address_to_attach_address (hw_parent (me), 347 ®.address, 348 &attach_space, &attach_address, me); 349 hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 350 351 if (attach_size != BFIN_MMR_GPIO_SIZE) 352 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_GPIO_SIZE); 353 354 hw_attach_address (hw_parent (me), 355 0, attach_space, attach_address, attach_size, me); 356 357 port->base = attach_address; 358 } 359 360 static void 361 bfin_gpio_finish (struct hw *me) 362 { 363 struct bfin_gpio *port; 364 365 port = HW_ZALLOC (me, struct bfin_gpio); 366 367 set_hw_data (me, port); 368 set_hw_io_read_buffer (me, bfin_gpio_io_read_buffer); 369 set_hw_io_write_buffer (me, bfin_gpio_io_write_buffer); 370 set_hw_ports (me, bfin_gpio_ports); 371 set_hw_port_event (me, bfin_gpio_port_event); 372 373 attach_bfin_gpio_regs (me, port); 374 } 375 376 const struct hw_descriptor dv_bfin_gpio_descriptor[] = 377 { 378 {"bfin_gpio", bfin_gpio_finish,}, 379 {NULL, NULL}, 380 }; 381