xref: /netbsd-src/external/gpl3/gdb/dist/sim/bfin/dv-bfin_eppi.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
1 /* Blackfin Enhanced Parallel Port Interface (EPPI) model
2    For "new style" PPIs on BF54x/etc... parts.
3 
4    Copyright (C) 2010-2024 Free Software Foundation, Inc.
5    Contributed by Analog Devices, Inc.
6 
7    This file is part of simulators.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 /* This must come before any other includes.  */
23 #include "defs.h"
24 
25 #include "sim-main.h"
26 #include "devices.h"
27 #include "dv-bfin_eppi.h"
28 #include "gui.h"
29 
30 /* XXX: TX is merely a stub.  */
31 
32 struct bfin_eppi
33 {
34   /* This top portion matches common dv_bfin struct.  */
35   bu32 base;
36   struct hw *dma_master;
37   bool acked;
38 
39   struct hw_event *handler;
40   char saved_byte;
41   int saved_count;
42 
43   /* GUI state.  */
44   void *gui_state;
45   int color;
46 
47   /* Order after here is important -- matches hardware MMR layout.  */
48   bu16 BFIN_MMR_16(status);
49   bu16 BFIN_MMR_16(hcount);
50   bu16 BFIN_MMR_16(hdelay);
51   bu16 BFIN_MMR_16(vcount);
52   bu16 BFIN_MMR_16(vdelay);
53   bu16 BFIN_MMR_16(frame);
54   bu16 BFIN_MMR_16(line);
55   bu16 BFIN_MMR_16(clkdiv);
56   bu32 control, fs1w_hbl, fs1p_avpl, fsw2_lvb, fs2p_lavf, clip, err;
57 };
58 #define mmr_base()      offsetof(struct bfin_eppi, status)
59 #define mmr_offset(mmr) (offsetof(struct bfin_eppi, mmr) - mmr_base())
60 
61 static const char * const mmr_names[] =
62 {
63   "EPPI_STATUS", "EPPI_HCOUNT", "EPPI_HDELAY", "EPPI_VCOUNT", "EPPI_VDELAY",
64   "EPPI_FRAME", "EPPI_LINE", "EPPI_CLKDIV", "EPPI_CONTROL", "EPPI_FS1W_HBL",
65   "EPPI_FS1P_AVPL", "EPPI_FS2W_LVB", "EPPI_FS2P_LAVF", "EPPI_CLIP", "EPPI_ERR",
66 };
67 #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
68 
69 static void
70 bfin_eppi_gui_setup (struct bfin_eppi *eppi)
71 {
72   /* If we are in RX mode, nothing to do.  */
73   if (!(eppi->control & PORT_DIR))
74     return;
75 
76   eppi->gui_state = bfin_gui_setup (eppi->gui_state,
77 				    eppi->control & PORT_EN,
78 				    eppi->hcount,
79 				    eppi->vcount,
80 				    eppi->color);
81 }
82 
83 static unsigned
84 bfin_eppi_io_write_buffer (struct hw *me, const void *source,
85 			   int space, address_word addr, unsigned nr_bytes)
86 {
87   struct bfin_eppi *eppi = hw_data (me);
88   bu32 mmr_off;
89   bu32 value;
90   bu16 *value16p;
91   bu32 *value32p;
92   void *valuep;
93 
94   /* Invalid access mode is higher priority than missing register.  */
95   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
96     return 0;
97 
98   if (nr_bytes == 4)
99     value = dv_load_4 (source);
100   else
101     value = dv_load_2 (source);
102 
103   mmr_off = addr - eppi->base;
104   valuep = (void *)((uintptr_t)eppi + mmr_base() + mmr_off);
105   value16p = valuep;
106   value32p = valuep;
107 
108   HW_TRACE_WRITE ();
109 
110   switch (mmr_off)
111     {
112     case mmr_offset(status):
113       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
114 	return 0;
115       dv_w1c_2 (value16p, value, 0x1ff);
116       break;
117     case mmr_offset(hcount):
118     case mmr_offset(hdelay):
119     case mmr_offset(vcount):
120     case mmr_offset(vdelay):
121     case mmr_offset(frame):
122     case mmr_offset(line):
123     case mmr_offset(clkdiv):
124       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
125 	return 0;
126       *value16p = value;
127       break;
128     case mmr_offset(control):
129       *value32p = value;
130       bfin_eppi_gui_setup (eppi);
131       break;
132     case mmr_offset(fs1w_hbl):
133     case mmr_offset(fs1p_avpl):
134     case mmr_offset(fsw2_lvb):
135     case mmr_offset(fs2p_lavf):
136     case mmr_offset(clip):
137     case mmr_offset(err):
138       if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
139 	return 0;
140       *value32p = value;
141       break;
142     default:
143       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
144       return 0;
145     }
146 
147   return nr_bytes;
148 }
149 
150 static unsigned
151 bfin_eppi_io_read_buffer (struct hw *me, void *dest,
152 			  int space, address_word addr, unsigned nr_bytes)
153 {
154   struct bfin_eppi *eppi = hw_data (me);
155   bu32 mmr_off;
156   bu16 *value16p;
157   bu32 *value32p;
158   void *valuep;
159 
160   /* Invalid access mode is higher priority than missing register.  */
161   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
162     return 0;
163 
164   mmr_off = addr - eppi->base;
165   valuep = (void *)((uintptr_t)eppi + mmr_base() + mmr_off);
166   value16p = valuep;
167   value32p = valuep;
168 
169   HW_TRACE_READ ();
170 
171   switch (mmr_off)
172     {
173     case mmr_offset(status):
174     case mmr_offset(hcount):
175     case mmr_offset(hdelay):
176     case mmr_offset(vcount):
177     case mmr_offset(vdelay):
178     case mmr_offset(frame):
179     case mmr_offset(line):
180     case mmr_offset(clkdiv):
181       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
182 	return 0;
183       dv_store_2 (dest, *value16p);
184       break;
185     case mmr_offset(control):
186     case mmr_offset(fs1w_hbl):
187     case mmr_offset(fs1p_avpl):
188     case mmr_offset(fsw2_lvb):
189     case mmr_offset(fs2p_lavf):
190     case mmr_offset(clip):
191     case mmr_offset(err):
192       if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, false))
193 	return 0;
194       dv_store_4 (dest, *value32p);
195       break;
196     default:
197       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
198       return 0;
199     }
200 
201   return nr_bytes;
202 }
203 
204 static unsigned
205 bfin_eppi_dma_read_buffer (struct hw *me, void *dest, int space,
206 			   unsigned_word addr, unsigned nr_bytes)
207 {
208   HW_TRACE_DMA_READ ();
209   return 0;
210 }
211 
212 static unsigned
213 bfin_eppi_dma_write_buffer (struct hw *me, const void *source,
214 			    int space, unsigned_word addr,
215 			    unsigned nr_bytes,
216 			    int violate_read_only_section)
217 {
218   struct bfin_eppi *eppi = hw_data (me);
219 
220   HW_TRACE_DMA_WRITE ();
221 
222   return bfin_gui_update (eppi->gui_state, source, nr_bytes);
223 }
224 
225 static const struct hw_port_descriptor bfin_eppi_ports[] =
226 {
227   { "stat", 0, 0, output_port, },
228   { NULL, 0, 0, 0, },
229 };
230 
231 static void
232 attach_bfin_eppi_regs (struct hw *me, struct bfin_eppi *eppi)
233 {
234   address_word attach_address;
235   int attach_space;
236   unsigned attach_size;
237   reg_property_spec reg;
238 
239   if (hw_find_property (me, "reg") == NULL)
240     hw_abort (me, "Missing \"reg\" property");
241 
242   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
243     hw_abort (me, "\"reg\" property must contain three addr/size entries");
244 
245   hw_unit_address_to_attach_address (hw_parent (me),
246 				     &reg.address,
247 				     &attach_space, &attach_address, me);
248   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
249 
250   if (attach_size != BFIN_MMR_EPPI_SIZE)
251     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EPPI_SIZE);
252 
253   hw_attach_address (hw_parent (me),
254 		     0, attach_space, attach_address, attach_size, me);
255 
256   eppi->base = attach_address;
257 }
258 
259 static void
260 bfin_eppi_finish (struct hw *me)
261 {
262   struct bfin_eppi *eppi;
263   const char *color;
264 
265   eppi = HW_ZALLOC (me, struct bfin_eppi);
266 
267   set_hw_data (me, eppi);
268   set_hw_io_read_buffer (me, bfin_eppi_io_read_buffer);
269   set_hw_io_write_buffer (me, bfin_eppi_io_write_buffer);
270   set_hw_dma_read_buffer (me, bfin_eppi_dma_read_buffer);
271   set_hw_dma_write_buffer (me, bfin_eppi_dma_write_buffer);
272   set_hw_ports (me, bfin_eppi_ports);
273 
274   attach_bfin_eppi_regs (me, eppi);
275 
276   /* Initialize the EPPI.  */
277   if (hw_find_property (me, "color"))
278     color = hw_find_string_property (me, "color");
279   else
280     color = NULL;
281   eppi->color = bfin_gui_color (color);
282 }
283 
284 const struct hw_descriptor dv_bfin_eppi_descriptor[] =
285 {
286   {"bfin_eppi", bfin_eppi_finish,},
287   {NULL, NULL},
288 };
289