1 /* Blackfin Serial Peripheral Interface (SPI) 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_spi.h"
26 
27 /* XXX: This is merely a stub.  */
28 
29 struct bfin_spi
30 {
31   /* This top portion matches common dv_bfin struct.  */
32   bu32 base;
33   struct hw *dma_master;
34   bool acked;
35 
36   struct hw_event *handler;
37   char saved_byte;
38   int saved_count;
39 
40   /* Order after here is important -- matches hardware MMR layout.  */
41   bu16 BFIN_MMR_16(ctl);
42   bu16 BFIN_MMR_16(flg);
43   bu16 BFIN_MMR_16(stat);
44   bu16 BFIN_MMR_16(tdbr);
45   bu16 BFIN_MMR_16(rdbr);
46   bu16 BFIN_MMR_16(baud);
47   bu16 BFIN_MMR_16(shadow);
48 };
49 #define mmr_base()      offsetof(struct bfin_spi, ctl)
50 #define mmr_offset(mmr) (offsetof(struct bfin_spi, mmr) - mmr_base())
51 
52 static const char * const mmr_names[] =
53 {
54   "SPI_CTL", "SPI_FLG", "SPI_STAT", "SPI_TDBR",
55   "SPI_RDBR", "SPI_BAUD", "SPI_SHADOW",
56 };
57 #define mmr_name(off) mmr_names[(off) / 4]
58 
59 static bool
bfin_spi_enabled(struct bfin_spi * spi)60 bfin_spi_enabled (struct bfin_spi *spi)
61 {
62   return (spi->ctl & SPE);
63 }
64 
65 static bu16
bfin_spi_timod(struct bfin_spi * spi)66 bfin_spi_timod (struct bfin_spi *spi)
67 {
68   return (spi->ctl & TIMOD);
69 }
70 
71 static unsigned
bfin_spi_io_write_buffer(struct hw * me,const void * source,int space,address_word addr,unsigned nr_bytes)72 bfin_spi_io_write_buffer (struct hw *me, const void *source, int space,
73 			  address_word addr, unsigned nr_bytes)
74 {
75   struct bfin_spi *spi = hw_data (me);
76   bu32 mmr_off;
77   bu32 value;
78   bu16 *valuep;
79 
80   value = dv_load_2 (source);
81   mmr_off = addr - spi->base;
82   valuep = (void *)((unsigned long)spi + mmr_base() + mmr_off);
83 
84   HW_TRACE_WRITE ();
85 
86   dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
87 
88   switch (mmr_off)
89     {
90     case mmr_offset(stat):
91       dv_w1c_2 (valuep, value, ~(SPIF | TXS | RXS));
92       break;
93     case mmr_offset(tdbr):
94       *valuep = value;
95       if (bfin_spi_enabled (spi) && bfin_spi_timod (spi) == TDBR_CORE)
96 	{
97 	  spi->stat |= RXS;
98 	  spi->stat &= ~TXS;
99 	}
100       break;
101     case mmr_offset(rdbr):
102     case mmr_offset(ctl):
103     case mmr_offset(flg):
104     case mmr_offset(baud):
105     case mmr_offset(shadow):
106       *valuep = value;
107       break;
108     default:
109       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
110       break;
111     }
112 
113   return nr_bytes;
114 }
115 
116 static unsigned
bfin_spi_io_read_buffer(struct hw * me,void * dest,int space,address_word addr,unsigned nr_bytes)117 bfin_spi_io_read_buffer (struct hw *me, void *dest, int space,
118 			 address_word addr, unsigned nr_bytes)
119 {
120   struct bfin_spi *spi = hw_data (me);
121   bu32 mmr_off;
122   bu16 *valuep;
123 
124   mmr_off = addr - spi->base;
125   valuep = (void *)((unsigned long)spi + mmr_base() + mmr_off);
126 
127   HW_TRACE_READ ();
128 
129   dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
130 
131   switch (mmr_off)
132     {
133     case mmr_offset(rdbr):
134       dv_store_2 (dest, *valuep);
135       if (bfin_spi_enabled (spi) && bfin_spi_timod (spi) == RDBR_CORE)
136 	spi->stat &= ~(RXS | TXS);
137       break;
138     case mmr_offset(ctl):
139     case mmr_offset(stat):
140     case mmr_offset(flg):
141     case mmr_offset(tdbr):
142     case mmr_offset(baud):
143     case mmr_offset(shadow):
144       dv_store_2 (dest, *valuep);
145       break;
146     default:
147       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
148       break;
149     }
150 
151   return nr_bytes;
152 }
153 
154 static unsigned
bfin_spi_dma_read_buffer(struct hw * me,void * dest,int space,unsigned_word addr,unsigned nr_bytes)155 bfin_spi_dma_read_buffer (struct hw *me, void *dest, int space,
156 			  unsigned_word addr, unsigned nr_bytes)
157 {
158   HW_TRACE_DMA_READ ();
159   return 0;
160 }
161 
162 static unsigned
bfin_spi_dma_write_buffer(struct hw * me,const void * source,int space,unsigned_word addr,unsigned nr_bytes,int violate_read_only_section)163 bfin_spi_dma_write_buffer (struct hw *me, const void *source,
164 			   int space, unsigned_word addr,
165 			   unsigned nr_bytes,
166 			   int violate_read_only_section)
167 {
168   HW_TRACE_DMA_WRITE ();
169   return 0;
170 }
171 
172 static const struct hw_port_descriptor bfin_spi_ports[] =
173 {
174   { "stat", 0, 0, output_port, },
175   { NULL, 0, 0, 0, },
176 };
177 
178 static void
attach_bfin_spi_regs(struct hw * me,struct bfin_spi * spi)179 attach_bfin_spi_regs (struct hw *me, struct bfin_spi *spi)
180 {
181   address_word attach_address;
182   int attach_space;
183   unsigned attach_size;
184   reg_property_spec reg;
185 
186   if (hw_find_property (me, "reg") == NULL)
187     hw_abort (me, "Missing \"reg\" property");
188 
189   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
190     hw_abort (me, "\"reg\" property must contain three addr/size entries");
191 
192   hw_unit_address_to_attach_address (hw_parent (me),
193 				     &reg.address,
194 				     &attach_space, &attach_address, me);
195   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
196 
197   if (attach_size != BFIN_MMR_SPI_SIZE)
198     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_SPI_SIZE);
199 
200   hw_attach_address (hw_parent (me),
201 		     0, attach_space, attach_address, attach_size, me);
202 
203   spi->base = attach_address;
204 }
205 
206 static void
bfin_spi_finish(struct hw * me)207 bfin_spi_finish (struct hw *me)
208 {
209   struct bfin_spi *spi;
210 
211   spi = HW_ZALLOC (me, struct bfin_spi);
212 
213   set_hw_data (me, spi);
214   set_hw_io_read_buffer (me, bfin_spi_io_read_buffer);
215   set_hw_io_write_buffer (me, bfin_spi_io_write_buffer);
216   set_hw_dma_read_buffer (me, bfin_spi_dma_read_buffer);
217   set_hw_dma_write_buffer (me, bfin_spi_dma_write_buffer);
218   set_hw_ports (me, bfin_spi_ports);
219 
220   attach_bfin_spi_regs (me, spi);
221 
222   /* Initialize the SPI.  */
223   spi->ctl  = 0x0400;
224   spi->flg  = 0xFF00;
225   spi->stat = 0x0001;
226 }
227 
228 const struct hw_descriptor dv_bfin_spi_descriptor[] =
229 {
230   {"bfin_spi", bfin_spi_finish,},
231   {NULL, NULL},
232 };
233