BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / dvb / cx23882 / cx23882.c
blobb0d33e5c50efda797561d9038d017b5c78bad9ea
1 /*
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.
25 #include "cx23882.h"
26 #include "util.h"
27 #include <KernelExport.h>
28 #include <ByteOrder.h>
29 #include <Drivers.h>
32 #define TRACE_CX23882
33 #ifdef TRACE_CX23882
34 #define TRACE dprintf
35 #else
36 #define TRACE(a...)
37 #endif
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);
69 void
70 cx23882_reset(cx23882_device *device)
72 // software reset (XXX Test)
73 reg_write32(0x38c06c, 1);
74 snooze(200000);
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);
108 status_t
109 cx23882_init(cx23882_device *device)
111 // assumes that cx23882_reset() has already been called
113 status_t err;
115 if ((err = cx23882_buffers_alloc(device)) < B_OK) {
116 dprintf("cx23882: Error, buffer alloc failed\n");
117 return err;
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);
131 // init sram
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");
155 return B_OK;
159 status_t
160 cx23882_terminate(cx23882_device *device)
162 cx23882_reset(device);
164 cx23882_buffers_free(device);
165 return B_OK;
169 status_t
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);
177 return B_OK;
181 status_t
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);
189 return B_OK;
193 static inline void
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);
204 return;
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) {
213 int32 count;
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);
218 if (count <= 0)
219 release_sem_etc(device->capture_sem, 1, B_DO_NOT_RESCHEDULE);
222 if (mstat & TS_INT_STAT_TS_RISC2) {
223 int32 count;
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);
228 if (count <= 0)
229 release_sem_etc(device->capture_sem, 1, B_DO_NOT_RESCHEDULE);
234 int32
235 cx23882_int(void *data)
237 cx23882_device *device = data;
238 uint32 mstat;
239 uint32 wmstat;
241 mstat = reg_read32(REG_PCI_INT_MSTAT);
242 if (!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);
255 if (wmstat)
256 reg_write32(REG_PCI_INT_STAT, wmstat);
258 if (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;
264 } else {
265 return B_HANDLED_INTERRUPT;
270 static status_t
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);
277 return B_NO_MEMORY;
279 return B_OK;
283 static void
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;
295 static void
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);
304 // setup CDMS
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");
321 static void
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;
326 int i;
328 #define set_opcode(a) (*rp++) = B_HOST_TO_LENDIAN_INT32((a))
330 dprintf("cx23882_risc_ram_setup enter\n");
332 // sync
333 set_opcode(RISC_RESYNC | 0);
335 // copy buffer 1
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);
341 // execute IRQ 1
342 set_opcode(RISC_SKIP | RISC_IRQ1 | RISC_SOL | 0);
344 // copy buffer 2
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);
350 // execute IRQ 2
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);
357 #undef set_opcode
359 dprintf("cx23882_risc_ram_setup leave\n");
363 static void
364 cx23882_via_sis_fixup(cx23882_device *device)
366 uint16 host_vendor;
367 uint32 dev_cntrl1;
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);
375 } else {
376 dprintf("cx23882: disabling VIA/SIS compatibility mode\n");
377 reg_write32(REG_F2_DEV_CNTRL1, dev_cntrl1 & ~F2_DEV_CNTRL1_EN_VSFX);