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
cpld_read(struct cobalt * cobalt,u32 offset)15 static u16 cpld_read(struct cobalt *cobalt, u32 offset)
16 {
17 return cobalt_bus_read32(cobalt->bar1, ADRS(offset));
18 }
19
cpld_write(struct cobalt * cobalt,u32 offset,u16 val)20 static void cpld_write(struct cobalt *cobalt, u32 offset, u16 val)
21 {
22 return cobalt_bus_write32(cobalt->bar1, ADRS(offset), val);
23 }
24
cpld_info_ver3(struct cobalt * cobalt)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, 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, 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, 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, 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, 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, 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, 0x54);
85 tmp = (rd * 2197) / 1000;
86 cobalt_info("\t\tADC ch8 0V9: %u,%03uV\n", tmp / 1000, tmp % 1000);
87 }
88
cobalt_cpld_status(struct cobalt * cobalt)89 void cobalt_cpld_status(struct cobalt *cobalt)
90 {
91 u32 rev = cpld_read(cobalt, 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
cobalt_cpld_set_freq(struct cobalt * cobalt,unsigned f_out)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((dco << 28) + f_xtal / 2, f_xtal, &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(dco << 28, 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(10000, 15000);
287 cpld_write(cobalt, SI570_REG7, regs[0]);
288 cpld_write(cobalt, SI570_REG8, regs[1]);
289 cpld_write(cobalt, SI570_REG9, regs[2]);
290 cpld_write(cobalt, SI570_REG10, regs[3]);
291 cpld_write(cobalt, SI570_REG11, regs[4]);
292 cpld_write(cobalt, SI570_REG12, 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(10000, 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(10000, 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(10000, 15000);
312 cpld_write(cobalt, SI570_CLOCK_CTRL,
313 S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN);
314 usleep_range(10000, 15000);
315
316 if (!memcmp(read_regs, regs, 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