1 /* Blackfin Enhanced Parallel Port Interface (EPPI) model
2    For "new style" PPIs on BF54x/etc... parts.
3 
4    Copyright (C) 2010-2013 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 #include "config.h"
23 
24 #include "sim-main.h"
25 #include "devices.h"
26 #include "dv-bfin_eppi.h"
27 #include "gui.h"
28 
29 /* XXX: TX is merely a stub.  */
30 
31 struct bfin_eppi
32 {
33   /* This top portion matches common dv_bfin struct.  */
34   bu32 base;
35   struct hw *dma_master;
36   bool acked;
37 
38   struct hw_event *handler;
39   char saved_byte;
40   int saved_count;
41 
42   /* GUI state.  */
43   void *gui_state;
44   int color;
45 
46   /* Order after here is important -- matches hardware MMR layout.  */
47   bu16 BFIN_MMR_16(status);
48   bu16 BFIN_MMR_16(hcount);
49   bu16 BFIN_MMR_16(hdelay);
50   bu16 BFIN_MMR_16(vcount);
51   bu16 BFIN_MMR_16(vdelay);
52   bu16 BFIN_MMR_16(frame);
53   bu16 BFIN_MMR_16(line);
54   bu16 BFIN_MMR_16(clkdiv);
55   bu32 control, fs1w_hbl, fs1p_avpl, fsw2_lvb, fs2p_lavf, clip, err;
56 };
57 #define mmr_base()      offsetof(struct bfin_eppi, status)
58 #define mmr_offset(mmr) (offsetof(struct bfin_eppi, mmr) - mmr_base())
59 
60 static const char * const mmr_names[] =
61 {
62   "EPPI_STATUS", "EPPI_HCOUNT", "EPPI_HDELAY", "EPPI_VCOUNT", "EPPI_VDELAY",
63   "EPPI_FRAME", "EPPI_LINE", "EPPI_CLKDIV", "EPPI_CONTROL", "EPPI_FS1W_HBL",
64   "EPPI_FS1P_AVPL", "EPPI_FS2W_LVB", "EPPI_FS2P_LAVF", "EPPI_CLIP", "EPPI_ERR",
65 };
66 #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
67 
68 static void
bfin_eppi_gui_setup(struct bfin_eppi * eppi)69 bfin_eppi_gui_setup (struct bfin_eppi *eppi)
70 {
71   /* If we are in RX mode, nothing to do.  */
72   if (!(eppi->control & PORT_DIR))
73     return;
74 
75   eppi->gui_state = bfin_gui_setup (eppi->gui_state,
76 				    eppi->control & PORT_EN,
77 				    eppi->hcount,
78 				    eppi->vcount,
79 				    eppi->color);
80 }
81 
82 static unsigned
bfin_eppi_io_write_buffer(struct hw * me,const void * source,int space,address_word addr,unsigned nr_bytes)83 bfin_eppi_io_write_buffer (struct hw *me, const void *source,
84 			   int space, address_word addr, unsigned nr_bytes)
85 {
86   struct bfin_eppi *eppi = hw_data (me);
87   bu32 mmr_off;
88   bu32 value;
89   bu16 *value16p;
90   bu32 *value32p;
91   void *valuep;
92 
93   if (nr_bytes == 4)
94     value = dv_load_4 (source);
95   else
96     value = dv_load_2 (source);
97 
98   mmr_off = addr - eppi->base;
99   valuep = (void *)((unsigned long)eppi + mmr_base() + mmr_off);
100   value16p = valuep;
101   value32p = valuep;
102 
103   HW_TRACE_WRITE ();
104 
105   switch (mmr_off)
106     {
107     case mmr_offset(status):
108       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
109       dv_w1c_2 (value16p, value, 0x1ff);
110       break;
111     case mmr_offset(hcount):
112     case mmr_offset(hdelay):
113     case mmr_offset(vcount):
114     case mmr_offset(vdelay):
115     case mmr_offset(frame):
116     case mmr_offset(line):
117     case mmr_offset(clkdiv):
118       dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
119       *value16p = value;
120       break;
121     case mmr_offset(control):
122       *value32p = value;
123       bfin_eppi_gui_setup (eppi);
124       break;
125     case mmr_offset(fs1w_hbl):
126     case mmr_offset(fs1p_avpl):
127     case mmr_offset(fsw2_lvb):
128     case mmr_offset(fs2p_lavf):
129     case mmr_offset(clip):
130     case mmr_offset(err):
131       dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
132       *value32p = value;
133       break;
134     default:
135       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
136       break;
137     }
138 
139   return nr_bytes;
140 }
141 
142 static unsigned
bfin_eppi_io_read_buffer(struct hw * me,void * dest,int space,address_word addr,unsigned nr_bytes)143 bfin_eppi_io_read_buffer (struct hw *me, void *dest,
144 			  int space, address_word addr, unsigned nr_bytes)
145 {
146   struct bfin_eppi *eppi = hw_data (me);
147   bu32 mmr_off;
148   bu16 *value16p;
149   bu32 *value32p;
150   void *valuep;
151 
152   mmr_off = addr - eppi->base;
153   valuep = (void *)((unsigned long)eppi + mmr_base() + mmr_off);
154   value16p = valuep;
155   value32p = valuep;
156 
157   HW_TRACE_READ ();
158 
159   switch (mmr_off)
160     {
161     case mmr_offset(status):
162     case mmr_offset(hcount):
163     case mmr_offset(hdelay):
164     case mmr_offset(vcount):
165     case mmr_offset(vdelay):
166     case mmr_offset(frame):
167     case mmr_offset(line):
168     case mmr_offset(clkdiv):
169       dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
170       dv_store_2 (dest, *value16p);
171       break;
172     case mmr_offset(control):
173     case mmr_offset(fs1w_hbl):
174     case mmr_offset(fs1p_avpl):
175     case mmr_offset(fsw2_lvb):
176     case mmr_offset(fs2p_lavf):
177     case mmr_offset(clip):
178     case mmr_offset(err):
179       dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
180       dv_store_4 (dest, *value32p);
181       break;
182     default:
183       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
184       break;
185     }
186 
187   return nr_bytes;
188 }
189 
190 static unsigned
bfin_eppi_dma_read_buffer(struct hw * me,void * dest,int space,unsigned_word addr,unsigned nr_bytes)191 bfin_eppi_dma_read_buffer (struct hw *me, void *dest, int space,
192 			   unsigned_word addr, unsigned nr_bytes)
193 {
194   HW_TRACE_DMA_READ ();
195   return 0;
196 }
197 
198 static unsigned
bfin_eppi_dma_write_buffer(struct hw * me,const void * source,int space,unsigned_word addr,unsigned nr_bytes,int violate_read_only_section)199 bfin_eppi_dma_write_buffer (struct hw *me, const void *source,
200 			    int space, unsigned_word addr,
201 			    unsigned nr_bytes,
202 			    int violate_read_only_section)
203 {
204   struct bfin_eppi *eppi = hw_data (me);
205 
206   HW_TRACE_DMA_WRITE ();
207 
208   return bfin_gui_update (eppi->gui_state, source, nr_bytes);
209 }
210 
211 static const struct hw_port_descriptor bfin_eppi_ports[] =
212 {
213   { "stat", 0, 0, output_port, },
214   { NULL, 0, 0, 0, },
215 };
216 
217 static void
attach_bfin_eppi_regs(struct hw * me,struct bfin_eppi * eppi)218 attach_bfin_eppi_regs (struct hw *me, struct bfin_eppi *eppi)
219 {
220   address_word attach_address;
221   int attach_space;
222   unsigned attach_size;
223   reg_property_spec reg;
224 
225   if (hw_find_property (me, "reg") == NULL)
226     hw_abort (me, "Missing \"reg\" property");
227 
228   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
229     hw_abort (me, "\"reg\" property must contain three addr/size entries");
230 
231   hw_unit_address_to_attach_address (hw_parent (me),
232 				     &reg.address,
233 				     &attach_space, &attach_address, me);
234   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
235 
236   if (attach_size != BFIN_MMR_EPPI_SIZE)
237     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EPPI_SIZE);
238 
239   hw_attach_address (hw_parent (me),
240 		     0, attach_space, attach_address, attach_size, me);
241 
242   eppi->base = attach_address;
243 }
244 
245 static void
bfin_eppi_finish(struct hw * me)246 bfin_eppi_finish (struct hw *me)
247 {
248   struct bfin_eppi *eppi;
249   const char *color;
250 
251   eppi = HW_ZALLOC (me, struct bfin_eppi);
252 
253   set_hw_data (me, eppi);
254   set_hw_io_read_buffer (me, bfin_eppi_io_read_buffer);
255   set_hw_io_write_buffer (me, bfin_eppi_io_write_buffer);
256   set_hw_dma_read_buffer (me, bfin_eppi_dma_read_buffer);
257   set_hw_dma_write_buffer (me, bfin_eppi_dma_write_buffer);
258   set_hw_ports (me, bfin_eppi_ports);
259 
260   attach_bfin_eppi_regs (me, eppi);
261 
262   /* Initialize the EPPI.  */
263   if (hw_find_property (me, "color"))
264     color = hw_find_string_property (me, "color");
265   else
266     color = NULL;
267   eppi->color = bfin_gui_color (color);
268 }
269 
270 const struct hw_descriptor dv_bfin_eppi_descriptor[] =
271 {
272   {"bfin_eppi", bfin_eppi_finish,},
273   {NULL, NULL},
274 };
275