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 * 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 * 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 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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