19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * Driver for Bt848 TV tuner.
39a747e4fSDavid du Colombier *
49a747e4fSDavid du Colombier */
59a747e4fSDavid du Colombier #include "u.h"
69a747e4fSDavid du Colombier #include "../port/lib.h"
79a747e4fSDavid du Colombier #include "mem.h"
89a747e4fSDavid du Colombier #include "dat.h"
99a747e4fSDavid du Colombier #include "fns.h"
109a747e4fSDavid du Colombier #include "../port/error.h"
119a747e4fSDavid du Colombier #include "io.h"
123ff48bf5SDavid du Colombier #include "hcwAMC.h"
133ff48bf5SDavid du Colombier
143ff48bf5SDavid du Colombier #define max(a, b) (((a) > (b))? (a): (b))
159a747e4fSDavid du Colombier
169a747e4fSDavid du Colombier enum {
179a747e4fSDavid du Colombier Qdir = 0,
183ff48bf5SDavid du Colombier Qsubdir,
193ff48bf5SDavid du Colombier Qsubbase,
203ff48bf5SDavid du Colombier Qvdata = Qsubbase,
213ff48bf5SDavid du Colombier Qadata,
229a747e4fSDavid du Colombier Qctl,
239a747e4fSDavid du Colombier Qregs,
249a747e4fSDavid du Colombier
259a747e4fSDavid du Colombier Brooktree_vid = 0x109e,
269a747e4fSDavid du Colombier Brooktree_848_did = 0x0350,
273ff48bf5SDavid du Colombier Brooktree_878_did = 0x036E,
289a747e4fSDavid du Colombier Intel_vid = 0x8086,
299a747e4fSDavid du Colombier Intel_82437_did = 0x122d,
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier K = 1024,
329a747e4fSDavid du Colombier M = K * K,
339a747e4fSDavid du Colombier
343ff48bf5SDavid du Colombier Ntvs = 4,
353ff48bf5SDavid du Colombier
369a747e4fSDavid du Colombier Numring = 16,
379a747e4fSDavid du Colombier
389a747e4fSDavid du Colombier ntsc_rawpixels = 910,
3941dd6b47SDavid du Colombier ntsc_sqpixels = 780, /* Including blanking & inactive */
409a747e4fSDavid du Colombier ntsc_hactive = 640,
419a747e4fSDavid du Colombier ntsc_vactive = 480,
4241dd6b47SDavid du Colombier ntsc_clkx1delay = 135, /* Clock ticks. */
439a747e4fSDavid du Colombier ntsc_clkx1hactive = 754,
4441dd6b47SDavid du Colombier ntsc_vdelay = 26, /* # of scan lines. */
459a747e4fSDavid du Colombier ntsc_vscale = 0,
469a747e4fSDavid du Colombier
473ff48bf5SDavid du Colombier i2c_nostop = 1 << 5,
483ff48bf5SDavid du Colombier i2c_nos1b = 1 << 4,
499a747e4fSDavid du Colombier i2c_timing = 7 << 4,
509a747e4fSDavid du Colombier i2c_bt848w3b = 1 << 2,
519a747e4fSDavid du Colombier i2c_bt848scl = 1 << 1,
529a747e4fSDavid du Colombier i2c_bt848sda = 1 << 0,
533ff48bf5SDavid du Colombier i2c_scl = i2c_bt848scl,
543ff48bf5SDavid du Colombier i2c_sda = i2c_bt848sda,
559a747e4fSDavid du Colombier
5641dd6b47SDavid du Colombier i2c_miroproee = 0x80, /* MIRO PRO EEPROM */
573ff48bf5SDavid du Colombier i2c_tea6300 = 0x80,
589a747e4fSDavid du Colombier i2c_tda8425 = 0x82,
599a747e4fSDavid du Colombier i2c_tda9840 = 0x84,
609a747e4fSDavid du Colombier i2c_tda9850 = 0xb6,
6141dd6b47SDavid du Colombier i2c_haupee = 0xa0, /* Hauppage EEPROM */
6241dd6b47SDavid du Colombier i2c_stbee = 0xae, /* STB EEPROM */
633ff48bf5SDavid du Colombier i2c_msp3400 = 0x80,
643ff48bf5SDavid du Colombier
653ff48bf5SDavid du Colombier i2c_timeout = 1000,
663ff48bf5SDavid du Colombier i2c_delay = 10,
679a747e4fSDavid du Colombier
689a747e4fSDavid du Colombier Bt848_miropro = 0,
699a747e4fSDavid du Colombier Bt848_miro,
703ff48bf5SDavid du Colombier Bt878_hauppauge,
719a747e4fSDavid du Colombier
7241dd6b47SDavid du Colombier /* Bit fields. */
7341dd6b47SDavid du Colombier iform_muxsel1 = 3 << 5, /* 004 */
749a747e4fSDavid du Colombier iform_muxsel0 = 2 << 5,
759a747e4fSDavid du Colombier iform_xtselmask = 3 << 3,
769a747e4fSDavid du Colombier iform_xtauto = 3 << 3,
779a747e4fSDavid du Colombier iform_formatmask = 7 << 0,
789a747e4fSDavid du Colombier iform_ntsc = 1 << 0,
799a747e4fSDavid du Colombier
8041dd6b47SDavid du Colombier control_ldec = 1 << 5, /* 02C */
8141dd6b47SDavid du Colombier contrast_100percent = 0xd8, /* 030 */
829a747e4fSDavid du Colombier
8341dd6b47SDavid du Colombier vscale_interlaced = 1 << 5, /* 04C */
849a747e4fSDavid du Colombier
8541dd6b47SDavid du Colombier adelay_ntsc = 104, /* 060 */
8641dd6b47SDavid du Colombier bdelay_ntsc = 93, /* 064 */
8741dd6b47SDavid du Colombier adc_crush = 1 << 0, /* 068 */
889a747e4fSDavid du Colombier
8941dd6b47SDavid du Colombier colorfmt_rgb16 = 2 << 4 | 2 << 0, /* 0D4 */
9041dd6b47SDavid du Colombier colorfmt_YCbCr422 = 8 << 4 | 8 << 0,
9141dd6b47SDavid du Colombier colorfmt_YCbCr411 = 9 << 4 | 9 << 0,
9241dd6b47SDavid du Colombier colorctl_gamma = 1 << 4, /* 0D8 */
9341dd6b47SDavid du Colombier capctl_fullframe = 1 << 4, /* 0DC */
949a747e4fSDavid du Colombier capctl_captureodd = 1 << 1,
959a747e4fSDavid du Colombier capctl_captureeven = 1 << 0,
9641dd6b47SDavid du Colombier vbipacksize = 0x190, /* 0E0 */
979a747e4fSDavid du Colombier
9841dd6b47SDavid du Colombier intstat_riscstatshift = 28, /* 100 */
999a747e4fSDavid du Colombier intstat_i2crack = 1 << 25,
1009a747e4fSDavid du Colombier intstat_scerr = 1 << 19,
1019a747e4fSDavid du Colombier intstat_ocerr = 1 << 18,
1023ff48bf5SDavid du Colombier intstat_pabort = 1 << 17,
1033ff48bf5SDavid du Colombier intstat_riperr = 1 << 16,
1043ff48bf5SDavid du Colombier intstat_pperr = 1 << 15,
1053ff48bf5SDavid du Colombier intstat_fdsr = 1 << 14,
1063ff48bf5SDavid du Colombier intstat_ftrgt = 1 << 13,
1079a747e4fSDavid du Colombier intstat_fbus = 1 << 12,
1089a747e4fSDavid du Colombier intstat_risci = 1 << 11,
1099a747e4fSDavid du Colombier intstat_i2cdone = 1 << 8,
1109a747e4fSDavid du Colombier intstat_vpress = 1 << 5,
1119a747e4fSDavid du Colombier intstat_hlock = 1 << 4,
1129a747e4fSDavid du Colombier intstat_vsync = 1 << 1,
1139a747e4fSDavid du Colombier intstat_fmtchg = 1 << 0,
11441dd6b47SDavid du Colombier intmask_etbf = 1 << 23, /* 104 */
1159a747e4fSDavid du Colombier
11641dd6b47SDavid du Colombier gpiodmactl_apwrdn = 1 << 26, /* 10C */
1173ff48bf5SDavid du Colombier gpiodmactl_daes2 = 1 << 13,
1183ff48bf5SDavid du Colombier gpiodmactl_daiomda = 1 << 6,
1193ff48bf5SDavid du Colombier gpiodmactl_pltp23_16 = 2 << 6,
1209a747e4fSDavid du Colombier gpiodmactl_pltp23_0 = 0 << 6,
1219a747e4fSDavid du Colombier gpiodmactl_pltp1_16 = 2 << 4,
1229a747e4fSDavid du Colombier gpiodmactl_pltp1_0 = 0 << 4,
1233ff48bf5SDavid du Colombier gpiodmactl_acapenable = 1 << 4,
1249a747e4fSDavid du Colombier gpiodmactl_pktp_32 = 3 << 2,
1259a747e4fSDavid du Colombier gpiodmactl_pktp_0 = 0 << 2,
1269a747e4fSDavid du Colombier gpiodmactl_riscenable = 1 << 1,
1279a747e4fSDavid du Colombier gpiodmactl_fifoenable = 1 << 0,
1289a747e4fSDavid du Colombier
12941dd6b47SDavid du Colombier /* RISC instructions and parameters. */
1309a747e4fSDavid du Colombier fifo_vre = 0x4,
1313ff48bf5SDavid du Colombier fifo_vro = 0xc,
1329a747e4fSDavid du Colombier fifo_fm1 = 0x6,
1333ff48bf5SDavid du Colombier fifo_fm3 = 0xe,
1349a747e4fSDavid du Colombier
1359a747e4fSDavid du Colombier riscirq = 1 << 24,
1363ff48bf5SDavid du Colombier riscwrite = 1 << 28,
1373ff48bf5SDavid du Colombier riscwrite123 = 9 << 28,
1383ff48bf5SDavid du Colombier riscwrite1s23 = 11 << 28,
1399a747e4fSDavid du Colombier riscwrite_sol = 1 << 27,
1409a747e4fSDavid du Colombier riscwrite_eol = 1 << 26,
1419a747e4fSDavid du Colombier riscskip = 0x2 << 28,
1429a747e4fSDavid du Colombier riscjmp = 0x7 << 28,
1439a747e4fSDavid du Colombier riscsync = 0x8 << 28,
1449a747e4fSDavid du Colombier riscsync_resync = 1 << 15,
1459a747e4fSDavid du Colombier riscsync_vre = fifo_vre << 0,
1469a747e4fSDavid du Colombier riscsync_vro = fifo_vro << 0,
1479a747e4fSDavid du Colombier riscsync_fm1 = fifo_fm1 << 0,
1483ff48bf5SDavid du Colombier riscsync_fm3 = fifo_fm3 << 0,
1499a747e4fSDavid du Colombier risclabelshift_set = 16,
1509a747e4fSDavid du Colombier risclabelshift_reset = 20,
1513ff48bf5SDavid du Colombier
1523ff48bf5SDavid du Colombier AudioTuner = 0,
1533ff48bf5SDavid du Colombier AudioRadio,
1543ff48bf5SDavid du Colombier AudioExtern,
1553ff48bf5SDavid du Colombier AudioIntern,
1563ff48bf5SDavid du Colombier AudioOff,
1573ff48bf5SDavid du Colombier AudioOn,
1583ff48bf5SDavid du Colombier
1593ff48bf5SDavid du Colombier asel_tv = 0,
1603ff48bf5SDavid du Colombier asel_radio,
1613ff48bf5SDavid du Colombier asel_mic,
1623ff48bf5SDavid du Colombier asel_smxc,
1633ff48bf5SDavid du Colombier
1643ff48bf5SDavid du Colombier Hwbase_ad = 448000,
1653ff48bf5SDavid du Colombier
1663ff48bf5SDavid du Colombier msp_dem = 0x10,
1673ff48bf5SDavid du Colombier msp_bbp = 0x12,
1683ff48bf5SDavid du Colombier
16941dd6b47SDavid du Colombier /* Altera definitions. */
1703ff48bf5SDavid du Colombier gpio_altera_data = 1 << 0,
1713ff48bf5SDavid du Colombier gpio_altera_clock = 1 << 20,
1723ff48bf5SDavid du Colombier gpio_altera_nconfig = 1 << 23,
1733ff48bf5SDavid du Colombier
1743ff48bf5SDavid du Colombier Ial = 0x140001,
1753ff48bf5SDavid du Colombier Idma = 0x100002,
1763ff48bf5SDavid du Colombier
1773ff48bf5SDavid du Colombier Adsp = 0x7fd8,
1783ff48bf5SDavid du Colombier Adsp_verifysystem = 1,
1793ff48bf5SDavid du Colombier Adsp_querysupportplay,
1803ff48bf5SDavid du Colombier Adsp_setstyle,
1813ff48bf5SDavid du Colombier Adsp_setsrate,
1823ff48bf5SDavid du Colombier Adsp_setchannels,
1833ff48bf5SDavid du Colombier Adsp_setresolution,
1843ff48bf5SDavid du Colombier Adsp_setcrcoptions,
1853ff48bf5SDavid du Colombier Adsp_bufenqfor,
1863ff48bf5SDavid du Colombier Adsp_logbuffer,
1873ff48bf5SDavid du Colombier Adsp_startplay,
1883ff48bf5SDavid du Colombier Adsp_stopplay,
1893ff48bf5SDavid du Colombier Adsp_autostop,
1903ff48bf5SDavid du Colombier Adsp_startrecord,
1913ff48bf5SDavid du Colombier Adsp_stoprecord,
1923ff48bf5SDavid du Colombier Adsp_getlastprocessed,
1933ff48bf5SDavid du Colombier Adsp_pause,
1943ff48bf5SDavid du Colombier Adsp_resume,
1953ff48bf5SDavid du Colombier Adsp_setvolume,
1963ff48bf5SDavid du Colombier Adsp_querysupportrecord,
1973ff48bf5SDavid du Colombier Adsp_generalbufenq,
1983ff48bf5SDavid du Colombier Adsp_setdownmixtype,
1993ff48bf5SDavid du Colombier Adsp_setigain,
2003ff48bf5SDavid du Colombier Adsp_setlineout,
2013ff48bf5SDavid du Colombier Adsp_setlangmixtype,
2023ff48bf5SDavid du Colombier
2033ff48bf5SDavid du Colombier Kfir_gc = 0,
2043ff48bf5SDavid du Colombier Kfir_dsp_riscmc,
2053ff48bf5SDavid du Colombier Kfir_dsp_risccram,
2063ff48bf5SDavid du Colombier Kfir_dsp_unitmc,
2073ff48bf5SDavid du Colombier Kfir_bsm_mc,
2083ff48bf5SDavid du Colombier Kfir_mux_mc,
2093ff48bf5SDavid du Colombier
2103ff48bf5SDavid du Colombier Kfir_devid_gc = 7,
2113ff48bf5SDavid du Colombier Kfir_devid_dsp = 4,
2123ff48bf5SDavid du Colombier Kfir_devid_bsm = 5,
2133ff48bf5SDavid du Colombier Kfir_devid_mux = 8,
2143ff48bf5SDavid du Colombier
2153ff48bf5SDavid du Colombier Kfir_200 = 200,
2163ff48bf5SDavid du Colombier Kfir_dev_inst = Kfir_200,
2173ff48bf5SDavid du Colombier Kfir_201 = 201,
2183ff48bf5SDavid du Colombier Kfir_exec = Kfir_201,
2193ff48bf5SDavid du Colombier Kfir_202 = 202,
2203ff48bf5SDavid du Colombier Kfir_adr_eready = 254,
2213ff48bf5SDavid du Colombier
2223ff48bf5SDavid du Colombier Kfir_d_eready_encoding = 0,
2233ff48bf5SDavid du Colombier Kfir_d_eready_ready,
2243ff48bf5SDavid du Colombier Kfir_d_eready_test,
2253ff48bf5SDavid du Colombier Kfir_d_eready_stopdetect,
2263ff48bf5SDavid du Colombier Kfir_d_eready_seqend,
2273ff48bf5SDavid du Colombier
2283ff48bf5SDavid du Colombier VT_KFIR_OFF = 0,
2293ff48bf5SDavid du Colombier VT_KFIR_ON,
2303ff48bf5SDavid du Colombier
2313ff48bf5SDavid du Colombier VT_KFIR_LAYER_II = 1,
2323ff48bf5SDavid du Colombier VT_KFIR_STEREO = 1,
2333ff48bf5SDavid du Colombier
2343ff48bf5SDavid du Colombier Gpioinit = 0,
2353ff48bf5SDavid du Colombier Gpiooutput,
2363ff48bf5SDavid du Colombier Gpioinput,
2373ff48bf5SDavid du Colombier
2383ff48bf5SDavid du Colombier Srate_5512 = 0,
2393ff48bf5SDavid du Colombier Srate_11025 = 2,
2403ff48bf5SDavid du Colombier Srate_16000 = 3,
2413ff48bf5SDavid du Colombier Srate_22050 = 4,
2423ff48bf5SDavid du Colombier Srate_32000 = 5,
2433ff48bf5SDavid du Colombier Srate_44100 = 6,
2443ff48bf5SDavid du Colombier Srate_48000 = 7,
2453ff48bf5SDavid du Colombier
2469a747e4fSDavid du Colombier };
2479a747e4fSDavid du Colombier
24859c21d95SDavid du Colombier typedef struct Variant Variant;
24959c21d95SDavid du Colombier struct Variant {
2509a747e4fSDavid du Colombier ushort vid;
2519a747e4fSDavid du Colombier ushort did;
2529a747e4fSDavid du Colombier char *name;
25359c21d95SDavid du Colombier };
2549a747e4fSDavid du Colombier
25559c21d95SDavid du Colombier typedef struct Bt848 Bt848;
25659c21d95SDavid du Colombier struct Bt848 {
25741dd6b47SDavid du Colombier ulong devstat; /* 000 */
25841dd6b47SDavid du Colombier ulong iform; /* 004 */
25941dd6b47SDavid du Colombier ulong tdec; /* 008 */
26041dd6b47SDavid du Colombier ulong ecrop; /* 00C */
26141dd6b47SDavid du Colombier ulong evdelaylo; /* 010 */
26241dd6b47SDavid du Colombier ulong evactivelo; /* 014 */
26341dd6b47SDavid du Colombier ulong ehdelaylo; /* 018 */
26441dd6b47SDavid du Colombier ulong ehactivelo; /* 01C */
26541dd6b47SDavid du Colombier ulong ehscalehi; /* 020 */
26641dd6b47SDavid du Colombier ulong ehscalelo; /* 024 */
26741dd6b47SDavid du Colombier ulong bright; /* 028 */
26841dd6b47SDavid du Colombier ulong econtrol; /* 02C */
26941dd6b47SDavid du Colombier ulong contrastlo; /* 030 */
27041dd6b47SDavid du Colombier ulong satulo; /* 034 */
27141dd6b47SDavid du Colombier ulong satvlo; /* 038 */
27241dd6b47SDavid du Colombier ulong hue; /* 03C */
27341dd6b47SDavid du Colombier ulong escloop; /* 040 */
27441dd6b47SDavid du Colombier ulong pad0; /* 044 */
27541dd6b47SDavid du Colombier ulong oform; /* 048 */
27641dd6b47SDavid du Colombier ulong evscalehi; /* 04C */
27741dd6b47SDavid du Colombier ulong evscalelo; /* 050 */
27841dd6b47SDavid du Colombier ulong test; /* 054 */
27941dd6b47SDavid du Colombier ulong pad1[2]; /* 058-05C */
28041dd6b47SDavid du Colombier ulong adelay; /* 060 */
28141dd6b47SDavid du Colombier ulong bdelay; /* 064 */
28241dd6b47SDavid du Colombier ulong adc; /* 068 */
28341dd6b47SDavid du Colombier ulong evtc; /* 06C */
28441dd6b47SDavid du Colombier ulong pad2[3]; /* 070-078 */
28541dd6b47SDavid du Colombier ulong sreset; /* 07C */
28641dd6b47SDavid du Colombier ulong tglb; /* 080 */
28741dd6b47SDavid du Colombier ulong tgctrl; /* 084 */
28841dd6b47SDavid du Colombier ulong pad3; /* 088 */
28941dd6b47SDavid du Colombier ulong ocrop; /* 08C */
29041dd6b47SDavid du Colombier ulong ovdelaylo; /* 090 */
29141dd6b47SDavid du Colombier ulong ovactivelo; /* 094 */
29241dd6b47SDavid du Colombier ulong ohdelaylo; /* 098 */
29341dd6b47SDavid du Colombier ulong ohactivelo; /* 09C */
29441dd6b47SDavid du Colombier ulong ohscalehi; /* 0A0 */
29541dd6b47SDavid du Colombier ulong ohscalelo; /* 0A4 */
29641dd6b47SDavid du Colombier ulong pad4; /* 0A8 */
29741dd6b47SDavid du Colombier ulong ocontrol; /* 0AC */
29841dd6b47SDavid du Colombier ulong pad5[4]; /* 0B0-0BC */
29941dd6b47SDavid du Colombier ulong oscloop; /* 0C0 */
30041dd6b47SDavid du Colombier ulong pad6[2]; /* 0C4-0C8 */
30141dd6b47SDavid du Colombier ulong ovscalehi; /* 0CC */
30241dd6b47SDavid du Colombier ulong ovscalelo; /* 0D0 */
30341dd6b47SDavid du Colombier ulong colorfmt; /* 0D4 */
30441dd6b47SDavid du Colombier ulong colorctl; /* 0D8 */
30541dd6b47SDavid du Colombier ulong capctl; /* 0DC */
30641dd6b47SDavid du Colombier ulong vbipacksize; /* 0E0 */
30741dd6b47SDavid du Colombier ulong vbipackdel; /* 0E4 */
30841dd6b47SDavid du Colombier ulong fcap; /* 0E8 */
30941dd6b47SDavid du Colombier ulong ovtc; /* 0EC */
31041dd6b47SDavid du Colombier ulong pllflo; /* 0F0 */
31141dd6b47SDavid du Colombier ulong pllfhi; /* 0F4 */
31241dd6b47SDavid du Colombier ulong pllxci; /* 0F8 */
31341dd6b47SDavid du Colombier ulong dvsif; /* 0FC */
31441dd6b47SDavid du Colombier ulong intstat; /* 100 */
31541dd6b47SDavid du Colombier ulong intmask; /* 104 */
31641dd6b47SDavid du Colombier ulong pad7; /* 108 */
31741dd6b47SDavid du Colombier ulong gpiodmactl; /* 10C */
31841dd6b47SDavid du Colombier ulong i2c; /* 110 */
31941dd6b47SDavid du Colombier ulong riscstrtadd; /* 114 */
32041dd6b47SDavid du Colombier ulong gpioouten; /* 118 */
32141dd6b47SDavid du Colombier ulong gpioreginp; /* 11C */
32241dd6b47SDavid du Colombier ulong risccount; /* 120 */
32341dd6b47SDavid du Colombier ulong pad8[55]; /* 124-1FC */
32441dd6b47SDavid du Colombier ulong gpiodata[64]; /* 200-2FC */
32559c21d95SDavid du Colombier };
3269a747e4fSDavid du Colombier
3273ff48bf5SDavid du Colombier #define packetlen i2c
3283ff48bf5SDavid du Colombier
32959c21d95SDavid du Colombier typedef struct Tuner Tuner;
33059c21d95SDavid du Colombier struct Tuner {
3319a747e4fSDavid du Colombier char *name;
33241dd6b47SDavid du Colombier ushort freq_vhfh; /* Start frequency */
3339a747e4fSDavid du Colombier ushort freq_uhf;
3349a747e4fSDavid du Colombier uchar VHF_L;
3359a747e4fSDavid du Colombier uchar VHF_H;
3369a747e4fSDavid du Colombier uchar UHF;
3379a747e4fSDavid du Colombier uchar cfg;
3389a747e4fSDavid du Colombier ushort offs;
33959c21d95SDavid du Colombier };
3409a747e4fSDavid du Colombier
34159c21d95SDavid du Colombier typedef struct Frame Frame;
34259c21d95SDavid du Colombier struct Frame {
3439a747e4fSDavid du Colombier ulong *fstart;
3449a747e4fSDavid du Colombier ulong *fjmp;
3459a747e4fSDavid du Colombier uchar *fbase;
34659c21d95SDavid du Colombier };
3479a747e4fSDavid du Colombier
34859c21d95SDavid du Colombier typedef struct Tv Tv;
34959c21d95SDavid du Colombier struct Tv {
3509a747e4fSDavid du Colombier Lock;
3513ff48bf5SDavid du Colombier Rendez;
3529a747e4fSDavid du Colombier Bt848 *bt848;
35341dd6b47SDavid du Colombier Bt848 *bt878; /* Really only audio control registers */
3549a747e4fSDavid du Colombier Variant *variant;
3559a747e4fSDavid du Colombier Tuner *tuner;
3569a747e4fSDavid du Colombier Pcidev *pci;
3579a747e4fSDavid du Colombier uchar i2ctuneraddr;
35841dd6b47SDavid du Colombier uchar i2ccmd; /* I2C command */
35941dd6b47SDavid du Colombier int board; /* What board is this? */
36041dd6b47SDavid du Colombier ulong cfmt; /* Current color format. */
36141dd6b47SDavid du Colombier int channel; /* Current channel */
36241dd6b47SDavid du Colombier Ref fref; /* Copying images? */
36341dd6b47SDavid du Colombier int nframes; /* Number of frames to capture. */
36441dd6b47SDavid du Colombier Frame *frames; /* DMA program */
36541dd6b47SDavid du Colombier int lvframe; /* Last video frame DMAed */
36641dd6b47SDavid du Colombier uchar *amux; /* Audio multiplexer. */
36741dd6b47SDavid du Colombier int nablocks; /* Number of audio blocks allocated */
36841dd6b47SDavid du Colombier int absize; /* Audio block size */
36941dd6b47SDavid du Colombier int narblocks; /* Number of audio blocks received */
37041dd6b47SDavid du Colombier ulong *arisc; /* Audio risc bloc */
37141dd6b47SDavid du Colombier uchar *abuf; /* Audio data buffers */
3723ff48bf5SDavid du Colombier char ainfo[128];
3733ff48bf5SDavid du Colombier
37441dd6b47SDavid du Colombier /* WinTV/PVR stuff. */
3753ff48bf5SDavid du Colombier int msp;
3763ff48bf5SDavid du Colombier Lock kfirlock;
37741dd6b47SDavid du Colombier ulong i2cstate; /* Last i2c state. */
37841dd6b47SDavid du Colombier int gpiostate; /* Current GPIO state */
37941dd6b47SDavid du Colombier ulong alterareg; /* Last used altera register */
38041dd6b47SDavid du Colombier ulong alteraclock; /* Used to clock the altera */
38141dd6b47SDavid du Colombier int asrate; /* Audio sample rate */
38241dd6b47SDavid du Colombier uchar aleft, aright; /* Left and right audio volume */
3833ff48bf5SDavid du Colombier ulong kfirclock;
38441dd6b47SDavid du Colombier Ref aref; /* Copying audio? */
38559c21d95SDavid du Colombier };
3869a747e4fSDavid du Colombier
3879a747e4fSDavid du Colombier enum {
3889a747e4fSDavid du Colombier TemicPAL = 0,
3899a747e4fSDavid du Colombier PhilipsPAL,
3909a747e4fSDavid du Colombier PhilipsNTSC,
3919a747e4fSDavid du Colombier PhilipsSECAM,
3929a747e4fSDavid du Colombier Notuner,
3939a747e4fSDavid du Colombier PhilipsPALI,
3949a747e4fSDavid du Colombier TemicNTSC,
3959a747e4fSDavid du Colombier TemicPALI,
3969a747e4fSDavid du Colombier Temic4036,
3979a747e4fSDavid du Colombier AlpsTSBH1,
3989a747e4fSDavid du Colombier AlpsTSBE1,
3999a747e4fSDavid du Colombier
4009a747e4fSDavid du Colombier Freqmultiplier = 16,
4019a747e4fSDavid du Colombier };
4029a747e4fSDavid du Colombier
4039a747e4fSDavid du Colombier static Tuner tuners[] = {
4049a747e4fSDavid du Colombier {"Temic PAL", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
4059a747e4fSDavid du Colombier 0x02, 0x04, 0x01, 0x8e, 623 },
4069a747e4fSDavid du Colombier {"Philips PAL_I", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
4079a747e4fSDavid du Colombier 0xa0, 0x90, 0x30, 0x8e, 623 },
4089a747e4fSDavid du Colombier {"Philips NTSC", Freqmultiplier * 157.25, Freqmultiplier * 451.25,
4099a747e4fSDavid du Colombier 0xA0, 0x90, 0x30, 0x8e, 732 },
4109a747e4fSDavid du Colombier {"Philips SECAM", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
4119a747e4fSDavid du Colombier 0xA7, 0x97, 0x37, 0x8e, 623 },
4129a747e4fSDavid du Colombier {"NoTuner", 0, 0,
4139a747e4fSDavid du Colombier 0x00, 0x00, 0x00, 0x00, 0 },
4149a747e4fSDavid du Colombier {"Philips PAL", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
4159a747e4fSDavid du Colombier 0xA0, 0x90, 0x30, 0x8e, 623 },
4169a747e4fSDavid du Colombier {"Temic NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
4179a747e4fSDavid du Colombier 0x02, 0x04, 0x01, 0x8e, 732 },
4189a747e4fSDavid du Colombier {"TEMIC PAL_I", Freqmultiplier * 170.00, Freqmultiplier * 450.00,
4199a747e4fSDavid du Colombier 0x02, 0x04, 0x01, 0x8e, 623 },
4209a747e4fSDavid du Colombier {"Temic 4036 FY5 NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
4219a747e4fSDavid du Colombier 0xa0, 0x90, 0x30, 0x8e, 732 },
4229a747e4fSDavid du Colombier {"Alps TSBH1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
4239a747e4fSDavid du Colombier 0x01, 0x02, 0x08, 0x8e, 732 },
4249a747e4fSDavid du Colombier {"Alps TSBE1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
4259a747e4fSDavid du Colombier 0x01, 0x02, 0x08, 0x8e, 732 },
4269a747e4fSDavid du Colombier };
4279a747e4fSDavid du Colombier
4283ff48bf5SDavid du Colombier static int hp_tuners[] = {
4293ff48bf5SDavid du Colombier Notuner,
4303ff48bf5SDavid du Colombier Notuner,
4313ff48bf5SDavid du Colombier Notuner,
4323ff48bf5SDavid du Colombier Notuner,
4333ff48bf5SDavid du Colombier Notuner,
4343ff48bf5SDavid du Colombier PhilipsNTSC,
4353ff48bf5SDavid du Colombier Notuner,
4363ff48bf5SDavid du Colombier Notuner,
4373ff48bf5SDavid du Colombier PhilipsPAL,
4383ff48bf5SDavid du Colombier PhilipsSECAM,
4393ff48bf5SDavid du Colombier PhilipsNTSC,
4403ff48bf5SDavid du Colombier PhilipsPALI,
4413ff48bf5SDavid du Colombier Notuner,
4423ff48bf5SDavid du Colombier Notuner,
4433ff48bf5SDavid du Colombier TemicPAL,
4443ff48bf5SDavid du Colombier TemicPALI,
4453ff48bf5SDavid du Colombier Notuner,
4463ff48bf5SDavid du Colombier PhilipsSECAM,
4473ff48bf5SDavid du Colombier PhilipsNTSC,
4483ff48bf5SDavid du Colombier PhilipsPALI,
4493ff48bf5SDavid du Colombier Notuner,
4503ff48bf5SDavid du Colombier PhilipsPAL,
4513ff48bf5SDavid du Colombier Notuner,
4523ff48bf5SDavid du Colombier PhilipsNTSC,
4533ff48bf5SDavid du Colombier };
4543ff48bf5SDavid du Colombier
4559a747e4fSDavid du Colombier enum {
4569a747e4fSDavid du Colombier CMvstart,
4573ff48bf5SDavid du Colombier CMastart,
4583ff48bf5SDavid du Colombier CMastop,
4599a747e4fSDavid du Colombier CMvgastart,
4609a747e4fSDavid du Colombier CMvstop,
4619a747e4fSDavid du Colombier CMchannel,
4623ff48bf5SDavid du Colombier CMcolormode,
4633ff48bf5SDavid du Colombier CMvolume,
4643ff48bf5SDavid du Colombier CMmute,
4659a747e4fSDavid du Colombier };
4669a747e4fSDavid du Colombier
4679a747e4fSDavid du Colombier static Cmdtab tvctlmsg[] = {
4689a747e4fSDavid du Colombier CMvstart, "vstart", 2,
4693ff48bf5SDavid du Colombier CMastart, "astart", 5,
4703ff48bf5SDavid du Colombier CMastop, "astop", 1,
4719a747e4fSDavid du Colombier CMvgastart, "vgastart", 3,
4729a747e4fSDavid du Colombier CMvstop, "vstop", 1,
4739a747e4fSDavid du Colombier CMchannel, "channel", 3,
4743ff48bf5SDavid du Colombier CMcolormode, "colormode", 2,
4753ff48bf5SDavid du Colombier CMvolume, "volume", 3,
4763ff48bf5SDavid du Colombier CMmute, "mute", 1,
4779a747e4fSDavid du Colombier };
4789a747e4fSDavid du Colombier
4799a747e4fSDavid du Colombier static Variant variant[] = {
4809a747e4fSDavid du Colombier { Brooktree_vid, Brooktree_848_did, "Brooktree 848 TV tuner", },
4813ff48bf5SDavid du Colombier { Brooktree_vid, Brooktree_878_did, "Brooktree 878 TV tuner", },
4829a747e4fSDavid du Colombier };
4839a747e4fSDavid du Colombier
4849a747e4fSDavid du Colombier static char *boards[] = {
4859a747e4fSDavid du Colombier "MIRO PRO",
4869a747e4fSDavid du Colombier "MIRO",
4873ff48bf5SDavid du Colombier "Hauppauge Bt878",
4889a747e4fSDavid du Colombier };
4899a747e4fSDavid du Colombier
4903ff48bf5SDavid du Colombier static ushort Adspfsample[] = {
4913ff48bf5SDavid du Colombier 0x500, 0x700, 0x400, 0x600, 0x300, 0x200, 0x000, 0x100
4923ff48bf5SDavid du Colombier };
4933ff48bf5SDavid du Colombier static ushort Adspstereorates[] = {
4943ff48bf5SDavid du Colombier 64, 96, 112, 128, 160, 192, 224, 256, 320, 384
4953ff48bf5SDavid du Colombier };
4963ff48bf5SDavid du Colombier
4973ff48bf5SDavid du Colombier static uchar miroamux[] = { 2, 0, 0, 0, 10, 0 };
4983ff48bf5SDavid du Colombier static uchar hauppaugeamux[] = { 0, 1, 2, 3, 4, 0 };
4993ff48bf5SDavid du Colombier static char *nicamstate[] = {
5003ff48bf5SDavid du Colombier "analog", "???", "digital", "bad digital receiption"
5013ff48bf5SDavid du Colombier };
5023ff48bf5SDavid du Colombier
5033ff48bf5SDavid du Colombier
5043ff48bf5SDavid du Colombier static Tv tvs[Ntvs];
5053ff48bf5SDavid du Colombier static int ntvs;
5069a747e4fSDavid du Colombier
5079a747e4fSDavid du Colombier static int i2cread(Tv *, uchar, uchar *);
5089a747e4fSDavid du Colombier static int i2cwrite(Tv *, uchar, uchar, uchar, int);
5099a747e4fSDavid du Colombier static void tvinterrupt(Ureg *, Tv *);
5109a747e4fSDavid du Colombier static void vgastart(Tv *, ulong, int);
5119a747e4fSDavid du Colombier static void vstart(Tv *, int, int, int, int);
5123ff48bf5SDavid du Colombier static void astart(Tv *, char *, uint, uint, uint);
5139a747e4fSDavid du Colombier static void vstop(Tv *);
5143ff48bf5SDavid du Colombier static void astop(Tv *);
5153ff48bf5SDavid du Colombier static void colormode(Tv *, char *);
5169a747e4fSDavid du Colombier static void frequency(Tv *, int, int);
5173ff48bf5SDavid du Colombier static int getbitspp(Tv *);
5183ff48bf5SDavid du Colombier static char *getcolormode(ulong);
5193ff48bf5SDavid du Colombier static int mspreset(Tv *);
5203ff48bf5SDavid du Colombier static void i2cscan(Tv *);
5213ff48bf5SDavid du Colombier static int kfirinitialize(Tv *);
5223ff48bf5SDavid du Colombier static void msptune(Tv *);
5233ff48bf5SDavid du Colombier static void mspvolume(Tv *, int, int, int);
5243ff48bf5SDavid du Colombier static void gpioenable(Tv *, ulong, ulong);
5253ff48bf5SDavid du Colombier static void gpiowrite(Tv *, ulong, ulong);
5269a747e4fSDavid du Colombier
5279a747e4fSDavid du Colombier static void
tvinit(void)5289a747e4fSDavid du Colombier tvinit(void)
5299a747e4fSDavid du Colombier {
5309a747e4fSDavid du Colombier Pcidev *pci;
5319a747e4fSDavid du Colombier ulong intmask;
5329a747e4fSDavid du Colombier
53341dd6b47SDavid du Colombier /* Test for a triton memory controller. */
5349a747e4fSDavid du Colombier intmask = 0;
5359a747e4fSDavid du Colombier if (pcimatch(nil, Intel_vid, Intel_82437_did))
5369a747e4fSDavid du Colombier intmask = intmask_etbf;
5379a747e4fSDavid du Colombier
5389a747e4fSDavid du Colombier pci = nil;
5399a747e4fSDavid du Colombier while ((pci = pcimatch(pci, 0, 0)) != nil) {
5409a747e4fSDavid du Colombier int i, t;
5413ff48bf5SDavid du Colombier Tv *tv;
5429a747e4fSDavid du Colombier Bt848 *bt848;
5439a747e4fSDavid du Colombier ushort hscale, hdelay;
5449a747e4fSDavid du Colombier uchar v;
5459a747e4fSDavid du Colombier
5469a747e4fSDavid du Colombier for (i = 0; i != nelem(variant); i++)
5479a747e4fSDavid du Colombier if (pci->vid == variant[i].vid && pci->did == variant[i].did)
5489a747e4fSDavid du Colombier break;
5499a747e4fSDavid du Colombier if (i == nelem(variant))
5509a747e4fSDavid du Colombier continue;
5519a747e4fSDavid du Colombier
5523ff48bf5SDavid du Colombier if (ntvs >= Ntvs) {
5533ff48bf5SDavid du Colombier print("#V: Too many TV cards found\n");
5549a747e4fSDavid du Colombier continue;
5559a747e4fSDavid du Colombier }
5569a747e4fSDavid du Colombier
5573ff48bf5SDavid du Colombier tv = &tvs[ntvs++];
5589a747e4fSDavid du Colombier tv->variant = &variant[i];
5599a747e4fSDavid du Colombier tv->pci = pci;
5604de34a7eSDavid du Colombier tv->bt848 = (Bt848 *)vmap(pci->mem[0].bar & ~0x0F, 4 * K);
5619a747e4fSDavid du Colombier if (tv->bt848 == nil)
5623ff48bf5SDavid du Colombier panic("#V: Cannot allocate memory for Bt848");
5639a747e4fSDavid du Colombier bt848 = tv->bt848;
5649a747e4fSDavid du Colombier
56541dd6b47SDavid du Colombier /* i2c stuff. */
5669a747e4fSDavid du Colombier if (pci->did >= 878)
5679a747e4fSDavid du Colombier tv->i2ccmd = 0x83;
5689a747e4fSDavid du Colombier else
5699a747e4fSDavid du Colombier tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda;
5709a747e4fSDavid du Colombier
5713ff48bf5SDavid du Colombier t = 0;
5723ff48bf5SDavid du Colombier if (i2cread(tv, i2c_haupee, &v)) {
5733ff48bf5SDavid du Colombier uchar ee[256];
5743ff48bf5SDavid du Colombier Pcidev *pci878;
5753ff48bf5SDavid du Colombier Bt848 *bt878;
5769a747e4fSDavid du Colombier
5773ff48bf5SDavid du Colombier tv->board = Bt878_hauppauge;
5783ff48bf5SDavid du Colombier if (!i2cwrite(tv, i2c_haupee, 0, 0, 0))
5793ff48bf5SDavid du Colombier panic("#V: Cannot write to Hauppauge EEPROM");
5803ff48bf5SDavid du Colombier for (i = 0; i != sizeof ee; i++)
5813ff48bf5SDavid du Colombier if (!i2cread(tv, i2c_haupee + 1, &ee[i]))
5823ff48bf5SDavid du Colombier panic("#V: Cannot read from Hauppauge EEPROM");
5833ff48bf5SDavid du Colombier
5843ff48bf5SDavid du Colombier if (ee[9] > sizeof hp_tuners / sizeof hp_tuners[0])
5853ff48bf5SDavid du Colombier panic("#V: Tuner out of range (max %d, this %d)",
5863ff48bf5SDavid du Colombier sizeof hp_tuners / sizeof hp_tuners[0], ee[9]);
5873ff48bf5SDavid du Colombier t = hp_tuners[ee[9]];
5883ff48bf5SDavid du Colombier
58941dd6b47SDavid du Colombier /* Initialize the audio channel. */
5903ff48bf5SDavid du Colombier if ((pci878 = pcimatch(nil, Brooktree_vid, 0x878)) == nil)
5913ff48bf5SDavid du Colombier panic("#V: Unsupported Hauppage board");
5923ff48bf5SDavid du Colombier
5933ff48bf5SDavid du Colombier tv->bt878 = bt878 =
5944de34a7eSDavid du Colombier (Bt848 *)vmap(pci878->mem[0].bar & ~0x0F, 4 * K);
5953ff48bf5SDavid du Colombier if (bt878 == nil)
5963ff48bf5SDavid du Colombier panic("#V: Cannot allocate memory for the Bt878");
5973ff48bf5SDavid du Colombier
5983ff48bf5SDavid du Colombier kfirinitialize(tv);
5993ff48bf5SDavid du Colombier // i2cscan(tv);
6003ff48bf5SDavid du Colombier mspreset(tv);
6013ff48bf5SDavid du Colombier
6023ff48bf5SDavid du Colombier bt878->gpiodmactl = 0;
6033ff48bf5SDavid du Colombier bt878->intstat = (ulong)-1;
6043ff48bf5SDavid du Colombier intrenable(pci878->intl, (void (*)(Ureg *, void *))tvinterrupt,
6053ff48bf5SDavid du Colombier tv, pci878->tbdf, "tv");
6063ff48bf5SDavid du Colombier
6073ff48bf5SDavid du Colombier tv->amux = hauppaugeamux;
6089a747e4fSDavid du Colombier }
6093ff48bf5SDavid du Colombier else if (i2cread(tv, i2c_stbee, &v)) {
6103ff48bf5SDavid du Colombier USED(t);
6119a747e4fSDavid du Colombier panic("#V: Cannot deal with STB cards\n");
6123ff48bf5SDavid du Colombier }
6133ff48bf5SDavid du Colombier else if (i2cread(tv, i2c_miroproee, &v)) {
6149a747e4fSDavid du Colombier tv->board = Bt848_miropro;
6159a747e4fSDavid du Colombier t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
6163ff48bf5SDavid du Colombier tv->amux = miroamux;
6179a747e4fSDavid du Colombier }
6189a747e4fSDavid du Colombier else {
6199a747e4fSDavid du Colombier tv->board = Bt848_miro;
6203ff48bf5SDavid du Colombier tv->amux = miroamux;
6219a747e4fSDavid du Colombier t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
6229a747e4fSDavid du Colombier }
6239a747e4fSDavid du Colombier
6249a747e4fSDavid du Colombier if (t >= nelem(tuners))
6259a747e4fSDavid du Colombier t = 4;
6269a747e4fSDavid du Colombier tv->tuner = &tuners[t];
6279a747e4fSDavid du Colombier tv->i2ctuneraddr =
6289a747e4fSDavid du Colombier i2cread(tv, 0xc1, &v)? 0xc0:
6299a747e4fSDavid du Colombier i2cread(tv, 0xc3, &v)? 0xc2:
6309a747e4fSDavid du Colombier i2cread(tv, 0xc5, &v)? 0xc4:
6319a747e4fSDavid du Colombier i2cread(tv, 0xc7, &v)? 0xc6: -1;
6329a747e4fSDavid du Colombier
6339a747e4fSDavid du Colombier bt848->capctl = capctl_fullframe;
6349a747e4fSDavid du Colombier bt848->adelay = adelay_ntsc;
6359a747e4fSDavid du Colombier bt848->bdelay = bdelay_ntsc;
6369a747e4fSDavid du Colombier bt848->iform = iform_muxsel0|iform_xtauto|iform_ntsc;
6379a747e4fSDavid du Colombier bt848->vbipacksize = vbipacksize & 0xff;
6389a747e4fSDavid du Colombier bt848->vbipackdel = (vbipacksize >> 8) & 1;
6399a747e4fSDavid du Colombier
6409a747e4fSDavid du Colombier // setpll(bt848);
6419a747e4fSDavid du Colombier
6423ff48bf5SDavid du Colombier tv->cfmt = bt848->colorfmt = colorfmt_rgb16;
6439a747e4fSDavid du Colombier
6449a747e4fSDavid du Colombier hscale = (ntsc_rawpixels * 4096) / ntsc_sqpixels - 4096;
6459a747e4fSDavid du Colombier hdelay = (ntsc_clkx1delay * ntsc_hactive) / ntsc_clkx1hactive;
6469a747e4fSDavid du Colombier
6479a747e4fSDavid du Colombier bt848->ovtc = bt848->evtc = 0;
6489a747e4fSDavid du Colombier bt848->ehscalehi = bt848->ohscalehi = (hscale >> 8) & 0xff;
6499a747e4fSDavid du Colombier bt848->ehscalelo = bt848->ohscalelo = hscale & 0xff;
6509a747e4fSDavid du Colombier bt848->evscalehi &= ~0x1f;
6519a747e4fSDavid du Colombier bt848->ovscalehi &= ~0x1f;
6529a747e4fSDavid du Colombier bt848->evscalehi |= vscale_interlaced | ((ntsc_vscale >> 8) & 0x1f);
6539a747e4fSDavid du Colombier bt848->ovscalehi |= vscale_interlaced | (ntsc_vscale >> 8) & 0x1f;
6549a747e4fSDavid du Colombier bt848->evscalelo = bt848->ovscalelo = ntsc_vscale & 0xff;
6559a747e4fSDavid du Colombier bt848->ehactivelo = bt848->ohactivelo = ntsc_hactive & 0xff;
6569a747e4fSDavid du Colombier bt848->ehdelaylo = bt848->ohdelaylo = hdelay & 0xff;
6579a747e4fSDavid du Colombier bt848->evactivelo = bt848->ovactivelo = ntsc_vactive & 0xff;
6589a747e4fSDavid du Colombier bt848->evdelaylo = bt848->ovdelaylo = ntsc_vdelay & 0xff;
6599a747e4fSDavid du Colombier bt848->ecrop = bt848->ocrop =
6609a747e4fSDavid du Colombier ((ntsc_hactive >> 8) & 0x03) |
6619a747e4fSDavid du Colombier ((hdelay >> 6) & 0x0C) |
6629a747e4fSDavid du Colombier ((ntsc_vactive >> 4) & 0x30) |
6639a747e4fSDavid du Colombier ((ntsc_vdelay >> 2) & 0xC0);
6649a747e4fSDavid du Colombier
6659a747e4fSDavid du Colombier bt848->colorctl = colorctl_gamma;
6669a747e4fSDavid du Colombier bt848->capctl = 0;
6679a747e4fSDavid du Colombier bt848->gpiodmactl = gpiodmactl_pltp23_16 |
6689a747e4fSDavid du Colombier gpiodmactl_pltp1_16 | gpiodmactl_pktp_32;
6699a747e4fSDavid du Colombier bt848->gpioreginp = 0;
6709a747e4fSDavid du Colombier bt848->contrastlo = contrast_100percent;
6719a747e4fSDavid du Colombier bt848->bright = 16;
6729a747e4fSDavid du Colombier bt848->adc = (2 << 6) | adc_crush;
6739a747e4fSDavid du Colombier bt848->econtrol = bt848->ocontrol = control_ldec;
6749a747e4fSDavid du Colombier bt848->escloop = bt848->oscloop = 0;
6759a747e4fSDavid du Colombier bt848->intstat = (ulong)-1;
6769a747e4fSDavid du Colombier bt848->intmask = intmask |
6779a747e4fSDavid du Colombier intstat_vsync | intstat_scerr | intstat_risci | intstat_ocerr |
6783ff48bf5SDavid du Colombier intstat_vpress | intstat_fmtchg;
6799a747e4fSDavid du Colombier
6809a747e4fSDavid du Colombier
6813ff48bf5SDavid du Colombier if (tv->amux) {
6823ff48bf5SDavid du Colombier gpioenable(tv, ~0xfff, 0xfff);
6833ff48bf5SDavid du Colombier gpiowrite(tv, ~0xfff, tv->amux[AudioRadio]);
6843ff48bf5SDavid du Colombier }
6853ff48bf5SDavid du Colombier
6863ff48bf5SDavid du Colombier print("#V%ld: %s (rev %d) (%s/%s) intl %d\n",
6873ff48bf5SDavid du Colombier tv - tvs, tv->variant->name, pci->rid, boards[tv->board],
6883ff48bf5SDavid du Colombier tv->tuner->name, pci->intl);
6899a747e4fSDavid du Colombier
6909a747e4fSDavid du Colombier intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt,
6919a747e4fSDavid du Colombier tv, pci->tbdf, "tv");
6929a747e4fSDavid du Colombier }
6939a747e4fSDavid du Colombier }
6949a747e4fSDavid du Colombier
6959a747e4fSDavid du Colombier static Chan*
tvattach(char * spec)6969a747e4fSDavid du Colombier tvattach(char *spec)
6979a747e4fSDavid du Colombier {
6989a747e4fSDavid du Colombier return devattach('V', spec);
6999a747e4fSDavid du Colombier }
7009a747e4fSDavid du Colombier
7013ff48bf5SDavid du Colombier #define TYPE(q) ((int)((q).path & 0xff))
7023ff48bf5SDavid du Colombier #define DEV(q) ((int)(((q).path >> 8) & 0xff))
7033ff48bf5SDavid du Colombier #define QID(d, t) ((((d) & 0xff) << 8) | (t))
7043ff48bf5SDavid du Colombier
7053ff48bf5SDavid du Colombier static int
tv1gen(Chan * c,int i,Dir * dp)7063ff48bf5SDavid du Colombier tv1gen(Chan *c, int i, Dir *dp)
7073ff48bf5SDavid du Colombier {
7083ff48bf5SDavid du Colombier Qid qid;
7093ff48bf5SDavid du Colombier
7103ff48bf5SDavid du Colombier switch (i) {
7113ff48bf5SDavid du Colombier case Qvdata:
7123ff48bf5SDavid du Colombier mkqid(&qid, QID(DEV(c->qid), Qvdata), 0, QTFILE);
7133ff48bf5SDavid du Colombier devdir(c, qid, "video", 0, eve, 0444, dp);
7143ff48bf5SDavid du Colombier return 1;
7153ff48bf5SDavid du Colombier case Qadata:
7163ff48bf5SDavid du Colombier mkqid(&qid, QID(DEV(c->qid), Qadata), 0, QTFILE);
7173ff48bf5SDavid du Colombier devdir(c, qid, "audio", 0, eve, 0444, dp);
7183ff48bf5SDavid du Colombier return 1;
7193ff48bf5SDavid du Colombier case Qctl:
7203ff48bf5SDavid du Colombier mkqid(&qid, QID(DEV(c->qid), Qctl), 0, QTFILE);
7213ff48bf5SDavid du Colombier devdir(c, qid, "ctl", 0, eve, 0444, dp);
7223ff48bf5SDavid du Colombier return 1;
7233ff48bf5SDavid du Colombier case Qregs:
7243ff48bf5SDavid du Colombier mkqid(&qid, QID(DEV(c->qid), Qregs), 0, QTFILE);
7253ff48bf5SDavid du Colombier devdir(c, qid, "regs", 0, eve, 0444, dp);
7263ff48bf5SDavid du Colombier return 1;
7273ff48bf5SDavid du Colombier }
7283ff48bf5SDavid du Colombier return -1;
7293ff48bf5SDavid du Colombier }
7303ff48bf5SDavid du Colombier
7313ff48bf5SDavid du Colombier static int
tvgen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)7323ff48bf5SDavid du Colombier tvgen(Chan *c, char *, Dirtab *, int, int i, Dir *dp)
7333ff48bf5SDavid du Colombier {
7343ff48bf5SDavid du Colombier Qid qid;
7353ff48bf5SDavid du Colombier int dev;
7363ff48bf5SDavid du Colombier
7373ff48bf5SDavid du Colombier dev = DEV(c->qid);
7383ff48bf5SDavid du Colombier switch (TYPE(c->qid)) {
7393ff48bf5SDavid du Colombier case Qdir:
7403ff48bf5SDavid du Colombier if (i == DEVDOTDOT) {
7413ff48bf5SDavid du Colombier mkqid(&qid, Qdir, 0, QTDIR);
7423ff48bf5SDavid du Colombier devdir(c, qid, "#V", 0, eve, 0555, dp);
7433ff48bf5SDavid du Colombier return 1;
7443ff48bf5SDavid du Colombier }
7453ff48bf5SDavid du Colombier
7463ff48bf5SDavid du Colombier if (i >= ntvs)
7473ff48bf5SDavid du Colombier return -1;
7483ff48bf5SDavid du Colombier
7493ff48bf5SDavid du Colombier mkqid(&qid, QID(i, Qsubdir), 0, QTDIR);
7503ff48bf5SDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "tv%d", i);
7513ff48bf5SDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
7523ff48bf5SDavid du Colombier return 1;
7533ff48bf5SDavid du Colombier
7543ff48bf5SDavid du Colombier case Qsubdir:
7553ff48bf5SDavid du Colombier if (i == DEVDOTDOT) {
7563ff48bf5SDavid du Colombier mkqid(&qid, QID(dev, Qdir), 0, QTDIR);
7573ff48bf5SDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "tv%d", dev);
7583ff48bf5SDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
7593ff48bf5SDavid du Colombier return 1;
7603ff48bf5SDavid du Colombier }
7613ff48bf5SDavid du Colombier
7623ff48bf5SDavid du Colombier return tv1gen(c, i + Qsubbase, dp);
7633ff48bf5SDavid du Colombier
7643ff48bf5SDavid du Colombier case Qvdata:
7653ff48bf5SDavid du Colombier case Qadata:
7663ff48bf5SDavid du Colombier case Qctl:
7673ff48bf5SDavid du Colombier case Qregs:
7683ff48bf5SDavid du Colombier return tv1gen(c, TYPE(c->qid), dp);
7693ff48bf5SDavid du Colombier
7703ff48bf5SDavid du Colombier default:
7713ff48bf5SDavid du Colombier return -1;
7723ff48bf5SDavid du Colombier }
7733ff48bf5SDavid du Colombier }
7743ff48bf5SDavid du Colombier
7759a747e4fSDavid du Colombier static Walkqid *
tvwalk(Chan * c,Chan * nc,char ** name,int nname)7769a747e4fSDavid du Colombier tvwalk(Chan *c, Chan *nc, char **name, int nname)
7779a747e4fSDavid du Colombier {
7783ff48bf5SDavid du Colombier return devwalk(c, nc, name, nname, 0, 0, tvgen);
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier
7819a747e4fSDavid du Colombier static int
tvstat(Chan * c,uchar * db,int n)7829a747e4fSDavid du Colombier tvstat(Chan *c, uchar *db, int n)
7839a747e4fSDavid du Colombier {
7843ff48bf5SDavid du Colombier return devstat(c, db, n, 0, 0, tvgen);
7859a747e4fSDavid du Colombier }
7869a747e4fSDavid du Colombier
7879a747e4fSDavid du Colombier static Chan*
tvopen(Chan * c,int omode)7889a747e4fSDavid du Colombier tvopen(Chan *c, int omode)
7899a747e4fSDavid du Colombier {
7903ff48bf5SDavid du Colombier if (omode != OREAD &&
7913ff48bf5SDavid du Colombier TYPE(c->qid) != Qctl && TYPE(c->qid) != Qvdata)
7923ff48bf5SDavid du Colombier error(Eperm);
7933ff48bf5SDavid du Colombier
7943ff48bf5SDavid du Colombier switch (TYPE(c->qid)) {
7959a747e4fSDavid du Colombier case Qdir:
7963ff48bf5SDavid du Colombier return devopen(c, omode, nil, 0, tvgen);
7973ff48bf5SDavid du Colombier case Qadata:
7983ff48bf5SDavid du Colombier if (tvs[DEV(c->qid)].bt878 == nil)
7993ff48bf5SDavid du Colombier error(Enonexist);
8003ff48bf5SDavid du Colombier break;
8019a747e4fSDavid du Colombier }
8029a747e4fSDavid du Colombier
8039a747e4fSDavid du Colombier c->mode = openmode(omode);
8049a747e4fSDavid du Colombier c->flag |= COPEN;
8059a747e4fSDavid du Colombier c->offset = 0;
8063ff48bf5SDavid du Colombier
8073ff48bf5SDavid du Colombier if (TYPE(c->qid) == Qadata)
808061a3f44SDavid du Colombier c->aux = nil;
8099a747e4fSDavid du Colombier return c;
8109a747e4fSDavid du Colombier }
8119a747e4fSDavid du Colombier
8129a747e4fSDavid du Colombier static void
tvclose(Chan *)8139a747e4fSDavid du Colombier tvclose(Chan *)
81441dd6b47SDavid du Colombier {
81541dd6b47SDavid du Colombier }
8169a747e4fSDavid du Colombier
8173ff48bf5SDavid du Colombier static int
audioblock(void *)8183ff48bf5SDavid du Colombier audioblock(void *)
8193ff48bf5SDavid du Colombier {
8203ff48bf5SDavid du Colombier return 1;
8213ff48bf5SDavid du Colombier }
8223ff48bf5SDavid du Colombier
8239a747e4fSDavid du Colombier static long
tvread(Chan * c,void * a,long n,vlong offset)8249a747e4fSDavid du Colombier tvread(Chan *c, void *a, long n, vlong offset)
8259a747e4fSDavid du Colombier {
8269a747e4fSDavid du Colombier static char regs[10 * K];
8279a747e4fSDavid du Colombier static int regslen;
8283ff48bf5SDavid du Colombier Tv *tv;
8299a747e4fSDavid du Colombier char *e, *p;
8303ff48bf5SDavid du Colombier uchar *src;
8319a747e4fSDavid du Colombier
8329a747e4fSDavid du Colombier USED(offset);
8339a747e4fSDavid du Colombier
8343ff48bf5SDavid du Colombier switch(TYPE(c->qid)) {
8359a747e4fSDavid du Colombier case Qdir:
8363ff48bf5SDavid du Colombier case Qsubdir:
8373ff48bf5SDavid du Colombier return devdirread(c, a, n, 0, 0, tvgen);
8389a747e4fSDavid du Colombier
8393ff48bf5SDavid du Colombier case Qvdata: {
8409a747e4fSDavid du Colombier int bpf, nb;
8419a747e4fSDavid du Colombier
8423ff48bf5SDavid du Colombier tv = &tvs[DEV(c->qid)];
8433ff48bf5SDavid du Colombier bpf = ntsc_hactive * ntsc_vactive * getbitspp(tv) / 8;
8449a747e4fSDavid du Colombier
8459a747e4fSDavid du Colombier if (offset >= bpf)
8469a747e4fSDavid du Colombier return 0;
8479a747e4fSDavid du Colombier
8489a747e4fSDavid du Colombier nb = n;
8499a747e4fSDavid du Colombier if (offset + nb > bpf)
8509a747e4fSDavid du Colombier nb = bpf - offset;
8519a747e4fSDavid du Colombier
8529a747e4fSDavid du Colombier ilock(tv);
8533ff48bf5SDavid du Colombier if (tv->frames == nil || tv->lvframe >= tv->nframes ||
8543ff48bf5SDavid du Colombier tv->frames[tv->lvframe].fbase == nil) {
8559a747e4fSDavid du Colombier iunlock(tv);
8569a747e4fSDavid du Colombier return 0;
8579a747e4fSDavid du Colombier }
8589a747e4fSDavid du Colombier
8593ff48bf5SDavid du Colombier src = tv->frames[tv->lvframe].fbase;
8609a747e4fSDavid du Colombier incref(&tv->fref);
8619a747e4fSDavid du Colombier iunlock(tv);
8629a747e4fSDavid du Colombier
8639a747e4fSDavid du Colombier memmove(a, src + offset, nb);
8649a747e4fSDavid du Colombier decref(&tv->fref);
8659a747e4fSDavid du Colombier return nb;
8669a747e4fSDavid du Colombier }
8679a747e4fSDavid du Colombier
8683ff48bf5SDavid du Colombier case Qadata: {
869061a3f44SDavid du Colombier ulong uablock = (ulong)c->aux, bnum, tvablock;
8703ff48bf5SDavid du Colombier int boffs, nbytes;
8713ff48bf5SDavid du Colombier
8723ff48bf5SDavid du Colombier tv = &tvs[DEV(c->qid)];
8733ff48bf5SDavid du Colombier if (tv->bt878 == nil)
8743ff48bf5SDavid du Colombier error("#V: No audio device");
8753ff48bf5SDavid du Colombier if (tv->absize == 0)
8763ff48bf5SDavid du Colombier error("#V: audio not initialized");
8773ff48bf5SDavid du Colombier
8783ff48bf5SDavid du Colombier bnum = offset / tv->absize;
8793ff48bf5SDavid du Colombier boffs = offset % tv->absize;
8803ff48bf5SDavid du Colombier nbytes = tv->absize - boffs;
8813ff48bf5SDavid du Colombier
8823ff48bf5SDavid du Colombier incref(&tv->aref);
88341dd6b47SDavid du Colombier for (;;) {
88441dd6b47SDavid du Colombier tvablock = tv->narblocks; /* Current tv block. */
8853ff48bf5SDavid du Colombier
8863ff48bf5SDavid du Colombier if (uablock == 0)
8873ff48bf5SDavid du Colombier uablock = tvablock - 1;
8883ff48bf5SDavid du Colombier
8893ff48bf5SDavid du Colombier if (tvablock >= uablock + bnum + tv->narblocks)
8903ff48bf5SDavid du Colombier uablock = tvablock - 1 - bnum;
8913ff48bf5SDavid du Colombier
8923ff48bf5SDavid du Colombier if (uablock + bnum == tvablock) {
8933ff48bf5SDavid du Colombier sleep(tv, audioblock, nil);
8943ff48bf5SDavid du Colombier continue;
8953ff48bf5SDavid du Colombier }
8963ff48bf5SDavid du Colombier break;
8973ff48bf5SDavid du Colombier }
8983ff48bf5SDavid du Colombier
8993ff48bf5SDavid du Colombier print("uablock %ld, bnum %ld, boffs %d, nbytes %d, tvablock %ld\n",
9003ff48bf5SDavid du Colombier uablock, bnum, boffs, nbytes, tvablock);
9013ff48bf5SDavid du Colombier src = tv->abuf + ((uablock + bnum) % tv->nablocks) * tv->absize;
902*567483c8SDavid du Colombier print("copying from %#p (abuf %#p), nbytes %d (block %ld.%ld)\n",
9033ff48bf5SDavid du Colombier src + boffs, tv->abuf, nbytes, uablock, bnum);
9043ff48bf5SDavid du Colombier
9053ff48bf5SDavid du Colombier memmove(a, src + boffs, nbytes);
9063ff48bf5SDavid du Colombier decref(&tv->aref);
9073ff48bf5SDavid du Colombier
9083ff48bf5SDavid du Colombier uablock += (boffs + nbytes) % tv->absize;
909061a3f44SDavid du Colombier c->aux = (void*)uablock;
9103ff48bf5SDavid du Colombier
9113ff48bf5SDavid du Colombier return nbytes;
9123ff48bf5SDavid du Colombier }
9133ff48bf5SDavid du Colombier
9149a747e4fSDavid du Colombier case Qctl: {
9159a747e4fSDavid du Colombier char str[128];
9169a747e4fSDavid du Colombier
9173ff48bf5SDavid du Colombier tv = &tvs[DEV(c->qid)];
9183ff48bf5SDavid du Colombier snprint(str, sizeof str, "%dx%dx%d %s channel %d %s\n",
9193ff48bf5SDavid du Colombier ntsc_hactive, ntsc_vactive, getbitspp(tv),
92041dd6b47SDavid du Colombier getcolormode(tv->cfmt), tv->channel, tv->ainfo);
9213ff48bf5SDavid du Colombier return readstr(offset, a, strlen(str) + 1, str);
9229a747e4fSDavid du Colombier }
9239a747e4fSDavid du Colombier
9249a747e4fSDavid du Colombier case Qregs:
9259a747e4fSDavid du Colombier if (offset == 0) {
9263ff48bf5SDavid du Colombier Bt848 *bt848;
9279a747e4fSDavid du Colombier int i;
9289a747e4fSDavid du Colombier
9293ff48bf5SDavid du Colombier tv = &tvs[DEV(c->qid)];
9303ff48bf5SDavid du Colombier bt848 = tv->bt848;
9313ff48bf5SDavid du Colombier
9329a747e4fSDavid du Colombier e = regs + sizeof(regs);
9339a747e4fSDavid du Colombier p = regs;
9349a747e4fSDavid du Colombier for (i = 0; i < 0x300 >> 2; i++)
93541dd6b47SDavid du Colombier p = seprint(p, e, "%.3X %.8ulX\n", i << 2,
93641dd6b47SDavid du Colombier ((ulong *)bt848)[i]);
9373ff48bf5SDavid du Colombier if (tv->bt878) {
9383ff48bf5SDavid du Colombier bt848 = tv->bt878;
9393ff48bf5SDavid du Colombier
9403ff48bf5SDavid du Colombier for (i = 0; i < 0x300 >> 2; i++)
9413ff48bf5SDavid du Colombier p = seprint(p, e, "%.3X %.8ulX\n",
9423ff48bf5SDavid du Colombier i << 2, ((ulong *)bt848)[i]);
9433ff48bf5SDavid du Colombier }
9443ff48bf5SDavid du Colombier
9459a747e4fSDavid du Colombier regslen = p - regs;
9469a747e4fSDavid du Colombier }
9479a747e4fSDavid du Colombier
9489a747e4fSDavid du Colombier if (offset >= regslen)
9499a747e4fSDavid du Colombier return 0;
9509a747e4fSDavid du Colombier if (offset + n > regslen)
9519a747e4fSDavid du Colombier n = regslen - offset;
9529a747e4fSDavid du Colombier
9539a747e4fSDavid du Colombier return readstr(offset, a, n, ®s[offset]);
9549a747e4fSDavid du Colombier
9559a747e4fSDavid du Colombier default:
9569a747e4fSDavid du Colombier n = 0;
9579a747e4fSDavid du Colombier break;
9589a747e4fSDavid du Colombier }
9599a747e4fSDavid du Colombier return n;
9609a747e4fSDavid du Colombier }
9619a747e4fSDavid du Colombier
9629a747e4fSDavid du Colombier static long
tvwrite(Chan * c,void * a,long n,vlong)9639a747e4fSDavid du Colombier tvwrite(Chan *c, void *a, long n, vlong)
9649a747e4fSDavid du Colombier {
9659a747e4fSDavid du Colombier Cmdbuf *cb;
9669a747e4fSDavid du Colombier Cmdtab *ct;
9673ff48bf5SDavid du Colombier Tv *tv;
9689a747e4fSDavid du Colombier
9693ff48bf5SDavid du Colombier tv = &tvs[DEV(c->qid)];
9703ff48bf5SDavid du Colombier switch(TYPE(c->qid)) {
9719a747e4fSDavid du Colombier case Qctl:
9729a747e4fSDavid du Colombier cb = parsecmd(a, n);
9739a747e4fSDavid du Colombier if(waserror()){
9749a747e4fSDavid du Colombier free(cb);
9759a747e4fSDavid du Colombier nexterror();
9769a747e4fSDavid du Colombier }
9779a747e4fSDavid du Colombier ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg));
9789a747e4fSDavid du Colombier switch (ct->index) {
9799a747e4fSDavid du Colombier case CMvstart:
9809a747e4fSDavid du Colombier vstart(tv, (int)strtol(cb->f[1], (char **)nil, 0),
9819a747e4fSDavid du Colombier ntsc_hactive, ntsc_vactive, ntsc_hactive);
9829a747e4fSDavid du Colombier break;
9839a747e4fSDavid du Colombier
9843ff48bf5SDavid du Colombier case CMastart:
9853ff48bf5SDavid du Colombier astart(tv, cb->f[1], (uint)strtol(cb->f[2], (char **)nil, 0),
9863ff48bf5SDavid du Colombier (uint)strtol(cb->f[3], (char **)nil, 0),
9873ff48bf5SDavid du Colombier (uint)strtol(cb->f[4], (char **)nil, 0));
9883ff48bf5SDavid du Colombier break;
9893ff48bf5SDavid du Colombier
9903ff48bf5SDavid du Colombier case CMastop:
9913ff48bf5SDavid du Colombier astop(tv);
9923ff48bf5SDavid du Colombier break;
9933ff48bf5SDavid du Colombier
9949a747e4fSDavid du Colombier case CMvgastart:
9959a747e4fSDavid du Colombier vgastart(tv, strtoul(cb->f[1], (char **)nil, 0),
9969a747e4fSDavid du Colombier (int)strtoul(cb->f[2], (char **)nil, 0));
9979a747e4fSDavid du Colombier break;
9989a747e4fSDavid du Colombier
9999a747e4fSDavid du Colombier case CMvstop:
10009a747e4fSDavid du Colombier vstop(tv);
10019a747e4fSDavid du Colombier break;
10029a747e4fSDavid du Colombier
10039a747e4fSDavid du Colombier case CMchannel:
10049a747e4fSDavid du Colombier frequency(tv, (int)strtol(cb->f[1], (char **)nil, 0),
10059a747e4fSDavid du Colombier (int)strtol(cb->f[2], (char **)nil, 0));
10069a747e4fSDavid du Colombier break;
10073ff48bf5SDavid du Colombier
10083ff48bf5SDavid du Colombier case CMcolormode:
10093ff48bf5SDavid du Colombier colormode(tv, cb->f[1]);
10103ff48bf5SDavid du Colombier break;
10113ff48bf5SDavid du Colombier
10123ff48bf5SDavid du Colombier case CMvolume:
10133ff48bf5SDavid du Colombier if (!tv->msp)
10143ff48bf5SDavid du Colombier error("#V: No volume control");
10153ff48bf5SDavid du Colombier
10163ff48bf5SDavid du Colombier mspvolume(tv, 0, (int)strtol(cb->f[1], (char **)nil, 0),
10173ff48bf5SDavid du Colombier (int)strtol(cb->f[2], (char **)nil, 0));
10183ff48bf5SDavid du Colombier break;
10193ff48bf5SDavid du Colombier
10203ff48bf5SDavid du Colombier case CMmute:
10213ff48bf5SDavid du Colombier if (!tv->msp)
10223ff48bf5SDavid du Colombier error("#V: No volume control");
10233ff48bf5SDavid du Colombier
10243ff48bf5SDavid du Colombier mspvolume(tv, 1, 0, 0);
10253ff48bf5SDavid du Colombier break;
10269a747e4fSDavid du Colombier }
10279a747e4fSDavid du Colombier poperror();
10283ff48bf5SDavid du Colombier free(cb);
10299a747e4fSDavid du Colombier break;
10309a747e4fSDavid du Colombier
10319a747e4fSDavid du Colombier default:
10329a747e4fSDavid du Colombier error(Eio);
10339a747e4fSDavid du Colombier }
10349a747e4fSDavid du Colombier return n;
10359a747e4fSDavid du Colombier }
10369a747e4fSDavid du Colombier
10379a747e4fSDavid du Colombier Dev tvdevtab = {
10389a747e4fSDavid du Colombier 'V',
10399a747e4fSDavid du Colombier "tv",
10409a747e4fSDavid du Colombier
10419a747e4fSDavid du Colombier devreset,
10429a747e4fSDavid du Colombier tvinit,
10439a747e4fSDavid du Colombier devshutdown,
10449a747e4fSDavid du Colombier tvattach,
10459a747e4fSDavid du Colombier tvwalk,
10469a747e4fSDavid du Colombier tvstat,
10479a747e4fSDavid du Colombier tvopen,
10489a747e4fSDavid du Colombier devcreate,
10499a747e4fSDavid du Colombier tvclose,
10509a747e4fSDavid du Colombier tvread,
10519a747e4fSDavid du Colombier devbread,
10529a747e4fSDavid du Colombier tvwrite,
10539a747e4fSDavid du Colombier devbwrite,
10549a747e4fSDavid du Colombier devremove,
10559a747e4fSDavid du Colombier devwstat,
10569a747e4fSDavid du Colombier };
10579a747e4fSDavid du Colombier
10589a747e4fSDavid du Colombier static void
tvinterrupt(Ureg *,Tv * tv)10599a747e4fSDavid du Colombier tvinterrupt(Ureg *, Tv *tv)
10609a747e4fSDavid du Colombier {
106141dd6b47SDavid du Colombier Bt848 *bt848 = tv->bt848, *bt878 = tv->bt878;
10629a747e4fSDavid du Colombier
106341dd6b47SDavid du Colombier for (;;) {
10643ff48bf5SDavid du Colombier ulong vstat, astat;
10659a747e4fSDavid du Colombier uchar fnum;
10669a747e4fSDavid du Colombier
10673ff48bf5SDavid du Colombier vstat = bt848->intstat;
10683ff48bf5SDavid du Colombier fnum = (vstat >> intstat_riscstatshift) & 0xf;
10693ff48bf5SDavid du Colombier vstat &= bt848->intmask;
10709a747e4fSDavid du Colombier
10713ff48bf5SDavid du Colombier if (bt878)
10723ff48bf5SDavid du Colombier astat = bt878->intstat & bt878->intmask;
10733ff48bf5SDavid du Colombier else
10743ff48bf5SDavid du Colombier astat = 0;
10753ff48bf5SDavid du Colombier
10763ff48bf5SDavid du Colombier if (vstat == 0 && astat == 0)
10779a747e4fSDavid du Colombier break;
10789a747e4fSDavid du Colombier
10793ff48bf5SDavid du Colombier if (astat)
10803ff48bf5SDavid du Colombier print("vstat %.8luX, astat %.8luX\n", vstat, astat);
10819a747e4fSDavid du Colombier
10823ff48bf5SDavid du Colombier bt848->intstat = vstat;
10833ff48bf5SDavid du Colombier if (bt878)
10843ff48bf5SDavid du Colombier bt878->intstat = astat;
10853ff48bf5SDavid du Colombier
10863ff48bf5SDavid du Colombier if ((vstat & intstat_fmtchg) == intstat_fmtchg) {
10879a747e4fSDavid du Colombier iprint("int: fmtchg\n");
10883ff48bf5SDavid du Colombier vstat &= ~intstat_fmtchg;
10899a747e4fSDavid du Colombier }
10909a747e4fSDavid du Colombier
10913ff48bf5SDavid du Colombier if ((vstat & intstat_vpress) == intstat_vpress) {
10923ff48bf5SDavid du Colombier // iprint("int: vpress\n");
10933ff48bf5SDavid du Colombier vstat &= ~intstat_vpress;
10949a747e4fSDavid du Colombier }
10959a747e4fSDavid du Colombier
109641dd6b47SDavid du Colombier if ((vstat & intstat_vsync) == intstat_vsync)
10973ff48bf5SDavid du Colombier vstat &= ~intstat_vsync;
10989a747e4fSDavid du Colombier
10993ff48bf5SDavid du Colombier if ((vstat & intstat_scerr) == intstat_scerr) {
11009a747e4fSDavid du Colombier iprint("int: scerr\n");
11019a747e4fSDavid du Colombier bt848->gpiodmactl &=
11029a747e4fSDavid du Colombier ~(gpiodmactl_riscenable|gpiodmactl_fifoenable);
11039a747e4fSDavid du Colombier bt848->gpiodmactl |= gpiodmactl_fifoenable;
11049a747e4fSDavid du Colombier bt848->gpiodmactl |= gpiodmactl_riscenable;
11053ff48bf5SDavid du Colombier vstat &= ~intstat_scerr;
11069a747e4fSDavid du Colombier }
11079a747e4fSDavid du Colombier
11083ff48bf5SDavid du Colombier if ((vstat & intstat_risci) == intstat_risci) {
11093ff48bf5SDavid du Colombier tv->lvframe = fnum;
11103ff48bf5SDavid du Colombier vstat &= ~intstat_risci;
11119a747e4fSDavid du Colombier }
11129a747e4fSDavid du Colombier
11133ff48bf5SDavid du Colombier if ((vstat & intstat_ocerr) == intstat_ocerr) {
11149a747e4fSDavid du Colombier iprint("int: ocerr\n");
11153ff48bf5SDavid du Colombier vstat &= ~intstat_ocerr;
11169a747e4fSDavid du Colombier }
11179a747e4fSDavid du Colombier
11183ff48bf5SDavid du Colombier if ((vstat & intstat_fbus) == intstat_fbus) {
11199a747e4fSDavid du Colombier iprint("int: fbus\n");
11203ff48bf5SDavid du Colombier vstat &= ~intstat_fbus;
11219a747e4fSDavid du Colombier }
11229a747e4fSDavid du Colombier
11233ff48bf5SDavid du Colombier if (vstat)
11243ff48bf5SDavid du Colombier iprint("int: (v) ignored interrupts %.8ulX\n", vstat);
11253ff48bf5SDavid du Colombier
11263ff48bf5SDavid du Colombier if ((astat & intstat_risci) == intstat_risci) {
11273ff48bf5SDavid du Colombier tv->narblocks++;
11283ff48bf5SDavid du Colombier if ((tv->narblocks % 100) == 0)
11293ff48bf5SDavid du Colombier print("a");
11303ff48bf5SDavid du Colombier wakeup(tv);
11313ff48bf5SDavid du Colombier astat &= ~intstat_risci;
11323ff48bf5SDavid du Colombier }
11333ff48bf5SDavid du Colombier
11343ff48bf5SDavid du Colombier if ((astat & intstat_fdsr) == intstat_fdsr) {
11353ff48bf5SDavid du Colombier iprint("int: (a) fdsr\n");
11363ff48bf5SDavid du Colombier bt848->gpiodmactl &=
11373ff48bf5SDavid du Colombier ~(gpiodmactl_acapenable |
11383ff48bf5SDavid du Colombier gpiodmactl_riscenable | gpiodmactl_fifoenable);
11393ff48bf5SDavid du Colombier astat &= ~intstat_fdsr;
11403ff48bf5SDavid du Colombier }
11413ff48bf5SDavid du Colombier
11423ff48bf5SDavid du Colombier if (astat)
11433ff48bf5SDavid du Colombier iprint("int: (a) ignored interrupts %.8ulX\n", astat);
11449a747e4fSDavid du Colombier }
11459a747e4fSDavid du Colombier }
11469a747e4fSDavid du Colombier
11479a747e4fSDavid du Colombier static int
i2cread(Tv * tv,uchar off,uchar * v)11489a747e4fSDavid du Colombier i2cread(Tv *tv, uchar off, uchar *v)
11499a747e4fSDavid du Colombier {
11509a747e4fSDavid du Colombier Bt848 *bt848 = tv->bt848;
11519a747e4fSDavid du Colombier ulong intstat;
11529a747e4fSDavid du Colombier int i;
11539a747e4fSDavid du Colombier
11549a747e4fSDavid du Colombier bt848->intstat = intstat_i2cdone;
11559a747e4fSDavid du Colombier bt848->i2c = (off << 24) | tv->i2ccmd;
11569a747e4fSDavid du Colombier
11579a747e4fSDavid du Colombier intstat = -1;
11589a747e4fSDavid du Colombier for (i = 0; i != 1000; i++) {
11599a747e4fSDavid du Colombier if ((intstat = bt848->intstat) & intstat_i2cdone)
11609a747e4fSDavid du Colombier break;
11619a747e4fSDavid du Colombier microdelay(1000);
11629a747e4fSDavid du Colombier }
11639a747e4fSDavid du Colombier
11649a747e4fSDavid du Colombier if (i == 1000) {
11659a747e4fSDavid du Colombier print("i2cread: timeout\n");
11669a747e4fSDavid du Colombier return 0;
11679a747e4fSDavid du Colombier }
11689a747e4fSDavid du Colombier
11699a747e4fSDavid du Colombier if ((intstat & intstat_i2crack) == 0)
11709a747e4fSDavid du Colombier return 0;
11719a747e4fSDavid du Colombier
11729a747e4fSDavid du Colombier *v = bt848->i2c >> 8;
11739a747e4fSDavid du Colombier return 1;
11749a747e4fSDavid du Colombier }
11759a747e4fSDavid du Colombier
11769a747e4fSDavid du Colombier static int
i2cwrite(Tv * tv,uchar addr,uchar sub,uchar data,int both)11773ff48bf5SDavid du Colombier i2cwrite(Tv *tv, uchar addr, uchar sub, uchar data, int both)
11789a747e4fSDavid du Colombier {
11799a747e4fSDavid du Colombier Bt848 *bt848 = tv->bt848;
11803ff48bf5SDavid du Colombier ulong intstat, d;
11819a747e4fSDavid du Colombier int i;
11829a747e4fSDavid du Colombier
11839a747e4fSDavid du Colombier bt848->intstat = intstat_i2cdone;
11843ff48bf5SDavid du Colombier d = (addr << 24) | (sub << 16) | tv->i2ccmd;
11859a747e4fSDavid du Colombier if (both)
11863ff48bf5SDavid du Colombier d |= (data << 8) | i2c_bt848w3b;
11873ff48bf5SDavid du Colombier bt848->i2c = d;
11889a747e4fSDavid du Colombier
11899a747e4fSDavid du Colombier intstat = 0;
11909a747e4fSDavid du Colombier for (i = 0; i != 1000; i++) {
11919a747e4fSDavid du Colombier if ((intstat = bt848->intstat) & intstat_i2cdone)
11929a747e4fSDavid du Colombier break;
11939a747e4fSDavid du Colombier microdelay(1000);
11949a747e4fSDavid du Colombier }
11959a747e4fSDavid du Colombier
11963ff48bf5SDavid du Colombier if (i == i2c_timeout) {
11973ff48bf5SDavid du Colombier print("i2cwrite: timeout\n");
11989a747e4fSDavid du Colombier return 0;
11999a747e4fSDavid du Colombier }
12009a747e4fSDavid du Colombier
12019a747e4fSDavid du Colombier if ((intstat & intstat_i2crack) == 0)
12029a747e4fSDavid du Colombier return 0;
12039a747e4fSDavid du Colombier
12049a747e4fSDavid du Colombier return 1;
12059a747e4fSDavid du Colombier }
12069a747e4fSDavid du Colombier
12079a747e4fSDavid du Colombier static ulong *
riscpacked(ulong pa,int fnum,int w,int h,int stride,ulong ** lastjmp)12084de34a7eSDavid du Colombier riscpacked(ulong pa, int fnum, int w, int h, int stride, ulong **lastjmp)
12099a747e4fSDavid du Colombier {
12109a747e4fSDavid du Colombier ulong *p, *pbase;
12119a747e4fSDavid du Colombier int i;
12129a747e4fSDavid du Colombier
12139a747e4fSDavid du Colombier pbase = p = (ulong *)malloc((h + 6) * 2 * sizeof(ulong));
12149a747e4fSDavid du Colombier assert(p);
12159a747e4fSDavid du Colombier
12169a747e4fSDavid du Colombier assert(w <= 0x7FF);
12179a747e4fSDavid du Colombier
12189a747e4fSDavid du Colombier *p++ = riscsync | riscsync_resync | riscsync_vre;
12199a747e4fSDavid du Colombier *p++ = 0;
12209a747e4fSDavid du Colombier
12219a747e4fSDavid du Colombier *p++ = riscsync | riscsync_fm1;
12229a747e4fSDavid du Colombier *p++ = 0;
12239a747e4fSDavid du Colombier
12249a747e4fSDavid du Colombier for (i = 0; i != h / 2; i++) {
12259a747e4fSDavid du Colombier *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
12264de34a7eSDavid du Colombier *p++ = pa + i * 2 * stride;
12279a747e4fSDavid du Colombier }
12289a747e4fSDavid du Colombier
12299a747e4fSDavid du Colombier *p++ = riscsync | riscsync_resync | riscsync_vro;
12309a747e4fSDavid du Colombier *p++ = 0;
12319a747e4fSDavid du Colombier
12329a747e4fSDavid du Colombier *p++ = riscsync | riscsync_fm1;
12339a747e4fSDavid du Colombier *p++ = 0;
12349a747e4fSDavid du Colombier
12359a747e4fSDavid du Colombier for (i = 0; i != h / 2; i++) {
12369a747e4fSDavid du Colombier *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
12374de34a7eSDavid du Colombier *p++ = pa + (i * 2 + 1) * stride;
12389a747e4fSDavid du Colombier }
12399a747e4fSDavid du Colombier
124041dd6b47SDavid du Colombier /* reset status. you really need two instructions ;-(. */
12419a747e4fSDavid du Colombier *p++ = riscjmp | (0xf << risclabelshift_reset);
12429a747e4fSDavid du Colombier *p++ = PADDR(p);
12439a747e4fSDavid du Colombier *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
12449a747e4fSDavid du Colombier *lastjmp = p;
12459a747e4fSDavid du Colombier
12469a747e4fSDavid du Colombier return pbase;
12479a747e4fSDavid du Colombier }
12489a747e4fSDavid du Colombier
12493ff48bf5SDavid du Colombier static ulong *
riscplanar411(ulong pa,int fnum,int w,int h,ulong ** lastjmp)12504de34a7eSDavid du Colombier riscplanar411(ulong pa, int fnum, int w, int h, ulong **lastjmp)
12513ff48bf5SDavid du Colombier {
12523ff48bf5SDavid du Colombier ulong *p, *pbase, Cw, Yw, Ch;
12533ff48bf5SDavid du Colombier uchar *Ybase, *Cbbase, *Crbase;
12543ff48bf5SDavid du Colombier int i, bitspp;
12553ff48bf5SDavid du Colombier
12563ff48bf5SDavid du Colombier bitspp = 6;
12573ff48bf5SDavid du Colombier assert(w * bitspp / 8 <= 0x7FF);
12583ff48bf5SDavid du Colombier pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
12593ff48bf5SDavid du Colombier assert(p);
12603ff48bf5SDavid du Colombier
12613ff48bf5SDavid du Colombier Yw = w;
12624de34a7eSDavid du Colombier Ybase = (uchar *)pa;
12633ff48bf5SDavid du Colombier Cw = w >> 1;
12643ff48bf5SDavid du Colombier Ch = h >> 1;
12653ff48bf5SDavid du Colombier Cbbase = Ybase + Yw * h;
12663ff48bf5SDavid du Colombier Crbase = Cbbase + Cw * Ch;
12673ff48bf5SDavid du Colombier
12683ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_resync | riscsync_vre;
12693ff48bf5SDavid du Colombier *p++ = 0;
12703ff48bf5SDavid du Colombier
12713ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_fm3;
12723ff48bf5SDavid du Colombier *p++ = 0;
12733ff48bf5SDavid du Colombier
12743ff48bf5SDavid du Colombier for (i = 0; i != h / 2; i++) {
12753ff48bf5SDavid du Colombier *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
12763ff48bf5SDavid du Colombier *p++ = (Cw << 16) | Cw;
12773ff48bf5SDavid du Colombier *p++ = (ulong)(Ybase + i * 2 * Yw);
127841dd6b47SDavid du Colombier *p++ = (ulong)(Cbbase + i * Cw); /* Do not interlace */
12793ff48bf5SDavid du Colombier *p++ = (ulong)(Crbase + i * Cw);
12803ff48bf5SDavid du Colombier }
12813ff48bf5SDavid du Colombier
12823ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_resync | riscsync_vro;
12833ff48bf5SDavid du Colombier *p++ = 0;
12843ff48bf5SDavid du Colombier
12853ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_fm3;
12863ff48bf5SDavid du Colombier *p++ = 0;
12873ff48bf5SDavid du Colombier
12883ff48bf5SDavid du Colombier for (i = 0; i != h / 2; i++) {
12893ff48bf5SDavid du Colombier *p++ = riscwrite1s23 | Yw | riscwrite_sol | riscwrite_eol;
12903ff48bf5SDavid du Colombier *p++ = (Cw << 16) | Cw;
12913ff48bf5SDavid du Colombier *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
12923ff48bf5SDavid du Colombier }
12933ff48bf5SDavid du Colombier
129441dd6b47SDavid du Colombier /* reset status. you really need two instructions ;-(. */
12953ff48bf5SDavid du Colombier *p++ = riscjmp | (0xf << risclabelshift_reset);
12963ff48bf5SDavid du Colombier *p++ = PADDR(p);
12973ff48bf5SDavid du Colombier *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
12983ff48bf5SDavid du Colombier *lastjmp = p;
12993ff48bf5SDavid du Colombier
13003ff48bf5SDavid du Colombier return pbase;
13013ff48bf5SDavid du Colombier }
13023ff48bf5SDavid du Colombier
13033ff48bf5SDavid du Colombier static ulong *
riscplanar422(ulong pa,int fnum,int w,int h,ulong ** lastjmp)13044de34a7eSDavid du Colombier riscplanar422(ulong pa, int fnum, int w, int h, ulong **lastjmp)
13053ff48bf5SDavid du Colombier {
13063ff48bf5SDavid du Colombier ulong *p, *pbase, Cw, Yw;
13073ff48bf5SDavid du Colombier uchar *Ybase, *Cbbase, *Crbase;
13083ff48bf5SDavid du Colombier int i, bpp;
13093ff48bf5SDavid du Colombier
13103ff48bf5SDavid du Colombier bpp = 2;
13113ff48bf5SDavid du Colombier assert(w * bpp <= 0x7FF);
13123ff48bf5SDavid du Colombier pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
13133ff48bf5SDavid du Colombier assert(p);
13143ff48bf5SDavid du Colombier
13153ff48bf5SDavid du Colombier Yw = w;
13164de34a7eSDavid du Colombier Ybase = (uchar *)pa;
13173ff48bf5SDavid du Colombier Cw = w >> 1;
13183ff48bf5SDavid du Colombier Cbbase = Ybase + Yw * h;
13193ff48bf5SDavid du Colombier Crbase = Cbbase + Cw * h;
13203ff48bf5SDavid du Colombier
13213ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_resync | riscsync_vre;
13223ff48bf5SDavid du Colombier *p++ = 0;
13233ff48bf5SDavid du Colombier
13243ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_fm3;
13253ff48bf5SDavid du Colombier *p++ = 0;
13263ff48bf5SDavid du Colombier
13273ff48bf5SDavid du Colombier for (i = 0; i != h / 2; i++) {
13283ff48bf5SDavid du Colombier *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
13293ff48bf5SDavid du Colombier *p++ = (Cw << 16) | Cw;
13303ff48bf5SDavid du Colombier *p++ = (ulong)(Ybase + i * 2 * Yw);
13313ff48bf5SDavid du Colombier *p++ = (ulong)(Cbbase + i * 2 * Cw);
13323ff48bf5SDavid du Colombier *p++ = (ulong)(Crbase + i * 2 * Cw);
13333ff48bf5SDavid du Colombier }
13343ff48bf5SDavid du Colombier
13353ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_resync | riscsync_vro;
13363ff48bf5SDavid du Colombier *p++ = 0;
13373ff48bf5SDavid du Colombier
13383ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_fm3;
13393ff48bf5SDavid du Colombier *p++ = 0;
13403ff48bf5SDavid du Colombier
13413ff48bf5SDavid du Colombier for (i = 0; i != h / 2; i++) {
13423ff48bf5SDavid du Colombier *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
13433ff48bf5SDavid du Colombier *p++ = (Cw << 16) | Cw;
13443ff48bf5SDavid du Colombier *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
13453ff48bf5SDavid du Colombier *p++ = (ulong)(Cbbase + (i * 2 + 1) * Cw);
13463ff48bf5SDavid du Colombier *p++ = (ulong)(Crbase + (i * 2 + 1) * Cw);
13473ff48bf5SDavid du Colombier }
13483ff48bf5SDavid du Colombier
134941dd6b47SDavid du Colombier /* reset status. you really need two instructions ;-(. */
13503ff48bf5SDavid du Colombier *p++ = riscjmp | (0xf << risclabelshift_reset);
13513ff48bf5SDavid du Colombier *p++ = PADDR(p);
13523ff48bf5SDavid du Colombier *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
13533ff48bf5SDavid du Colombier *lastjmp = p;
13543ff48bf5SDavid du Colombier
13553ff48bf5SDavid du Colombier return pbase;
13563ff48bf5SDavid du Colombier }
13573ff48bf5SDavid du Colombier
13583ff48bf5SDavid du Colombier static ulong *
riscaudio(ulong pa,int nblocks,int bsize)13594de34a7eSDavid du Colombier riscaudio(ulong pa, int nblocks, int bsize)
13603ff48bf5SDavid du Colombier {
13613ff48bf5SDavid du Colombier ulong *p, *pbase;
13623ff48bf5SDavid du Colombier int i;
13633ff48bf5SDavid du Colombier
13643ff48bf5SDavid du Colombier pbase = p = (ulong *)malloc((nblocks + 3) * 2 * sizeof(ulong));
13653ff48bf5SDavid du Colombier assert(p);
13663ff48bf5SDavid du Colombier
13673ff48bf5SDavid du Colombier *p++ = riscsync|riscsync_fm1;
13683ff48bf5SDavid du Colombier *p++ = 0;
13693ff48bf5SDavid du Colombier
13703ff48bf5SDavid du Colombier for (i = 0; i != nblocks; i++) {
13713ff48bf5SDavid du Colombier *p++ = riscwrite | riscwrite_sol | riscwrite_eol | bsize | riscirq |
13723ff48bf5SDavid du Colombier ((i & 0xf) << risclabelshift_set) |
13733ff48bf5SDavid du Colombier ((~i & 0xf) << risclabelshift_reset);
13744de34a7eSDavid du Colombier *p++ = pa + i * bsize;
13753ff48bf5SDavid du Colombier }
13763ff48bf5SDavid du Colombier
13773ff48bf5SDavid du Colombier *p++ = riscsync | riscsync_vro;
13783ff48bf5SDavid du Colombier *p++ = 0;
13793ff48bf5SDavid du Colombier *p++ = riscjmp;
13803ff48bf5SDavid du Colombier *p++ = PADDR(pbase);
13813ff48bf5SDavid du Colombier USED(p);
13823ff48bf5SDavid du Colombier
13833ff48bf5SDavid du Colombier return pbase;
13843ff48bf5SDavid du Colombier }
13853ff48bf5SDavid du Colombier
13863ff48bf5SDavid du Colombier
13879a747e4fSDavid du Colombier static void
vactivate(Tv * tv,Frame * frames,int nframes)13889a747e4fSDavid du Colombier vactivate(Tv *tv, Frame *frames, int nframes)
13899a747e4fSDavid du Colombier {
13909a747e4fSDavid du Colombier Bt848 *bt848 = tv->bt848;
13919a747e4fSDavid du Colombier
13929a747e4fSDavid du Colombier ilock(tv);
13939a747e4fSDavid du Colombier if (tv->frames) {
13949a747e4fSDavid du Colombier iunlock(tv);
13959a747e4fSDavid du Colombier error(Einuse);
13969a747e4fSDavid du Colombier }
13979a747e4fSDavid du Colombier poperror();
13989a747e4fSDavid du Colombier
13999a747e4fSDavid du Colombier tv->frames = frames;
14009a747e4fSDavid du Colombier tv->nframes = nframes;
14019a747e4fSDavid du Colombier
14029a747e4fSDavid du Colombier bt848->riscstrtadd = PADDR(tv->frames[0].fstart);
14039a747e4fSDavid du Colombier bt848->capctl |= capctl_captureodd|capctl_captureeven;
14049a747e4fSDavid du Colombier bt848->gpiodmactl |= gpiodmactl_fifoenable;
14059a747e4fSDavid du Colombier bt848->gpiodmactl |= gpiodmactl_riscenable;
14069a747e4fSDavid du Colombier
14079a747e4fSDavid du Colombier iunlock(tv);
14089a747e4fSDavid du Colombier }
14099a747e4fSDavid du Colombier
14109a747e4fSDavid du Colombier static void
vstart(Tv * tv,int nframes,int w,int h,int stride)14119a747e4fSDavid du Colombier vstart(Tv *tv, int nframes, int w, int h, int stride)
14129a747e4fSDavid du Colombier {
14139a747e4fSDavid du Colombier Frame *frames;
14143ff48bf5SDavid du Colombier int bitspp, i, bpf;
14159a747e4fSDavid du Colombier
14169a747e4fSDavid du Colombier if (nframes >= 0x10)
14179a747e4fSDavid du Colombier error(Ebadarg);
14189a747e4fSDavid du Colombier
14193ff48bf5SDavid du Colombier bitspp = getbitspp(tv);
14203ff48bf5SDavid du Colombier bpf = w * h * bitspp / 8;
14219a747e4fSDavid du Colombier
142241dd6b47SDavid du Colombier /* Add one as a spare. */
14239a747e4fSDavid du Colombier frames = (Frame *)malloc(nframes * sizeof(Frame));
14249a747e4fSDavid du Colombier assert(frames);
14259a747e4fSDavid du Colombier if (waserror()) {
14269a747e4fSDavid du Colombier for (i = 0; i != nframes; i++)
14279a747e4fSDavid du Colombier if (frames[i].fbase)
14289a747e4fSDavid du Colombier free(frames[i].fbase);
14299a747e4fSDavid du Colombier free(frames);
14309a747e4fSDavid du Colombier nexterror();
14319a747e4fSDavid du Colombier }
14329a747e4fSDavid du Colombier memset(frames, 0, nframes * sizeof(Frame));
14339a747e4fSDavid du Colombier
14349a747e4fSDavid du Colombier for (i = 0; i != nframes; i++) {
14359a747e4fSDavid du Colombier if ((frames[i].fbase = (uchar *)malloc(bpf)) == nil)
14369a747e4fSDavid du Colombier error(Enomem);
14379a747e4fSDavid du Colombier
14383ff48bf5SDavid du Colombier switch (tv->cfmt) {
14393ff48bf5SDavid du Colombier case colorfmt_YCbCr422:
144041dd6b47SDavid du Colombier frames[i].fstart = riscplanar422(PADDR(frames[i].fbase), i, w, h, &frames[i].fjmp);
14413ff48bf5SDavid du Colombier break;
14423ff48bf5SDavid du Colombier case colorfmt_YCbCr411:
144341dd6b47SDavid du Colombier frames[i].fstart = riscplanar411(PADDR(frames[i].fbase),
144441dd6b47SDavid du Colombier i, w, h, &frames[i].fjmp);
14453ff48bf5SDavid du Colombier break;
14463ff48bf5SDavid du Colombier case colorfmt_rgb16:
14473ff48bf5SDavid du Colombier frames[i].fstart = riscpacked(PADDR(frames[i].fbase), i,
14483ff48bf5SDavid du Colombier w * bitspp / 8, h, stride * bitspp / 8,
14499a747e4fSDavid du Colombier &frames[i].fjmp);
14503ff48bf5SDavid du Colombier break;
14513ff48bf5SDavid du Colombier default:
14523ff48bf5SDavid du Colombier panic("vstart: Unsupport colorformat\n");
14533ff48bf5SDavid du Colombier }
14549a747e4fSDavid du Colombier }
14559a747e4fSDavid du Colombier
14569a747e4fSDavid du Colombier for (i = 0; i != nframes; i++)
145741dd6b47SDavid du Colombier *frames[i].fjmp = PADDR(i == nframes - 1? frames[0].fstart:
145841dd6b47SDavid du Colombier frames[i + 1].fstart);
14599a747e4fSDavid du Colombier
14609a747e4fSDavid du Colombier vactivate(tv, frames, nframes);
14619a747e4fSDavid du Colombier }
14629a747e4fSDavid du Colombier
14639a747e4fSDavid du Colombier static void
astart(Tv * tv,char * input,uint rate,uint nab,uint nasz)14643ff48bf5SDavid du Colombier astart(Tv *tv, char *input, uint rate, uint nab, uint nasz)
14653ff48bf5SDavid du Colombier {
14663ff48bf5SDavid du Colombier Bt848 *bt878 = tv->bt878;
14673ff48bf5SDavid du Colombier ulong *arisc;
14683ff48bf5SDavid du Colombier int selector;
14693ff48bf5SDavid du Colombier uchar *abuf;
14703ff48bf5SDavid du Colombier int s, d;
14713ff48bf5SDavid du Colombier
14723ff48bf5SDavid du Colombier if (bt878 == nil || tv->amux == nil)
14733ff48bf5SDavid du Colombier error("#V: Card does not support audio");
14743ff48bf5SDavid du Colombier
14753ff48bf5SDavid du Colombier selector = 0;
14763ff48bf5SDavid du Colombier if (!strcmp(input, "tv"))
14773ff48bf5SDavid du Colombier selector = asel_tv;
14783ff48bf5SDavid du Colombier else if (!strcmp(input, "radio"))
14793ff48bf5SDavid du Colombier selector = asel_radio;
14803ff48bf5SDavid du Colombier else if (!strcmp(input, "mic"))
14813ff48bf5SDavid du Colombier selector = asel_mic;
14823ff48bf5SDavid du Colombier else if (!strcmp(input, "smxc"))
14833ff48bf5SDavid du Colombier selector = asel_smxc;
14843ff48bf5SDavid du Colombier else
14853ff48bf5SDavid du Colombier error("#V: Invalid input");
14863ff48bf5SDavid du Colombier
14873ff48bf5SDavid du Colombier if (nasz > 0xfff)
14883ff48bf5SDavid du Colombier error("#V: Audio block size too big (max 0xfff)");
14893ff48bf5SDavid du Colombier
14903ff48bf5SDavid du Colombier abuf = (uchar *)malloc(nab * nasz * sizeof(uchar));
14913ff48bf5SDavid du Colombier assert(abuf);
14923ff48bf5SDavid du Colombier arisc = riscaudio(PADDR(abuf), nab, nasz);
14933ff48bf5SDavid du Colombier
14943ff48bf5SDavid du Colombier ilock(tv);
14953ff48bf5SDavid du Colombier if (tv->arisc) {
14963ff48bf5SDavid du Colombier iunlock(tv);
14973ff48bf5SDavid du Colombier free(abuf);
14983ff48bf5SDavid du Colombier free(arisc);
14993ff48bf5SDavid du Colombier error(Einuse);
15003ff48bf5SDavid du Colombier }
15013ff48bf5SDavid du Colombier
15023ff48bf5SDavid du Colombier tv->arisc = arisc;
15033ff48bf5SDavid du Colombier tv->abuf = abuf;
15043ff48bf5SDavid du Colombier tv->nablocks = nab;
15053ff48bf5SDavid du Colombier tv->absize = nasz;
15063ff48bf5SDavid du Colombier
15073ff48bf5SDavid du Colombier bt878->riscstrtadd = PADDR(tv->arisc);
15083ff48bf5SDavid du Colombier bt878->packetlen = (nab << 16) | nasz;
150941dd6b47SDavid du Colombier bt878->intmask = intstat_scerr | intstat_ocerr | intstat_risci |
15103ff48bf5SDavid du Colombier intstat_pabort | intstat_riperr | intstat_pperr |
15113ff48bf5SDavid du Colombier intstat_fdsr | intstat_ftrgt | intstat_fbus;
15123ff48bf5SDavid du Colombier
15133ff48bf5SDavid du Colombier /* Assume analog, 16bpp */
15143ff48bf5SDavid du Colombier for (s = 0; s < 16; s++)
15153ff48bf5SDavid du Colombier if (rate << s > Hwbase_ad * 4 / 15)
15163ff48bf5SDavid du Colombier break;
15173ff48bf5SDavid du Colombier for (d = 15; d >= 4; d--)
15183ff48bf5SDavid du Colombier if (rate << s < Hwbase_ad * 4 / d)
15193ff48bf5SDavid du Colombier break;
15203ff48bf5SDavid du Colombier
15213ff48bf5SDavid du Colombier print("astart: sampleshift %d, decimation %d\n", s, d);
15223ff48bf5SDavid du Colombier
15233ff48bf5SDavid du Colombier tv->narblocks = 0;
15243ff48bf5SDavid du Colombier bt878->gpiodmactl = gpiodmactl_fifoenable |
15253ff48bf5SDavid du Colombier gpiodmactl_riscenable | gpiodmactl_acapenable |
15263ff48bf5SDavid du Colombier gpiodmactl_daes2 | /* gpiodmactl_apwrdn | */
152741dd6b47SDavid du Colombier gpiodmactl_daiomda | d << 8 | 9 << 28 | selector << 24;
15283ff48bf5SDavid du Colombier print("dmactl %.8ulX\n", bt878->gpiodmactl);
15293ff48bf5SDavid du Colombier iunlock(tv);
15303ff48bf5SDavid du Colombier }
15313ff48bf5SDavid du Colombier
15323ff48bf5SDavid du Colombier static void
astop(Tv * tv)15333ff48bf5SDavid du Colombier astop(Tv *tv)
15343ff48bf5SDavid du Colombier {
15353ff48bf5SDavid du Colombier Bt848 *bt878 = tv->bt878;
15363ff48bf5SDavid du Colombier
15373ff48bf5SDavid du Colombier ilock(tv);
15383ff48bf5SDavid du Colombier if (tv->aref.ref > 0) {
15393ff48bf5SDavid du Colombier iunlock(tv);
15403ff48bf5SDavid du Colombier error(Einuse);
15413ff48bf5SDavid du Colombier }
15423ff48bf5SDavid du Colombier
15433ff48bf5SDavid du Colombier if (tv->abuf) {
15443ff48bf5SDavid du Colombier bt878->gpiodmactl &= ~gpiodmactl_riscenable;
15453ff48bf5SDavid du Colombier bt878->gpiodmactl &= ~gpiodmactl_fifoenable;
15463ff48bf5SDavid du Colombier
15473ff48bf5SDavid du Colombier free(tv->abuf);
15483ff48bf5SDavid du Colombier tv->abuf = nil;
15493ff48bf5SDavid du Colombier free(tv->arisc);
15503ff48bf5SDavid du Colombier tv->arisc = nil;
15513ff48bf5SDavid du Colombier }
15523ff48bf5SDavid du Colombier iunlock(tv);
15533ff48bf5SDavid du Colombier }
15543ff48bf5SDavid du Colombier
15553ff48bf5SDavid du Colombier static void
vgastart(Tv * tv,ulong pa,int stride)15564de34a7eSDavid du Colombier vgastart(Tv *tv, ulong pa, int stride)
15579a747e4fSDavid du Colombier {
15589a747e4fSDavid du Colombier Frame *frame;
15599a747e4fSDavid du Colombier
15609a747e4fSDavid du Colombier frame = (Frame *)malloc(sizeof(Frame));
15619a747e4fSDavid du Colombier assert(frame);
15629a747e4fSDavid du Colombier if (waserror()) {
15639a747e4fSDavid du Colombier free(frame);
15649a747e4fSDavid du Colombier nexterror();
15659a747e4fSDavid du Colombier }
15669a747e4fSDavid du Colombier
15679a747e4fSDavid du Colombier frame->fbase = nil;
15684de34a7eSDavid du Colombier frame->fstart = riscpacked(pa, 0, ntsc_hactive * getbitspp(tv) / 8,
156941dd6b47SDavid du Colombier ntsc_vactive, stride * getbitspp(tv) / 8, &frame->fjmp);
15709a747e4fSDavid du Colombier *frame->fjmp = PADDR(frame->fstart);
15719a747e4fSDavid du Colombier
15729a747e4fSDavid du Colombier vactivate(tv, frame, 1);
15739a747e4fSDavid du Colombier }
15749a747e4fSDavid du Colombier
15759a747e4fSDavid du Colombier static void
vstop(Tv * tv)15769a747e4fSDavid du Colombier vstop(Tv *tv)
15779a747e4fSDavid du Colombier {
15789a747e4fSDavid du Colombier Bt848 *bt848 = tv->bt848;
15799a747e4fSDavid du Colombier
15809a747e4fSDavid du Colombier ilock(tv);
15819a747e4fSDavid du Colombier if (tv->fref.ref > 0) {
15829a747e4fSDavid du Colombier iunlock(tv);
15839a747e4fSDavid du Colombier error(Einuse);
15849a747e4fSDavid du Colombier }
15859a747e4fSDavid du Colombier
15869a747e4fSDavid du Colombier if (tv->frames) {
15879a747e4fSDavid du Colombier int i;
15889a747e4fSDavid du Colombier
15899a747e4fSDavid du Colombier bt848->gpiodmactl &= ~gpiodmactl_riscenable;
15909a747e4fSDavid du Colombier bt848->gpiodmactl &= ~gpiodmactl_fifoenable;
15919a747e4fSDavid du Colombier bt848->capctl &= ~(capctl_captureodd|capctl_captureeven);
15929a747e4fSDavid du Colombier
15939a747e4fSDavid du Colombier for (i = 0; i != tv->nframes; i++)
15949a747e4fSDavid du Colombier if (tv->frames[i].fbase)
15959a747e4fSDavid du Colombier free(tv->frames[i].fbase);
15969a747e4fSDavid du Colombier free(tv->frames);
15979a747e4fSDavid du Colombier tv->frames = nil;
15989a747e4fSDavid du Colombier }
15999a747e4fSDavid du Colombier iunlock(tv);
16009a747e4fSDavid du Colombier }
16019a747e4fSDavid du Colombier
160241dd6b47SDavid du Colombier static long hrcfreq[] = { /* HRC CATV frequencies */
16039a747e4fSDavid du Colombier 0, 7200, 5400, 6000, 6600, 7800, 8400, 17400,
16049a747e4fSDavid du Colombier 18000, 18600, 19200, 19800, 20400, 21000, 12000, 12600,
16059a747e4fSDavid du Colombier 13200, 13800, 14400, 15000, 15600, 16200, 16800, 21600,
16069a747e4fSDavid du Colombier 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400,
16079a747e4fSDavid du Colombier 27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200,
16089a747e4fSDavid du Colombier 31800, 32400, 33000, 33600, 34200, 34800, 35400, 36000,
16099a747e4fSDavid du Colombier 36600, 37200, 37800, 38400, 39000, 39600, 40200, 40800,
16109a747e4fSDavid du Colombier 41400, 42000, 42600, 43200, 43800, 44400, 45000, 45600,
16119a747e4fSDavid du Colombier 46200, 46800, 47400, 48000, 48600, 49200, 49800, 50400,
16129a747e4fSDavid du Colombier 51000, 51600, 52200, 52800, 53400, 54000, 54600, 55200,
16139a747e4fSDavid du Colombier 55800, 56400, 57000, 57600, 58200, 58800, 59400, 60000,
16149a747e4fSDavid du Colombier 60600, 61200, 61800, 62400, 63000, 63600, 64200, 9000,
16159a747e4fSDavid du Colombier 9600, 10200, 10800, 11400, 64800, 65400, 66000, 66600,
16169a747e4fSDavid du Colombier 67200, 67800, 68400, 69000, 69600, 70200, 70800, 71400,
16179a747e4fSDavid du Colombier 72000, 72600, 73200, 73800, 74400, 75000, 75600, 76200,
16189a747e4fSDavid du Colombier 76800, 77400, 78000, 78600, 79200, 79800,
16199a747e4fSDavid du Colombier };
16209a747e4fSDavid du Colombier
16219a747e4fSDavid du Colombier static void
frequency(Tv * tv,int channel,int finetune)16229a747e4fSDavid du Colombier frequency(Tv *tv, int channel, int finetune)
16239a747e4fSDavid du Colombier {
16249a747e4fSDavid du Colombier Tuner *tuner = tv->tuner;
16259a747e4fSDavid du Colombier long freq;
16269a747e4fSDavid du Colombier ushort div;
16279a747e4fSDavid du Colombier uchar cfg;
16289a747e4fSDavid du Colombier
16299a747e4fSDavid du Colombier if (channel < 0 || channel > nelem(hrcfreq))
16309a747e4fSDavid du Colombier error(Ebadarg);
16319a747e4fSDavid du Colombier
16329a747e4fSDavid du Colombier freq = (hrcfreq[channel] * Freqmultiplier) / 100;
16339a747e4fSDavid du Colombier
16349a747e4fSDavid du Colombier if (freq < tuner->freq_vhfh)
16359a747e4fSDavid du Colombier cfg = tuner->VHF_L;
16369a747e4fSDavid du Colombier else if (freq < tuner->freq_uhf)
16379a747e4fSDavid du Colombier cfg = tuner->VHF_H;
16389a747e4fSDavid du Colombier else
16399a747e4fSDavid du Colombier cfg = tuner->UHF;
16409a747e4fSDavid du Colombier
16419a747e4fSDavid du Colombier div = (freq + tuner->offs + finetune) & 0x7fff;
16429a747e4fSDavid du Colombier
16433ff48bf5SDavid du Colombier if (!i2cwrite(tv, tv->i2ctuneraddr, (div >> 8) & 0x7f, div, 1))
16449a747e4fSDavid du Colombier error(Eio);
16459a747e4fSDavid du Colombier
16463ff48bf5SDavid du Colombier if (!i2cwrite(tv, tv->i2ctuneraddr, tuner->cfg, cfg, 1))
16479a747e4fSDavid du Colombier error(Eio);
16483ff48bf5SDavid du Colombier
16493ff48bf5SDavid du Colombier tv->channel = channel;
16503ff48bf5SDavid du Colombier if (tv->msp)
16513ff48bf5SDavid du Colombier msptune(tv);
16523ff48bf5SDavid du Colombier }
16533ff48bf5SDavid du Colombier
16543ff48bf5SDavid du Colombier static struct {
16553ff48bf5SDavid du Colombier char *cmode;
16563ff48bf5SDavid du Colombier ulong realmode;
16573ff48bf5SDavid du Colombier ulong cbits;
16583ff48bf5SDavid du Colombier } colormodes[] = {
16593ff48bf5SDavid du Colombier { "RGB16", colorfmt_rgb16, colorfmt_rgb16, },
16603ff48bf5SDavid du Colombier { "YCbCr422", colorfmt_YCbCr422, colorfmt_YCbCr422, },
16613ff48bf5SDavid du Colombier { "YCbCr411", colorfmt_YCbCr411, colorfmt_YCbCr422, },
16623ff48bf5SDavid du Colombier };
16633ff48bf5SDavid du Colombier
16643ff48bf5SDavid du Colombier static void
colormode(Tv * tv,char * colormode)16653ff48bf5SDavid du Colombier colormode(Tv *tv, char *colormode)
16663ff48bf5SDavid du Colombier {
16673ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
16683ff48bf5SDavid du Colombier int i;
16693ff48bf5SDavid du Colombier
16703ff48bf5SDavid du Colombier for (i = 0; i != nelem(colormodes); i++)
16713ff48bf5SDavid du Colombier if (!strcmp(colormodes[i].cmode, colormode))
16723ff48bf5SDavid du Colombier break;
16733ff48bf5SDavid du Colombier
16743ff48bf5SDavid du Colombier if (i == nelem(colormodes))
16753ff48bf5SDavid du Colombier error(Ebadarg);
16763ff48bf5SDavid du Colombier
16773ff48bf5SDavid du Colombier tv->cfmt = colormodes[i].realmode;
16783ff48bf5SDavid du Colombier bt848->colorfmt = colormodes[i].cbits;
16799a747e4fSDavid du Colombier }
16809a747e4fSDavid du Colombier
16819a747e4fSDavid du Colombier static int
getbitspp(Tv * tv)16823ff48bf5SDavid du Colombier getbitspp(Tv *tv)
16839a747e4fSDavid du Colombier {
16843ff48bf5SDavid du Colombier switch (tv->cfmt) {
16859a747e4fSDavid du Colombier case colorfmt_rgb16:
16863ff48bf5SDavid du Colombier case colorfmt_YCbCr422:
16873ff48bf5SDavid du Colombier return 16;
16883ff48bf5SDavid du Colombier case colorfmt_YCbCr411:
16893ff48bf5SDavid du Colombier return 12;
16909a747e4fSDavid du Colombier default:
16913ff48bf5SDavid du Colombier error("getbitspp: Unsupport color format\n");
16929a747e4fSDavid du Colombier }
16939a747e4fSDavid du Colombier return -1;
16949a747e4fSDavid du Colombier }
16959a747e4fSDavid du Colombier
16963ff48bf5SDavid du Colombier static char *
getcolormode(ulong cmode)16973ff48bf5SDavid du Colombier getcolormode(ulong cmode)
16983ff48bf5SDavid du Colombier {
16993ff48bf5SDavid du Colombier switch (cmode) {
17003ff48bf5SDavid du Colombier case colorfmt_rgb16:
17013ff48bf5SDavid du Colombier return "RGB16";
17023ff48bf5SDavid du Colombier case colorfmt_YCbCr411:
17033ff48bf5SDavid du Colombier return "YCbCr411";
17043ff48bf5SDavid du Colombier case colorfmt_YCbCr422:
17053ff48bf5SDavid du Colombier return (cmode == colorfmt_YCbCr422)? "YCbCr422": "YCbCr411";
17063ff48bf5SDavid du Colombier default:
17073ff48bf5SDavid du Colombier error("getcolormode: Unsupport color format\n");
17083ff48bf5SDavid du Colombier }
17093ff48bf5SDavid du Colombier return nil;
17103ff48bf5SDavid du Colombier }
17113ff48bf5SDavid du Colombier
17123ff48bf5SDavid du Colombier static void
i2c_set(Tv * tv,int scl,int sda)17133ff48bf5SDavid du Colombier i2c_set(Tv *tv, int scl, int sda)
17143ff48bf5SDavid du Colombier {
17153ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
17163ff48bf5SDavid du Colombier ulong d;
17173ff48bf5SDavid du Colombier
17183ff48bf5SDavid du Colombier bt848->i2c = (scl << 1) | sda;
17193ff48bf5SDavid du Colombier d = bt848->i2c;
17203ff48bf5SDavid du Colombier USED(d);
17213ff48bf5SDavid du Colombier microdelay(i2c_delay);
17223ff48bf5SDavid du Colombier }
17233ff48bf5SDavid du Colombier
17243ff48bf5SDavid du Colombier static uchar
i2c_getsda(Tv * tv)17253ff48bf5SDavid du Colombier i2c_getsda(Tv *tv)
17263ff48bf5SDavid du Colombier {
17273ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
17283ff48bf5SDavid du Colombier
17293ff48bf5SDavid du Colombier return bt848->i2c & i2c_sda;
17303ff48bf5SDavid du Colombier }
17313ff48bf5SDavid du Colombier
17323ff48bf5SDavid du Colombier static void
i2c_start(Tv * tv)17333ff48bf5SDavid du Colombier i2c_start(Tv *tv)
17343ff48bf5SDavid du Colombier {
17353ff48bf5SDavid du Colombier i2c_set(tv, 0, 1);
17363ff48bf5SDavid du Colombier i2c_set(tv, 1, 1);
17373ff48bf5SDavid du Colombier i2c_set(tv, 1, 0);
17383ff48bf5SDavid du Colombier i2c_set(tv, 0, 0);
17393ff48bf5SDavid du Colombier }
17403ff48bf5SDavid du Colombier
17413ff48bf5SDavid du Colombier static void
i2c_stop(Tv * tv)17423ff48bf5SDavid du Colombier i2c_stop(Tv *tv)
17433ff48bf5SDavid du Colombier {
17443ff48bf5SDavid du Colombier i2c_set(tv, 0, 0);
17453ff48bf5SDavid du Colombier i2c_set(tv, 1, 0);
17463ff48bf5SDavid du Colombier i2c_set(tv, 1, 1);
17473ff48bf5SDavid du Colombier }
17483ff48bf5SDavid du Colombier
17493ff48bf5SDavid du Colombier static void
i2c_bit(Tv * tv,int sda)17503ff48bf5SDavid du Colombier i2c_bit(Tv *tv, int sda)
17513ff48bf5SDavid du Colombier {
17523ff48bf5SDavid du Colombier i2c_set(tv, 0, sda);
17533ff48bf5SDavid du Colombier i2c_set(tv, 1, sda);
17543ff48bf5SDavid du Colombier i2c_set(tv, 0, sda);
17553ff48bf5SDavid du Colombier }
17563ff48bf5SDavid du Colombier
17573ff48bf5SDavid du Colombier static int
i2c_getack(Tv * tv)17583ff48bf5SDavid du Colombier i2c_getack(Tv *tv)
17593ff48bf5SDavid du Colombier {
17603ff48bf5SDavid du Colombier int ack;
17613ff48bf5SDavid du Colombier
17623ff48bf5SDavid du Colombier i2c_set(tv, 0, 1);
17633ff48bf5SDavid du Colombier i2c_set(tv, 1, 1);
17643ff48bf5SDavid du Colombier ack = i2c_getsda(tv);
17653ff48bf5SDavid du Colombier i2c_set(tv, 0, 1);
17663ff48bf5SDavid du Colombier return ack;
17673ff48bf5SDavid du Colombier }
17683ff48bf5SDavid du Colombier
17693ff48bf5SDavid du Colombier static int
i2c_wr8(Tv * tv,uchar d,int wait)17703ff48bf5SDavid du Colombier i2c_wr8(Tv *tv, uchar d, int wait)
17713ff48bf5SDavid du Colombier {
17723ff48bf5SDavid du Colombier int i, ack;
17733ff48bf5SDavid du Colombier
17743ff48bf5SDavid du Colombier i2c_set(tv, 0, 0);
17753ff48bf5SDavid du Colombier for (i = 0; i != 8; i++) {
17763ff48bf5SDavid du Colombier i2c_bit(tv, (d & 0x80)? 1: 0);
17773ff48bf5SDavid du Colombier d <<= 1;
17783ff48bf5SDavid du Colombier }
17793ff48bf5SDavid du Colombier if (wait)
17803ff48bf5SDavid du Colombier microdelay(wait);
17813ff48bf5SDavid du Colombier
17823ff48bf5SDavid du Colombier ack = i2c_getack(tv);
17833ff48bf5SDavid du Colombier return ack == 0;
17843ff48bf5SDavid du Colombier }
17853ff48bf5SDavid du Colombier
17863ff48bf5SDavid du Colombier static uchar
i2c_rd8(Tv * tv,int lastbyte)17873ff48bf5SDavid du Colombier i2c_rd8(Tv *tv, int lastbyte)
17883ff48bf5SDavid du Colombier {
17893ff48bf5SDavid du Colombier int i;
17903ff48bf5SDavid du Colombier uchar d;
17913ff48bf5SDavid du Colombier
17923ff48bf5SDavid du Colombier d = 0;
17933ff48bf5SDavid du Colombier i2c_set(tv, 0, 1);
17943ff48bf5SDavid du Colombier for (i = 0; i != 8; i++) {
17953ff48bf5SDavid du Colombier i2c_set(tv, 1, 1);
17963ff48bf5SDavid du Colombier d <<= 1;
17973ff48bf5SDavid du Colombier if (i2c_getsda(tv))
17983ff48bf5SDavid du Colombier d |= 1;
17993ff48bf5SDavid du Colombier i2c_set(tv, 0, 1);
18003ff48bf5SDavid du Colombier }
18013ff48bf5SDavid du Colombier
18023ff48bf5SDavid du Colombier i2c_bit(tv, lastbyte? 1: 0);
18033ff48bf5SDavid du Colombier return d;
18043ff48bf5SDavid du Colombier }
18053ff48bf5SDavid du Colombier
18063ff48bf5SDavid du Colombier static int
mspsend(Tv * tv,uchar * cmd,int ncmd)18073ff48bf5SDavid du Colombier mspsend(Tv *tv, uchar *cmd, int ncmd)
18083ff48bf5SDavid du Colombier {
18093ff48bf5SDavid du Colombier int i, j, delay;
18103ff48bf5SDavid du Colombier
18113ff48bf5SDavid du Colombier for (i = 0; i != 3; i++) {
18123ff48bf5SDavid du Colombier delay = 2000;
18133ff48bf5SDavid du Colombier
18143ff48bf5SDavid du Colombier i2c_start(tv);
18153ff48bf5SDavid du Colombier for (j = 0; j != ncmd; j++) {
18163ff48bf5SDavid du Colombier if (!i2c_wr8(tv, cmd[j], delay))
18173ff48bf5SDavid du Colombier break;
18183ff48bf5SDavid du Colombier delay = 0;
18193ff48bf5SDavid du Colombier }
18203ff48bf5SDavid du Colombier i2c_stop(tv);
18213ff48bf5SDavid du Colombier
18223ff48bf5SDavid du Colombier if (j == ncmd)
18233ff48bf5SDavid du Colombier return 1;
18243ff48bf5SDavid du Colombier
18253ff48bf5SDavid du Colombier microdelay(10000);
18263ff48bf5SDavid du Colombier print("mspsend: retrying\n");
18273ff48bf5SDavid du Colombier }
18283ff48bf5SDavid du Colombier
18293ff48bf5SDavid du Colombier return 0;
18303ff48bf5SDavid du Colombier }
18313ff48bf5SDavid du Colombier
18323ff48bf5SDavid du Colombier static int
mspwrite(Tv * tv,uchar sub,ushort reg,ushort v)18333ff48bf5SDavid du Colombier mspwrite(Tv *tv, uchar sub, ushort reg, ushort v)
18343ff48bf5SDavid du Colombier {
18353ff48bf5SDavid du Colombier uchar b[6];
18363ff48bf5SDavid du Colombier
18373ff48bf5SDavid du Colombier b[0] = i2c_msp3400;
18383ff48bf5SDavid du Colombier b[1] = sub;
18393ff48bf5SDavid du Colombier b[2] = reg >> 8;
18403ff48bf5SDavid du Colombier b[3] = reg;
18413ff48bf5SDavid du Colombier b[4] = v >> 8;
18423ff48bf5SDavid du Colombier b[5] = v;
18433ff48bf5SDavid du Colombier return mspsend(tv, b, sizeof b);
18443ff48bf5SDavid du Colombier }
18453ff48bf5SDavid du Colombier
18463ff48bf5SDavid du Colombier static int
mspread(Tv * tv,uchar sub,ushort reg,ushort * data)18473ff48bf5SDavid du Colombier mspread(Tv *tv, uchar sub, ushort reg, ushort *data)
18483ff48bf5SDavid du Colombier {
18493ff48bf5SDavid du Colombier uchar b[4];
18503ff48bf5SDavid du Colombier int i;
18513ff48bf5SDavid du Colombier
18523ff48bf5SDavid du Colombier b[0] = i2c_msp3400;
18533ff48bf5SDavid du Colombier b[1] = sub;
18543ff48bf5SDavid du Colombier b[2] = reg >> 8;
18553ff48bf5SDavid du Colombier b[3] = reg;
18563ff48bf5SDavid du Colombier
18573ff48bf5SDavid du Colombier for (i = 0; i != 3; i++) {
18583ff48bf5SDavid du Colombier i2c_start(tv);
18593ff48bf5SDavid du Colombier if (!i2c_wr8(tv, b[0], 2000) ||
18603ff48bf5SDavid du Colombier !i2c_wr8(tv, b[1] | 1, 0) ||
18613ff48bf5SDavid du Colombier !i2c_wr8(tv, b[2], 0) ||
18623ff48bf5SDavid du Colombier !i2c_wr8(tv, b[3], 0)) {
18633ff48bf5SDavid du Colombier
18643ff48bf5SDavid du Colombier i2c_stop(tv);
18653ff48bf5SDavid du Colombier microdelay(10000);
18663ff48bf5SDavid du Colombier print("retrying\n");
18673ff48bf5SDavid du Colombier continue;
18683ff48bf5SDavid du Colombier }
18693ff48bf5SDavid du Colombier
18703ff48bf5SDavid du Colombier i2c_start(tv);
18713ff48bf5SDavid du Colombier
18723ff48bf5SDavid du Colombier if (!i2c_wr8(tv, b[0] | 1, 2000)) {
18733ff48bf5SDavid du Colombier i2c_stop(tv);
18743ff48bf5SDavid du Colombier continue;
18753ff48bf5SDavid du Colombier }
18763ff48bf5SDavid du Colombier
18773ff48bf5SDavid du Colombier *data = i2c_rd8(tv, 0) << 8;
18783ff48bf5SDavid du Colombier *data |= i2c_rd8(tv, 1);
18793ff48bf5SDavid du Colombier i2c_stop(tv);
18803ff48bf5SDavid du Colombier return 1;
18813ff48bf5SDavid du Colombier }
18823ff48bf5SDavid du Colombier return 0;
18833ff48bf5SDavid du Colombier }
18843ff48bf5SDavid du Colombier
18853ff48bf5SDavid du Colombier static uchar mspt_reset[] = { i2c_msp3400, 0, 0x80, 0 };
18863ff48bf5SDavid du Colombier static uchar mspt_on[] = { i2c_msp3400, 0, 0, 0 };
18873ff48bf5SDavid du Colombier
18883ff48bf5SDavid du Colombier static int
mspreset(Tv * tv)18893ff48bf5SDavid du Colombier mspreset(Tv *tv)
18903ff48bf5SDavid du Colombier {
18913ff48bf5SDavid du Colombier ushort v, p;
18923ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
18933ff48bf5SDavid du Colombier ulong b;
18943ff48bf5SDavid du Colombier
18953ff48bf5SDavid du Colombier b = 1 << 5;
18963ff48bf5SDavid du Colombier gpioenable(tv, ~b, b);
18973ff48bf5SDavid du Colombier gpiowrite(tv, ~b, 0);
18983ff48bf5SDavid du Colombier microdelay(2500);
18993ff48bf5SDavid du Colombier gpiowrite(tv, ~b, b);
19003ff48bf5SDavid du Colombier
19013ff48bf5SDavid du Colombier bt848->i2c = 0x80;
19023ff48bf5SDavid du Colombier
19033ff48bf5SDavid du Colombier microdelay(2000);
19043ff48bf5SDavid du Colombier mspsend(tv, mspt_reset, sizeof mspt_reset);
19053ff48bf5SDavid du Colombier
19063ff48bf5SDavid du Colombier microdelay(2000);
19073ff48bf5SDavid du Colombier if (!mspsend(tv, mspt_on, sizeof mspt_on)) {
19083ff48bf5SDavid du Colombier print("#V: Cannot find MSP34x5G on the I2C bus (on)\n");
19093ff48bf5SDavid du Colombier return 0;
19103ff48bf5SDavid du Colombier }
19113ff48bf5SDavid du Colombier microdelay(2000);
19123ff48bf5SDavid du Colombier
19133ff48bf5SDavid du Colombier if (!mspread(tv, msp_bbp, 0x001e, &v)) {
19143ff48bf5SDavid du Colombier print("#V: Cannot read MSP34xG5 chip version\n");
19153ff48bf5SDavid du Colombier return 0;
19163ff48bf5SDavid du Colombier }
19173ff48bf5SDavid du Colombier
19183ff48bf5SDavid du Colombier if (!mspread(tv, msp_bbp, 0x001f, &p)) {
19193ff48bf5SDavid du Colombier print("#V: Cannot read MSP34xG5 product code\n");
19203ff48bf5SDavid du Colombier return 0;
19213ff48bf5SDavid du Colombier }
19223ff48bf5SDavid du Colombier
19233ff48bf5SDavid du Colombier print("#V: MSP34%dg ROM %.d, %d.%d\n",
19243ff48bf5SDavid du Colombier (uchar)(p >> 8), (uchar)p, (uchar)(v >> 8), (uchar)v);
19253ff48bf5SDavid du Colombier
19263ff48bf5SDavid du Colombier tv->msp = 1;
19273ff48bf5SDavid du Colombier return 1;
19283ff48bf5SDavid du Colombier }
19293ff48bf5SDavid du Colombier
19303ff48bf5SDavid du Colombier static void
mspvolume(Tv * tv,int mute,int l,int r)19313ff48bf5SDavid du Colombier mspvolume(Tv *tv, int mute, int l, int r)
19323ff48bf5SDavid du Colombier {
19333ff48bf5SDavid du Colombier short v, d;
19343ff48bf5SDavid du Colombier ushort b;
19353ff48bf5SDavid du Colombier
19363ff48bf5SDavid du Colombier if (mute) {
19373ff48bf5SDavid du Colombier v = 0;
19383ff48bf5SDavid du Colombier b = 0;
19393ff48bf5SDavid du Colombier }
19403ff48bf5SDavid du Colombier else {
19413ff48bf5SDavid du Colombier tv->aleft = l;
19423ff48bf5SDavid du Colombier tv->aright = r;
19433ff48bf5SDavid du Colombier d = v = max(l, r);
19443ff48bf5SDavid du Colombier if (d == 0)
19453ff48bf5SDavid du Colombier d++;
19463ff48bf5SDavid du Colombier b = ((r - l) * 0x7f) / d;
19473ff48bf5SDavid du Colombier }
19483ff48bf5SDavid du Colombier
19493ff48bf5SDavid du Colombier mspwrite(tv, msp_bbp, 0, v << 8);
19503ff48bf5SDavid du Colombier mspwrite(tv, msp_bbp, 7, v? 0x4000: 0);
19513ff48bf5SDavid du Colombier mspwrite(tv, msp_bbp, 1, b << 8);
19523ff48bf5SDavid du Colombier }
19533ff48bf5SDavid du Colombier
19543ff48bf5SDavid du Colombier static char *
mspaformat(int f)19553ff48bf5SDavid du Colombier mspaformat(int f)
19563ff48bf5SDavid du Colombier {
19573ff48bf5SDavid du Colombier switch (f) {
19583ff48bf5SDavid du Colombier case 0:
19593ff48bf5SDavid du Colombier return "unknown";
19603ff48bf5SDavid du Colombier case 2:
19613ff48bf5SDavid du Colombier case 0x20:
19623ff48bf5SDavid du Colombier case 0x30:
19633ff48bf5SDavid du Colombier return "M-BTSC";
19643ff48bf5SDavid du Colombier case 3:
19653ff48bf5SDavid du Colombier return "B/G-FM";
19663ff48bf5SDavid du Colombier case 4:
19673ff48bf5SDavid du Colombier case 9:
19683ff48bf5SDavid du Colombier case 0xB:
19693ff48bf5SDavid du Colombier return "L-AM/NICAM D/Kn";
19703ff48bf5SDavid du Colombier case 8:
19713ff48bf5SDavid du Colombier return "B/G-NICAM";
19723ff48bf5SDavid du Colombier case 0xA:
19733ff48bf5SDavid du Colombier return "I";
19743ff48bf5SDavid du Colombier case 0x40:
19753ff48bf5SDavid du Colombier return "FM-Radio";
19763ff48bf5SDavid du Colombier }
19773ff48bf5SDavid du Colombier return "unknown format";
19783ff48bf5SDavid du Colombier }
19793ff48bf5SDavid du Colombier
19803ff48bf5SDavid du Colombier
19813ff48bf5SDavid du Colombier static void
msptune(Tv * tv)19823ff48bf5SDavid du Colombier msptune(Tv *tv)
19833ff48bf5SDavid du Colombier {
19843ff48bf5SDavid du Colombier ushort d, s, nicam;
19853ff48bf5SDavid du Colombier int i;
19863ff48bf5SDavid du Colombier
19873ff48bf5SDavid du Colombier mspvolume(tv, 1, 0, 0);
19883ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_dem, 0x0030, 0x2033))
19893ff48bf5SDavid du Colombier error("#V: Cannot set MODUS register");
19903ff48bf5SDavid du Colombier
19913ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_bbp, 0x0008, 0x0320))
19923ff48bf5SDavid du Colombier error("#V: Cannot set loadspeaker input");
19933ff48bf5SDavid du Colombier
19943ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_dem, 0x0040, 0x0001))
19953ff48bf5SDavid du Colombier error("#V: Cannot set I2S clock freq");
19963ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_bbp, 0x000d, 0x1900))
19973ff48bf5SDavid du Colombier error("#V: Cannot set SCART prescale");
19983ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_bbp, 0x000e, 0x2403))
19993ff48bf5SDavid du Colombier error("#V: Cannot set FM/AM prescale");
20003ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_bbp, 0x0010, 0x5a00))
20013ff48bf5SDavid du Colombier error("#V: Cannot set NICAM prescale");
20023ff48bf5SDavid du Colombier if (!mspwrite(tv, msp_dem, 0x0020, 0x0001))
20033ff48bf5SDavid du Colombier error("#V: Cannot start auto detect");
20043ff48bf5SDavid du Colombier
20053ff48bf5SDavid du Colombier for (d = (ushort)-1, i = 0; i != 10; i++) {
20063ff48bf5SDavid du Colombier if (!mspread(tv, msp_dem, 0x007e, &d))
20073ff48bf5SDavid du Colombier error("#V: Cannot get autodetect info MSP34xG5");
20083ff48bf5SDavid du Colombier
20093ff48bf5SDavid du Colombier if (d == 0 || d < 0x800)
20103ff48bf5SDavid du Colombier break;
20113ff48bf5SDavid du Colombier delay(50);
20123ff48bf5SDavid du Colombier }
20133ff48bf5SDavid du Colombier
20143ff48bf5SDavid du Colombier if (!mspread(tv, msp_dem, 0x0200, &s))
20153ff48bf5SDavid du Colombier error("#V: Cannot get status info MSP34xG5");
20163ff48bf5SDavid du Colombier
20173ff48bf5SDavid du Colombier mspvolume(tv, 0, tv->aleft, tv->aright);
20183ff48bf5SDavid du Colombier
20193ff48bf5SDavid du Colombier nicam = ((s >> 4) & 2) | ((s >> 9) & 1);
20203ff48bf5SDavid du Colombier snprint(tv->ainfo, sizeof tv->ainfo, "%s %s %s",
20213ff48bf5SDavid du Colombier mspaformat(d), (s & (1 << 6))? "stereo": "mono",
20223ff48bf5SDavid du Colombier nicamstate[nicam]);
20233ff48bf5SDavid du Colombier }
20243ff48bf5SDavid du Colombier
20253ff48bf5SDavid du Colombier static void
i2cscan(Tv * tv)20263ff48bf5SDavid du Colombier i2cscan(Tv *tv)
20273ff48bf5SDavid du Colombier {
20283ff48bf5SDavid du Colombier int i, ack;
20293ff48bf5SDavid du Colombier
20303ff48bf5SDavid du Colombier for (i = 0; i < 0x100; i += 2) {
20313ff48bf5SDavid du Colombier i2c_start(tv);
20323ff48bf5SDavid du Colombier ack = i2c_wr8(tv, i, 0);
20333ff48bf5SDavid du Colombier i2c_stop(tv);
203441dd6b47SDavid du Colombier if (ack)
20353ff48bf5SDavid du Colombier print("i2c device @%.2uX\n", i);
20363ff48bf5SDavid du Colombier }
20373ff48bf5SDavid du Colombier
20383ff48bf5SDavid du Colombier for (i = 0xf0; i != 0xff; i++) {
20393ff48bf5SDavid du Colombier i2c_start(tv);
20403ff48bf5SDavid du Colombier ack = i2c_wr8(tv, i, 0);
20413ff48bf5SDavid du Colombier i2c_stop(tv);
20423ff48bf5SDavid du Colombier if (ack)
20433ff48bf5SDavid du Colombier print("i2c device may be at @%.2uX\n", i);
20443ff48bf5SDavid du Colombier }
20453ff48bf5SDavid du Colombier }
20463ff48bf5SDavid du Colombier
20473ff48bf5SDavid du Colombier static void
gpioenable(Tv * tv,ulong mask,ulong data)20483ff48bf5SDavid du Colombier gpioenable(Tv *tv, ulong mask, ulong data)
20493ff48bf5SDavid du Colombier {
20503ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
20513ff48bf5SDavid du Colombier
20523ff48bf5SDavid du Colombier bt848->gpioouten = (bt848->gpioouten & mask) | data;
20533ff48bf5SDavid du Colombier }
20543ff48bf5SDavid du Colombier
20553ff48bf5SDavid du Colombier static void
gpiowrite(Tv * tv,ulong mask,ulong data)20563ff48bf5SDavid du Colombier gpiowrite(Tv *tv, ulong mask, ulong data)
20573ff48bf5SDavid du Colombier {
20583ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
20593ff48bf5SDavid du Colombier
20603ff48bf5SDavid du Colombier bt848->gpiodata[0] = (bt848->gpiodata[0] & mask) | data;
20613ff48bf5SDavid du Colombier }
20623ff48bf5SDavid du Colombier
20633ff48bf5SDavid du Colombier static void
alteraoutput(Tv * tv)20643ff48bf5SDavid du Colombier alteraoutput(Tv *tv)
20653ff48bf5SDavid du Colombier {
20663ff48bf5SDavid du Colombier if (tv->gpiostate == Gpiooutput)
20673ff48bf5SDavid du Colombier return;
20683ff48bf5SDavid du Colombier
20693ff48bf5SDavid du Colombier gpioenable(tv, ~0xffffff, 0x56ffff);
20703ff48bf5SDavid du Colombier microdelay(10);
20713ff48bf5SDavid du Colombier tv->gpiostate = Gpiooutput;
20723ff48bf5SDavid du Colombier }
20733ff48bf5SDavid du Colombier
20743ff48bf5SDavid du Colombier static void
alterainput(Tv * tv)20753ff48bf5SDavid du Colombier alterainput(Tv *tv)
20763ff48bf5SDavid du Colombier {
20773ff48bf5SDavid du Colombier if (tv->gpiostate == Gpioinput)
20783ff48bf5SDavid du Colombier return;
20793ff48bf5SDavid du Colombier
20803ff48bf5SDavid du Colombier gpioenable(tv, ~0xffffff, 0x570000);
20813ff48bf5SDavid du Colombier microdelay(10);
20823ff48bf5SDavid du Colombier tv->gpiostate = Gpioinput;
20833ff48bf5SDavid du Colombier }
20843ff48bf5SDavid du Colombier
20853ff48bf5SDavid du Colombier static void
alterareg(Tv * tv,ulong reg)20863ff48bf5SDavid du Colombier alterareg(Tv *tv, ulong reg)
20873ff48bf5SDavid du Colombier {
20883ff48bf5SDavid du Colombier if (tv->alterareg == reg)
20893ff48bf5SDavid du Colombier return;
20903ff48bf5SDavid du Colombier
20913ff48bf5SDavid du Colombier gpiowrite(tv, ~0x56ffff, (reg & 0x54ffff) | tv->alteraclock);
20923ff48bf5SDavid du Colombier microdelay(10);
20933ff48bf5SDavid du Colombier tv->alterareg = reg;
20943ff48bf5SDavid du Colombier }
20953ff48bf5SDavid du Colombier
20963ff48bf5SDavid du Colombier static void
alterawrite(Tv * tv,ulong reg,ushort data)20973ff48bf5SDavid du Colombier alterawrite(Tv *tv, ulong reg, ushort data)
20983ff48bf5SDavid du Colombier {
20993ff48bf5SDavid du Colombier alteraoutput(tv);
21003ff48bf5SDavid du Colombier alterareg(tv, reg);
21013ff48bf5SDavid du Colombier
21023ff48bf5SDavid du Colombier tv->alteraclock ^= 0x20000;
21033ff48bf5SDavid du Colombier gpiowrite(tv, ~0x56ffff, (reg & 0x540000) | data | tv->alteraclock);
21043ff48bf5SDavid du Colombier microdelay(10);
21053ff48bf5SDavid du Colombier }
21063ff48bf5SDavid du Colombier
21073ff48bf5SDavid du Colombier static void
alteraread(Tv * tv,int reg,ushort * data)21083ff48bf5SDavid du Colombier alteraread(Tv *tv, int reg, ushort *data)
21093ff48bf5SDavid du Colombier {
21103ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
21113ff48bf5SDavid du Colombier
21123ff48bf5SDavid du Colombier if (tv->alterareg != reg) {
21133ff48bf5SDavid du Colombier alteraoutput(tv);
21143ff48bf5SDavid du Colombier alterareg(tv, reg);
21153ff48bf5SDavid du Colombier }
21163ff48bf5SDavid du Colombier else {
21173ff48bf5SDavid du Colombier gpioenable(tv, ~0xffffff, 0x560000);
21183ff48bf5SDavid du Colombier microdelay(10);
21193ff48bf5SDavid du Colombier }
21203ff48bf5SDavid du Colombier
21213ff48bf5SDavid du Colombier alterainput(tv);
21223ff48bf5SDavid du Colombier gpiowrite(tv, ~0x570000, (reg & 0x560000) | tv->alteraclock);
21233ff48bf5SDavid du Colombier microdelay(10);
21243ff48bf5SDavid du Colombier *data = (ushort)bt848->gpiodata[0];
21253ff48bf5SDavid du Colombier microdelay(10);
21263ff48bf5SDavid du Colombier }
21273ff48bf5SDavid du Colombier
21283ff48bf5SDavid du Colombier static void
kfirloadu(Tv * tv,uchar * u,int ulen)21293ff48bf5SDavid du Colombier kfirloadu(Tv *tv, uchar *u, int ulen)
21303ff48bf5SDavid du Colombier {
21313ff48bf5SDavid du Colombier Bt848 *bt848 = tv->bt848;
21323ff48bf5SDavid du Colombier int i, j;
21333ff48bf5SDavid du Colombier
21343ff48bf5SDavid du Colombier ilock(&tv->kfirlock);
21353ff48bf5SDavid du Colombier bt848->gpioouten &= 0xff000000;
21363ff48bf5SDavid du Colombier bt848->gpioouten |= gpio_altera_data |
21373ff48bf5SDavid du Colombier gpio_altera_clock | gpio_altera_nconfig;
21383ff48bf5SDavid du Colombier bt848->gpiodata[0] &= 0xff000000;
21393ff48bf5SDavid du Colombier microdelay(10);
21403ff48bf5SDavid du Colombier bt848->gpiodata[0] |= gpio_altera_nconfig;
21413ff48bf5SDavid du Colombier microdelay(10);
21423ff48bf5SDavid du Colombier
214341dd6b47SDavid du Colombier /* Download the microcode */
21443ff48bf5SDavid du Colombier for (i = 0; i != ulen; i++)
21453ff48bf5SDavid du Colombier for (j = 0; j != 8; j++) {
21463ff48bf5SDavid du Colombier bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
21473ff48bf5SDavid du Colombier if (u[i] & 1)
21483ff48bf5SDavid du Colombier bt848->gpiodata[0] |= gpio_altera_data;
21493ff48bf5SDavid du Colombier bt848->gpiodata[0] |= gpio_altera_clock;
21503ff48bf5SDavid du Colombier u[i] >>= 1;
21513ff48bf5SDavid du Colombier }
21523ff48bf5SDavid du Colombier bt848->gpiodata[0] &= ~gpio_altera_clock;
21533ff48bf5SDavid du Colombier microdelay(100);
21543ff48bf5SDavid du Colombier
215541dd6b47SDavid du Colombier /* Initialize. */
21563ff48bf5SDavid du Colombier for (i = 0; i != 30; i++) {
21573ff48bf5SDavid du Colombier bt848->gpiodata[0] &= ~gpio_altera_clock;
21583ff48bf5SDavid du Colombier bt848->gpiodata[0] |= gpio_altera_clock;
21593ff48bf5SDavid du Colombier }
21603ff48bf5SDavid du Colombier bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
21613ff48bf5SDavid du Colombier iunlock(&tv->kfirlock);
21623ff48bf5SDavid du Colombier
21633ff48bf5SDavid du Colombier tv->gpiostate = Gpioinit;
21643ff48bf5SDavid du Colombier }
21653ff48bf5SDavid du Colombier
21663ff48bf5SDavid du Colombier static void
kfirreset(Tv * tv)21673ff48bf5SDavid du Colombier kfirreset(Tv *tv)
21683ff48bf5SDavid du Colombier {
21693ff48bf5SDavid du Colombier alterawrite(tv, 0, 0);
21703ff48bf5SDavid du Colombier microdelay(10);
21713ff48bf5SDavid du Colombier alterawrite(tv, 0x40000, 0);
21723ff48bf5SDavid du Colombier microdelay(10);
21733ff48bf5SDavid du Colombier alterawrite(tv, 0x40006, 0x80);
21743ff48bf5SDavid du Colombier microdelay(10);
21753ff48bf5SDavid du Colombier alterawrite(tv, 8, 1);
21763ff48bf5SDavid du Colombier microdelay(10);
21773ff48bf5SDavid du Colombier alterawrite(tv, 0x40004, 2);
21783ff48bf5SDavid du Colombier microdelay(10);
21793ff48bf5SDavid du Colombier alterawrite(tv, 4, 3);
21803ff48bf5SDavid du Colombier microdelay(3);
21813ff48bf5SDavid du Colombier }
21823ff48bf5SDavid du Colombier
21833ff48bf5SDavid du Colombier static int
kfirinitialize(Tv * tv)21843ff48bf5SDavid du Colombier kfirinitialize(Tv *tv)
21853ff48bf5SDavid du Colombier {
218641dd6b47SDavid du Colombier /* Initialize parameters? */
21873ff48bf5SDavid du Colombier
21883ff48bf5SDavid du Colombier tv->gpiostate = Gpioinit;
21893ff48bf5SDavid du Colombier tv->alterareg = -1;
21903ff48bf5SDavid du Colombier tv->alteraclock = 0x20000;
21913ff48bf5SDavid du Colombier kfirloadu(tv, hcwAMC, sizeof hcwAMC);
21923ff48bf5SDavid du Colombier kfirreset(tv);
21933ff48bf5SDavid du Colombier return 1;
21943ff48bf5SDavid du Colombier }
2195