1254 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Support for a cx23416 mpeg encoder via cx2388x host port.4 * "blackbird" reference design.5 *6 * (c) 2004 Jelle Foks <jelle@foks.us>7 * (c) 2004 Gerd Knorr <kraxel@bytesex.org>8 *9 * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@kernel.org>10 * - video_ioctl2 conversion11 *12 * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>13 */14 15#include "cx88.h"16 17#include <linux/module.h>18#include <linux/init.h>19#include <linux/slab.h>20#include <linux/fs.h>21#include <linux/delay.h>22#include <linux/device.h>23#include <linux/firmware.h>24#include <media/v4l2-common.h>25#include <media/v4l2-ioctl.h>26#include <media/v4l2-event.h>27#include <media/drv-intf/cx2341x.h>28 29MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");30MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");31MODULE_LICENSE("GPL v2");32MODULE_VERSION(CX88_VERSION);33 34static unsigned int debug;35module_param(debug, int, 0644);36MODULE_PARM_DESC(debug, "enable debug messages [blackbird]");37 38#define dprintk(level, fmt, arg...) do { \39 if (debug + 1 > level) \40 printk(KERN_DEBUG pr_fmt("%s: blackbird:" fmt), \41 __func__, ##arg); \42} while (0)43 44/* ------------------------------------------------------------------ */45 46#define BLACKBIRD_FIRM_IMAGE_SIZE 37683647 48/* defines below are from ivtv-driver.h */49 50#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF51 52/* Firmware API commands */53#define IVTV_API_STD_TIMEOUT 50054 55enum blackbird_capture_type {56 BLACKBIRD_MPEG_CAPTURE,57 BLACKBIRD_RAW_CAPTURE,58 BLACKBIRD_RAW_PASSTHRU_CAPTURE59};60 61enum blackbird_capture_bits {62 BLACKBIRD_RAW_BITS_NONE = 0x00,63 BLACKBIRD_RAW_BITS_YUV_CAPTURE = 0x01,64 BLACKBIRD_RAW_BITS_PCM_CAPTURE = 0x02,65 BLACKBIRD_RAW_BITS_VBI_CAPTURE = 0x04,66 BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,67 BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x1068};69 70enum blackbird_capture_end {71 BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */72 BLACKBIRD_END_NOW, /* stop immediately, no irq */73};74 75enum blackbird_framerate {76 BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */77 BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */78};79 80enum blackbird_stream_port {81 BLACKBIRD_OUTPUT_PORT_MEMORY,82 BLACKBIRD_OUTPUT_PORT_STREAMING,83 BLACKBIRD_OUTPUT_PORT_SERIAL84};85 86enum blackbird_data_xfer_status {87 BLACKBIRD_MORE_BUFFERS_FOLLOW,88 BLACKBIRD_LAST_BUFFER,89};90 91enum blackbird_picture_mask {92 BLACKBIRD_PICTURE_MASK_NONE,93 BLACKBIRD_PICTURE_MASK_I_FRAMES,94 BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,95 BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,96};97 98enum blackbird_vbi_mode_bits {99 BLACKBIRD_VBI_BITS_SLICED,100 BLACKBIRD_VBI_BITS_RAW,101};102 103enum blackbird_vbi_insertion_bits {104 BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,105 BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,106 BLACKBIRD_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,107 BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,108 BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,109};110 111enum blackbird_dma_unit {112 BLACKBIRD_DMA_BYTES,113 BLACKBIRD_DMA_FRAMES,114};115 116enum blackbird_dma_transfer_status_bits {117 BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,118 BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,119 BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,120};121 122enum blackbird_pause {123 BLACKBIRD_PAUSE_ENCODING,124 BLACKBIRD_RESUME_ENCODING,125};126 127enum blackbird_copyright {128 BLACKBIRD_COPYRIGHT_OFF,129 BLACKBIRD_COPYRIGHT_ON,130};131 132enum blackbird_notification_type {133 BLACKBIRD_NOTIFICATION_REFRESH,134};135 136enum blackbird_notification_status {137 BLACKBIRD_NOTIFICATION_OFF,138 BLACKBIRD_NOTIFICATION_ON,139};140 141enum blackbird_notification_mailbox {142 BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,143};144 145enum blackbird_field1_lines {146 BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */147 BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */148 BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */149};150 151enum blackbird_field2_lines {152 BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */153 BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */154 BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */155};156 157enum blackbird_custom_data_type {158 BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,159 BLACKBIRD_CUSTOM_PRIVATE_PACKET,160};161 162enum blackbird_mute {163 BLACKBIRD_UNMUTE,164 BLACKBIRD_MUTE,165};166 167enum blackbird_mute_video_mask {168 BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00,169 BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000,170 BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000,171};172 173enum blackbird_mute_video_shift {174 BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8,175 BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,176 BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,177};178 179/* Registers */180#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)181#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/)182#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/)183#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/)184#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/)185#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/)186 187/* ------------------------------------------------------------------ */188 189static void host_setup(struct cx88_core *core)190{191 /* toggle reset of the host */192 cx_write(MO_GPHST_SOFT_RST, 1);193 udelay(100);194 cx_write(MO_GPHST_SOFT_RST, 0);195 udelay(100);196 197 /* host port setup */198 cx_write(MO_GPHST_WSC, 0x44444444U);199 cx_write(MO_GPHST_XFR, 0);200 cx_write(MO_GPHST_WDTH, 15);201 cx_write(MO_GPHST_HDSHK, 0);202 cx_write(MO_GPHST_MUX16, 0x44448888U);203 cx_write(MO_GPHST_MODE, 0);204}205 206/* ------------------------------------------------------------------ */207 208#define P1_MDATA0 0x390000209#define P1_MDATA1 0x390001210#define P1_MDATA2 0x390002211#define P1_MDATA3 0x390003212#define P1_MADDR2 0x390004213#define P1_MADDR1 0x390005214#define P1_MADDR0 0x390006215#define P1_RDATA0 0x390008216#define P1_RDATA1 0x390009217#define P1_RDATA2 0x39000A218#define P1_RDATA3 0x39000B219#define P1_RADDR0 0x39000C220#define P1_RADDR1 0x39000D221#define P1_RRDWR 0x39000E222 223static int wait_ready_gpio0_bit1(struct cx88_core *core, u32 state)224{225 unsigned long timeout = jiffies + msecs_to_jiffies(1);226 u32 gpio0, need;227 228 need = state ? 2 : 0;229 for (;;) {230 gpio0 = cx_read(MO_GP0_IO) & 2;231 if (need == gpio0)232 return 0;233 if (time_after(jiffies, timeout))234 return -1;235 udelay(1);236 }237}238 239static int memory_write(struct cx88_core *core, u32 address, u32 value)240{241 /* Warning: address is dword address (4 bytes) */242 cx_writeb(P1_MDATA0, (unsigned int)value);243 cx_writeb(P1_MDATA1, (unsigned int)(value >> 8));244 cx_writeb(P1_MDATA2, (unsigned int)(value >> 16));245 cx_writeb(P1_MDATA3, (unsigned int)(value >> 24));246 cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40);247 cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));248 cx_writeb(P1_MADDR0, (unsigned int)address);249 cx_read(P1_MDATA0);250 cx_read(P1_MADDR0);251 252 return wait_ready_gpio0_bit1(core, 1);253}254 255static int memory_read(struct cx88_core *core, u32 address, u32 *value)256{257 int retval;258 u32 val;259 260 /* Warning: address is dword address (4 bytes) */261 cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0);262 cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));263 cx_writeb(P1_MADDR0, (unsigned int)address);264 cx_read(P1_MADDR0);265 266 retval = wait_ready_gpio0_bit1(core, 1);267 268 cx_writeb(P1_MDATA3, 0);269 val = (unsigned char)cx_read(P1_MDATA3) << 24;270 cx_writeb(P1_MDATA2, 0);271 val |= (unsigned char)cx_read(P1_MDATA2) << 16;272 cx_writeb(P1_MDATA1, 0);273 val |= (unsigned char)cx_read(P1_MDATA1) << 8;274 cx_writeb(P1_MDATA0, 0);275 val |= (unsigned char)cx_read(P1_MDATA0);276 277 *value = val;278 return retval;279}280 281static int register_write(struct cx88_core *core, u32 address, u32 value)282{283 cx_writeb(P1_RDATA0, (unsigned int)value);284 cx_writeb(P1_RDATA1, (unsigned int)(value >> 8));285 cx_writeb(P1_RDATA2, (unsigned int)(value >> 16));286 cx_writeb(P1_RDATA3, (unsigned int)(value >> 24));287 cx_writeb(P1_RADDR0, (unsigned int)address);288 cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));289 cx_writeb(P1_RRDWR, 1);290 cx_read(P1_RDATA0);291 cx_read(P1_RADDR0);292 293 return wait_ready_gpio0_bit1(core, 1);294}295 296static int register_read(struct cx88_core *core, u32 address, u32 *value)297{298 int retval;299 u32 val;300 301 cx_writeb(P1_RADDR0, (unsigned int)address);302 cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));303 cx_writeb(P1_RRDWR, 0);304 cx_read(P1_RADDR0);305 306 retval = wait_ready_gpio0_bit1(core, 1);307 val = (unsigned char)cx_read(P1_RDATA0);308 val |= (unsigned char)cx_read(P1_RDATA1) << 8;309 val |= (unsigned char)cx_read(P1_RDATA2) << 16;310 val |= (unsigned char)cx_read(P1_RDATA3) << 24;311 312 *value = val;313 return retval;314}315 316/* ------------------------------------------------------------------ */317 318static int blackbird_mbox_func(void *priv, u32 command, int in,319 int out, u32 data[CX2341X_MBOX_MAX_DATA])320{321 struct cx8802_dev *dev = priv;322 unsigned long timeout;323 u32 value, flag, retval;324 int i;325 326 dprintk(1, "%s: 0x%X\n", __func__, command);327 328 /*329 * this may not be 100% safe if we can't read any memory location330 * without side effects331 */332 memory_read(dev->core, dev->mailbox - 4, &value);333 if (value != 0x12345678) {334 dprintk(0,335 "Firmware and/or mailbox pointer not initialized or corrupted\n");336 return -EIO;337 }338 339 memory_read(dev->core, dev->mailbox, &flag);340 if (flag) {341 dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag);342 return -EIO;343 }344 345 flag |= 1; /* tell 'em we're working on it */346 memory_write(dev->core, dev->mailbox, flag);347 348 /* write command + args + fill remaining with zeros */349 memory_write(dev->core, dev->mailbox + 1, command); /* command code */350 /* timeout */351 memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT);352 for (i = 0; i < in; i++) {353 memory_write(dev->core, dev->mailbox + 4 + i, data[i]);354 dprintk(1, "API Input %d = %d\n", i, data[i]);355 }356 for (; i < CX2341X_MBOX_MAX_DATA; i++)357 memory_write(dev->core, dev->mailbox + 4 + i, 0);358 359 flag |= 3; /* tell 'em we're done writing */360 memory_write(dev->core, dev->mailbox, flag);361 362 /* wait for firmware to handle the API command */363 timeout = jiffies + msecs_to_jiffies(1000);364 for (;;) {365 memory_read(dev->core, dev->mailbox, &flag);366 if (0 != (flag & 4))367 break;368 if (time_after(jiffies, timeout)) {369 dprintk(0, "ERROR: API Mailbox timeout %x\n", command);370 return -EIO;371 }372 udelay(10);373 }374 375 /* read output values */376 for (i = 0; i < out; i++) {377 memory_read(dev->core, dev->mailbox + 4 + i, data + i);378 dprintk(1, "API Output %d = %d\n", i, data[i]);379 }380 381 memory_read(dev->core, dev->mailbox + 2, &retval);382 dprintk(1, "API result = %d\n", retval);383 384 flag = 0;385 memory_write(dev->core, dev->mailbox, flag);386 return retval;387}388 389/* ------------------------------------------------------------------ */390 391/*392 * We don't need to call the API often, so using just one mailbox393 * will probably suffice394 */395static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,396 u32 inputcnt, u32 outputcnt, ...)397{398 u32 data[CX2341X_MBOX_MAX_DATA];399 va_list vargs;400 int i, err;401 402 va_start(vargs, outputcnt);403 404 for (i = 0; i < inputcnt; i++)405 data[i] = va_arg(vargs, int);406 407 err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);408 for (i = 0; i < outputcnt; i++) {409 int *vptr = va_arg(vargs, int *);410 *vptr = data[i];411 }412 va_end(vargs);413 return err;414}415 416static int blackbird_find_mailbox(struct cx8802_dev *dev)417{418 u32 signature[4] = {0x12345678, 0x34567812, 0x56781234, 0x78123456};419 int signaturecnt = 0;420 u32 value;421 int i;422 423 for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {424 memory_read(dev->core, i, &value);425 if (value == signature[signaturecnt])426 signaturecnt++;427 else428 signaturecnt = 0;429 if (signaturecnt == 4) {430 dprintk(1, "Mailbox signature found\n");431 return i + 1;432 }433 }434 dprintk(0, "Mailbox signature values not found!\n");435 return -EIO;436}437 438static int blackbird_load_firmware(struct cx8802_dev *dev)439{440 static const unsigned char magic[8] = {441 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa442 };443 const struct firmware *firmware;444 int i, retval = 0;445 u32 value = 0;446 u32 checksum = 0;447 __le32 *dataptr;448 449 retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);450 retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS,451 IVTV_CMD_HW_BLOCKS_RST);452 retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH,453 0x80000640);454 retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE,455 0x1A);456 usleep_range(10000, 20000);457 retval |= register_write(dev->core, IVTV_REG_APU, 0);458 459 if (retval < 0)460 dprintk(0, "Error with register_write\n");461 462 retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,463 &dev->pci->dev);464 465 if (retval != 0) {466 pr_err("Hotplug firmware request failed (%s).\n",467 CX2341X_FIRM_ENC_FILENAME);468 pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");469 return -EIO;470 }471 472 if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {473 pr_err("Firmware size mismatch (have %zd, expected %d)\n",474 firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);475 release_firmware(firmware);476 return -EINVAL;477 }478 479 if (memcmp(firmware->data, magic, 8) != 0) {480 pr_err("Firmware magic mismatch, wrong file?\n");481 release_firmware(firmware);482 return -EINVAL;483 }484 485 /* transfer to the chip */486 dprintk(1, "Loading firmware ...\n");487 dataptr = (__le32 *)firmware->data;488 for (i = 0; i < (firmware->size >> 2); i++) {489 value = le32_to_cpu(*dataptr);490 checksum += ~value;491 memory_write(dev->core, i, value);492 dataptr++;493 }494 495 /* read back to verify with the checksum */496 for (i--; i >= 0; i--) {497 memory_read(dev->core, i, &value);498 checksum -= ~value;499 }500 release_firmware(firmware);501 if (checksum) {502 pr_err("Firmware load might have failed (checksum mismatch).\n");503 return -EIO;504 }505 dprintk(0, "Firmware upload successful.\n");506 507 retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS,508 IVTV_CMD_HW_BLOCKS_RST);509 retval |= register_read(dev->core, IVTV_REG_SPU, &value);510 retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);511 usleep_range(10000, 20000);512 513 retval |= register_read(dev->core, IVTV_REG_VPU, &value);514 retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);515 516 if (retval < 0)517 dprintk(0, "Error with register_write\n");518 return 0;519}520 521/*522 * Settings used by the windows tv app for PVR2000:523 * =================================================================================================================524 * Profile | Codec | Resolution | CBR/VBR | Video Qlty | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode525 * -----------------------------------------------------------------------------------------------------------------526 * MPEG-1 | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 2000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo527 * MPEG-2 | MPEG2 | 720x576PAL | VBR | 600 :Good | 4000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo528 * VCD | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 1150 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo529 * DVD | MPEG2 | 720x576PAL | VBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo530 * DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo531 * =================================================================================================================532 * [*] DB: "DirectBurn"533 */534 535static void blackbird_codec_settings(struct cx8802_dev *dev)536{537 struct cx88_core *core = dev->core;538 539 /* assign frame size */540 blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,541 core->height, core->width);542 543 dev->cxhdl.width = core->width;544 dev->cxhdl.height = core->height;545 cx2341x_handler_set_50hz(&dev->cxhdl,546 dev->core->tvnorm & V4L2_STD_625_50);547 cx2341x_handler_setup(&dev->cxhdl);548}549 550static int blackbird_initialize_codec(struct cx8802_dev *dev)551{552 struct cx88_core *core = dev->core;553 int version;554 int retval;555 556 dprintk(1, "Initialize codec\n");557 retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */558 if (retval < 0) {559 /* ping was not successful, reset and upload firmware */560 cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */561 cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */562 retval = blackbird_load_firmware(dev);563 if (retval < 0)564 return retval;565 566 retval = blackbird_find_mailbox(dev);567 if (retval < 0)568 return -1;569 570 dev->mailbox = retval;571 572 /* ping */573 retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);574 if (retval < 0) {575 dprintk(0, "ERROR: Firmware ping failed!\n");576 return -1;577 }578 579 retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION,580 0, 1, &version);581 if (retval < 0) {582 dprintk(0,583 "ERROR: Firmware get encoder version failed!\n");584 return -1;585 }586 dprintk(0, "Firmware version is 0x%08x\n", version);587 }588 589 cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */590 cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */591 cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */592 cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */593 594 blackbird_codec_settings(dev);595 596 blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,597 BLACKBIRD_FIELD1_SAA7115, BLACKBIRD_FIELD2_SAA7115);598 599 blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,600 BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,601 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);602 603 return 0;604}605 606static int blackbird_start_codec(struct cx8802_dev *dev)607{608 struct cx88_core *core = dev->core;609 /* start capturing to the host interface */610 u32 reg;611 612 int i;613 int lastchange = -1;614 int lastval = 0;615 616 for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) {617 reg = cx_read(AUD_STATUS);618 619 dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg);620 if ((reg & 0x0F) != lastval) {621 lastval = reg & 0x0F;622 lastchange = i;623 }624 msleep(100);625 }626 627 /* unmute audio source */628 cx_clear(AUD_VOL_CTL, (1 << 6));629 630 blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0);631 632 /* initialize the video input */633 blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);634 635 cx2341x_handler_set_busy(&dev->cxhdl, 1);636 637 /* start capturing to the host interface */638 blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,639 BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE);640 641 return 0;642}643 644static int blackbird_stop_codec(struct cx8802_dev *dev)645{646 blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,647 BLACKBIRD_END_NOW,648 BLACKBIRD_MPEG_CAPTURE,649 BLACKBIRD_RAW_BITS_NONE);650 651 cx2341x_handler_set_busy(&dev->cxhdl, 0);652 653 return 0;654}655 656/* ------------------------------------------------------------------ */657 658static int queue_setup(struct vb2_queue *q,659 unsigned int *num_buffers, unsigned int *num_planes,660 unsigned int sizes[], struct device *alloc_devs[])661{662 struct cx8802_dev *dev = q->drv_priv;663 664 *num_planes = 1;665 dev->ts_packet_size = 188 * 4;666 dev->ts_packet_count = 32;667 sizes[0] = dev->ts_packet_size * dev->ts_packet_count;668 return 0;669}670 671static int buffer_prepare(struct vb2_buffer *vb)672{673 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);674 struct cx8802_dev *dev = vb->vb2_queue->drv_priv;675 struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb);676 677 return cx8802_buf_prepare(vb->vb2_queue, dev, buf);678}679 680static void buffer_finish(struct vb2_buffer *vb)681{682 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);683 struct cx8802_dev *dev = vb->vb2_queue->drv_priv;684 struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb);685 struct cx88_riscmem *risc = &buf->risc;686 687 if (risc->cpu)688 dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,689 risc->dma);690 memset(risc, 0, sizeof(*risc));691}692 693static void buffer_queue(struct vb2_buffer *vb)694{695 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);696 struct cx8802_dev *dev = vb->vb2_queue->drv_priv;697 struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb);698 699 cx8802_buf_queue(dev, buf);700}701 702static int start_streaming(struct vb2_queue *q, unsigned int count)703{704 struct cx8802_dev *dev = q->drv_priv;705 struct cx88_dmaqueue *dmaq = &dev->mpegq;706 struct cx8802_driver *drv;707 struct cx88_buffer *buf;708 unsigned long flags;709 int err;710 711 /* Make sure we can acquire the hardware */712 drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);713 if (!drv) {714 dprintk(1, "%s: blackbird driver is not loaded\n", __func__);715 err = -ENODEV;716 goto fail;717 }718 719 err = drv->request_acquire(drv);720 if (err != 0) {721 dprintk(1, "%s: Unable to acquire hardware, %d\n", __func__,722 err);723 goto fail;724 }725 726 if (blackbird_initialize_codec(dev) < 0) {727 drv->request_release(drv);728 err = -EINVAL;729 goto fail;730 }731 732 err = blackbird_start_codec(dev);733 if (err == 0) {734 buf = list_entry(dmaq->active.next, struct cx88_buffer, list);735 cx8802_start_dma(dev, dmaq, buf);736 return 0;737 }738 739fail:740 spin_lock_irqsave(&dev->slock, flags);741 while (!list_empty(&dmaq->active)) {742 struct cx88_buffer *buf = list_entry(dmaq->active.next,743 struct cx88_buffer, list);744 745 list_del(&buf->list);746 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);747 }748 spin_unlock_irqrestore(&dev->slock, flags);749 return err;750}751 752static void stop_streaming(struct vb2_queue *q)753{754 struct cx8802_dev *dev = q->drv_priv;755 struct cx88_dmaqueue *dmaq = &dev->mpegq;756 struct cx8802_driver *drv = NULL;757 unsigned long flags;758 759 cx8802_cancel_buffers(dev);760 blackbird_stop_codec(dev);761 762 /* Make sure we release the hardware */763 drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);764 WARN_ON(!drv);765 if (drv)766 drv->request_release(drv);767 768 spin_lock_irqsave(&dev->slock, flags);769 while (!list_empty(&dmaq->active)) {770 struct cx88_buffer *buf = list_entry(dmaq->active.next,771 struct cx88_buffer, list);772 773 list_del(&buf->list);774 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);775 }776 spin_unlock_irqrestore(&dev->slock, flags);777}778 779static const struct vb2_ops blackbird_qops = {780 .queue_setup = queue_setup,781 .buf_prepare = buffer_prepare,782 .buf_finish = buffer_finish,783 .buf_queue = buffer_queue,784 .wait_prepare = vb2_ops_wait_prepare,785 .wait_finish = vb2_ops_wait_finish,786 .start_streaming = start_streaming,787 .stop_streaming = stop_streaming,788};789 790/* ------------------------------------------------------------------ */791 792static int vidioc_querycap(struct file *file, void *priv,793 struct v4l2_capability *cap)794{795 struct cx8802_dev *dev = video_drvdata(file);796 struct cx88_core *core = dev->core;797 798 strscpy(cap->driver, "cx88_blackbird", sizeof(cap->driver));799 return cx88_querycap(file, core, cap);800}801 802static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,803 struct v4l2_fmtdesc *f)804{805 if (f->index != 0)806 return -EINVAL;807 808 f->pixelformat = V4L2_PIX_FMT_MPEG;809 return 0;810}811 812static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,813 struct v4l2_format *f)814{815 struct cx8802_dev *dev = video_drvdata(file);816 struct cx88_core *core = dev->core;817 818 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;819 f->fmt.pix.bytesperline = 0;820 f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count;821 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;822 f->fmt.pix.width = core->width;823 f->fmt.pix.height = core->height;824 f->fmt.pix.field = core->field;825 return 0;826}827 828static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,829 struct v4l2_format *f)830{831 struct cx8802_dev *dev = video_drvdata(file);832 struct cx88_core *core = dev->core;833 unsigned int maxw, maxh;834 enum v4l2_field field;835 836 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;837 f->fmt.pix.bytesperline = 0;838 f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count;839 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;840 841 maxw = norm_maxw(core->tvnorm);842 maxh = norm_maxh(core->tvnorm);843 844 field = f->fmt.pix.field;845 846 switch (field) {847 case V4L2_FIELD_TOP:848 case V4L2_FIELD_BOTTOM:849 case V4L2_FIELD_INTERLACED:850 case V4L2_FIELD_SEQ_BT:851 case V4L2_FIELD_SEQ_TB:852 break;853 default:854 field = (f->fmt.pix.height > maxh / 2)855 ? V4L2_FIELD_INTERLACED856 : V4L2_FIELD_BOTTOM;857 break;858 }859 if (V4L2_FIELD_HAS_T_OR_B(field))860 maxh /= 2;861 862 v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,863 &f->fmt.pix.height, 32, maxh, 0, 0);864 f->fmt.pix.field = field;865 return 0;866}867 868static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,869 struct v4l2_format *f)870{871 struct cx8802_dev *dev = video_drvdata(file);872 struct cx88_core *core = dev->core;873 874 if (vb2_is_busy(&dev->vb2_mpegq))875 return -EBUSY;876 if (core->v4ldev && (vb2_is_busy(&core->v4ldev->vb2_vidq) ||877 vb2_is_busy(&core->v4ldev->vb2_vbiq)))878 return -EBUSY;879 vidioc_try_fmt_vid_cap(file, priv, f);880 core->width = f->fmt.pix.width;881 core->height = f->fmt.pix.height;882 core->field = f->fmt.pix.field;883 cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height,884 f->fmt.pix.field);885 blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,886 f->fmt.pix.height, f->fmt.pix.width);887 return 0;888}889 890static int vidioc_s_frequency(struct file *file, void *priv,891 const struct v4l2_frequency *f)892{893 struct cx8802_dev *dev = video_drvdata(file);894 struct cx88_core *core = dev->core;895 bool streaming;896 897 if (unlikely(core->board.tuner_type == UNSET))898 return -EINVAL;899 if (unlikely(f->tuner != 0))900 return -EINVAL;901 streaming = vb2_start_streaming_called(&dev->vb2_mpegq);902 if (streaming)903 blackbird_stop_codec(dev);904 905 cx88_set_freq(core, f);906 blackbird_initialize_codec(dev);907 cx88_set_scale(core, core->width, core->height, core->field);908 if (streaming)909 blackbird_start_codec(dev);910 return 0;911}912 913static int vidioc_log_status(struct file *file, void *priv)914{915 struct cx8802_dev *dev = video_drvdata(file);916 struct cx88_core *core = dev->core;917 char name[32 + 2];918 919 snprintf(name, sizeof(name), "%s/2", core->name);920 call_all(core, core, log_status);921 v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);922 return 0;923}924 925static int vidioc_enum_input(struct file *file, void *priv,926 struct v4l2_input *i)927{928 struct cx8802_dev *dev = video_drvdata(file);929 struct cx88_core *core = dev->core;930 931 return cx88_enum_input(core, i);932}933 934static int vidioc_g_frequency(struct file *file, void *priv,935 struct v4l2_frequency *f)936{937 struct cx8802_dev *dev = video_drvdata(file);938 struct cx88_core *core = dev->core;939 940 if (unlikely(core->board.tuner_type == UNSET))941 return -EINVAL;942 if (unlikely(f->tuner != 0))943 return -EINVAL;944 945 f->frequency = core->freq;946 call_all(core, tuner, g_frequency, f);947 948 return 0;949}950 951static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)952{953 struct cx8802_dev *dev = video_drvdata(file);954 struct cx88_core *core = dev->core;955 956 *i = core->input;957 return 0;958}959 960static int vidioc_s_input(struct file *file, void *priv, unsigned int i)961{962 struct cx8802_dev *dev = video_drvdata(file);963 struct cx88_core *core = dev->core;964 965 if (i >= 4)966 return -EINVAL;967 if (!INPUT(i).type)968 return -EINVAL;969 970 cx88_newstation(core);971 cx88_video_mux(core, i);972 return 0;973}974 975static int vidioc_g_tuner(struct file *file, void *priv,976 struct v4l2_tuner *t)977{978 struct cx8802_dev *dev = video_drvdata(file);979 struct cx88_core *core = dev->core;980 u32 reg;981 982 if (unlikely(core->board.tuner_type == UNSET))983 return -EINVAL;984 if (t->index != 0)985 return -EINVAL;986 987 strscpy(t->name, "Television", sizeof(t->name));988 t->capability = V4L2_TUNER_CAP_NORM;989 t->rangehigh = 0xffffffffUL;990 call_all(core, tuner, g_tuner, t);991 992 cx88_get_stereo(core, t);993 reg = cx_read(MO_DEVICE_STATUS);994 t->signal = (reg & (1 << 5)) ? 0xffff : 0x0000;995 return 0;996}997 998static int vidioc_s_tuner(struct file *file, void *priv,999 const struct v4l2_tuner *t)1000{1001 struct cx8802_dev *dev = video_drvdata(file);1002 struct cx88_core *core = dev->core;1003 1004 if (core->board.tuner_type == UNSET)1005 return -EINVAL;1006 if (t->index != 0)1007 return -EINVAL;1008 1009 cx88_set_stereo(core, t->audmode, 1);1010 return 0;1011}1012 1013static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)1014{1015 struct cx8802_dev *dev = video_drvdata(file);1016 struct cx88_core *core = dev->core;1017 1018 *tvnorm = core->tvnorm;1019 return 0;1020}1021 1022static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)1023{1024 struct cx8802_dev *dev = video_drvdata(file);1025 struct cx88_core *core = dev->core;1026 1027 return cx88_set_tvnorm(core, id);1028}1029 1030static const struct v4l2_file_operations mpeg_fops = {1031 .owner = THIS_MODULE,1032 .open = v4l2_fh_open,1033 .release = vb2_fop_release,1034 .read = vb2_fop_read,1035 .poll = vb2_fop_poll,1036 .mmap = vb2_fop_mmap,1037 .unlocked_ioctl = video_ioctl2,1038};1039 1040static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {1041 .vidioc_querycap = vidioc_querycap,1042 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,1043 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,1044 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,1045 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,1046 .vidioc_reqbufs = vb2_ioctl_reqbufs,1047 .vidioc_querybuf = vb2_ioctl_querybuf,1048 .vidioc_qbuf = vb2_ioctl_qbuf,1049 .vidioc_dqbuf = vb2_ioctl_dqbuf,1050 .vidioc_streamon = vb2_ioctl_streamon,1051 .vidioc_streamoff = vb2_ioctl_streamoff,1052 .vidioc_s_frequency = vidioc_s_frequency,1053 .vidioc_log_status = vidioc_log_status,1054 .vidioc_enum_input = vidioc_enum_input,1055 .vidioc_g_frequency = vidioc_g_frequency,1056 .vidioc_g_input = vidioc_g_input,1057 .vidioc_s_input = vidioc_s_input,1058 .vidioc_g_tuner = vidioc_g_tuner,1059 .vidioc_s_tuner = vidioc_s_tuner,1060 .vidioc_g_std = vidioc_g_std,1061 .vidioc_s_std = vidioc_s_std,1062 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,1063 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,1064};1065 1066static const struct video_device cx8802_mpeg_template = {1067 .name = "cx8802",1068 .fops = &mpeg_fops,1069 .ioctl_ops = &mpeg_ioctl_ops,1070 .tvnorms = CX88_NORMS,1071};1072 1073/* ------------------------------------------------------------------ */1074 1075/* The CX8802 MPEG API will call this when we can use the hardware */1076static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)1077{1078 struct cx88_core *core = drv->core;1079 int err = 0;1080 1081 switch (core->boardnr) {1082 case CX88_BOARD_HAUPPAUGE_HVR1300:1083 /*1084 * By default, core setup will leave the cx22702 out of reset,1085 * on the bus.1086 * We left the hardware on power up with the cx22702 active.1087 * We're being given access to re-arrange the GPIOs.1088 * Take the bus off the cx22702 and put the cx23416 on it.1089 */1090 /* Toggle reset on cx22702 leaving i2c active */1091 cx_set(MO_GP0_IO, 0x00000080);1092 udelay(1000);1093 cx_clear(MO_GP0_IO, 0x00000080);1094 udelay(50);1095 cx_set(MO_GP0_IO, 0x00000080);1096 udelay(1000);1097 /* tri-state the cx22702 pins */1098 cx_set(MO_GP0_IO, 0x00000004);1099 udelay(1000);1100 break;1101 default:1102 err = -ENODEV;1103 }1104 return err;1105}1106 1107/* The CX8802 MPEG API will call this when we need to release the hardware */1108static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)1109{1110 struct cx88_core *core = drv->core;1111 int err = 0;1112 1113 switch (core->boardnr) {1114 case CX88_BOARD_HAUPPAUGE_HVR1300:1115 /* Exit leaving the cx23416 on the bus */1116 break;1117 default:1118 err = -ENODEV;1119 }1120 return err;1121}1122 1123static void blackbird_unregister_video(struct cx8802_dev *dev)1124{1125 video_unregister_device(&dev->mpeg_dev);1126}1127 1128static int blackbird_register_video(struct cx8802_dev *dev)1129{1130 int err;1131 1132 cx88_vdev_init(dev->core, dev->pci, &dev->mpeg_dev,1133 &cx8802_mpeg_template, "mpeg");1134 dev->mpeg_dev.ctrl_handler = &dev->cxhdl.hdl;1135 video_set_drvdata(&dev->mpeg_dev, dev);1136 dev->mpeg_dev.queue = &dev->vb2_mpegq;1137 dev->mpeg_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |1138 V4L2_CAP_VIDEO_CAPTURE;1139 if (dev->core->board.tuner_type != UNSET)1140 dev->mpeg_dev.device_caps |= V4L2_CAP_TUNER;1141 err = video_register_device(&dev->mpeg_dev, VFL_TYPE_VIDEO, -1);1142 if (err < 0) {1143 pr_info("can't register mpeg device\n");1144 return err;1145 }1146 pr_info("registered device %s [mpeg]\n",1147 video_device_node_name(&dev->mpeg_dev));1148 return 0;1149}1150 1151/* ----------------------------------------------------------- */1152 1153static int cx8802_blackbird_probe(struct cx8802_driver *drv)1154{1155 struct cx88_core *core = drv->core;1156 struct cx8802_dev *dev = core->dvbdev;1157 struct vb2_queue *q;1158 int err;1159 1160 dprintk(1, "%s\n", __func__);1161 dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",1162 core->boardnr,1163 core->name,1164 core->pci_bus,1165 core->pci_slot);1166 1167 err = -ENODEV;1168 if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))1169 goto fail_core;1170 1171 dev->cxhdl.port = CX2341X_PORT_STREAMING;1172 dev->cxhdl.width = core->width;1173 dev->cxhdl.height = core->height;1174 dev->cxhdl.func = blackbird_mbox_func;1175 dev->cxhdl.priv = dev;1176 err = cx2341x_handler_init(&dev->cxhdl, 36);1177 if (err)1178 goto fail_core;1179 v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl, NULL, false);1180 1181 /* blackbird stuff */1182 pr_info("cx23416 based mpeg encoder (blackbird reference design)\n");1183 host_setup(dev->core);1184 1185 blackbird_initialize_codec(dev);1186 1187 /* initial device configuration: needed ? */1188// init_controls(core);1189 cx88_set_tvnorm(core, core->tvnorm);1190 cx88_video_mux(core, 0);1191 cx2341x_handler_set_50hz(&dev->cxhdl, core->height == 576);1192 cx2341x_handler_setup(&dev->cxhdl);1193 1194 q = &dev->vb2_mpegq;1195 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;1196 q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;1197 q->gfp_flags = GFP_DMA32;1198 q->min_queued_buffers = 2;1199 q->drv_priv = dev;1200 q->buf_struct_size = sizeof(struct cx88_buffer);1201 q->ops = &blackbird_qops;1202 q->mem_ops = &vb2_dma_sg_memops;1203 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;1204 q->lock = &core->lock;1205 q->dev = &dev->pci->dev;1206 1207 err = vb2_queue_init(q);1208 if (err < 0)1209 goto fail_core;1210 1211 blackbird_register_video(dev);1212 1213 return 0;1214 1215fail_core:1216 return err;1217}1218 1219static int cx8802_blackbird_remove(struct cx8802_driver *drv)1220{1221 struct cx88_core *core = drv->core;1222 struct cx8802_dev *dev = core->dvbdev;1223 1224 /* blackbird */1225 blackbird_unregister_video(drv->core->dvbdev);1226 v4l2_ctrl_handler_free(&dev->cxhdl.hdl);1227 1228 return 0;1229}1230 1231static struct cx8802_driver cx8802_blackbird_driver = {1232 .type_id = CX88_MPEG_BLACKBIRD,1233 .hw_access = CX8802_DRVCTL_SHARED,1234 .probe = cx8802_blackbird_probe,1235 .remove = cx8802_blackbird_remove,1236 .advise_acquire = cx8802_blackbird_advise_acquire,1237 .advise_release = cx8802_blackbird_advise_release,1238};1239 1240static int __init blackbird_init(void)1241{1242 pr_info("cx2388x blackbird driver version %s loaded\n",1243 CX88_VERSION);1244 return cx8802_register_driver(&cx8802_blackbird_driver);1245}1246 1247static void __exit blackbird_fini(void)1248{1249 cx8802_unregister_driver(&cx8802_blackbird_driver);1250}1251 1252module_init(blackbird_init);1253module_exit(blackbird_fini);1254