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