dv-bfin_otp.c revision 1.1.1.9
1/* Blackfin One-Time Programmable Memory (OTP) model
2
3   Copyright (C) 2010-2023 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/* This must come before any other includes.  */
22#include "defs.h"
23
24#include "sim-main.h"
25#include "devices.h"
26#include "dv-bfin_otp.h"
27
28/* XXX: No public documentation on this interface.  This seems to work
29        with the on-chip ROM functions though and was figured out by
30        disassembling & walking that code.  */
31/* XXX: About only thing that should be done here are CRC fields.  And
32        supposedly there is an interrupt that could be generated.  */
33
34struct bfin_otp
35{
36  bu32 base;
37
38  /* The actual OTP storage -- 0x200 pages, each page is 128bits.
39     While certain pages have predefined and/or secure access, we don't
40     bother trying to implement that coverage.  All pages are open for
41     reading & writing.  */
42  bu32 mem[0x200 * 4];
43
44  /* Order after here is important -- matches hardware MMR layout.  */
45  bu16 BFIN_MMR_16(control);
46  bu16 BFIN_MMR_16(ben);
47  bu16 BFIN_MMR_16(status);
48  bu32 timing;
49  bu32 _pad0[28];
50  bu32 data0, data1, data2, data3;
51};
52#define mmr_base()      offsetof(struct bfin_otp, control)
53#define mmr_offset(mmr) (offsetof(struct bfin_otp, mmr) - mmr_base())
54#define mmr_idx(mmr)    (mmr_offset (mmr) / 4)
55
56static const char * const mmr_names[] =
57{
58  "OTP_CONTROL", "OTP_BEN", "OTP_STATUS", "OTP_TIMING",
59  [mmr_idx (data0)] = "OTP_DATA0", "OTP_DATA1", "OTP_DATA2", "OTP_DATA3",
60};
61#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
62
63/* XXX: This probably misbehaves with big endian hosts.  */
64static void
65bfin_otp_transfer (struct bfin_otp *otp, void *vdst, void *vsrc)
66{
67  bu8 *dst = vdst, *src = vsrc;
68  int bidx;
69  for (bidx = 0; bidx < 16; ++bidx)
70    if (otp->ben & (1 << bidx))
71      dst[bidx] = src[bidx];
72}
73
74static void
75bfin_otp_read_page (struct bfin_otp *otp, bu16 page)
76{
77  bfin_otp_transfer (otp, &otp->data0, &otp->mem[page * 4]);
78}
79
80static void
81bfin_otp_write_page_val (struct bfin_otp *otp, bu16 page, bu64 val[2])
82{
83  bfin_otp_transfer (otp, &otp->mem[page * 4], val);
84}
85static void
86bfin_otp_write_page_val2 (struct bfin_otp *otp, bu16 page, bu64 lo, bu64 hi)
87{
88  bu64 val[2] = { lo, hi };
89  bfin_otp_write_page_val (otp, page, val);
90}
91static void
92bfin_otp_write_page (struct bfin_otp *otp, bu16 page)
93{
94  bfin_otp_write_page_val2 (otp, page, ((bu64)otp->data1 << 32) | otp->data0,
95			    ((bu64)otp->data3 << 32) | otp->data2);
96}
97
98static unsigned
99bfin_otp_io_write_buffer (struct hw *me, const void *source, int space,
100			  address_word addr, unsigned nr_bytes)
101{
102  struct bfin_otp *otp = hw_data (me);
103  bu32 mmr_off;
104  bu32 value;
105  bu16 *value16p;
106  bu32 *value32p;
107  void *valuep;
108
109  /* Invalid access mode is higher priority than missing register.  */
110  if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
111    return 0;
112
113  if (nr_bytes == 4)
114    value = dv_load_4 (source);
115  else
116    value = dv_load_2 (source);
117
118  mmr_off = addr - otp->base;
119  valuep = (void *)((uintptr_t)otp + mmr_base() + mmr_off);
120  value16p = valuep;
121  value32p = valuep;
122
123  HW_TRACE_WRITE ();
124
125  switch (mmr_off)
126    {
127    case mmr_offset(control):
128      {
129	int page;
130
131	if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
132	  return 0;
133	/* XXX: Seems like these bits aren't writable.  */
134	*value16p = value & 0x39FF;
135
136	/* Low bits seem to be the page address.  */
137	page = value & PAGE_ADDR;
138
139	/* Write operation.  */
140	if (value & DO_WRITE)
141	  bfin_otp_write_page (otp, page);
142
143	/* Read operation.  */
144	if (value & DO_READ)
145	  bfin_otp_read_page (otp, page);
146
147	otp->status |= STATUS_DONE;
148
149	break;
150      }
151    case mmr_offset(ben):
152      if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
153	return 0;
154      /* XXX: All bits seem to be writable.  */
155      *value16p = value;
156      break;
157    case mmr_offset(status):
158      if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
159	return 0;
160      /* XXX: All bits seem to be W1C.  */
161      dv_w1c_2 (value16p, value, -1);
162      break;
163    case mmr_offset(timing):
164    case mmr_offset(data0):
165    case mmr_offset(data1):
166    case mmr_offset(data2):
167    case mmr_offset(data3):
168      if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
169	return 0;
170      *value32p = value;
171      break;
172    default:
173      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
174      return 0;
175    }
176
177  return nr_bytes;
178}
179
180static unsigned
181bfin_otp_io_read_buffer (struct hw *me, void *dest, int space,
182			 address_word addr, unsigned nr_bytes)
183{
184  struct bfin_otp *otp = hw_data (me);
185  bu32 mmr_off;
186  bu16 *value16p;
187  bu32 *value32p;
188  void *valuep;
189
190  /* Invalid access mode is higher priority than missing register.  */
191  if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, false))
192    return 0;
193
194  mmr_off = addr - otp->base;
195  valuep = (void *)((uintptr_t)otp + mmr_base() + mmr_off);
196  value16p = valuep;
197  value32p = valuep;
198
199  HW_TRACE_READ ();
200
201  switch (mmr_off)
202    {
203    case mmr_offset(control):
204    case mmr_offset(ben):
205    case mmr_offset(status):
206      if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
207	return 0;
208      dv_store_2 (dest, *value16p);
209      break;
210    case mmr_offset(timing):
211    case mmr_offset(data0):
212    case mmr_offset(data1):
213    case mmr_offset(data2):
214    case mmr_offset(data3):
215      if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, false))
216	return 0;
217      dv_store_4 (dest, *value32p);
218      break;
219    default:
220      dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
221      return 0;
222    }
223
224  return nr_bytes;
225}
226
227static void
228attach_bfin_otp_regs (struct hw *me, struct bfin_otp *otp)
229{
230  address_word attach_address;
231  int attach_space;
232  unsigned attach_size;
233  reg_property_spec reg;
234
235  if (hw_find_property (me, "reg") == NULL)
236    hw_abort (me, "Missing \"reg\" property");
237
238  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
239    hw_abort (me, "\"reg\" property must contain three addr/size entries");
240
241  hw_unit_address_to_attach_address (hw_parent (me),
242				     &reg.address,
243				     &attach_space, &attach_address, me);
244  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
245
246  if (attach_size != BFIN_MMR_OTP_SIZE)
247    hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_OTP_SIZE);
248
249  hw_attach_address (hw_parent (me),
250		     0, attach_space, attach_address, attach_size, me);
251
252  otp->base = attach_address;
253}
254
255static const struct hw_port_descriptor bfin_otp_ports[] =
256{
257  { "stat", 0, 0, output_port, },
258  { NULL, 0, 0, 0, },
259};
260
261static void
262bfin_otp_finish (struct hw *me)
263{
264  char part_str[16];
265  struct bfin_otp *otp;
266  unsigned int fps03;
267  int type = hw_find_integer_property (me, "type");
268
269  otp = HW_ZALLOC (me, struct bfin_otp);
270
271  set_hw_data (me, otp);
272  set_hw_io_read_buffer (me, bfin_otp_io_read_buffer);
273  set_hw_io_write_buffer (me, bfin_otp_io_write_buffer);
274  set_hw_ports (me, bfin_otp_ports);
275
276  attach_bfin_otp_regs (me, otp);
277
278  /* Initialize the OTP.  */
279  otp->ben     = 0xFFFF;
280  otp->timing  = 0x00001485;
281
282  /* Semi-random value for unique chip id.  */
283  bfin_otp_write_page_val2 (otp, FPS00, (uintptr_t)otp, ~(uintptr_t)otp);
284
285  memset (part_str, 0, sizeof (part_str));
286  sprintf (part_str, "ADSP-BF%iX", type);
287  switch (type)
288    {
289    case 512:
290      fps03 = FPS03_BF512;
291      break;
292    case 514:
293      fps03 = FPS03_BF514;
294      break;
295    case 516:
296      fps03 = FPS03_BF516;
297      break;
298    case 518:
299      fps03 = FPS03_BF518;
300      break;
301    case 522:
302      fps03 = FPS03_BF522;
303      break;
304    case 523:
305      fps03 = FPS03_BF523;
306      break;
307    case 524:
308      fps03 = FPS03_BF524;
309      break;
310    case 525:
311      fps03 = FPS03_BF525;
312      break;
313    case 526:
314      fps03 = FPS03_BF526;
315      break;
316    case 527:
317      fps03 = FPS03_BF527;
318      break;
319    default:
320      fps03 = 0;
321      break;
322    }
323  part_str[14] = (fps03 >> 0);
324  part_str[15] = (fps03 >> 8);
325  bfin_otp_write_page_val (otp, FPS03, (void *)part_str);
326}
327
328const struct hw_descriptor dv_bfin_otp_descriptor[] =
329{
330  {"bfin_otp", bfin_otp_finish,},
331  {NULL, NULL},
332};
333