1a1ba9ba4Schristos /* Blackfin Phase Lock Loop (PLL) model.
2a1ba9ba4Schristos 
3*184b2d41Schristos    Copyright (C) 2010-2020 Free Software Foundation, Inc.
4a1ba9ba4Schristos    Contributed by Analog Devices, Inc.
5a1ba9ba4Schristos 
6a1ba9ba4Schristos    This file is part of simulators.
7a1ba9ba4Schristos 
8a1ba9ba4Schristos    This program is free software; you can redistribute it and/or modify
9a1ba9ba4Schristos    it under the terms of the GNU General Public License as published by
10a1ba9ba4Schristos    the Free Software Foundation; either version 3 of the License, or
11a1ba9ba4Schristos    (at your option) any later version.
12a1ba9ba4Schristos 
13a1ba9ba4Schristos    This program is distributed in the hope that it will be useful,
14a1ba9ba4Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
15a1ba9ba4Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a1ba9ba4Schristos    GNU General Public License for more details.
17a1ba9ba4Schristos 
18a1ba9ba4Schristos    You should have received a copy of the GNU General Public License
19a1ba9ba4Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20a1ba9ba4Schristos 
21a1ba9ba4Schristos #include "config.h"
22a1ba9ba4Schristos 
23a1ba9ba4Schristos #include "sim-main.h"
24a1ba9ba4Schristos #include "machs.h"
25a1ba9ba4Schristos #include "devices.h"
26a1ba9ba4Schristos #include "dv-bfin_pll.h"
27a1ba9ba4Schristos 
28a1ba9ba4Schristos struct bfin_pll
29a1ba9ba4Schristos {
30a1ba9ba4Schristos   bu32 base;
31a1ba9ba4Schristos 
32a1ba9ba4Schristos   /* Order after here is important -- matches hardware MMR layout.  */
33a1ba9ba4Schristos   bu16 BFIN_MMR_16(pll_ctl);
34a1ba9ba4Schristos   bu16 BFIN_MMR_16(pll_div);
35a1ba9ba4Schristos   bu16 BFIN_MMR_16(vr_ctl);
36a1ba9ba4Schristos   bu16 BFIN_MMR_16(pll_stat);
37a1ba9ba4Schristos   bu16 BFIN_MMR_16(pll_lockcnt);
38a1ba9ba4Schristos 
39a1ba9ba4Schristos   /* XXX: Not really the best place for this ...  */
40a1ba9ba4Schristos   bu32 chipid;
41a1ba9ba4Schristos };
42a1ba9ba4Schristos #define mmr_base()      offsetof(struct bfin_pll, pll_ctl)
43a1ba9ba4Schristos #define mmr_offset(mmr) (offsetof(struct bfin_pll, mmr) - mmr_base())
44a1ba9ba4Schristos 
45a1ba9ba4Schristos static const char * const mmr_names[] =
46a1ba9ba4Schristos {
47a1ba9ba4Schristos   "PLL_CTL", "PLL_DIV", "VR_CTL", "PLL_STAT", "PLL_LOCKCNT", "CHIPID",
48a1ba9ba4Schristos };
49a1ba9ba4Schristos #define mmr_name(off) mmr_names[(off) / 4]
50a1ba9ba4Schristos 
51a1ba9ba4Schristos static unsigned
bfin_pll_io_write_buffer(struct hw * me,const void * source,int space,address_word addr,unsigned nr_bytes)52a1ba9ba4Schristos bfin_pll_io_write_buffer (struct hw *me, const void *source,
53a1ba9ba4Schristos 			  int space, address_word addr, unsigned nr_bytes)
54a1ba9ba4Schristos {
55a1ba9ba4Schristos   struct bfin_pll *pll = hw_data (me);
56a1ba9ba4Schristos   bu32 mmr_off;
57a1ba9ba4Schristos   bu32 value;
58a1ba9ba4Schristos   bu16 *value16p;
59a1ba9ba4Schristos   bu32 *value32p;
60a1ba9ba4Schristos   void *valuep;
61a1ba9ba4Schristos 
62b2396a7bSchristos   /* Invalid access mode is higher priority than missing register.  */
63b2396a7bSchristos   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
64b2396a7bSchristos     return 0;
65b2396a7bSchristos 
66a1ba9ba4Schristos   if (nr_bytes == 4)
67a1ba9ba4Schristos     value = dv_load_4 (source);
68a1ba9ba4Schristos   else
69a1ba9ba4Schristos     value = dv_load_2 (source);
70a1ba9ba4Schristos 
71a1ba9ba4Schristos   mmr_off = addr - pll->base;
72a1ba9ba4Schristos   valuep = (void *)((unsigned long)pll + mmr_base() + mmr_off);
73a1ba9ba4Schristos   value16p = valuep;
74a1ba9ba4Schristos   value32p = valuep;
75a1ba9ba4Schristos 
76a1ba9ba4Schristos   HW_TRACE_WRITE ();
77a1ba9ba4Schristos 
78a1ba9ba4Schristos   switch (mmr_off)
79a1ba9ba4Schristos     {
80a1ba9ba4Schristos     case mmr_offset(pll_stat):
81b2396a7bSchristos       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
82b2396a7bSchristos 	return 0;
83a1ba9ba4Schristos     case mmr_offset(chipid):
84a1ba9ba4Schristos       /* Discard writes.  */
85a1ba9ba4Schristos       break;
86a1ba9ba4Schristos     default:
87b2396a7bSchristos       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
88b2396a7bSchristos 	return 0;
89a1ba9ba4Schristos       *value16p = value;
90a1ba9ba4Schristos       break;
91a1ba9ba4Schristos     }
92a1ba9ba4Schristos 
93a1ba9ba4Schristos   return nr_bytes;
94a1ba9ba4Schristos }
95a1ba9ba4Schristos 
96a1ba9ba4Schristos static unsigned
bfin_pll_io_read_buffer(struct hw * me,void * dest,int space,address_word addr,unsigned nr_bytes)97a1ba9ba4Schristos bfin_pll_io_read_buffer (struct hw *me, void *dest,
98a1ba9ba4Schristos 			 int space, address_word addr, unsigned nr_bytes)
99a1ba9ba4Schristos {
100a1ba9ba4Schristos   struct bfin_pll *pll = hw_data (me);
101a1ba9ba4Schristos   bu32 mmr_off;
102a1ba9ba4Schristos   bu32 *value32p;
103a1ba9ba4Schristos   bu16 *value16p;
104a1ba9ba4Schristos   void *valuep;
105a1ba9ba4Schristos 
106b2396a7bSchristos   /* Invalid access mode is higher priority than missing register.  */
107b2396a7bSchristos   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, false))
108b2396a7bSchristos     return 0;
109b2396a7bSchristos 
110a1ba9ba4Schristos   mmr_off = addr - pll->base;
111a1ba9ba4Schristos   valuep = (void *)((unsigned long)pll + mmr_base() + mmr_off);
112a1ba9ba4Schristos   value16p = valuep;
113a1ba9ba4Schristos   value32p = valuep;
114a1ba9ba4Schristos 
115a1ba9ba4Schristos   HW_TRACE_READ ();
116a1ba9ba4Schristos 
117a1ba9ba4Schristos   switch (mmr_off)
118a1ba9ba4Schristos     {
119a1ba9ba4Schristos     case mmr_offset(chipid):
120a1ba9ba4Schristos       dv_store_4 (dest, *value32p);
121a1ba9ba4Schristos       break;
122a1ba9ba4Schristos     default:
123b2396a7bSchristos       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
124b2396a7bSchristos 	return 0;
125a1ba9ba4Schristos       dv_store_2 (dest, *value16p);
126a1ba9ba4Schristos       break;
127a1ba9ba4Schristos     }
128a1ba9ba4Schristos 
129a1ba9ba4Schristos   return nr_bytes;
130a1ba9ba4Schristos }
131a1ba9ba4Schristos 
132a1ba9ba4Schristos static const struct hw_port_descriptor bfin_pll_ports[] =
133a1ba9ba4Schristos {
134a1ba9ba4Schristos   { "pll", 0, 0, output_port, },
135a1ba9ba4Schristos   { NULL, 0, 0, 0, },
136a1ba9ba4Schristos };
137a1ba9ba4Schristos 
138a1ba9ba4Schristos static void
attach_bfin_pll_regs(struct hw * me,struct bfin_pll * pll)139a1ba9ba4Schristos attach_bfin_pll_regs (struct hw *me, struct bfin_pll *pll)
140a1ba9ba4Schristos {
141a1ba9ba4Schristos   address_word attach_address;
142a1ba9ba4Schristos   int attach_space;
143a1ba9ba4Schristos   unsigned attach_size;
144a1ba9ba4Schristos   reg_property_spec reg;
145a1ba9ba4Schristos 
146a1ba9ba4Schristos   if (hw_find_property (me, "reg") == NULL)
147a1ba9ba4Schristos     hw_abort (me, "Missing \"reg\" property");
148a1ba9ba4Schristos 
149a1ba9ba4Schristos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
150a1ba9ba4Schristos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
151a1ba9ba4Schristos 
152a1ba9ba4Schristos   hw_unit_address_to_attach_address (hw_parent (me),
153a1ba9ba4Schristos 				     &reg.address,
154a1ba9ba4Schristos 				     &attach_space, &attach_address, me);
155a1ba9ba4Schristos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
156a1ba9ba4Schristos 
157a1ba9ba4Schristos   if (attach_size != BFIN_MMR_PLL_SIZE)
158a1ba9ba4Schristos     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PLL_SIZE);
159a1ba9ba4Schristos 
160a1ba9ba4Schristos   hw_attach_address (hw_parent (me),
161a1ba9ba4Schristos 		     0, attach_space, attach_address, attach_size, me);
162a1ba9ba4Schristos 
163a1ba9ba4Schristos   pll->base = attach_address;
164a1ba9ba4Schristos }
165a1ba9ba4Schristos 
166a1ba9ba4Schristos static void
bfin_pll_finish(struct hw * me)167a1ba9ba4Schristos bfin_pll_finish (struct hw *me)
168a1ba9ba4Schristos {
169a1ba9ba4Schristos   struct bfin_pll *pll;
170a1ba9ba4Schristos 
171a1ba9ba4Schristos   pll = HW_ZALLOC (me, struct bfin_pll);
172a1ba9ba4Schristos 
173a1ba9ba4Schristos   set_hw_data (me, pll);
174a1ba9ba4Schristos   set_hw_io_read_buffer (me, bfin_pll_io_read_buffer);
175a1ba9ba4Schristos   set_hw_io_write_buffer (me, bfin_pll_io_write_buffer);
176a1ba9ba4Schristos   set_hw_ports (me, bfin_pll_ports);
177a1ba9ba4Schristos 
178a1ba9ba4Schristos   attach_bfin_pll_regs (me, pll);
179a1ba9ba4Schristos 
180a1ba9ba4Schristos   /* Initialize the PLL.  */
181a1ba9ba4Schristos   /* XXX: Depends on part ?  */
182a1ba9ba4Schristos   pll->pll_ctl = 0x1400;
183a1ba9ba4Schristos   pll->pll_div = 0x0005;
184a1ba9ba4Schristos   pll->vr_ctl = 0x40DB;
185a1ba9ba4Schristos   pll->pll_stat = 0x00A2;
186a1ba9ba4Schristos   pll->pll_lockcnt = 0x0200;
187a1ba9ba4Schristos   pll->chipid = bfin_model_get_chipid (hw_system (me));
188a1ba9ba4Schristos 
189a1ba9ba4Schristos   /* XXX: slow it down!  */
190a1ba9ba4Schristos   pll->pll_ctl = 0xa800;
191a1ba9ba4Schristos   pll->pll_div = 0x4;
192a1ba9ba4Schristos   pll->vr_ctl = 0x40fb;
193a1ba9ba4Schristos   pll->pll_stat = 0xa2;
194a1ba9ba4Schristos   pll->pll_lockcnt = 0x300;
195a1ba9ba4Schristos }
196a1ba9ba4Schristos 
197a1ba9ba4Schristos const struct hw_descriptor dv_bfin_pll_descriptor[] =
198a1ba9ba4Schristos {
199a1ba9ba4Schristos   {"bfin_pll", bfin_pll_finish,},
200a1ba9ba4Schristos   {NULL, NULL},
201a1ba9ba4Schristos };
202