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