2 * Driver for Bt848 TV tuner.
6 #include "../port/lib.h"
10 #include "../port/error.h"
14 #define max(a, b) (((a) > (b))? (a): (b))
25 Brooktree_vid = 0x109e,
26 Brooktree_848_did = 0x0350,
27 Brooktree_878_did = 0x036E,
29 Intel_82437_did = 0x122d,
39 ntsc_sqpixels = 780, /* Including blanking & inactive */
42 ntsc_clkx1delay = 135, /* Clock ticks. */
43 ntsc_clkx1hactive = 754,
44 ntsc_vdelay = 26, /* # of scan lines. */
50 i2c_bt848w3b = 1 << 2,
51 i2c_bt848scl = 1 << 1,
52 i2c_bt848sda = 1 << 0,
53 i2c_scl = i2c_bt848scl,
54 i2c_sda = i2c_bt848sda,
56 i2c_miroproee = 0x80, /* MIRO PRO EEPROM */
61 i2c_haupee = 0xa0, /* Hauppage EEPROM */
62 i2c_stbee = 0xae, /* STB EEPROM */
73 iform_muxsel1 = 3 << 5, /* 004 */
74 iform_muxsel0 = 2 << 5,
75 iform_xtselmask = 3 << 3,
76 iform_xtauto = 3 << 3,
77 iform_formatmask = 7 << 0,
80 control_ldec = 1 << 5, /* 02C */
81 contrast_100percent = 0xd8, /* 030 */
83 vscale_interlaced = 1 << 5, /* 04C */
85 adelay_ntsc = 104, /* 060 */
86 bdelay_ntsc = 93, /* 064 */
87 adc_crush = 1 << 0, /* 068 */
89 colorfmt_rgb16 = 2 << 4 | 2 << 0, /* 0D4 */
90 colorfmt_YCbCr422 = 8 << 4 | 8 << 0,
91 colorfmt_YCbCr411 = 9 << 4 | 9 << 0,
92 colorctl_gamma = 1 << 4, /* 0D8 */
93 capctl_fullframe = 1 << 4, /* 0DC */
94 capctl_captureodd = 1 << 1,
95 capctl_captureeven = 1 << 0,
96 vbipacksize = 0x190, /* 0E0 */
98 intstat_riscstatshift = 28, /* 100 */
99 intstat_i2crack = 1 << 25,
100 intstat_scerr = 1 << 19,
101 intstat_ocerr = 1 << 18,
102 intstat_pabort = 1 << 17,
103 intstat_riperr = 1 << 16,
104 intstat_pperr = 1 << 15,
105 intstat_fdsr = 1 << 14,
106 intstat_ftrgt = 1 << 13,
107 intstat_fbus = 1 << 12,
108 intstat_risci = 1 << 11,
109 intstat_i2cdone = 1 << 8,
110 intstat_vpress = 1 << 5,
111 intstat_hlock = 1 << 4,
112 intstat_vsync = 1 << 1,
113 intstat_fmtchg = 1 << 0,
114 intmask_etbf = 1 << 23, /* 104 */
116 gpiodmactl_apwrdn = 1 << 26, /* 10C */
117 gpiodmactl_daes2 = 1 << 13,
118 gpiodmactl_daiomda = 1 << 6,
119 gpiodmactl_pltp23_16 = 2 << 6,
120 gpiodmactl_pltp23_0 = 0 << 6,
121 gpiodmactl_pltp1_16 = 2 << 4,
122 gpiodmactl_pltp1_0 = 0 << 4,
123 gpiodmactl_acapenable = 1 << 4,
124 gpiodmactl_pktp_32 = 3 << 2,
125 gpiodmactl_pktp_0 = 0 << 2,
126 gpiodmactl_riscenable = 1 << 1,
127 gpiodmactl_fifoenable = 1 << 0,
129 /* RISC instructions and parameters. */
137 riscwrite123 = 9 << 28,
138 riscwrite1s23 = 11 << 28,
139 riscwrite_sol = 1 << 27,
140 riscwrite_eol = 1 << 26,
141 riscskip = 0x2 << 28,
143 riscsync = 0x8 << 28,
144 riscsync_resync = 1 << 15,
145 riscsync_vre = fifo_vre << 0,
146 riscsync_vro = fifo_vro << 0,
147 riscsync_fm1 = fifo_fm1 << 0,
148 riscsync_fm3 = fifo_fm3 << 0,
149 risclabelshift_set = 16,
150 risclabelshift_reset = 20,
169 /* Altera definitions. */
170 gpio_altera_data = 1 << 0,
171 gpio_altera_clock = 1 << 20,
172 gpio_altera_nconfig = 1 << 23,
178 Adsp_verifysystem = 1,
179 Adsp_querysupportplay,
192 Adsp_getlastprocessed,
196 Adsp_querysupportrecord,
216 Kfir_dev_inst = Kfir_200,
218 Kfir_exec = Kfir_201,
220 Kfir_adr_eready = 254,
222 Kfir_d_eready_encoding = 0,
225 Kfir_d_eready_stopdetect,
226 Kfir_d_eready_seqend,
231 VT_KFIR_LAYER_II = 1,
248 typedef struct Variant Variant;
255 typedef struct Bt848 Bt848;
257 ulong devstat; /* 000 */
258 ulong iform; /* 004 */
259 ulong tdec; /* 008 */
260 ulong ecrop; /* 00C */
261 ulong evdelaylo; /* 010 */
262 ulong evactivelo; /* 014 */
263 ulong ehdelaylo; /* 018 */
264 ulong ehactivelo; /* 01C */
265 ulong ehscalehi; /* 020 */
266 ulong ehscalelo; /* 024 */
267 ulong bright; /* 028 */
268 ulong econtrol; /* 02C */
269 ulong contrastlo; /* 030 */
270 ulong satulo; /* 034 */
271 ulong satvlo; /* 038 */
273 ulong escloop; /* 040 */
274 ulong pad0; /* 044 */
275 ulong oform; /* 048 */
276 ulong evscalehi; /* 04C */
277 ulong evscalelo; /* 050 */
278 ulong test; /* 054 */
279 ulong pad1[2]; /* 058-05C */
280 ulong adelay; /* 060 */
281 ulong bdelay; /* 064 */
283 ulong evtc; /* 06C */
284 ulong pad2[3]; /* 070-078 */
285 ulong sreset; /* 07C */
286 ulong tglb; /* 080 */
287 ulong tgctrl; /* 084 */
288 ulong pad3; /* 088 */
289 ulong ocrop; /* 08C */
290 ulong ovdelaylo; /* 090 */
291 ulong ovactivelo; /* 094 */
292 ulong ohdelaylo; /* 098 */
293 ulong ohactivelo; /* 09C */
294 ulong ohscalehi; /* 0A0 */
295 ulong ohscalelo; /* 0A4 */
296 ulong pad4; /* 0A8 */
297 ulong ocontrol; /* 0AC */
298 ulong pad5[4]; /* 0B0-0BC */
299 ulong oscloop; /* 0C0 */
300 ulong pad6[2]; /* 0C4-0C8 */
301 ulong ovscalehi; /* 0CC */
302 ulong ovscalelo; /* 0D0 */
303 ulong colorfmt; /* 0D4 */
304 ulong colorctl; /* 0D8 */
305 ulong capctl; /* 0DC */
306 ulong vbipacksize; /* 0E0 */
307 ulong vbipackdel; /* 0E4 */
308 ulong fcap; /* 0E8 */
309 ulong ovtc; /* 0EC */
310 ulong pllflo; /* 0F0 */
311 ulong pllfhi; /* 0F4 */
312 ulong pllxci; /* 0F8 */
313 ulong dvsif; /* 0FC */
314 ulong intstat; /* 100 */
315 ulong intmask; /* 104 */
316 ulong pad7; /* 108 */
317 ulong gpiodmactl; /* 10C */
319 ulong riscstrtadd; /* 114 */
320 ulong gpioouten; /* 118 */
321 ulong gpioreginp; /* 11C */
322 ulong risccount; /* 120 */
323 ulong pad8[55]; /* 124-1FC */
324 ulong gpiodata[64]; /* 200-2FC */
327 #define packetlen i2c
329 typedef struct Tuner Tuner;
332 ushort freq_vhfh; /* Start frequency */
341 typedef struct Frame Frame;
348 typedef struct Tv Tv;
353 Bt848 *bt878; /* Really only audio control registers */
358 uchar i2ccmd; /* I2C command */
359 int board; /* What board is this? */
360 ulong cfmt; /* Current color format. */
361 int channel; /* Current channel */
362 Ref fref; /* Copying images? */
363 int nframes; /* Number of frames to capture. */
364 Frame *frames; /* DMA program */
365 int lvframe; /* Last video frame DMAed */
366 uchar *amux; /* Audio multiplexer. */
367 int nablocks; /* Number of audio blocks allocated */
368 int absize; /* Audio block size */
369 int narblocks; /* Number of audio blocks received */
370 ulong *arisc; /* Audio risc bloc */
371 uchar *abuf; /* Audio data buffers */
374 /* WinTV/PVR stuff. */
377 ulong i2cstate; /* Last i2c state. */
378 int gpiostate; /* Current GPIO state */
379 ulong alterareg; /* Last used altera register */
380 ulong alteraclock; /* Used to clock the altera */
381 int asrate; /* Audio sample rate */
382 uchar aleft, aright; /* Left and right audio volume */
384 Ref aref; /* Copying audio? */
403 static Tuner tuners[] = {
404 {"Temic PAL", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
405 0x02, 0x04, 0x01, 0x8e, 623 },
406 {"Philips PAL_I", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
407 0xa0, 0x90, 0x30, 0x8e, 623 },
408 {"Philips NTSC", Freqmultiplier * 157.25, Freqmultiplier * 451.25,
409 0xA0, 0x90, 0x30, 0x8e, 732 },
410 {"Philips SECAM", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
411 0xA7, 0x97, 0x37, 0x8e, 623 },
413 0x00, 0x00, 0x00, 0x00, 0 },
414 {"Philips PAL", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
415 0xA0, 0x90, 0x30, 0x8e, 623 },
416 {"Temic NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
417 0x02, 0x04, 0x01, 0x8e, 732 },
418 {"TEMIC PAL_I", Freqmultiplier * 170.00, Freqmultiplier * 450.00,
419 0x02, 0x04, 0x01, 0x8e, 623 },
420 {"Temic 4036 FY5 NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
421 0xa0, 0x90, 0x30, 0x8e, 732 },
422 {"Alps TSBH1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
423 0x01, 0x02, 0x08, 0x8e, 732 },
424 {"Alps TSBE1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
425 0x01, 0x02, 0x08, 0x8e, 732 },
428 static int hp_tuners[] = {
467 static Cmdtab tvctlmsg[] = {
468 CMvstart, "vstart", 2,
469 CMastart, "astart", 5,
471 CMvgastart, "vgastart", 3,
473 CMchannel, "channel", 3,
474 CMcolormode, "colormode", 2,
475 CMvolume, "volume", 3,
479 static Variant variant[] = {
480 { Brooktree_vid, Brooktree_848_did, "Brooktree 848 TV tuner", },
481 { Brooktree_vid, Brooktree_878_did, "Brooktree 878 TV tuner", },
484 static char *boards[] = {
490 static ushort Adspfsample[] = {
491 0x500, 0x700, 0x400, 0x600, 0x300, 0x200, 0x000, 0x100
493 static ushort Adspstereorates[] = {
494 64, 96, 112, 128, 160, 192, 224, 256, 320, 384
497 static uchar miroamux[] = { 2, 0, 0, 0, 10, 0 };
498 static uchar hauppaugeamux[] = { 0, 1, 2, 3, 4, 0 };
499 static char *nicamstate[] = {
500 "analog", "???", "digital", "bad digital receiption"
507 static int i2cread(Tv *, uchar, uchar *);
508 static int i2cwrite(Tv *, uchar, uchar, uchar, int);
509 static void tvinterrupt(Ureg *, Tv *);
510 static void vgastart(Tv *, ulong, int);
511 static void vstart(Tv *, int, int, int, int);
512 static void astart(Tv *, char *, uint, uint, uint);
513 static void vstop(Tv *);
514 static void astop(Tv *);
515 static void colormode(Tv *, char *);
516 static void frequency(Tv *, int, int);
517 static int getbitspp(Tv *);
518 static char *getcolormode(ulong);
519 static int mspreset(Tv *);
520 static void i2cscan(Tv *);
521 static int kfirinitialize(Tv *);
522 static void msptune(Tv *);
523 static void mspvolume(Tv *, int, int, int);
524 static void gpioenable(Tv *, ulong, ulong);
525 static void gpiowrite(Tv *, ulong, ulong);
533 /* Test for a triton memory controller. */
535 if (pcimatch(nil, Intel_vid, Intel_82437_did))
536 intmask = intmask_etbf;
539 while ((pci = pcimatch(pci, 0, 0)) != nil) {
543 ushort hscale, hdelay;
546 for (i = 0; i != nelem(variant); i++)
547 if (pci->vid == variant[i].vid && pci->did == variant[i].did)
549 if (i == nelem(variant))
553 print("#V: Too many TV cards found\n");
558 tv->variant = &variant[i];
560 tv->bt848 = (Bt848 *)vmap(pci->mem[0].bar & ~0x0F, 4 * K);
561 if (tv->bt848 == nil)
562 panic("#V: Cannot allocate memory for Bt848");
569 tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda;
572 if (i2cread(tv, i2c_haupee, &v)) {
577 tv->board = Bt878_hauppauge;
578 if (!i2cwrite(tv, i2c_haupee, 0, 0, 0))
579 panic("#V: Cannot write to Hauppauge EEPROM");
580 for (i = 0; i != sizeof ee; i++)
581 if (!i2cread(tv, i2c_haupee + 1, &ee[i]))
582 panic("#V: Cannot read from Hauppauge EEPROM");
584 if (ee[9] > sizeof hp_tuners / sizeof hp_tuners[0])
585 panic("#V: Tuner out of range (max %d, this %d)",
586 sizeof hp_tuners / sizeof hp_tuners[0], ee[9]);
587 t = hp_tuners[ee[9]];
589 /* Initialize the audio channel. */
590 if ((pci878 = pcimatch(nil, Brooktree_vid, 0x878)) == nil)
591 panic("#V: Unsupported Hauppage board");
594 (Bt848 *)vmap(pci878->mem[0].bar & ~0x0F, 4 * K);
596 panic("#V: Cannot allocate memory for the Bt878");
602 bt878->gpiodmactl = 0;
603 bt878->intstat = (ulong)-1;
604 intrenable(pci878->intl, (void (*)(Ureg *, void *))tvinterrupt,
605 tv, pci878->tbdf, "tv");
607 tv->amux = hauppaugeamux;
609 else if (i2cread(tv, i2c_stbee, &v)) {
611 panic("#V: Cannot deal with STB cards\n");
613 else if (i2cread(tv, i2c_miroproee, &v)) {
614 tv->board = Bt848_miropro;
615 t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
619 tv->board = Bt848_miro;
621 t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
624 if (t >= nelem(tuners))
626 tv->tuner = &tuners[t];
628 i2cread(tv, 0xc1, &v)? 0xc0:
629 i2cread(tv, 0xc3, &v)? 0xc2:
630 i2cread(tv, 0xc5, &v)? 0xc4:
631 i2cread(tv, 0xc7, &v)? 0xc6: -1;
633 bt848->capctl = capctl_fullframe;
634 bt848->adelay = adelay_ntsc;
635 bt848->bdelay = bdelay_ntsc;
636 bt848->iform = iform_muxsel0|iform_xtauto|iform_ntsc;
637 bt848->vbipacksize = vbipacksize & 0xff;
638 bt848->vbipackdel = (vbipacksize >> 8) & 1;
642 tv->cfmt = bt848->colorfmt = colorfmt_rgb16;
644 hscale = (ntsc_rawpixels * 4096) / ntsc_sqpixels - 4096;
645 hdelay = (ntsc_clkx1delay * ntsc_hactive) / ntsc_clkx1hactive;
647 bt848->ovtc = bt848->evtc = 0;
648 bt848->ehscalehi = bt848->ohscalehi = (hscale >> 8) & 0xff;
649 bt848->ehscalelo = bt848->ohscalelo = hscale & 0xff;
650 bt848->evscalehi &= ~0x1f;
651 bt848->ovscalehi &= ~0x1f;
652 bt848->evscalehi |= vscale_interlaced | ((ntsc_vscale >> 8) & 0x1f);
653 bt848->ovscalehi |= vscale_interlaced | (ntsc_vscale >> 8) & 0x1f;
654 bt848->evscalelo = bt848->ovscalelo = ntsc_vscale & 0xff;
655 bt848->ehactivelo = bt848->ohactivelo = ntsc_hactive & 0xff;
656 bt848->ehdelaylo = bt848->ohdelaylo = hdelay & 0xff;
657 bt848->evactivelo = bt848->ovactivelo = ntsc_vactive & 0xff;
658 bt848->evdelaylo = bt848->ovdelaylo = ntsc_vdelay & 0xff;
659 bt848->ecrop = bt848->ocrop =
660 ((ntsc_hactive >> 8) & 0x03) |
661 ((hdelay >> 6) & 0x0C) |
662 ((ntsc_vactive >> 4) & 0x30) |
663 ((ntsc_vdelay >> 2) & 0xC0);
665 bt848->colorctl = colorctl_gamma;
667 bt848->gpiodmactl = gpiodmactl_pltp23_16 |
668 gpiodmactl_pltp1_16 | gpiodmactl_pktp_32;
669 bt848->gpioreginp = 0;
670 bt848->contrastlo = contrast_100percent;
672 bt848->adc = (2 << 6) | adc_crush;
673 bt848->econtrol = bt848->ocontrol = control_ldec;
674 bt848->escloop = bt848->oscloop = 0;
675 bt848->intstat = (ulong)-1;
676 bt848->intmask = intmask |
677 intstat_vsync | intstat_scerr | intstat_risci | intstat_ocerr |
678 intstat_vpress | intstat_fmtchg;
682 gpioenable(tv, ~0xfff, 0xfff);
683 gpiowrite(tv, ~0xfff, tv->amux[AudioRadio]);
686 print("#V%ld: %s (rev %d) (%s/%s) intl %d\n",
687 tv - tvs, tv->variant->name, pci->rid, boards[tv->board],
688 tv->tuner->name, pci->intl);
690 intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt,
691 tv, pci->tbdf, "tv");
698 return devattach('V', spec);
701 #define TYPE(q) ((int)((q).path & 0xff))
702 #define DEV(q) ((int)(((q).path >> 8) & 0xff))
703 #define QID(d, t) ((((d) & 0xff) << 8) | (t))
706 tv1gen(Chan *c, int i, Dir *dp)
712 mkqid(&qid, QID(DEV(c->qid), Qvdata), 0, QTFILE);
713 devdir(c, qid, "video", 0, eve, 0444, dp);
716 mkqid(&qid, QID(DEV(c->qid), Qadata), 0, QTFILE);
717 devdir(c, qid, "audio", 0, eve, 0444, dp);
720 mkqid(&qid, QID(DEV(c->qid), Qctl), 0, QTFILE);
721 devdir(c, qid, "ctl", 0, eve, 0444, dp);
724 mkqid(&qid, QID(DEV(c->qid), Qregs), 0, QTFILE);
725 devdir(c, qid, "regs", 0, eve, 0444, dp);
732 tvgen(Chan *c, char *, Dirtab *, int, int i, Dir *dp)
738 switch (TYPE(c->qid)) {
740 if (i == DEVDOTDOT) {
741 mkqid(&qid, Qdir, 0, QTDIR);
742 devdir(c, qid, "#V", 0, eve, 0555, dp);
749 mkqid(&qid, QID(i, Qsubdir), 0, QTDIR);
750 snprint(up->genbuf, sizeof(up->genbuf), "tv%d", i);
751 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
755 if (i == DEVDOTDOT) {
756 mkqid(&qid, QID(dev, Qdir), 0, QTDIR);
757 snprint(up->genbuf, sizeof(up->genbuf), "tv%d", dev);
758 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
762 return tv1gen(c, i + Qsubbase, dp);
768 return tv1gen(c, TYPE(c->qid), dp);
776 tvwalk(Chan *c, Chan *nc, char **name, int nname)
778 return devwalk(c, nc, name, nname, 0, 0, tvgen);
782 tvstat(Chan *c, uchar *db, int n)
784 return devstat(c, db, n, 0, 0, tvgen);
788 tvopen(Chan *c, int omode)
790 if (omode != OREAD &&
791 TYPE(c->qid) != Qctl && TYPE(c->qid) != Qvdata)
794 switch (TYPE(c->qid)) {
796 return devopen(c, omode, nil, 0, tvgen);
798 if (tvs[DEV(c->qid)].bt878 == nil)
803 c->mode = openmode(omode);
807 if (TYPE(c->qid) == Qadata)
824 tvread(Chan *c, void *a, long n, vlong offset)
826 static char regs[10 * K];
834 switch(TYPE(c->qid)) {
837 return devdirread(c, a, n, 0, 0, tvgen);
842 tv = &tvs[DEV(c->qid)];
843 bpf = ntsc_hactive * ntsc_vactive * getbitspp(tv) / 8;
849 if (offset + nb > bpf)
853 if (tv->frames == nil || tv->lvframe >= tv->nframes ||
854 tv->frames[tv->lvframe].fbase == nil) {
859 src = tv->frames[tv->lvframe].fbase;
863 memmove(a, src + offset, nb);
869 ulong uablock = (ulong)c->aux, bnum, tvablock;
872 tv = &tvs[DEV(c->qid)];
873 if (tv->bt878 == nil)
874 error("#V: No audio device");
876 error("#V: audio not initialized");
878 bnum = offset / tv->absize;
879 boffs = offset % tv->absize;
880 nbytes = tv->absize - boffs;
884 tvablock = tv->narblocks; /* Current tv block. */
887 uablock = tvablock - 1;
889 if (tvablock >= uablock + bnum + tv->narblocks)
890 uablock = tvablock - 1 - bnum;
892 if (uablock + bnum == tvablock) {
893 sleep(tv, audioblock, nil);
899 print("uablock %ld, bnum %ld, boffs %d, nbytes %d, tvablock %ld\n",
900 uablock, bnum, boffs, nbytes, tvablock);
901 src = tv->abuf + ((uablock + bnum) % tv->nablocks) * tv->absize;
902 print("copying from %#p (abuf %#p), nbytes %d (block %ld.%ld)\n",
903 src + boffs, tv->abuf, nbytes, uablock, bnum);
905 memmove(a, src + boffs, nbytes);
908 uablock += (boffs + nbytes) % tv->absize;
909 c->aux = (void*)uablock;
917 tv = &tvs[DEV(c->qid)];
918 snprint(str, sizeof str, "%dx%dx%d %s channel %d %s\n",
919 ntsc_hactive, ntsc_vactive, getbitspp(tv),
920 getcolormode(tv->cfmt), tv->channel, tv->ainfo);
921 return readstr(offset, a, strlen(str) + 1, str);
929 tv = &tvs[DEV(c->qid)];
932 e = regs + sizeof(regs);
934 for (i = 0; i < 0x300 >> 2; i++)
935 p = seprint(p, e, "%.3X %.8ulX\n", i << 2,
936 ((ulong *)bt848)[i]);
940 for (i = 0; i < 0x300 >> 2; i++)
941 p = seprint(p, e, "%.3X %.8ulX\n",
942 i << 2, ((ulong *)bt848)[i]);
948 if (offset >= regslen)
950 if (offset + n > regslen)
951 n = regslen - offset;
953 return readstr(offset, a, n, ®s[offset]);
963 tvwrite(Chan *c, void *a, long n, vlong)
969 tv = &tvs[DEV(c->qid)];
970 switch(TYPE(c->qid)) {
977 ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg));
980 vstart(tv, (int)strtol(cb->f[1], (char **)nil, 0),
981 ntsc_hactive, ntsc_vactive, ntsc_hactive);
985 astart(tv, cb->f[1], (uint)strtol(cb->f[2], (char **)nil, 0),
986 (uint)strtol(cb->f[3], (char **)nil, 0),
987 (uint)strtol(cb->f[4], (char **)nil, 0));
995 vgastart(tv, strtoul(cb->f[1], (char **)nil, 0),
996 (int)strtoul(cb->f[2], (char **)nil, 0));
1004 frequency(tv, (int)strtol(cb->f[1], (char **)nil, 0),
1005 (int)strtol(cb->f[2], (char **)nil, 0));
1009 colormode(tv, cb->f[1]);
1014 error("#V: No volume control");
1016 mspvolume(tv, 0, (int)strtol(cb->f[1], (char **)nil, 0),
1017 (int)strtol(cb->f[2], (char **)nil, 0));
1022 error("#V: No volume control");
1024 mspvolume(tv, 1, 0, 0);
1059 tvinterrupt(Ureg *, Tv *tv)
1061 Bt848 *bt848 = tv->bt848, *bt878 = tv->bt878;
1067 vstat = bt848->intstat;
1068 fnum = (vstat >> intstat_riscstatshift) & 0xf;
1069 vstat &= bt848->intmask;
1072 astat = bt878->intstat & bt878->intmask;
1076 if (vstat == 0 && astat == 0)
1080 print("vstat %.8luX, astat %.8luX\n", vstat, astat);
1082 bt848->intstat = vstat;
1084 bt878->intstat = astat;
1086 if ((vstat & intstat_fmtchg) == intstat_fmtchg) {
1087 iprint("int: fmtchg\n");
1088 vstat &= ~intstat_fmtchg;
1091 if ((vstat & intstat_vpress) == intstat_vpress) {
1092 // iprint("int: vpress\n");
1093 vstat &= ~intstat_vpress;
1096 if ((vstat & intstat_vsync) == intstat_vsync)
1097 vstat &= ~intstat_vsync;
1099 if ((vstat & intstat_scerr) == intstat_scerr) {
1100 iprint("int: scerr\n");
1101 bt848->gpiodmactl &=
1102 ~(gpiodmactl_riscenable|gpiodmactl_fifoenable);
1103 bt848->gpiodmactl |= gpiodmactl_fifoenable;
1104 bt848->gpiodmactl |= gpiodmactl_riscenable;
1105 vstat &= ~intstat_scerr;
1108 if ((vstat & intstat_risci) == intstat_risci) {
1110 vstat &= ~intstat_risci;
1113 if ((vstat & intstat_ocerr) == intstat_ocerr) {
1114 iprint("int: ocerr\n");
1115 vstat &= ~intstat_ocerr;
1118 if ((vstat & intstat_fbus) == intstat_fbus) {
1119 iprint("int: fbus\n");
1120 vstat &= ~intstat_fbus;
1124 iprint("int: (v) ignored interrupts %.8ulX\n", vstat);
1126 if ((astat & intstat_risci) == intstat_risci) {
1128 if ((tv->narblocks % 100) == 0)
1131 astat &= ~intstat_risci;
1134 if ((astat & intstat_fdsr) == intstat_fdsr) {
1135 iprint("int: (a) fdsr\n");
1136 bt848->gpiodmactl &=
1137 ~(gpiodmactl_acapenable |
1138 gpiodmactl_riscenable | gpiodmactl_fifoenable);
1139 astat &= ~intstat_fdsr;
1143 iprint("int: (a) ignored interrupts %.8ulX\n", astat);
1148 i2cread(Tv *tv, uchar off, uchar *v)
1150 Bt848 *bt848 = tv->bt848;
1154 bt848->intstat = intstat_i2cdone;
1155 bt848->i2c = (off << 24) | tv->i2ccmd;
1158 for (i = 0; i != 1000; i++) {
1159 if ((intstat = bt848->intstat) & intstat_i2cdone)
1165 print("i2cread: timeout\n");
1169 if ((intstat & intstat_i2crack) == 0)
1172 *v = bt848->i2c >> 8;
1177 i2cwrite(Tv *tv, uchar addr, uchar sub, uchar data, int both)
1179 Bt848 *bt848 = tv->bt848;
1183 bt848->intstat = intstat_i2cdone;
1184 d = (addr << 24) | (sub << 16) | tv->i2ccmd;
1186 d |= (data << 8) | i2c_bt848w3b;
1190 for (i = 0; i != 1000; i++) {
1191 if ((intstat = bt848->intstat) & intstat_i2cdone)
1196 if (i == i2c_timeout) {
1197 print("i2cwrite: timeout\n");
1201 if ((intstat & intstat_i2crack) == 0)
1208 riscpacked(ulong pa, int fnum, int w, int h, int stride, ulong **lastjmp)
1213 pbase = p = (ulong *)malloc((h + 6) * 2 * sizeof(ulong));
1218 *p++ = riscsync | riscsync_resync | riscsync_vre;
1221 *p++ = riscsync | riscsync_fm1;
1224 for (i = 0; i != h / 2; i++) {
1225 *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
1226 *p++ = pa + i * 2 * stride;
1229 *p++ = riscsync | riscsync_resync | riscsync_vro;
1232 *p++ = riscsync | riscsync_fm1;
1235 for (i = 0; i != h / 2; i++) {
1236 *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
1237 *p++ = pa + (i * 2 + 1) * stride;
1240 /* reset status. you really need two instructions ;-(. */
1241 *p++ = riscjmp | (0xf << risclabelshift_reset);
1243 *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
1250 riscplanar411(ulong pa, int fnum, int w, int h, ulong **lastjmp)
1252 ulong *p, *pbase, Cw, Yw, Ch;
1253 uchar *Ybase, *Cbbase, *Crbase;
1257 assert(w * bitspp / 8 <= 0x7FF);
1258 pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
1262 Ybase = (uchar *)pa;
1265 Cbbase = Ybase + Yw * h;
1266 Crbase = Cbbase + Cw * Ch;
1268 *p++ = riscsync | riscsync_resync | riscsync_vre;
1271 *p++ = riscsync | riscsync_fm3;
1274 for (i = 0; i != h / 2; i++) {
1275 *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
1276 *p++ = (Cw << 16) | Cw;
1277 *p++ = (ulong)(Ybase + i * 2 * Yw);
1278 *p++ = (ulong)(Cbbase + i * Cw); /* Do not interlace */
1279 *p++ = (ulong)(Crbase + i * Cw);
1282 *p++ = riscsync | riscsync_resync | riscsync_vro;
1285 *p++ = riscsync | riscsync_fm3;
1288 for (i = 0; i != h / 2; i++) {
1289 *p++ = riscwrite1s23 | Yw | riscwrite_sol | riscwrite_eol;
1290 *p++ = (Cw << 16) | Cw;
1291 *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
1294 /* reset status. you really need two instructions ;-(. */
1295 *p++ = riscjmp | (0xf << risclabelshift_reset);
1297 *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
1304 riscplanar422(ulong pa, int fnum, int w, int h, ulong **lastjmp)
1306 ulong *p, *pbase, Cw, Yw;
1307 uchar *Ybase, *Cbbase, *Crbase;
1311 assert(w * bpp <= 0x7FF);
1312 pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
1316 Ybase = (uchar *)pa;
1318 Cbbase = Ybase + Yw * h;
1319 Crbase = Cbbase + Cw * h;
1321 *p++ = riscsync | riscsync_resync | riscsync_vre;
1324 *p++ = riscsync | riscsync_fm3;
1327 for (i = 0; i != h / 2; i++) {
1328 *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
1329 *p++ = (Cw << 16) | Cw;
1330 *p++ = (ulong)(Ybase + i * 2 * Yw);
1331 *p++ = (ulong)(Cbbase + i * 2 * Cw);
1332 *p++ = (ulong)(Crbase + i * 2 * Cw);
1335 *p++ = riscsync | riscsync_resync | riscsync_vro;
1338 *p++ = riscsync | riscsync_fm3;
1341 for (i = 0; i != h / 2; i++) {
1342 *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
1343 *p++ = (Cw << 16) | Cw;
1344 *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
1345 *p++ = (ulong)(Cbbase + (i * 2 + 1) * Cw);
1346 *p++ = (ulong)(Crbase + (i * 2 + 1) * Cw);
1349 /* reset status. you really need two instructions ;-(. */
1350 *p++ = riscjmp | (0xf << risclabelshift_reset);
1352 *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
1359 riscaudio(ulong pa, int nblocks, int bsize)
1364 pbase = p = (ulong *)malloc((nblocks + 3) * 2 * sizeof(ulong));
1367 *p++ = riscsync|riscsync_fm1;
1370 for (i = 0; i != nblocks; i++) {
1371 *p++ = riscwrite | riscwrite_sol | riscwrite_eol | bsize | riscirq |
1372 ((i & 0xf) << risclabelshift_set) |
1373 ((~i & 0xf) << risclabelshift_reset);
1374 *p++ = pa + i * bsize;
1377 *p++ = riscsync | riscsync_vro;
1380 *p++ = PADDR(pbase);
1388 vactivate(Tv *tv, Frame *frames, int nframes)
1390 Bt848 *bt848 = tv->bt848;
1399 tv->frames = frames;
1400 tv->nframes = nframes;
1402 bt848->riscstrtadd = PADDR(tv->frames[0].fstart);
1403 bt848->capctl |= capctl_captureodd|capctl_captureeven;
1404 bt848->gpiodmactl |= gpiodmactl_fifoenable;
1405 bt848->gpiodmactl |= gpiodmactl_riscenable;
1411 vstart(Tv *tv, int nframes, int w, int h, int stride)
1416 if (nframes >= 0x10)
1419 bitspp = getbitspp(tv);
1420 bpf = w * h * bitspp / 8;
1422 /* Add one as a spare. */
1423 frames = (Frame *)malloc(nframes * sizeof(Frame));
1426 for (i = 0; i != nframes; i++)
1427 if (frames[i].fbase)
1428 free(frames[i].fbase);
1432 memset(frames, 0, nframes * sizeof(Frame));
1434 for (i = 0; i != nframes; i++) {
1435 if ((frames[i].fbase = (uchar *)malloc(bpf)) == nil)
1439 case colorfmt_YCbCr422:
1440 frames[i].fstart = riscplanar422(PADDR(frames[i].fbase), i, w, h, &frames[i].fjmp);
1442 case colorfmt_YCbCr411:
1443 frames[i].fstart = riscplanar411(PADDR(frames[i].fbase),
1444 i, w, h, &frames[i].fjmp);
1446 case colorfmt_rgb16:
1447 frames[i].fstart = riscpacked(PADDR(frames[i].fbase), i,
1448 w * bitspp / 8, h, stride * bitspp / 8,
1452 panic("vstart: Unsupport colorformat\n");
1456 for (i = 0; i != nframes; i++)
1457 *frames[i].fjmp = PADDR(i == nframes - 1? frames[0].fstart:
1458 frames[i + 1].fstart);
1460 vactivate(tv, frames, nframes);
1464 astart(Tv *tv, char *input, uint rate, uint nab, uint nasz)
1466 Bt848 *bt878 = tv->bt878;
1472 if (bt878 == nil || tv->amux == nil)
1473 error("#V: Card does not support audio");
1476 if (!strcmp(input, "tv"))
1478 else if (!strcmp(input, "radio"))
1479 selector = asel_radio;
1480 else if (!strcmp(input, "mic"))
1481 selector = asel_mic;
1482 else if (!strcmp(input, "smxc"))
1483 selector = asel_smxc;
1485 error("#V: Invalid input");
1488 error("#V: Audio block size too big (max 0xfff)");
1490 abuf = (uchar *)malloc(nab * nasz * sizeof(uchar));
1492 arisc = riscaudio(PADDR(abuf), nab, nasz);
1507 bt878->riscstrtadd = PADDR(tv->arisc);
1508 bt878->packetlen = (nab << 16) | nasz;
1509 bt878->intmask = intstat_scerr | intstat_ocerr | intstat_risci |
1510 intstat_pabort | intstat_riperr | intstat_pperr |
1511 intstat_fdsr | intstat_ftrgt | intstat_fbus;
1513 /* Assume analog, 16bpp */
1514 for (s = 0; s < 16; s++)
1515 if (rate << s > Hwbase_ad * 4 / 15)
1517 for (d = 15; d >= 4; d--)
1518 if (rate << s < Hwbase_ad * 4 / d)
1521 print("astart: sampleshift %d, decimation %d\n", s, d);
1524 bt878->gpiodmactl = gpiodmactl_fifoenable |
1525 gpiodmactl_riscenable | gpiodmactl_acapenable |
1526 gpiodmactl_daes2 | /* gpiodmactl_apwrdn | */
1527 gpiodmactl_daiomda | d << 8 | 9 << 28 | selector << 24;
1528 print("dmactl %.8ulX\n", bt878->gpiodmactl);
1535 Bt848 *bt878 = tv->bt878;
1538 if (tv->aref.ref > 0) {
1544 bt878->gpiodmactl &= ~gpiodmactl_riscenable;
1545 bt878->gpiodmactl &= ~gpiodmactl_fifoenable;
1556 vgastart(Tv *tv, ulong pa, int stride)
1560 frame = (Frame *)malloc(sizeof(Frame));
1568 frame->fstart = riscpacked(pa, 0, ntsc_hactive * getbitspp(tv) / 8,
1569 ntsc_vactive, stride * getbitspp(tv) / 8, &frame->fjmp);
1570 *frame->fjmp = PADDR(frame->fstart);
1572 vactivate(tv, frame, 1);
1578 Bt848 *bt848 = tv->bt848;
1581 if (tv->fref.ref > 0) {
1589 bt848->gpiodmactl &= ~gpiodmactl_riscenable;
1590 bt848->gpiodmactl &= ~gpiodmactl_fifoenable;
1591 bt848->capctl &= ~(capctl_captureodd|capctl_captureeven);
1593 for (i = 0; i != tv->nframes; i++)
1594 if (tv->frames[i].fbase)
1595 free(tv->frames[i].fbase);
1602 static long hrcfreq[] = { /* HRC CATV frequencies */
1603 0, 7200, 5400, 6000, 6600, 7800, 8400, 17400,
1604 18000, 18600, 19200, 19800, 20400, 21000, 12000, 12600,
1605 13200, 13800, 14400, 15000, 15600, 16200, 16800, 21600,
1606 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400,
1607 27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200,
1608 31800, 32400, 33000, 33600, 34200, 34800, 35400, 36000,
1609 36600, 37200, 37800, 38400, 39000, 39600, 40200, 40800,
1610 41400, 42000, 42600, 43200, 43800, 44400, 45000, 45600,
1611 46200, 46800, 47400, 48000, 48600, 49200, 49800, 50400,
1612 51000, 51600, 52200, 52800, 53400, 54000, 54600, 55200,
1613 55800, 56400, 57000, 57600, 58200, 58800, 59400, 60000,
1614 60600, 61200, 61800, 62400, 63000, 63600, 64200, 9000,
1615 9600, 10200, 10800, 11400, 64800, 65400, 66000, 66600,
1616 67200, 67800, 68400, 69000, 69600, 70200, 70800, 71400,
1617 72000, 72600, 73200, 73800, 74400, 75000, 75600, 76200,
1618 76800, 77400, 78000, 78600, 79200, 79800,
1622 frequency(Tv *tv, int channel, int finetune)
1624 Tuner *tuner = tv->tuner;
1629 if (channel < 0 || channel > nelem(hrcfreq))
1632 freq = (hrcfreq[channel] * Freqmultiplier) / 100;
1634 if (freq < tuner->freq_vhfh)
1636 else if (freq < tuner->freq_uhf)
1641 div = (freq + tuner->offs + finetune) & 0x7fff;
1643 if (!i2cwrite(tv, tv->i2ctuneraddr, (div >> 8) & 0x7f, div, 1))
1646 if (!i2cwrite(tv, tv->i2ctuneraddr, tuner->cfg, cfg, 1))
1649 tv->channel = channel;
1659 { "RGB16", colorfmt_rgb16, colorfmt_rgb16, },
1660 { "YCbCr422", colorfmt_YCbCr422, colorfmt_YCbCr422, },
1661 { "YCbCr411", colorfmt_YCbCr411, colorfmt_YCbCr422, },
1665 colormode(Tv *tv, char *colormode)
1667 Bt848 *bt848 = tv->bt848;
1670 for (i = 0; i != nelem(colormodes); i++)
1671 if (!strcmp(colormodes[i].cmode, colormode))
1674 if (i == nelem(colormodes))
1677 tv->cfmt = colormodes[i].realmode;
1678 bt848->colorfmt = colormodes[i].cbits;
1685 case colorfmt_rgb16:
1686 case colorfmt_YCbCr422:
1688 case colorfmt_YCbCr411:
1691 error("getbitspp: Unsupport color format\n");
1697 getcolormode(ulong cmode)
1700 case colorfmt_rgb16:
1702 case colorfmt_YCbCr411:
1704 case colorfmt_YCbCr422:
1705 return (cmode == colorfmt_YCbCr422)? "YCbCr422": "YCbCr411";
1707 error("getcolormode: Unsupport color format\n");
1713 i2c_set(Tv *tv, int scl, int sda)
1715 Bt848 *bt848 = tv->bt848;
1718 bt848->i2c = (scl << 1) | sda;
1721 microdelay(i2c_delay);
1727 Bt848 *bt848 = tv->bt848;
1729 return bt848->i2c & i2c_sda;
1750 i2c_bit(Tv *tv, int sda)
1752 i2c_set(tv, 0, sda);
1753 i2c_set(tv, 1, sda);
1754 i2c_set(tv, 0, sda);
1764 ack = i2c_getsda(tv);
1770 i2c_wr8(Tv *tv, uchar d, int wait)
1775 for (i = 0; i != 8; i++) {
1776 i2c_bit(tv, (d & 0x80)? 1: 0);
1782 ack = i2c_getack(tv);
1787 i2c_rd8(Tv *tv, int lastbyte)
1794 for (i = 0; i != 8; i++) {
1802 i2c_bit(tv, lastbyte? 1: 0);
1807 mspsend(Tv *tv, uchar *cmd, int ncmd)
1811 for (i = 0; i != 3; i++) {
1815 for (j = 0; j != ncmd; j++) {
1816 if (!i2c_wr8(tv, cmd[j], delay))
1826 print("mspsend: retrying\n");
1833 mspwrite(Tv *tv, uchar sub, ushort reg, ushort v)
1843 return mspsend(tv, b, sizeof b);
1847 mspread(Tv *tv, uchar sub, ushort reg, ushort *data)
1857 for (i = 0; i != 3; i++) {
1859 if (!i2c_wr8(tv, b[0], 2000) ||
1860 !i2c_wr8(tv, b[1] | 1, 0) ||
1861 !i2c_wr8(tv, b[2], 0) ||
1862 !i2c_wr8(tv, b[3], 0)) {
1866 print("retrying\n");
1872 if (!i2c_wr8(tv, b[0] | 1, 2000)) {
1877 *data = i2c_rd8(tv, 0) << 8;
1878 *data |= i2c_rd8(tv, 1);
1885 static uchar mspt_reset[] = { i2c_msp3400, 0, 0x80, 0 };
1886 static uchar mspt_on[] = { i2c_msp3400, 0, 0, 0 };
1892 Bt848 *bt848 = tv->bt848;
1896 gpioenable(tv, ~b, b);
1897 gpiowrite(tv, ~b, 0);
1899 gpiowrite(tv, ~b, b);
1904 mspsend(tv, mspt_reset, sizeof mspt_reset);
1907 if (!mspsend(tv, mspt_on, sizeof mspt_on)) {
1908 print("#V: Cannot find MSP34x5G on the I2C bus (on)\n");
1913 if (!mspread(tv, msp_bbp, 0x001e, &v)) {
1914 print("#V: Cannot read MSP34xG5 chip version\n");
1918 if (!mspread(tv, msp_bbp, 0x001f, &p)) {
1919 print("#V: Cannot read MSP34xG5 product code\n");
1923 print("#V: MSP34%dg ROM %.d, %d.%d\n",
1924 (uchar)(p >> 8), (uchar)p, (uchar)(v >> 8), (uchar)v);
1931 mspvolume(Tv *tv, int mute, int l, int r)
1946 b = ((r - l) * 0x7f) / d;
1949 mspwrite(tv, msp_bbp, 0, v << 8);
1950 mspwrite(tv, msp_bbp, 7, v? 0x4000: 0);
1951 mspwrite(tv, msp_bbp, 1, b << 8);
1969 return "L-AM/NICAM D/Kn";
1977 return "unknown format";
1987 mspvolume(tv, 1, 0, 0);
1988 if (!mspwrite(tv, msp_dem, 0x0030, 0x2033))
1989 error("#V: Cannot set MODUS register");
1991 if (!mspwrite(tv, msp_bbp, 0x0008, 0x0320))
1992 error("#V: Cannot set loadspeaker input");
1994 if (!mspwrite(tv, msp_dem, 0x0040, 0x0001))
1995 error("#V: Cannot set I2S clock freq");
1996 if (!mspwrite(tv, msp_bbp, 0x000d, 0x1900))
1997 error("#V: Cannot set SCART prescale");
1998 if (!mspwrite(tv, msp_bbp, 0x000e, 0x2403))
1999 error("#V: Cannot set FM/AM prescale");
2000 if (!mspwrite(tv, msp_bbp, 0x0010, 0x5a00))
2001 error("#V: Cannot set NICAM prescale");
2002 if (!mspwrite(tv, msp_dem, 0x0020, 0x0001))
2003 error("#V: Cannot start auto detect");
2005 for (d = (ushort)-1, i = 0; i != 10; i++) {
2006 if (!mspread(tv, msp_dem, 0x007e, &d))
2007 error("#V: Cannot get autodetect info MSP34xG5");
2009 if (d == 0 || d < 0x800)
2014 if (!mspread(tv, msp_dem, 0x0200, &s))
2015 error("#V: Cannot get status info MSP34xG5");
2017 mspvolume(tv, 0, tv->aleft, tv->aright);
2019 nicam = ((s >> 4) & 2) | ((s >> 9) & 1);
2020 snprint(tv->ainfo, sizeof tv->ainfo, "%s %s %s",
2021 mspaformat(d), (s & (1 << 6))? "stereo": "mono",
2030 for (i = 0; i < 0x100; i += 2) {
2032 ack = i2c_wr8(tv, i, 0);
2035 print("i2c device @%.2uX\n", i);
2038 for (i = 0xf0; i != 0xff; i++) {
2040 ack = i2c_wr8(tv, i, 0);
2043 print("i2c device may be at @%.2uX\n", i);
2048 gpioenable(Tv *tv, ulong mask, ulong data)
2050 Bt848 *bt848 = tv->bt848;
2052 bt848->gpioouten = (bt848->gpioouten & mask) | data;
2056 gpiowrite(Tv *tv, ulong mask, ulong data)
2058 Bt848 *bt848 = tv->bt848;
2060 bt848->gpiodata[0] = (bt848->gpiodata[0] & mask) | data;
2064 alteraoutput(Tv *tv)
2066 if (tv->gpiostate == Gpiooutput)
2069 gpioenable(tv, ~0xffffff, 0x56ffff);
2071 tv->gpiostate = Gpiooutput;
2077 if (tv->gpiostate == Gpioinput)
2080 gpioenable(tv, ~0xffffff, 0x570000);
2082 tv->gpiostate = Gpioinput;
2086 alterareg(Tv *tv, ulong reg)
2088 if (tv->alterareg == reg)
2091 gpiowrite(tv, ~0x56ffff, (reg & 0x54ffff) | tv->alteraclock);
2093 tv->alterareg = reg;
2097 alterawrite(Tv *tv, ulong reg, ushort data)
2102 tv->alteraclock ^= 0x20000;
2103 gpiowrite(tv, ~0x56ffff, (reg & 0x540000) | data | tv->alteraclock);
2108 alteraread(Tv *tv, int reg, ushort *data)
2110 Bt848 *bt848 = tv->bt848;
2112 if (tv->alterareg != reg) {
2117 gpioenable(tv, ~0xffffff, 0x560000);
2122 gpiowrite(tv, ~0x570000, (reg & 0x560000) | tv->alteraclock);
2124 *data = (ushort)bt848->gpiodata[0];
2129 kfirloadu(Tv *tv, uchar *u, int ulen)
2131 Bt848 *bt848 = tv->bt848;
2134 ilock(&tv->kfirlock);
2135 bt848->gpioouten &= 0xff000000;
2136 bt848->gpioouten |= gpio_altera_data |
2137 gpio_altera_clock | gpio_altera_nconfig;
2138 bt848->gpiodata[0] &= 0xff000000;
2140 bt848->gpiodata[0] |= gpio_altera_nconfig;
2143 /* Download the microcode */
2144 for (i = 0; i != ulen; i++)
2145 for (j = 0; j != 8; j++) {
2146 bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
2148 bt848->gpiodata[0] |= gpio_altera_data;
2149 bt848->gpiodata[0] |= gpio_altera_clock;
2152 bt848->gpiodata[0] &= ~gpio_altera_clock;
2156 for (i = 0; i != 30; i++) {
2157 bt848->gpiodata[0] &= ~gpio_altera_clock;
2158 bt848->gpiodata[0] |= gpio_altera_clock;
2160 bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
2161 iunlock(&tv->kfirlock);
2163 tv->gpiostate = Gpioinit;
2169 alterawrite(tv, 0, 0);
2171 alterawrite(tv, 0x40000, 0);
2173 alterawrite(tv, 0x40006, 0x80);
2175 alterawrite(tv, 8, 1);
2177 alterawrite(tv, 0x40004, 2);
2179 alterawrite(tv, 4, 3);
2184 kfirinitialize(Tv *tv)
2186 /* Initialize parameters? */
2188 tv->gpiostate = Gpioinit;
2190 tv->alteraclock = 0x20000;
2191 kfirloadu(tv, hcwAMC, sizeof hcwAMC);