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 
27 struct 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 
53 static 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 
63 static unsigned
bfin_gpio_io_write_buffer(struct hw * me,const void * source,int space,address_word addr,unsigned nr_bytes)64 bfin_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 
121 static unsigned
bfin_gpio_io_read_buffer(struct hw * me,void * dest,int space,address_word addr,unsigned nr_bytes)122 bfin_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 
171 static 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 
193 static void
bfin_gpio_port_event(struct hw * me,int my_port,struct hw * source,int source_port,int level)194 bfin_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 
277 static void
attach_bfin_gpio_regs(struct hw * me,struct bfin_gpio * port)278 attach_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, &reg))
289     hw_abort (me, "\"reg\" property must contain three addr/size entries");
290 
291   hw_unit_address_to_attach_address (hw_parent (me),
292 				     &reg.address,
293 				     &attach_space, &attach_address, me);
294   hw_unit_size_to_attach_size (hw_parent (me), &reg.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 
305 static void
bfin_gpio_finish(struct hw * me)306 bfin_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 
321 const struct hw_descriptor dv_bfin_gpio_descriptor[] =
322 {
323   {"bfin_gpio", bfin_gpio_finish,},
324   {NULL, NULL},
325 };
326