2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify,
8 * merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
27 #include <KernelExport.h>
28 #include <ByteOrder.h>
39 // settings for hardware stream sync
40 #define MPEG2_SYNC_BYTE 0x47
41 #define MPEG2_PACKET_SIZE 188
42 #define SYNC_PACKET_COUNT 7 // 0 and 5 don't seem to work
44 // Line size is also used as FIFO size!
45 // BYTES_PER_LINE must be a multiple of 8 and <= 4096 bytes
46 #define PACKETS_PER_LINE 20
47 #define BYTES_PER_LINE (PACKETS_PER_LINE * MPEG2_PACKET_SIZE)
49 #define SRAM_START_ADDRESS 0x180000
50 #define SRAM_BASE_CMDS_TS 0x200
51 #define SRAM_BASE_RISC_PROG 0x400
52 #define SRAM_BASE_RISC_QUEUE 0x800
53 #define SRAM_BASE_CDT 0x900
54 #define SRAM_BASE_FIFO_0 0x1000
55 #define SRAM_BASE_FIFO_1 0x2000
57 // About 64 kByte DMA buffer size
58 #define LINES_PER_BUFFER 16
59 #define DMA_BUFFER_SIZE (LINES_PER_BUFFER * BYTES_PER_LINE)
62 static status_t
cx23882_buffers_alloc(cx23882_device
*device
);
63 static void cx23882_buffers_free(cx23882_device
*device
);
64 static void cx23882_risc_ram_setup(cx23882_device
*device
);
65 static void cx23882_sram_setup(cx23882_device
*device
);
66 static void cx23882_via_sis_fixup(cx23882_device
*device
);
70 cx23882_reset(cx23882_device
*device
)
72 // software reset (XXX Test)
73 reg_write32(0x38c06c, 1);
76 // disable RISC controller
77 reg_write32(REG_DEV_CNTRL2
, 0);
79 // disable TS interface DMA
80 reg_write32(REG_TS_DMA_CNTRL
, 0x0);
82 // disable VIP interface up- & downstram DMA
83 reg_write32(REG_VIP_STREAM_EN
, 0x0);
85 // disable host interface up- & downstram DMA
86 reg_write32(REG_HST_STREAM_EN
, 0x0);
88 // stop all interrupts
89 reg_write32(REG_PCI_INT_MSK
, 0x0);
90 reg_write32(REG_VID_INT_MSK
, 0x0);
91 reg_write32(REG_AUD_INT_MSK
, 0x0);
92 reg_write32(REG_TS_INT_MSK
, 0x0);
93 reg_write32(REG_VIP_INT_MSK
, 0x0);
94 reg_write32(REG_HST_INT_MSK
, 0x0);
95 reg_write32(REG_DMA_RISC_INT_MSK
, 0x0);
97 // clear all pending interrupts
98 reg_write32(REG_PCI_INT_STAT
, 0xffffffff);
99 reg_write32(REG_VID_INT_STAT
, 0xffffffff);
100 reg_write32(REG_AUD_INT_STAT
, 0xffffffff);
101 reg_write32(REG_TS_INT_STAT
, 0xffffffff);
102 reg_write32(REG_VIP_INT_STAT
, 0xffffffff);
103 reg_write32(REG_HST_INT_STAT
, 0xffffffff);
104 reg_write32(REG_DMA_RISC_INT_MSK
, 0xffffffff);
109 cx23882_init(cx23882_device
*device
)
111 // assumes that cx23882_reset() has already been called
115 if ((err
= cx23882_buffers_alloc(device
)) < B_OK
) {
116 dprintf("cx23882: Error, buffer alloc failed\n");
120 device
->capture_size
= DMA_BUFFER_SIZE
;
122 cx23882_via_sis_fixup(device
);
124 // Set FIFO thresholds, should be 0 < x <= 7
125 reg_write32(REG_PDMA_STHRSH
, PDMA_ISBTHRSH_6
| PDMA_PCITHRSH_6
);
126 reg_write32(REG_PDMA_DTHRSH
, PDMA_ISBTHRSH_6
| PDMA_PCITHRSH_6
);
128 // init risc programm
129 cx23882_risc_ram_setup(device
);
132 cx23882_sram_setup(device
);
134 // Reset counter to 0
135 reg_write32(REG_TS_GP_CNT_CNTRL
, 0x3);
137 // Line length for RISC DMA
138 reg_write32(REG_TS_LNGTH
, BYTES_PER_LINE
);
140 // Set serial interface mode
141 reg_write32(REG_TS_GEN_CONTROL
, reg_read32(REG_TS_GEN_CONTROL
) | TS_GEN_CONTROL_IPB_SMODE
);
143 // Setup hardware MPEG2 fec interface
144 reg_write32(REG_HW_SOP_CONTROL
, (MPEG2_SYNC_BYTE
<< 16) | (MPEG2_PACKET_SIZE
<< 4) | SYNC_PACKET_COUNT
);
146 // Setup TSSTOP status, active low, rising and falling edge, single bit width
147 reg_write32(REG_TS_SOP_STATUS
, reg_read32(REG_TS_SOP_STATUS
) | 0x18000);
148 reg_write32(REG_TS_SOP_STATUS
, reg_read32(REG_TS_SOP_STATUS
) & ~0x06000);
150 // Enable interrupts for MPEG TS and all errors
151 reg_write32(REG_PCI_INT_MSK
, reg_read32(REG_PCI_INT_MSK
) | PCI_INT_STAT_TS_INT
| 0x00fc00);
152 reg_write32(REG_TS_INT_MSK
, reg_read32(REG_TS_INT_MSK
) | TS_INT_STAT_TS_RISC1
| TS_INT_STAT_TS_RISC2
| 0x1f1100);
154 TRACE("cx23882_init done\n");
160 cx23882_terminate(cx23882_device
*device
)
162 cx23882_reset(device
);
164 cx23882_buffers_free(device
);
170 cx23882_start_capture(cx23882_device
*device
)
172 TRACE("cx23882_start_capture\n");
174 // start RISC processor and DMA
175 reg_write32(REG_DEV_CNTRL2
, reg_read32(REG_DEV_CNTRL2
) | DEV_CNTRL2_RUN_RISC
);
176 reg_write32(REG_TS_DMA_CNTRL
, reg_read32(REG_TS_DMA_CNTRL
) | TS_DMA_CNTRL_TS_FIFO_EN
| TS_DMA_CNTRL_TS_RISC_EN
);
182 cx23882_stop_capture(cx23882_device
*device
)
184 TRACE("cx23882_stop_capture\n");
186 // stop RISC processor and DMA
187 reg_write32(REG_TS_DMA_CNTRL
, reg_read32(REG_TS_DMA_CNTRL
) & ~(TS_DMA_CNTRL_TS_FIFO_EN
| TS_DMA_CNTRL_TS_RISC_EN
));
188 reg_write32(REG_DEV_CNTRL2
, reg_read32(REG_DEV_CNTRL2
) & ~DEV_CNTRL2_RUN_RISC
);
194 cx23882_mpegts_int(cx23882_device
*device
)
196 uint32 mstat
= reg_read32(REG_TS_INT_MSTAT
);
197 reg_write32(REG_TS_INT_STAT
, mstat
);
199 // dprintf("cx23882_mpegts_int got 0x%08lx\n", mstat);
201 if (mstat
& TS_INT_STAT_OPC_ERR
) {
202 dprintf("cx23882_mpegts_int RISC opcode error\n");
203 reg_write32(REG_PCI_INT_MSK
, 0);
207 if ((mstat
& (TS_INT_STAT_TS_RISC1
| TS_INT_STAT_TS_RISC2
)) == (TS_INT_STAT_TS_RISC1
| TS_INT_STAT_TS_RISC2
)) {
208 dprintf("cx23882_mpegts_int both buffers ready\n");
209 mstat
= TS_INT_STAT_TS_RISC1
;
212 if (mstat
& TS_INT_STAT_TS_RISC1
) {
214 // dprintf("cx23882_mpegts_int buffer 1 at %Ld\n", system_time());
215 device
->capture_data
= device
->dma_buf1_virt
;
216 device
->capture_end_time
= system_time();
217 get_sem_count(device
->capture_sem
, &count
);
219 release_sem_etc(device
->capture_sem
, 1, B_DO_NOT_RESCHEDULE
);
222 if (mstat
& TS_INT_STAT_TS_RISC2
) {
224 // dprintf("cx23882_mpegts_int buffer 2 at %Ld\n", system_time());
225 device
->capture_data
= device
->dma_buf2_virt
;
226 device
->capture_end_time
= system_time();
227 get_sem_count(device
->capture_sem
, &count
);
229 release_sem_etc(device
->capture_sem
, 1, B_DO_NOT_RESCHEDULE
);
235 cx23882_int(void *data
)
237 cx23882_device
*device
= data
;
241 mstat
= reg_read32(REG_PCI_INT_MSTAT
);
243 return B_UNHANDLED_INTERRUPT
;
245 if (mstat
& (PCI_INT_STAT_HST_INT
| PCI_INT_STAT_VIP_INT
| PCI_INT_STAT_AUD_INT
| PCI_INT_STAT_VID_INT
)) {
246 // serious error, these bits should not be set
247 dprintf("cx23882_int error: msk 0x%08" B_PRIx32
", stat 0x%08" B_PRIx32
248 ", mstat 0x%08" B_PRIx32
"\n", reg_read32(REG_PCI_INT_MSK
),
249 reg_read32(REG_PCI_INT_STAT
), mstat
);
250 reg_write32(REG_PCI_INT_MSK
, 0);
251 return B_HANDLED_INTERRUPT
;
254 wmstat
= mstat
& ~(PCI_INT_STAT_HST_INT
| PCI_INT_STAT_VIP_INT
| PCI_INT_STAT_TS_INT
| PCI_INT_STAT_AUD_INT
| PCI_INT_STAT_VID_INT
);
256 reg_write32(REG_PCI_INT_STAT
, wmstat
);
259 dprintf("cx23882_int got 0x%08" B_PRIx32
"\n", wmstat
);
261 if (mstat
& PCI_INT_STAT_TS_INT
) {
262 cx23882_mpegts_int(device
);
263 return B_INVOKE_SCHEDULER
;
265 return B_HANDLED_INTERRUPT
;
271 cx23882_buffers_alloc(cx23882_device
*device
)
273 device
->dma_buf1_area
= alloc_mem(&device
->dma_buf1_virt
, &device
->dma_buf1_phys
, DMA_BUFFER_SIZE
, B_READ_AREA
, "cx23882 dma buf 1");
274 device
->dma_buf2_area
= alloc_mem(&device
->dma_buf2_virt
, &device
->dma_buf2_phys
, DMA_BUFFER_SIZE
, B_READ_AREA
, "cx23882 dma buf 2");
275 if (device
->dma_buf1_area
< B_OK
|| device
->dma_buf2_area
< B_OK
) {
276 cx23882_buffers_free(device
);
284 cx23882_buffers_free(cx23882_device
*device
)
286 if (device
->dma_buf1_area
>= 0)
287 delete_area(device
->dma_buf1_area
);
288 if (device
->dma_buf2_area
>= 0)
289 delete_area(device
->dma_buf2_area
);
290 device
->dma_buf1_area
= -1;
291 device
->dma_buf2_area
= -1;
296 cx23882_sram_setup(cx23882_device
*device
)
298 dprintf("cx23882_sram_setup enter\n");
300 // setup CDT entries for both FIFOs
301 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CDT
, SRAM_START_ADDRESS
+ SRAM_BASE_FIFO_0
);
302 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CDT
+ 16, SRAM_START_ADDRESS
+ SRAM_BASE_FIFO_1
);
305 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CMDS_TS
+ 0x00, SRAM_START_ADDRESS
+ SRAM_BASE_RISC_PROG
);
306 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CMDS_TS
+ 0x04, SRAM_START_ADDRESS
+ SRAM_BASE_CDT
);
307 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CMDS_TS
+ 0x08, (2 * 16) / 8); // FIFO count = 2
308 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CMDS_TS
+ 0x0c, SRAM_START_ADDRESS
+ SRAM_BASE_RISC_QUEUE
);
309 reg_write32(SRAM_START_ADDRESS
+ SRAM_BASE_CMDS_TS
+ 0x10, 0x80000000 | (0x100 / 4));
311 // setup DMA registers
312 reg_write32(REG_DMA28_PTR1
, SRAM_START_ADDRESS
+ SRAM_BASE_FIFO_0
);
313 reg_write32(REG_DMA28_PTR2
, SRAM_START_ADDRESS
+ SRAM_BASE_CDT
);
314 reg_write32(REG_DMA28_CNT1
, BYTES_PER_LINE
/ 8);
315 reg_write32(REG_DMA28_CNT2
, (2 * 16) / 8); // FIFO count = 2
317 dprintf("cx23882_sram_setup leave\n");
322 cx23882_risc_ram_setup(cx23882_device
*device
)
324 char *start
= (char *)(device
->regs
) + SRAM_START_ADDRESS
+ SRAM_BASE_RISC_PROG
;
325 volatile uint32
*rp
= (volatile uint32
*)start
;
328 #define set_opcode(a) (*rp++) = B_HOST_TO_LENDIAN_INT32((a))
330 dprintf("cx23882_risc_ram_setup enter\n");
333 set_opcode(RISC_RESYNC
| 0);
336 for (i
= 0; i
< LINES_PER_BUFFER
; i
++) {
337 set_opcode(RISC_WRITE
| RISC_SOL
| RISC_EOL
| BYTES_PER_LINE
);
338 set_opcode((unsigned long)device
->dma_buf1_phys
+ i
* BYTES_PER_LINE
);
342 set_opcode(RISC_SKIP
| RISC_IRQ1
| RISC_SOL
| 0);
345 for (i
= 0; i
< LINES_PER_BUFFER
; i
++) {
346 set_opcode(RISC_WRITE
| RISC_SOL
| RISC_EOL
| BYTES_PER_LINE
);
347 set_opcode((unsigned long)device
->dma_buf2_phys
+ i
* BYTES_PER_LINE
);
351 set_opcode(RISC_SKIP
| RISC_IRQ2
| RISC_SOL
| 0);
353 // jmp to start, but skip sync instruction
354 set_opcode(RISC_JUMP
| RISC_SRP
);
355 set_opcode(SRAM_START_ADDRESS
+ SRAM_BASE_RISC_PROG
+ 4);
359 dprintf("cx23882_risc_ram_setup leave\n");
364 cx23882_via_sis_fixup(cx23882_device
*device
)
369 host_vendor
= gPci
->read_pci_config(0, 0, 0, PCI_vendor_id
, 2);
370 dev_cntrl1
= reg_read32(REG_F2_DEV_CNTRL1
);
372 if (host_vendor
== PCI_VENDOR_VIA
|| host_vendor
== PCI_VENDOR_SIS
) {
373 dprintf("cx23882: enabling VIA/SIS compatibility mode\n");
374 reg_write32(REG_F2_DEV_CNTRL1
, dev_cntrl1
| F2_DEV_CNTRL1_EN_VSFX
);
376 dprintf("cx23882: disabling VIA/SIS compatibility mode\n");
377 reg_write32(REG_F2_DEV_CNTRL1
, dev_cntrl1
& ~F2_DEV_CNTRL1_EN_VSFX
);