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