xref: /linux/drivers/media/pci/cobalt/cobalt-cpld.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
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 
23 #include "cobalt-cpld.h"
24 
25 #define ADRS(offset) (COBALT_BUS_CPLD_BASE + offset)
26 
27 static u16 cpld_read(struct cobalt *cobalt, u32 offset)
28 {
29 	return cobalt_bus_read32(cobalt->bar1, ADRS(offset));
30 }
31 
32 static void cpld_write(struct cobalt *cobalt, u32 offset, u16 val)
33 {
34 	return cobalt_bus_write32(cobalt->bar1, ADRS(offset), val);
35 }
36 
37 static 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 
101 void 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 
135 struct 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  */
143 static 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 
240 bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out)
241 {
242 	const unsigned f_xtal = 39170000;	/* xtal for si598 */
243 	u64 dco;
244 	u64 rfreq;
245 	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;
256 		u32 d;
257 
258 		dco = (u64)f_out * mult;
259 		if (dco < DCO_MIN || dco > DCO_MAX)
260 			continue;
261 		div_u64_rem((dco << 28) + f_xtal / 2, f_xtal, &d);
262 		if (d < delta) {
263 			found = 1;
264 			i_best = i;
265 			delta = d;
266 		}
267 	}
268 	if (!found)
269 		return false;
270 	dco = (u64)f_out * multipliers[i_best].mult;
271 	n1 = multipliers[i_best].n1 - 1;
272 	hsdiv = multipliers[i_best].hsdiv - 4;
273 	rfreq = div_u64(dco << 28, f_xtal);
274 
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 }
342