1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Cobalt CPLD functions |
4 | * |
5 | * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. |
6 | * All rights reserved. |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | |
11 | #include "cobalt-cpld.h" |
12 | |
13 | #define ADRS(offset) (COBALT_BUS_CPLD_BASE + offset) |
14 | |
15 | static u16 cpld_read(struct cobalt *cobalt, u32 offset) |
16 | { |
17 | return cobalt_bus_read32(bar1: cobalt->bar1, ADRS(offset)); |
18 | } |
19 | |
20 | static void cpld_write(struct cobalt *cobalt, u32 offset, u16 val) |
21 | { |
22 | return cobalt_bus_write32(bar1: cobalt->bar1, ADRS(offset), data: val); |
23 | } |
24 | |
25 | static void cpld_info_ver3(struct cobalt *cobalt) |
26 | { |
27 | u32 rd; |
28 | u32 tmp; |
29 | |
30 | cobalt_info("CPLD System control register (read/write)\n" ); |
31 | cobalt_info("\t\tSystem control: 0x%04x (0x0f00)\n" , |
32 | cpld_read(cobalt, 0)); |
33 | cobalt_info("CPLD Clock control register (read/write)\n" ); |
34 | cobalt_info("\t\tClock control: 0x%04x (0x0000)\n" , |
35 | cpld_read(cobalt, 0x04)); |
36 | cobalt_info("CPLD HSMA Clk Osc register (read/write) - Must set wr trigger to load default values\n" ); |
37 | cobalt_info("\t\tRegister #7:\t0x%04x (0x0022)\n" , |
38 | cpld_read(cobalt, 0x08)); |
39 | cobalt_info("\t\tRegister #8:\t0x%04x (0x0047)\n" , |
40 | cpld_read(cobalt, 0x0c)); |
41 | cobalt_info("\t\tRegister #9:\t0x%04x (0x00fa)\n" , |
42 | cpld_read(cobalt, 0x10)); |
43 | cobalt_info("\t\tRegister #10:\t0x%04x (0x0061)\n" , |
44 | cpld_read(cobalt, 0x14)); |
45 | cobalt_info("\t\tRegister #11:\t0x%04x (0x001e)\n" , |
46 | cpld_read(cobalt, 0x18)); |
47 | cobalt_info("\t\tRegister #12:\t0x%04x (0x0045)\n" , |
48 | cpld_read(cobalt, 0x1c)); |
49 | cobalt_info("\t\tRegister #135:\t0x%04x\n" , |
50 | cpld_read(cobalt, 0x20)); |
51 | cobalt_info("\t\tRegister #137:\t0x%04x\n" , |
52 | cpld_read(cobalt, 0x24)); |
53 | cobalt_info("CPLD System status register (read only)\n" ); |
54 | cobalt_info("\t\tSystem status: 0x%04x\n" , |
55 | cpld_read(cobalt, 0x28)); |
56 | cobalt_info("CPLD MAXII info register (read only)\n" ); |
57 | cobalt_info("\t\tBoard serial number: 0x%04x\n" , |
58 | cpld_read(cobalt, 0x2c)); |
59 | cobalt_info("\t\tMAXII program revision: 0x%04x\n" , |
60 | cpld_read(cobalt, 0x30)); |
61 | cobalt_info("CPLD temp and voltage ADT7411 registers (read only)\n" ); |
62 | cobalt_info("\t\tBoard temperature: %u Celsius\n" , |
63 | cpld_read(cobalt, 0x34) / 4); |
64 | cobalt_info("\t\tFPGA temperature: %u Celsius\n" , |
65 | cpld_read(cobalt, 0x38) / 4); |
66 | rd = cpld_read(cobalt, offset: 0x3c); |
67 | tmp = (rd * 33 * 1000) / (483 * 10); |
68 | cobalt_info("\t\tVDD 3V3: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
69 | rd = cpld_read(cobalt, offset: 0x40); |
70 | tmp = (rd * 74 * 2197) / (27 * 1000); |
71 | cobalt_info("\t\tADC ch3 5V: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
72 | rd = cpld_read(cobalt, offset: 0x44); |
73 | tmp = (rd * 74 * 2197) / (47 * 1000); |
74 | cobalt_info("\t\tADC ch4 3V: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
75 | rd = cpld_read(cobalt, offset: 0x48); |
76 | tmp = (rd * 57 * 2197) / (47 * 1000); |
77 | cobalt_info("\t\tADC ch5 2V5: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
78 | rd = cpld_read(cobalt, offset: 0x4c); |
79 | tmp = (rd * 2197) / 1000; |
80 | cobalt_info("\t\tADC ch6 1V8: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
81 | rd = cpld_read(cobalt, offset: 0x50); |
82 | tmp = (rd * 2197) / 1000; |
83 | cobalt_info("\t\tADC ch7 1V5: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
84 | rd = cpld_read(cobalt, offset: 0x54); |
85 | tmp = (rd * 2197) / 1000; |
86 | cobalt_info("\t\tADC ch8 0V9: %u,%03uV\n" , tmp / 1000, tmp % 1000); |
87 | } |
88 | |
89 | void cobalt_cpld_status(struct cobalt *cobalt) |
90 | { |
91 | u32 rev = cpld_read(cobalt, offset: 0x30); |
92 | |
93 | switch (rev) { |
94 | case 3: |
95 | case 4: |
96 | case 5: |
97 | cpld_info_ver3(cobalt); |
98 | break; |
99 | default: |
100 | cobalt_info("CPLD revision %u is not supported!\n" , rev); |
101 | break; |
102 | } |
103 | } |
104 | |
105 | #define DCO_MIN 4850000000ULL |
106 | #define DCO_MAX 5670000000ULL |
107 | |
108 | #define SI570_CLOCK_CTRL 0x04 |
109 | #define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER 0x200 |
110 | #define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER 0x100 |
111 | #define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL 0x80 |
112 | #define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN 0x40 |
113 | |
114 | #define SI570_REG7 0x08 |
115 | #define SI570_REG8 0x0c |
116 | #define SI570_REG9 0x10 |
117 | #define SI570_REG10 0x14 |
118 | #define SI570_REG11 0x18 |
119 | #define SI570_REG12 0x1c |
120 | #define SI570_REG135 0x20 |
121 | #define SI570_REG137 0x24 |
122 | |
123 | struct multiplier { |
124 | unsigned mult, hsdiv, n1; |
125 | }; |
126 | |
127 | /* List all possible multipliers (= hsdiv * n1). There are lots of duplicates, |
128 | which are all removed in this list to keep the list as short as possible. |
129 | The values for hsdiv and n1 are the actual values, not the register values. |
130 | */ |
131 | static const struct multiplier multipliers[] = { |
132 | { 4, 4, 1 }, { 5, 5, 1 }, { 6, 6, 1 }, |
133 | { 7, 7, 1 }, { 8, 4, 2 }, { 9, 9, 1 }, |
134 | { 10, 5, 2 }, { 11, 11, 1 }, { 12, 6, 2 }, |
135 | { 14, 7, 2 }, { 16, 4, 4 }, { 18, 9, 2 }, |
136 | { 20, 5, 4 }, { 22, 11, 2 }, { 24, 4, 6 }, |
137 | { 28, 7, 4 }, { 30, 5, 6 }, { 32, 4, 8 }, |
138 | { 36, 6, 6 }, { 40, 4, 10 }, { 42, 7, 6 }, |
139 | { 44, 11, 4 }, { 48, 4, 12 }, { 50, 5, 10 }, |
140 | { 54, 9, 6 }, { 56, 4, 14 }, { 60, 5, 12 }, |
141 | { 64, 4, 16 }, { 66, 11, 6 }, { 70, 5, 14 }, |
142 | { 72, 4, 18 }, { 80, 4, 20 }, { 84, 6, 14 }, |
143 | { 88, 11, 8 }, { 90, 5, 18 }, { 96, 4, 24 }, |
144 | { 98, 7, 14 }, { 100, 5, 20 }, { 104, 4, 26 }, |
145 | { 108, 6, 18 }, { 110, 11, 10 }, { 112, 4, 28 }, |
146 | { 120, 4, 30 }, { 126, 7, 18 }, { 128, 4, 32 }, |
147 | { 130, 5, 26 }, { 132, 11, 12 }, { 136, 4, 34 }, |
148 | { 140, 5, 28 }, { 144, 4, 36 }, { 150, 5, 30 }, |
149 | { 152, 4, 38 }, { 154, 11, 14 }, { 156, 6, 26 }, |
150 | { 160, 4, 40 }, { 162, 9, 18 }, { 168, 4, 42 }, |
151 | { 170, 5, 34 }, { 176, 11, 16 }, { 180, 5, 36 }, |
152 | { 182, 7, 26 }, { 184, 4, 46 }, { 190, 5, 38 }, |
153 | { 192, 4, 48 }, { 196, 7, 28 }, { 198, 11, 18 }, |
154 | { 198, 9, 22 }, { 200, 4, 50 }, { 204, 6, 34 }, |
155 | { 208, 4, 52 }, { 210, 5, 42 }, { 216, 4, 54 }, |
156 | { 220, 11, 20 }, { 224, 4, 56 }, { 228, 6, 38 }, |
157 | { 230, 5, 46 }, { 232, 4, 58 }, { 234, 9, 26 }, |
158 | { 238, 7, 34 }, { 240, 4, 60 }, { 242, 11, 22 }, |
159 | { 248, 4, 62 }, { 250, 5, 50 }, { 252, 6, 42 }, |
160 | { 256, 4, 64 }, { 260, 5, 52 }, { 264, 11, 24 }, |
161 | { 266, 7, 38 }, { 270, 5, 54 }, { 272, 4, 68 }, |
162 | { 276, 6, 46 }, { 280, 4, 70 }, { 286, 11, 26 }, |
163 | { 288, 4, 72 }, { 290, 5, 58 }, { 294, 7, 42 }, |
164 | { 296, 4, 74 }, { 300, 5, 60 }, { 304, 4, 76 }, |
165 | { 306, 9, 34 }, { 308, 11, 28 }, { 310, 5, 62 }, |
166 | { 312, 4, 78 }, { 320, 4, 80 }, { 322, 7, 46 }, |
167 | { 324, 6, 54 }, { 328, 4, 82 }, { 330, 11, 30 }, |
168 | { 336, 4, 84 }, { 340, 5, 68 }, { 342, 9, 38 }, |
169 | { 344, 4, 86 }, { 348, 6, 58 }, { 350, 5, 70 }, |
170 | { 352, 11, 32 }, { 360, 4, 90 }, { 364, 7, 52 }, |
171 | { 368, 4, 92 }, { 370, 5, 74 }, { 372, 6, 62 }, |
172 | { 374, 11, 34 }, { 376, 4, 94 }, { 378, 7, 54 }, |
173 | { 380, 5, 76 }, { 384, 4, 96 }, { 390, 5, 78 }, |
174 | { 392, 4, 98 }, { 396, 11, 36 }, { 400, 4, 100 }, |
175 | { 406, 7, 58 }, { 408, 4, 102 }, { 410, 5, 82 }, |
176 | { 414, 9, 46 }, { 416, 4, 104 }, { 418, 11, 38 }, |
177 | { 420, 5, 84 }, { 424, 4, 106 }, { 430, 5, 86 }, |
178 | { 432, 4, 108 }, { 434, 7, 62 }, { 440, 11, 40 }, |
179 | { 444, 6, 74 }, { 448, 4, 112 }, { 450, 5, 90 }, |
180 | { 456, 4, 114 }, { 460, 5, 92 }, { 462, 11, 42 }, |
181 | { 464, 4, 116 }, { 468, 6, 78 }, { 470, 5, 94 }, |
182 | { 472, 4, 118 }, { 476, 7, 68 }, { 480, 4, 120 }, |
183 | { 484, 11, 44 }, { 486, 9, 54 }, { 488, 4, 122 }, |
184 | { 490, 5, 98 }, { 492, 6, 82 }, { 496, 4, 124 }, |
185 | { 500, 5, 100 }, { 504, 4, 126 }, { 506, 11, 46 }, |
186 | { 510, 5, 102 }, { 512, 4, 128 }, { 516, 6, 86 }, |
187 | { 518, 7, 74 }, { 520, 5, 104 }, { 522, 9, 58 }, |
188 | { 528, 11, 48 }, { 530, 5, 106 }, { 532, 7, 76 }, |
189 | { 540, 5, 108 }, { 546, 7, 78 }, { 550, 11, 50 }, |
190 | { 552, 6, 92 }, { 558, 9, 62 }, { 560, 5, 112 }, |
191 | { 564, 6, 94 }, { 570, 5, 114 }, { 572, 11, 52 }, |
192 | { 574, 7, 82 }, { 576, 6, 96 }, { 580, 5, 116 }, |
193 | { 588, 6, 98 }, { 590, 5, 118 }, { 594, 11, 54 }, |
194 | { 600, 5, 120 }, { 602, 7, 86 }, { 610, 5, 122 }, |
195 | { 612, 6, 102 }, { 616, 11, 56 }, { 620, 5, 124 }, |
196 | { 624, 6, 104 }, { 630, 5, 126 }, { 636, 6, 106 }, |
197 | { 638, 11, 58 }, { 640, 5, 128 }, { 644, 7, 92 }, |
198 | { 648, 6, 108 }, { 658, 7, 94 }, { 660, 11, 60 }, |
199 | { 666, 9, 74 }, { 672, 6, 112 }, { 682, 11, 62 }, |
200 | { 684, 6, 114 }, { 686, 7, 98 }, { 696, 6, 116 }, |
201 | { 700, 7, 100 }, { 702, 9, 78 }, { 704, 11, 64 }, |
202 | { 708, 6, 118 }, { 714, 7, 102 }, { 720, 6, 120 }, |
203 | { 726, 11, 66 }, { 728, 7, 104 }, { 732, 6, 122 }, |
204 | { 738, 9, 82 }, { 742, 7, 106 }, { 744, 6, 124 }, |
205 | { 748, 11, 68 }, { 756, 6, 126 }, { 768, 6, 128 }, |
206 | { 770, 11, 70 }, { 774, 9, 86 }, { 784, 7, 112 }, |
207 | { 792, 11, 72 }, { 798, 7, 114 }, { 810, 9, 90 }, |
208 | { 812, 7, 116 }, { 814, 11, 74 }, { 826, 7, 118 }, |
209 | { 828, 9, 92 }, { 836, 11, 76 }, { 840, 7, 120 }, |
210 | { 846, 9, 94 }, { 854, 7, 122 }, { 858, 11, 78 }, |
211 | { 864, 9, 96 }, { 868, 7, 124 }, { 880, 11, 80 }, |
212 | { 882, 7, 126 }, { 896, 7, 128 }, { 900, 9, 100 }, |
213 | { 902, 11, 82 }, { 918, 9, 102 }, { 924, 11, 84 }, |
214 | { 936, 9, 104 }, { 946, 11, 86 }, { 954, 9, 106 }, |
215 | { 968, 11, 88 }, { 972, 9, 108 }, { 990, 11, 90 }, |
216 | { 1008, 9, 112 }, { 1012, 11, 92 }, { 1026, 9, 114 }, |
217 | { 1034, 11, 94 }, { 1044, 9, 116 }, { 1056, 11, 96 }, |
218 | { 1062, 9, 118 }, { 1078, 11, 98 }, { 1080, 9, 120 }, |
219 | { 1098, 9, 122 }, { 1100, 11, 100 }, { 1116, 9, 124 }, |
220 | { 1122, 11, 102 }, { 1134, 9, 126 }, { 1144, 11, 104 }, |
221 | { 1152, 9, 128 }, { 1166, 11, 106 }, { 1188, 11, 108 }, |
222 | { 1210, 11, 110 }, { 1232, 11, 112 }, { 1254, 11, 114 }, |
223 | { 1276, 11, 116 }, { 1298, 11, 118 }, { 1320, 11, 120 }, |
224 | { 1342, 11, 122 }, { 1364, 11, 124 }, { 1386, 11, 126 }, |
225 | { 1408, 11, 128 }, |
226 | }; |
227 | |
228 | bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out) |
229 | { |
230 | const unsigned f_xtal = 39170000; /* xtal for si598 */ |
231 | u64 dco; |
232 | u64 rfreq; |
233 | unsigned delta = 0xffffffff; |
234 | unsigned i_best = 0; |
235 | unsigned i; |
236 | u8 n1, hsdiv; |
237 | u8 regs[6]; |
238 | int found = 0; |
239 | int retries = 3; |
240 | |
241 | for (i = 0; i < ARRAY_SIZE(multipliers); i++) { |
242 | unsigned mult = multipliers[i].mult; |
243 | u32 d; |
244 | |
245 | dco = (u64)f_out * mult; |
246 | if (dco < DCO_MIN || dco > DCO_MAX) |
247 | continue; |
248 | div_u64_rem(dividend: (dco << 28) + f_xtal / 2, divisor: f_xtal, remainder: &d); |
249 | if (d < delta) { |
250 | found = 1; |
251 | i_best = i; |
252 | delta = d; |
253 | } |
254 | } |
255 | if (!found) |
256 | return false; |
257 | dco = (u64)f_out * multipliers[i_best].mult; |
258 | n1 = multipliers[i_best].n1 - 1; |
259 | hsdiv = multipliers[i_best].hsdiv - 4; |
260 | rfreq = div_u64(dividend: dco << 28, divisor: f_xtal); |
261 | |
262 | cpld_read(cobalt, SI570_CLOCK_CTRL); |
263 | |
264 | regs[0] = (hsdiv << 5) | (n1 >> 2); |
265 | regs[1] = ((n1 & 0x3) << 6) | (rfreq >> 32); |
266 | regs[2] = (rfreq >> 24) & 0xff; |
267 | regs[3] = (rfreq >> 16) & 0xff; |
268 | regs[4] = (rfreq >> 8) & 0xff; |
269 | regs[5] = rfreq & 0xff; |
270 | |
271 | /* The sequence of clock_ctrl flags to set is very weird. It looks |
272 | like I have to reset it, then set the new frequency and reset it |
273 | again. It shouldn't be necessary to do a reset, but if I don't, |
274 | then a strange frequency is set (156.412034 MHz, or register values |
275 | 0x01, 0xc7, 0xfc, 0x7f, 0x53, 0x62). |
276 | */ |
277 | |
278 | cobalt_dbg(1, "%u: %6ph\n" , f_out, regs); |
279 | |
280 | while (retries--) { |
281 | u8 read_regs[6]; |
282 | |
283 | cpld_write(cobalt, SI570_CLOCK_CTRL, |
284 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | |
285 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL); |
286 | usleep_range(min: 10000, max: 15000); |
287 | cpld_write(cobalt, SI570_REG7, val: regs[0]); |
288 | cpld_write(cobalt, SI570_REG8, val: regs[1]); |
289 | cpld_write(cobalt, SI570_REG9, val: regs[2]); |
290 | cpld_write(cobalt, SI570_REG10, val: regs[3]); |
291 | cpld_write(cobalt, SI570_REG11, val: regs[4]); |
292 | cpld_write(cobalt, SI570_REG12, val: regs[5]); |
293 | cpld_write(cobalt, SI570_CLOCK_CTRL, |
294 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | |
295 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER); |
296 | usleep_range(min: 10000, max: 15000); |
297 | cpld_write(cobalt, SI570_CLOCK_CTRL, |
298 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | |
299 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL); |
300 | usleep_range(min: 10000, max: 15000); |
301 | read_regs[0] = cpld_read(cobalt, SI570_REG7); |
302 | read_regs[1] = cpld_read(cobalt, SI570_REG8); |
303 | read_regs[2] = cpld_read(cobalt, SI570_REG9); |
304 | read_regs[3] = cpld_read(cobalt, SI570_REG10); |
305 | read_regs[4] = cpld_read(cobalt, SI570_REG11); |
306 | read_regs[5] = cpld_read(cobalt, SI570_REG12); |
307 | cpld_write(cobalt, SI570_CLOCK_CTRL, |
308 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | |
309 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL | |
310 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER); |
311 | usleep_range(min: 10000, max: 15000); |
312 | cpld_write(cobalt, SI570_CLOCK_CTRL, |
313 | S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN); |
314 | usleep_range(min: 10000, max: 15000); |
315 | |
316 | if (!memcmp(p: read_regs, q: regs, size: sizeof(read_regs))) |
317 | break; |
318 | cobalt_dbg(1, "retry: %6ph\n" , read_regs); |
319 | } |
320 | if (2 - retries) |
321 | cobalt_info("Needed %d retries\n" , 2 - retries); |
322 | |
323 | return true; |
324 | } |
325 | |