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