1 /* 2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de> 3 * 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: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 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. 23 */ 24 25 #include "cx23882.h" 26 #include "util.h" 27 #include <KernelExport.h> 28 #include <ByteOrder.h> 29 #include <Drivers.h> 30 31 32 #define TRACE_CX23882 33 #ifdef TRACE_CX23882 34 #define TRACE dprintf 35 #else 36 #define TRACE(a...) 37 #endif 38 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 43 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) 48 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 56 57 // About 64 kByte DMA buffer size 58 #define LINES_PER_BUFFER 16 59 #define DMA_BUFFER_SIZE (LINES_PER_BUFFER * BYTES_PER_LINE) 60 61 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); 67 68 69 void 70 cx23882_reset(cx23882_device *device) 71 { 72 // software reset (XXX Test) 73 reg_write32(0x38c06c, 1); 74 snooze(200000); 75 76 // disable RISC controller 77 reg_write32(REG_DEV_CNTRL2, 0); 78 79 // disable TS interface DMA 80 reg_write32(REG_TS_DMA_CNTRL, 0x0); 81 82 // disable VIP interface up- & downstram DMA 83 reg_write32(REG_VIP_STREAM_EN, 0x0); 84 85 // disable host interface up- & downstram DMA 86 reg_write32(REG_HST_STREAM_EN, 0x0); 87 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); 96 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); 105 } 106 107 108 status_t 109 cx23882_init(cx23882_device *device) 110 { 111 // assumes that cx23882_reset() has already been called 112 113 status_t err; 114 115 if ((err = cx23882_buffers_alloc(device)) < B_OK) { 116 dprintf("cx23882: Error, buffer alloc failed\n"); 117 return err; 118 } 119 120 device->capture_size = DMA_BUFFER_SIZE; 121 122 cx23882_via_sis_fixup(device); 123 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); 127 128 // init risc programm 129 cx23882_risc_ram_setup(device); 130 131 // init sram 132 cx23882_sram_setup(device); 133 134 // Reset counter to 0 135 reg_write32(REG_TS_GP_CNT_CNTRL, 0x3); 136 137 // Line length for RISC DMA 138 reg_write32(REG_TS_LNGTH, BYTES_PER_LINE); 139 140 // Set serial interface mode 141 reg_write32(REG_TS_GEN_CONTROL, reg_read32(REG_TS_GEN_CONTROL) | TS_GEN_CONTROL_IPB_SMODE); 142 143 // Setup hardware MPEG2 fec interface 144 reg_write32(REG_HW_SOP_CONTROL, (MPEG2_SYNC_BYTE << 16) | (MPEG2_PACKET_SIZE << 4) | SYNC_PACKET_COUNT); 145 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); 149 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); 153 154 TRACE("cx23882_init done\n"); 155 return B_OK; 156 } 157 158 159 status_t 160 cx23882_terminate(cx23882_device *device) 161 { 162 cx23882_reset(device); 163 164 cx23882_buffers_free(device); 165 return B_OK; 166 } 167 168 169 status_t 170 cx23882_start_capture(cx23882_device *device) 171 { 172 TRACE("cx23882_start_capture\n"); 173 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; 178 } 179 180 181 status_t 182 cx23882_stop_capture(cx23882_device *device) 183 { 184 TRACE("cx23882_stop_capture\n"); 185 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; 190 } 191 192 193 static inline void 194 cx23882_mpegts_int(cx23882_device *device) 195 { 196 uint32 mstat = reg_read32(REG_TS_INT_MSTAT); 197 reg_write32(REG_TS_INT_STAT, mstat); 198 199 // dprintf("cx23882_mpegts_int got 0x%08lx\n", mstat); 200 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; 205 } 206 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; 210 } 211 212 if (mstat & TS_INT_STAT_TS_RISC1) { 213 int32 count; 214 // dprintf("cx23882_mpegts_int buffer 1 at %lld\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); 220 } 221 222 if (mstat & TS_INT_STAT_TS_RISC2) { 223 int32 count; 224 // dprintf("cx23882_mpegts_int buffer 2 at %lld\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); 230 } 231 } 232 233 234 int32 235 cx23882_int(void *data) 236 { 237 cx23882_device *device = data; 238 uint32 mstat; 239 uint32 wmstat; 240 241 mstat = reg_read32(REG_PCI_INT_MSTAT); 242 if (!mstat) 243 return B_UNHANDLED_INTERRUPT; 244 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; 252 } 253 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); 257 258 if (wmstat) 259 dprintf("cx23882_int got 0x%08" B_PRIx32 "\n", wmstat); 260 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; 266 } 267 } 268 269 270 static status_t 271 cx23882_buffers_alloc(cx23882_device *device) 272 { 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; 278 } 279 return B_OK; 280 } 281 282 283 static void 284 cx23882_buffers_free(cx23882_device *device) 285 { 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; 292 } 293 294 295 static void 296 cx23882_sram_setup(cx23882_device *device) 297 { 298 dprintf("cx23882_sram_setup enter\n"); 299 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); 303 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)); 310 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 316 317 dprintf("cx23882_sram_setup leave\n"); 318 } 319 320 321 static void 322 cx23882_risc_ram_setup(cx23882_device *device) 323 { 324 char *start = (char *)(device->regs) + SRAM_START_ADDRESS + SRAM_BASE_RISC_PROG; 325 volatile uint32 *rp = (volatile uint32 *)start; 326 int i; 327 328 #define set_opcode(a) (*rp++) = B_HOST_TO_LENDIAN_INT32((a)) 329 330 dprintf("cx23882_risc_ram_setup enter\n"); 331 332 // sync 333 set_opcode(RISC_RESYNC | 0); 334 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); 339 } 340 341 // execute IRQ 1 342 set_opcode(RISC_SKIP | RISC_IRQ1 | RISC_SOL | 0); 343 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); 348 } 349 350 // execute IRQ 2 351 set_opcode(RISC_SKIP | RISC_IRQ2 | RISC_SOL | 0); 352 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); 356 357 #undef set_opcode 358 359 dprintf("cx23882_risc_ram_setup leave\n"); 360 } 361 362 363 static void 364 cx23882_via_sis_fixup(cx23882_device *device) 365 { 366 uint16 host_vendor; 367 uint32 dev_cntrl1; 368 369 host_vendor = gPci->read_pci_config(0, 0, 0, PCI_vendor_id, 2); 370 dev_cntrl1 = reg_read32(REG_F2_DEV_CNTRL1); 371 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); 378 } 379 } 380