1 /* $NetBSD: xc3028.c,v 1.9 2018/09/03 16:29:31 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * Xceive XC3028L
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: xc3028.c,v 1.9 2018/09/03 16:29:31 riastradh Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/conf.h>
40 #include <sys/bus.h>
41 #include <sys/kmem.h>
42 #include <sys/mutex.h>
43 #include <sys/module.h>
44
45 #include <dev/firmload.h>
46 #include <dev/i2c/i2cvar.h>
47
48 #include <dev/i2c/xc3028reg.h>
49 #include <dev/i2c/xc3028var.h>
50
51 #define XC3028_FIRMWARE_DRVNAME "xc3028"
52
53 #define XC3028_FREQ_MIN 1000000
54 #define XC3028_FREQ_MAX 1023000000
55
56 #define XC3028_FW_BASE (1 << 0)
57 #define XC3028_FW_D2633 (1 << 4)
58 #define XC3028_FW_DTV6 (1 << 5)
59 #define XC3028_FW_QAM (1 << 6)
60 #define XC3028_FW_ATSC (1 << 16)
61 #define XC3028_FW_LG60 (1 << 18)
62 #define XC3028_FW_F6MHZ (1 << 27)
63 #define XC3028_FW_SCODE (1 << 29)
64 #define XC3028_FW_HAS_IF (1 << 30)
65
66 #define XC3028_FW_DEFAULT (XC3028_FW_ATSC|XC3028_FW_D2633|XC3028_FW_DTV6)
67
68 static kmutex_t xc3028_firmware_lock;
69
70 static int xc3028_reset(struct xc3028 *);
71 static int xc3028_read_2(struct xc3028 *, uint16_t, uint16_t *);
72 static int xc3028_write_buffer(struct xc3028 *, const uint8_t *, size_t);
73 static int xc3028_firmware_open(struct xc3028 *);
74 static int xc3028_firmware_parse(struct xc3028 *, const uint8_t *, size_t);
75 static int xc3028_firmware_upload(struct xc3028 *, struct xc3028_fw *);
76 static int xc3028_scode_upload(struct xc3028 *, struct xc3028_fw *);
77 static void xc3028_dump_fw(struct xc3028 *, struct xc3028_fw *,
78 const char *);
79
80 static const char *
xc3028_name(struct xc3028 * xc)81 xc3028_name(struct xc3028 *xc)
82 {
83 if (xc->type == XC3028L)
84 return "xc3028l";
85 else
86 return "xc3028";
87 }
88
89 static const char *
xc3028_firmware_name(struct xc3028 * xc)90 xc3028_firmware_name(struct xc3028 *xc)
91 {
92 if (xc->type == XC3028L)
93 return "xc3028L-v36.fw";
94 else
95 return "xc3028-v27.fw";
96 }
97
98 static int
xc3028_reset(struct xc3028 * xc)99 xc3028_reset(struct xc3028 *xc)
100 {
101 int error = 0;
102
103 if (xc->reset)
104 error = xc->reset(xc->reset_priv);
105
106 return error;
107 }
108
109 static struct xc3028_fw *
xc3028_get_basefw(struct xc3028 * xc)110 xc3028_get_basefw(struct xc3028 *xc)
111 {
112 struct xc3028_fw *fw;
113 unsigned int i;
114
115 for (i = 0; i < xc->nfw; i++) {
116 fw = &xc->fw[i];
117 if (fw->type == XC3028_FW_BASE)
118 return fw;
119 }
120
121 return NULL;
122 }
123
124 static struct xc3028_fw *
xc3028_get_stdfw(struct xc3028 * xc)125 xc3028_get_stdfw(struct xc3028 *xc)
126 {
127 struct xc3028_fw *fw;
128 unsigned int i;
129
130 for (i = 0; i < xc->nfw; i++) {
131 fw = &xc->fw[i];
132 if (fw->type == (XC3028_FW_D2633|XC3028_FW_DTV6|XC3028_FW_ATSC))
133 return fw;
134 }
135
136 return NULL;
137 }
138
139 static struct xc3028_fw *
xc3028_get_scode(struct xc3028 * xc)140 xc3028_get_scode(struct xc3028 *xc)
141 {
142 struct xc3028_fw *fw;
143 unsigned int i;
144
145 for (i = 0; i < xc->nfw; i++) {
146 fw = &xc->fw[i];
147 if (fw->type ==
148 (XC3028_FW_DTV6|XC3028_FW_QAM|XC3028_FW_ATSC|XC3028_FW_LG60|
149 XC3028_FW_F6MHZ|XC3028_FW_SCODE|XC3028_FW_HAS_IF) &&
150 fw->int_freq == 6200)
151 return fw;
152 }
153
154 return NULL;
155 }
156
157 static int
xc3028_firmware_open(struct xc3028 * xc)158 xc3028_firmware_open(struct xc3028 *xc)
159 {
160 firmware_handle_t fwh;
161 struct xc3028_fw *basefw, *stdfw, *scode;
162 uint8_t *fw = NULL;
163 uint16_t xcversion = 0;
164 size_t fwlen;
165 int error;
166
167 mutex_enter(&xc3028_firmware_lock);
168
169 error = firmware_open(XC3028_FIRMWARE_DRVNAME,
170 xc3028_firmware_name(xc), &fwh);
171 if (error)
172 goto done;
173 fwlen = firmware_get_size(fwh);
174 fw = firmware_malloc(fwlen);
175 if (fw == NULL) {
176 firmware_close(fwh);
177 error = ENOMEM;
178 goto done;
179 }
180 error = firmware_read(fwh, 0, fw, fwlen);
181 firmware_close(fwh);
182 if (error)
183 goto done;
184
185 device_printf(xc->parent, "%s: loading firmware '%s/%s'\n",
186 xc3028_name(xc), XC3028_FIRMWARE_DRVNAME, xc3028_firmware_name(xc));
187 error = xc3028_firmware_parse(xc, fw, fwlen);
188 if (!error) {
189 basefw = xc3028_get_basefw(xc);
190 stdfw = xc3028_get_stdfw(xc);
191 scode = xc3028_get_scode(xc);
192 if (basefw && stdfw) {
193 xc3028_reset(xc);
194 xc3028_dump_fw(xc, basefw, "base");
195 error = xc3028_firmware_upload(xc, basefw);
196 if (error)
197 return error;
198 xc3028_dump_fw(xc, stdfw, "std");
199 error = xc3028_firmware_upload(xc, stdfw);
200 if (error)
201 return error;
202 if (scode) {
203 xc3028_dump_fw(xc, scode, "scode");
204 error = xc3028_scode_upload(xc, scode);
205 if (error)
206 return error;
207 }
208 } else
209 error = ENODEV;
210 }
211 if (!error) {
212 xc3028_read_2(xc, XC3028_REG_VERSION, &xcversion);
213
214 device_printf(xc->parent, "%s: hw %d.%d, fw %d.%d\n",
215 xc3028_name(xc),
216 (xcversion >> 12) & 0xf, (xcversion >> 8) & 0xf,
217 (xcversion >> 4) & 0xf, (xcversion >> 0) & 0xf);
218 }
219
220 done:
221 if (fw)
222 firmware_free(fw, fwlen);
223 mutex_exit(&xc3028_firmware_lock);
224
225 if (error)
226 aprint_error_dev(xc->parent,
227 "%s: couldn't open firmware '%s/%s' (error=%d)\n",
228 xc3028_name(xc), XC3028_FIRMWARE_DRVNAME,
229 xc3028_firmware_name(xc), error);
230
231 return error;
232 }
233
234 static const char *xc3028_fw_types[] = {
235 "BASE",
236 "F8MHZ",
237 "MTS",
238 "D2620",
239 "D2633",
240 "DTV6",
241 "QAM",
242 "DTV7",
243 "DTV78",
244 "DTV8",
245 "FM",
246 "INPUT1",
247 "LCD",
248 "NOGD",
249 "INIT1",
250 "MONO",
251 "ATSC",
252 "IF",
253 "LG60",
254 "ATI638",
255 "OREN538",
256 "OREN36",
257 "TOYOTA388",
258 "TOYOTA794",
259 "DIBCOM52",
260 "ZARLINK456",
261 "CHINA",
262 "F6MHZ",
263 "INPUT2",
264 "SCODE",
265 "HAS_IF",
266 };
267
268 static void
xc3028_dump_fw(struct xc3028 * xc,struct xc3028_fw * xcfw,const char * type)269 xc3028_dump_fw(struct xc3028 *xc, struct xc3028_fw *xcfw, const char *type)
270 {
271 unsigned int i;
272
273 device_printf(xc->parent, "%s: %s:", xc3028_name(xc), type);
274 if (xcfw == NULL) {
275 printf(" <none>\n");
276 return;
277 }
278 for (i = 0; i < __arraycount(xc3028_fw_types); i++) {
279 if (xcfw->type & (1 << i))
280 printf(" %s", xc3028_fw_types[i]);
281 }
282 if (xcfw->type & (1 << 30))
283 printf("_%d", xcfw->int_freq);
284 if (xcfw->id)
285 printf(" id=%" PRIx64, xcfw->id);
286 printf(" size=%u\n", xcfw->data_size);
287 }
288
289 static int
xc3028_firmware_parse(struct xc3028 * xc,const uint8_t * fw,size_t fwlen)290 xc3028_firmware_parse(struct xc3028 *xc, const uint8_t *fw, size_t fwlen)
291 {
292 const uint8_t *p = fw, *endp = p + fwlen;
293 char fwname[32 + 1];
294 uint16_t fwver, narr;
295 unsigned int index;
296 struct xc3028_fw *xcfw;
297
298 if (fwlen < 36)
299 return EINVAL;
300
301 /* first 32 bytes are the firmware name string */
302 memset(fwname, 0, sizeof(fwname));
303 memcpy(fwname, p, sizeof(fwname) - 1);
304 p += (sizeof(fwname) - 1);
305
306 fwver = le16dec(p);
307 p += sizeof(fwver);
308 narr = le16dec(p);
309 p += sizeof(narr);
310
311 aprint_debug_dev(xc->parent, "%s: fw type %s, ver %d.%d, %d images\n",
312 xc3028_name(xc), fwname, fwver >> 8, fwver & 0xff, narr);
313
314 xc->fw = kmem_zalloc(sizeof(*xc->fw) * narr, KM_SLEEP);
315 xc->nfw = narr;
316
317 for (index = 0; index < xc->nfw && p < endp; index++) {
318 xcfw = &xc->fw[index];
319
320 if (endp - p < 16)
321 goto corrupt;
322
323 xcfw->type = le32dec(p);
324 p += sizeof(xcfw->type);
325
326 xcfw->id = le64dec(p);
327 p += sizeof(xcfw->id);
328
329 if (xcfw->type & XC3028_FW_HAS_IF) {
330 xcfw->int_freq = le16dec(p);
331 p += sizeof(xcfw->int_freq);
332 if ((uint32_t)(endp - p) < sizeof(xcfw->data_size))
333 goto corrupt;
334 }
335
336 xcfw->data_size = le32dec(p);
337 p += sizeof(xcfw->data_size);
338
339 if (xcfw->data_size == 0 ||
340 xcfw->data_size > (uint32_t)(endp - p))
341 goto corrupt;
342 xcfw->data = kmem_alloc(xcfw->data_size, KM_SLEEP);
343 memcpy(xcfw->data, p, xcfw->data_size);
344 p += xcfw->data_size;
345 }
346
347 return 0;
348
349 corrupt:
350 aprint_error_dev(xc->parent, "%s: fw image corrupt\n", xc3028_name(xc));
351 for (index = 0; index < xc->nfw; index++) {
352 if (xc->fw[index].data)
353 kmem_free(xc->fw[index].data, xc->fw[index].data_size);
354 }
355 kmem_free(xc->fw, sizeof(*xc->fw) * xc->nfw);
356 xc->nfw = 0;
357
358 return ENXIO;
359 }
360
361 static int
xc3028_firmware_upload(struct xc3028 * xc,struct xc3028_fw * xcfw)362 xc3028_firmware_upload(struct xc3028 *xc, struct xc3028_fw *xcfw)
363 {
364 const uint8_t *fw = xcfw->data, *p;
365 uint32_t fwlen = xcfw->data_size;
366 uint8_t cmd[64];
367 unsigned int i;
368 uint16_t len, rem;
369 size_t wrlen;
370 int error;
371
372 for (i = 0; i < fwlen - 2;) {
373 len = le16dec(&fw[i]);
374 i += 2;
375 if (len == 0xffff)
376 break;
377
378 /* reset command */
379 if (len == 0x0000) {
380 error = xc3028_reset(xc);
381 if (error)
382 return error;
383 continue;
384 }
385 /* reset clk command */
386 if (len == 0xff00) {
387 continue;
388 }
389 /* delay command */
390 if (len & 0x8000) {
391 delay((len & 0x7fff) * 1000);
392 continue;
393 }
394
395 if (i + len > fwlen) {
396 printf("weird len, i=%u len=%u fwlen=%u'\n", i, len, fwlen);
397 return EINVAL;
398 }
399
400 cmd[0] = fw[i];
401 p = &fw[i + 1];
402 rem = len - 1;
403 while (rem > 0) {
404 wrlen = uimin(rem, __arraycount(cmd) - 1);
405 memcpy(&cmd[1], p, wrlen);
406 error = xc3028_write_buffer(xc, cmd, wrlen + 1);
407 if (error)
408 return error;
409 p += wrlen;
410 rem -= wrlen;
411 }
412 i += len;
413 }
414
415 return 0;
416 }
417
418 static int
xc3028_scode_upload(struct xc3028 * xc,struct xc3028_fw * xcfw)419 xc3028_scode_upload(struct xc3028 *xc, struct xc3028_fw *xcfw)
420 {
421 static uint8_t scode_init[] = { 0xa0, 0x00, 0x00, 0x00 };
422 static uint8_t scode_fini[] = { 0x00, 0x8c };
423 int error;
424
425 if (xcfw->data_size < 12)
426 return EINVAL;
427 error = xc3028_write_buffer(xc, scode_init, sizeof(scode_init));
428 if (error)
429 return error;
430 error = xc3028_write_buffer(xc, xcfw->data, 12);
431 if (error)
432 return error;
433 error = xc3028_write_buffer(xc, scode_fini, sizeof(scode_fini));
434 if (error)
435 return error;
436
437 return 0;
438 }
439
440 static int
xc3028_read_2(struct xc3028 * xc,uint16_t reg,uint16_t * val)441 xc3028_read_2(struct xc3028 *xc, uint16_t reg, uint16_t *val)
442 {
443 uint8_t cmd[2], resp[2];
444 int error;
445
446 cmd[0] = reg >> 8;
447 cmd[1] = reg & 0xff;
448 error = iic_exec(xc->i2c, I2C_OP_WRITE, xc->i2c_addr,
449 cmd, sizeof(cmd), NULL, 0, 0);
450 if (error)
451 return error;
452 resp[0] = resp[1] = 0;
453 error = iic_exec(xc->i2c, I2C_OP_READ, xc->i2c_addr,
454 NULL, 0, resp, sizeof(resp), 0);
455 if (error)
456 return error;
457
458 *val = (resp[0] << 8) | resp[1];
459
460 return 0;
461 }
462
463 static int
xc3028_write_buffer(struct xc3028 * xc,const uint8_t * data,size_t datalen)464 xc3028_write_buffer(struct xc3028 *xc, const uint8_t *data, size_t datalen)
465 {
466 return iic_exec(xc->i2c, I2C_OP_WRITE_WITH_STOP, xc->i2c_addr,
467 data, datalen, NULL, 0, 0);
468 }
469
470 #if notyet
471 static int
xc3028_write_2(struct xc3028 * xc,uint16_t reg,uint16_t val)472 xc3028_write_2(struct xc3028 *xc, uint16_t reg, uint16_t val)
473 {
474 uint8_t data[4];
475
476 data[0] = reg >> 8;
477 data[1] = reg & 0xff;
478 data[2] = val >> 8;
479 data[3] = val & 0xff;
480
481 return xc3028_write_buffer(xc, data, sizeof(data));
482 }
483 #endif
484
485 struct xc3028 *
xc3028_open(device_t parent,i2c_tag_t i2c,i2c_addr_t addr,xc3028_reset_cb reset,void * reset_priv,enum xc3028_type type)486 xc3028_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr,
487 xc3028_reset_cb reset, void *reset_priv, enum xc3028_type type)
488 {
489 struct xc3028 *xc;
490
491 xc = kmem_alloc(sizeof(*xc), KM_SLEEP);
492 xc->parent = parent;
493 xc->i2c = i2c;
494 xc->i2c_addr = addr;
495 xc->reset = reset;
496 xc->reset_priv = reset_priv;
497 xc->type = type;
498
499 if (xc3028_firmware_open(xc)) {
500 aprint_error_dev(parent, "%s: fw open failed\n",
501 xc3028_name(xc));
502 goto failed;
503 }
504
505 return xc;
506
507 failed:
508 kmem_free(xc, sizeof(*xc));
509 return NULL;
510 }
511
512 void
xc3028_close(struct xc3028 * xc)513 xc3028_close(struct xc3028 *xc)
514 {
515 unsigned int index;
516
517 if (xc->fw) {
518 for (index = 0; index < xc->nfw; index++) {
519 if (xc->fw[index].data)
520 kmem_free(xc->fw[index].data,
521 xc->fw[index].data_size);
522 }
523 kmem_free(xc->fw, sizeof(*xc->fw) * xc->nfw);
524 }
525 kmem_free(xc, sizeof(*xc));
526 }
527
528 int
xc3028_tune_dtv(struct xc3028 * xc,const struct dvb_frontend_parameters * params)529 xc3028_tune_dtv(struct xc3028 *xc, const struct dvb_frontend_parameters *params)
530 {
531 static uint8_t freq_init[] = { 0x80, 0x02, 0x00, 0x00 };
532 uint8_t freq_buf[4];
533 uint32_t div, offset = 0;
534 int error;
535
536 if (params->u.vsb.modulation == VSB_8) {
537 offset = 1750000;
538 } else {
539 return EINVAL;
540 }
541
542 div = (params->frequency - offset + 15625 / 2) / 15625;
543
544 error = xc3028_write_buffer(xc, freq_init, sizeof(freq_init));
545 if (error)
546 return error;
547 delay(10000);
548
549 freq_buf[0] = (div >> 24) & 0xff;
550 freq_buf[1] = (div >> 16) & 0xff;
551 freq_buf[2] = (div >> 8) & 0xff;
552 freq_buf[3] = (div >> 0) & 0xff;
553 error = xc3028_write_buffer(xc, freq_buf, sizeof(freq_buf));
554 if (error)
555 return error;
556 delay(100000);
557
558 return 0;
559 }
560
561 MODULE(MODULE_CLASS_DRIVER, xc3028, "i2cexec");
562
563 static int
xc3028_modcmd(modcmd_t cmd,void * opaque)564 xc3028_modcmd(modcmd_t cmd, void *opaque)
565 {
566 switch (cmd) {
567 case MODULE_CMD_INIT:
568 mutex_init(&xc3028_firmware_lock, MUTEX_DEFAULT, IPL_NONE);
569 return 0;
570 case MODULE_CMD_FINI:
571 mutex_destroy(&xc3028_firmware_lock);
572 return 0;
573 default:
574 return ENOTTY;
575 }
576 }
577