Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12 1381 lines 38 kB view raw
1/* 2 * SuperH Video Output Unit (VOU) driver 3 * 4 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11#include <linux/dma-mapping.h> 12#include <linux/delay.h> 13#include <linux/errno.h> 14#include <linux/fs.h> 15#include <linux/i2c.h> 16#include <linux/init.h> 17#include <linux/interrupt.h> 18#include <linux/kernel.h> 19#include <linux/platform_device.h> 20#include <linux/pm_runtime.h> 21#include <linux/slab.h> 22#include <linux/videodev2.h> 23#include <linux/module.h> 24 25#include <media/drv-intf/sh_vou.h> 26#include <media/v4l2-common.h> 27#include <media/v4l2-device.h> 28#include <media/v4l2-ioctl.h> 29#include <media/v4l2-mediabus.h> 30#include <media/videobuf2-v4l2.h> 31#include <media/videobuf2-dma-contig.h> 32 33/* Mirror addresses are not available for all registers */ 34#define VOUER 0 35#define VOUCR 4 36#define VOUSTR 8 37#define VOUVCR 0xc 38#define VOUISR 0x10 39#define VOUBCR 0x14 40#define VOUDPR 0x18 41#define VOUDSR 0x1c 42#define VOUVPR 0x20 43#define VOUIR 0x24 44#define VOUSRR 0x28 45#define VOUMSR 0x2c 46#define VOUHIR 0x30 47#define VOUDFR 0x34 48#define VOUAD1R 0x38 49#define VOUAD2R 0x3c 50#define VOUAIR 0x40 51#define VOUSWR 0x44 52#define VOURCR 0x48 53#define VOURPR 0x50 54 55enum sh_vou_status { 56 SH_VOU_IDLE, 57 SH_VOU_INITIALISING, 58 SH_VOU_RUNNING, 59}; 60 61#define VOU_MIN_IMAGE_WIDTH 16 62#define VOU_MAX_IMAGE_WIDTH 720 63#define VOU_MIN_IMAGE_HEIGHT 16 64 65struct sh_vou_buffer { 66 struct vb2_v4l2_buffer vb; 67 struct list_head list; 68}; 69 70static inline struct 71sh_vou_buffer *to_sh_vou_buffer(struct vb2_v4l2_buffer *vb2) 72{ 73 return container_of(vb2, struct sh_vou_buffer, vb); 74} 75 76struct sh_vou_device { 77 struct v4l2_device v4l2_dev; 78 struct video_device vdev; 79 struct sh_vou_pdata *pdata; 80 spinlock_t lock; 81 void __iomem *base; 82 /* State information */ 83 struct v4l2_pix_format pix; 84 struct v4l2_rect rect; 85 struct list_head buf_list; 86 v4l2_std_id std; 87 int pix_idx; 88 struct vb2_queue queue; 89 struct sh_vou_buffer *active; 90 enum sh_vou_status status; 91 unsigned sequence; 92 struct mutex fop_lock; 93}; 94 95/* Register access routines for sides A, B and mirror addresses */ 96static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg, 97 u32 value) 98{ 99 __raw_writel(value, vou_dev->base + reg); 100} 101 102static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg, 103 u32 value) 104{ 105 __raw_writel(value, vou_dev->base + reg); 106 __raw_writel(value, vou_dev->base + reg + 0x1000); 107} 108 109static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg, 110 u32 value) 111{ 112 __raw_writel(value, vou_dev->base + reg + 0x2000); 113} 114 115static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg) 116{ 117 return __raw_readl(vou_dev->base + reg); 118} 119 120static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg, 121 u32 value, u32 mask) 122{ 123 u32 old = __raw_readl(vou_dev->base + reg); 124 125 value = (value & mask) | (old & ~mask); 126 __raw_writel(value, vou_dev->base + reg); 127} 128 129static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg, 130 u32 value, u32 mask) 131{ 132 sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask); 133} 134 135static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg, 136 u32 value, u32 mask) 137{ 138 sh_vou_reg_a_set(vou_dev, reg, value, mask); 139 sh_vou_reg_b_set(vou_dev, reg, value, mask); 140} 141 142struct sh_vou_fmt { 143 u32 pfmt; 144 char *desc; 145 unsigned char bpp; 146 unsigned char bpl; 147 unsigned char rgb; 148 unsigned char yf; 149 unsigned char pkf; 150}; 151 152/* Further pixel formats can be added */ 153static struct sh_vou_fmt vou_fmt[] = { 154 { 155 .pfmt = V4L2_PIX_FMT_NV12, 156 .bpp = 12, 157 .bpl = 1, 158 .desc = "YVU420 planar", 159 .yf = 0, 160 .rgb = 0, 161 }, 162 { 163 .pfmt = V4L2_PIX_FMT_NV16, 164 .bpp = 16, 165 .bpl = 1, 166 .desc = "YVYU planar", 167 .yf = 1, 168 .rgb = 0, 169 }, 170 { 171 .pfmt = V4L2_PIX_FMT_RGB24, 172 .bpp = 24, 173 .bpl = 3, 174 .desc = "RGB24", 175 .pkf = 2, 176 .rgb = 1, 177 }, 178 { 179 .pfmt = V4L2_PIX_FMT_RGB565, 180 .bpp = 16, 181 .bpl = 2, 182 .desc = "RGB565", 183 .pkf = 3, 184 .rgb = 1, 185 }, 186 { 187 .pfmt = V4L2_PIX_FMT_RGB565X, 188 .bpp = 16, 189 .bpl = 2, 190 .desc = "RGB565 byteswapped", 191 .pkf = 3, 192 .rgb = 1, 193 }, 194}; 195 196static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, 197 struct vb2_v4l2_buffer *vbuf) 198{ 199 dma_addr_t addr1, addr2; 200 201 addr1 = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); 202 switch (vou_dev->pix.pixelformat) { 203 case V4L2_PIX_FMT_NV12: 204 case V4L2_PIX_FMT_NV16: 205 addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height; 206 break; 207 default: 208 addr2 = 0; 209 } 210 211 sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1); 212 sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2); 213} 214 215static void sh_vou_stream_config(struct sh_vou_device *vou_dev) 216{ 217 unsigned int row_coeff; 218#ifdef __LITTLE_ENDIAN 219 u32 dataswap = 7; 220#else 221 u32 dataswap = 0; 222#endif 223 224 switch (vou_dev->pix.pixelformat) { 225 default: 226 case V4L2_PIX_FMT_NV12: 227 case V4L2_PIX_FMT_NV16: 228 row_coeff = 1; 229 break; 230 case V4L2_PIX_FMT_RGB565: 231 dataswap ^= 1; 232 case V4L2_PIX_FMT_RGB565X: 233 row_coeff = 2; 234 break; 235 case V4L2_PIX_FMT_RGB24: 236 row_coeff = 3; 237 break; 238 } 239 240 sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap); 241 sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff); 242} 243 244/* Locking: caller holds fop_lock mutex */ 245static int sh_vou_queue_setup(struct vb2_queue *vq, 246 unsigned int *nbuffers, unsigned int *nplanes, 247 unsigned int sizes[], struct device *alloc_devs[]) 248{ 249 struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); 250 struct v4l2_pix_format *pix = &vou_dev->pix; 251 int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; 252 253 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 254 255 if (*nplanes) 256 return sizes[0] < pix->height * bytes_per_line ? -EINVAL : 0; 257 *nplanes = 1; 258 sizes[0] = pix->height * bytes_per_line; 259 return 0; 260} 261 262static int sh_vou_buf_prepare(struct vb2_buffer *vb) 263{ 264 struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); 265 struct v4l2_pix_format *pix = &vou_dev->pix; 266 unsigned bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; 267 unsigned size = pix->height * bytes_per_line; 268 269 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 270 271 if (vb2_plane_size(vb, 0) < size) { 272 /* User buffer too small */ 273 dev_warn(vou_dev->v4l2_dev.dev, "buffer too small (%lu < %u)\n", 274 vb2_plane_size(vb, 0), size); 275 return -EINVAL; 276 } 277 278 vb2_set_plane_payload(vb, 0, size); 279 return 0; 280} 281 282/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ 283static void sh_vou_buf_queue(struct vb2_buffer *vb) 284{ 285 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 286 struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); 287 struct sh_vou_buffer *shbuf = to_sh_vou_buffer(vbuf); 288 unsigned long flags; 289 290 spin_lock_irqsave(&vou_dev->lock, flags); 291 list_add_tail(&shbuf->list, &vou_dev->buf_list); 292 spin_unlock_irqrestore(&vou_dev->lock, flags); 293} 294 295static int sh_vou_start_streaming(struct vb2_queue *vq, unsigned int count) 296{ 297 struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); 298 struct sh_vou_buffer *buf, *node; 299 int ret; 300 301 vou_dev->sequence = 0; 302 ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, 303 video, s_stream, 1); 304 if (ret < 0 && ret != -ENOIOCTLCMD) { 305 list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { 306 vb2_buffer_done(&buf->vb.vb2_buf, 307 VB2_BUF_STATE_QUEUED); 308 list_del(&buf->list); 309 } 310 vou_dev->active = NULL; 311 return ret; 312 } 313 314 buf = list_entry(vou_dev->buf_list.next, struct sh_vou_buffer, list); 315 316 vou_dev->active = buf; 317 318 /* Start from side A: we use mirror addresses, so, set B */ 319 sh_vou_reg_a_write(vou_dev, VOURPR, 1); 320 dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", 321 __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); 322 sh_vou_schedule_next(vou_dev, &buf->vb); 323 324 buf = list_entry(buf->list.next, struct sh_vou_buffer, list); 325 326 /* Second buffer - initialise register side B */ 327 sh_vou_reg_a_write(vou_dev, VOURPR, 0); 328 sh_vou_schedule_next(vou_dev, &buf->vb); 329 330 /* Register side switching with frame VSYNC */ 331 sh_vou_reg_a_write(vou_dev, VOURCR, 5); 332 333 sh_vou_stream_config(vou_dev); 334 /* Enable End-of-Frame (VSYNC) interrupts */ 335 sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); 336 337 /* Two buffers on the queue - activate the hardware */ 338 vou_dev->status = SH_VOU_RUNNING; 339 sh_vou_reg_a_write(vou_dev, VOUER, 0x107); 340 return 0; 341} 342 343static void sh_vou_stop_streaming(struct vb2_queue *vq) 344{ 345 struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); 346 struct sh_vou_buffer *buf, *node; 347 unsigned long flags; 348 349 v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, 350 video, s_stream, 0); 351 /* disable output */ 352 sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); 353 /* ...but the current frame will complete */ 354 sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); 355 msleep(50); 356 spin_lock_irqsave(&vou_dev->lock, flags); 357 list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { 358 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 359 list_del(&buf->list); 360 } 361 vou_dev->active = NULL; 362 spin_unlock_irqrestore(&vou_dev->lock, flags); 363} 364 365static const struct vb2_ops sh_vou_qops = { 366 .queue_setup = sh_vou_queue_setup, 367 .buf_prepare = sh_vou_buf_prepare, 368 .buf_queue = sh_vou_buf_queue, 369 .start_streaming = sh_vou_start_streaming, 370 .stop_streaming = sh_vou_stop_streaming, 371 .wait_prepare = vb2_ops_wait_prepare, 372 .wait_finish = vb2_ops_wait_finish, 373}; 374 375/* Video IOCTLs */ 376static int sh_vou_querycap(struct file *file, void *priv, 377 struct v4l2_capability *cap) 378{ 379 struct sh_vou_device *vou_dev = video_drvdata(file); 380 381 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 382 383 strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); 384 strlcpy(cap->driver, "sh-vou", sizeof(cap->driver)); 385 strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); 386 cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE | 387 V4L2_CAP_STREAMING; 388 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; 389 return 0; 390} 391 392/* Enumerate formats, that the device can accept from the user */ 393static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv, 394 struct v4l2_fmtdesc *fmt) 395{ 396 struct sh_vou_device *vou_dev = video_drvdata(file); 397 398 if (fmt->index >= ARRAY_SIZE(vou_fmt)) 399 return -EINVAL; 400 401 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 402 403 fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 404 strlcpy(fmt->description, vou_fmt[fmt->index].desc, 405 sizeof(fmt->description)); 406 fmt->pixelformat = vou_fmt[fmt->index].pfmt; 407 408 return 0; 409} 410 411static int sh_vou_g_fmt_vid_out(struct file *file, void *priv, 412 struct v4l2_format *fmt) 413{ 414 struct sh_vou_device *vou_dev = video_drvdata(file); 415 416 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 417 418 fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 419 fmt->fmt.pix = vou_dev->pix; 420 421 return 0; 422} 423 424static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4}; 425static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1}; 426static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3}; 427static const unsigned char vou_scale_v_num[] = {1, 2, 4}; 428static const unsigned char vou_scale_v_den[] = {1, 1, 1}; 429static const unsigned char vou_scale_v_fld[] = {0, 1}; 430 431static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev, 432 int pix_idx, int w_idx, int h_idx) 433{ 434 struct sh_vou_fmt *fmt = vou_fmt + pix_idx; 435 unsigned int black_left, black_top, width_max, 436 frame_in_height, frame_out_height, frame_out_top; 437 struct v4l2_rect *rect = &vou_dev->rect; 438 struct v4l2_pix_format *pix = &vou_dev->pix; 439 u32 vouvcr = 0, dsr_h, dsr_v; 440 441 if (vou_dev->std & V4L2_STD_525_60) { 442 width_max = 858; 443 /* height_max = 262; */ 444 } else { 445 width_max = 864; 446 /* height_max = 312; */ 447 } 448 449 frame_in_height = pix->height / 2; 450 frame_out_height = rect->height / 2; 451 frame_out_top = rect->top / 2; 452 453 /* 454 * Cropping scheme: max useful image is 720x480, and the total video 455 * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts 456 * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock, 457 * of which the first 33 / 25 clocks HSYNC must be held active. This 458 * has to be configured in CR[HW]. 1 pixel equals 2 clock periods. 459 * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives 460 * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area, 461 * beyond DSR, specified on the left and top by the VPR register "black 462 * pixels" and out-of-image area (DPR) "background pixels." We fix VPR 463 * at 138 / 144 : 20, because that's the HSYNC timing, that our first 464 * client requires, and that's exactly what leaves us 720 pixels for the 465 * image; we leave VPR[VVP] at default 20 for now, because the client 466 * doesn't seem to have any special requirements for it. Otherwise we 467 * could also set it to max - 240 = 22 / 72. Thus VPR depends only on 468 * the selected standard, and DPR and DSR are selected according to 469 * cropping. Q: how does the client detect the first valid line? Does 470 * HSYNC stay inactive during invalid (black) lines? 471 */ 472 black_left = width_max - VOU_MAX_IMAGE_WIDTH; 473 black_top = 20; 474 475 dsr_h = rect->width + rect->left; 476 dsr_v = frame_out_height + frame_out_top; 477 478 dev_dbg(vou_dev->v4l2_dev.dev, 479 "image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n", 480 pix->width, frame_in_height, black_left, black_top, 481 rect->left, frame_out_top, dsr_h, dsr_v); 482 483 /* VOUISR height - half of a frame height in frame mode */ 484 sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height); 485 sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top); 486 sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top); 487 sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v); 488 489 /* 490 * if necessary, we could set VOUHIR to 491 * max(black_left + dsr_h, width_max) here 492 */ 493 494 if (w_idx) 495 vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4); 496 if (h_idx) 497 vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1]; 498 499 dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr); 500 501 /* To produce a colour bar for testing set bit 23 of VOUVCR */ 502 sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr); 503 sh_vou_reg_ab_write(vou_dev, VOUDFR, 504 fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16)); 505} 506 507struct sh_vou_geometry { 508 struct v4l2_rect output; 509 unsigned int in_width; 510 unsigned int in_height; 511 int scale_idx_h; 512 int scale_idx_v; 513}; 514 515/* 516 * Find input geometry, that we can use to produce output, closest to the 517 * requested rectangle, using VOU scaling 518 */ 519static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std) 520{ 521 /* The compiler cannot know, that best and idx will indeed be set */ 522 unsigned int best_err = UINT_MAX, best = 0, img_height_max; 523 int i, idx = 0; 524 525 if (std & V4L2_STD_525_60) 526 img_height_max = 480; 527 else 528 img_height_max = 576; 529 530 /* Image width must be a multiple of 4 */ 531 v4l_bound_align_image(&geo->in_width, 532 VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, 533 &geo->in_height, 534 VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); 535 536 /* Select scales to come as close as possible to the output image */ 537 for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) { 538 unsigned int err; 539 unsigned int found = geo->output.width * vou_scale_h_den[i] / 540 vou_scale_h_num[i]; 541 542 if (found > VOU_MAX_IMAGE_WIDTH) 543 /* scales increase */ 544 break; 545 546 err = abs(found - geo->in_width); 547 if (err < best_err) { 548 best_err = err; 549 idx = i; 550 best = found; 551 } 552 if (!err) 553 break; 554 } 555 556 geo->in_width = best; 557 geo->scale_idx_h = idx; 558 559 best_err = UINT_MAX; 560 561 /* This loop can be replaced with one division */ 562 for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) { 563 unsigned int err; 564 unsigned int found = geo->output.height * vou_scale_v_den[i] / 565 vou_scale_v_num[i]; 566 567 if (found > img_height_max) 568 /* scales increase */ 569 break; 570 571 err = abs(found - geo->in_height); 572 if (err < best_err) { 573 best_err = err; 574 idx = i; 575 best = found; 576 } 577 if (!err) 578 break; 579 } 580 581 geo->in_height = best; 582 geo->scale_idx_v = idx; 583} 584 585/* 586 * Find output geometry, that we can produce, using VOU scaling, closest to 587 * the requested rectangle 588 */ 589static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) 590{ 591 unsigned int best_err = UINT_MAX, best = geo->in_width, 592 width_max, height_max, img_height_max; 593 int i, idx_h = 0, idx_v = 0; 594 595 if (std & V4L2_STD_525_60) { 596 width_max = 858; 597 height_max = 262 * 2; 598 img_height_max = 480; 599 } else { 600 width_max = 864; 601 height_max = 312 * 2; 602 img_height_max = 576; 603 } 604 605 /* Select scales to come as close as possible to the output image */ 606 for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) { 607 unsigned int err; 608 unsigned int found = geo->in_width * vou_scale_h_num[i] / 609 vou_scale_h_den[i]; 610 611 if (found > VOU_MAX_IMAGE_WIDTH) 612 /* scales increase */ 613 break; 614 615 err = abs(found - geo->output.width); 616 if (err < best_err) { 617 best_err = err; 618 idx_h = i; 619 best = found; 620 } 621 if (!err) 622 break; 623 } 624 625 geo->output.width = best; 626 geo->scale_idx_h = idx_h; 627 if (geo->output.left + best > width_max) 628 geo->output.left = width_max - best; 629 630 pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width, 631 vou_scale_h_num[idx_h], vou_scale_h_den[idx_h], best); 632 633 best_err = UINT_MAX; 634 635 /* This loop can be replaced with one division */ 636 for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) { 637 unsigned int err; 638 unsigned int found = geo->in_height * vou_scale_v_num[i] / 639 vou_scale_v_den[i]; 640 641 if (found > img_height_max) 642 /* scales increase */ 643 break; 644 645 err = abs(found - geo->output.height); 646 if (err < best_err) { 647 best_err = err; 648 idx_v = i; 649 best = found; 650 } 651 if (!err) 652 break; 653 } 654 655 geo->output.height = best; 656 geo->scale_idx_v = idx_v; 657 if (geo->output.top + best > height_max) 658 geo->output.top = height_max - best; 659 660 pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height, 661 vou_scale_v_num[idx_v], vou_scale_v_den[idx_v], best); 662} 663 664static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, 665 struct v4l2_format *fmt) 666{ 667 struct sh_vou_device *vou_dev = video_drvdata(file); 668 struct v4l2_pix_format *pix = &fmt->fmt.pix; 669 unsigned int img_height_max; 670 int pix_idx; 671 672 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 673 674 pix->field = V4L2_FIELD_INTERLACED; 675 pix->colorspace = V4L2_COLORSPACE_SMPTE170M; 676 pix->ycbcr_enc = pix->quantization = 0; 677 678 for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) 679 if (vou_fmt[pix_idx].pfmt == pix->pixelformat) 680 break; 681 682 if (pix_idx == ARRAY_SIZE(vou_fmt)) 683 return -EINVAL; 684 685 if (vou_dev->std & V4L2_STD_525_60) 686 img_height_max = 480; 687 else 688 img_height_max = 576; 689 690 v4l_bound_align_image(&pix->width, 691 VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, 692 &pix->height, 693 VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); 694 pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl; 695 pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3); 696 697 return 0; 698} 699 700static int sh_vou_set_fmt_vid_out(struct sh_vou_device *vou_dev, 701 struct v4l2_pix_format *pix) 702{ 703 unsigned int img_height_max; 704 struct sh_vou_geometry geo; 705 struct v4l2_subdev_format format = { 706 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 707 /* Revisit: is this the correct code? */ 708 .format.code = MEDIA_BUS_FMT_YUYV8_2X8, 709 .format.field = V4L2_FIELD_INTERLACED, 710 .format.colorspace = V4L2_COLORSPACE_SMPTE170M, 711 }; 712 struct v4l2_mbus_framefmt *mbfmt = &format.format; 713 int pix_idx; 714 int ret; 715 716 if (vb2_is_busy(&vou_dev->queue)) 717 return -EBUSY; 718 719 for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) 720 if (vou_fmt[pix_idx].pfmt == pix->pixelformat) 721 break; 722 723 geo.in_width = pix->width; 724 geo.in_height = pix->height; 725 geo.output = vou_dev->rect; 726 727 vou_adjust_output(&geo, vou_dev->std); 728 729 mbfmt->width = geo.output.width; 730 mbfmt->height = geo.output.height; 731 ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, 732 set_fmt, NULL, &format); 733 /* Must be implemented, so, don't check for -ENOIOCTLCMD */ 734 if (ret < 0) 735 return ret; 736 737 dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, 738 geo.output.width, geo.output.height, mbfmt->width, mbfmt->height); 739 740 if (vou_dev->std & V4L2_STD_525_60) 741 img_height_max = 480; 742 else 743 img_height_max = 576; 744 745 /* Sanity checks */ 746 if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH || 747 (unsigned)mbfmt->height > img_height_max || 748 mbfmt->code != MEDIA_BUS_FMT_YUYV8_2X8) 749 return -EIO; 750 751 if (mbfmt->width != geo.output.width || 752 mbfmt->height != geo.output.height) { 753 geo.output.width = mbfmt->width; 754 geo.output.height = mbfmt->height; 755 756 vou_adjust_input(&geo, vou_dev->std); 757 } 758 759 /* We tried to preserve output rectangle, but it could have changed */ 760 vou_dev->rect = geo.output; 761 pix->width = geo.in_width; 762 pix->height = geo.in_height; 763 764 dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__, 765 pix->width, pix->height); 766 767 vou_dev->pix_idx = pix_idx; 768 769 vou_dev->pix = *pix; 770 771 sh_vou_configure_geometry(vou_dev, pix_idx, 772 geo.scale_idx_h, geo.scale_idx_v); 773 774 return 0; 775} 776 777static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, 778 struct v4l2_format *fmt) 779{ 780 struct sh_vou_device *vou_dev = video_drvdata(file); 781 int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); 782 783 if (ret) 784 return ret; 785 return sh_vou_set_fmt_vid_out(vou_dev, &fmt->fmt.pix); 786} 787 788static int sh_vou_enum_output(struct file *file, void *fh, 789 struct v4l2_output *a) 790{ 791 struct sh_vou_device *vou_dev = video_drvdata(file); 792 793 if (a->index) 794 return -EINVAL; 795 strlcpy(a->name, "Video Out", sizeof(a->name)); 796 a->type = V4L2_OUTPUT_TYPE_ANALOG; 797 a->std = vou_dev->vdev.tvnorms; 798 return 0; 799} 800 801static int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) 802{ 803 *i = 0; 804 return 0; 805} 806 807static int sh_vou_s_output(struct file *file, void *fh, unsigned int i) 808{ 809 return i ? -EINVAL : 0; 810} 811 812static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) 813{ 814 switch (bus_fmt) { 815 default: 816 pr_warn("%s(): Invalid bus-format code %d, using default 8-bit\n", 817 __func__, bus_fmt); 818 case SH_VOU_BUS_8BIT: 819 return 1; 820 case SH_VOU_BUS_16BIT: 821 return 0; 822 case SH_VOU_BUS_BT656: 823 return 3; 824 } 825} 826 827static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) 828{ 829 struct sh_vou_device *vou_dev = video_drvdata(file); 830 int ret; 831 832 dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); 833 834 if (std_id == vou_dev->std) 835 return 0; 836 837 if (vb2_is_busy(&vou_dev->queue)) 838 return -EBUSY; 839 840 ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, 841 s_std_output, std_id); 842 /* Shall we continue, if the subdev doesn't support .s_std_output()? */ 843 if (ret < 0 && ret != -ENOIOCTLCMD) 844 return ret; 845 846 vou_dev->rect.top = vou_dev->rect.left = 0; 847 vou_dev->rect.width = VOU_MAX_IMAGE_WIDTH; 848 if (std_id & V4L2_STD_525_60) { 849 sh_vou_reg_ab_set(vou_dev, VOUCR, 850 sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); 851 vou_dev->rect.height = 480; 852 } else { 853 sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); 854 vou_dev->rect.height = 576; 855 } 856 857 vou_dev->pix.width = vou_dev->rect.width; 858 vou_dev->pix.height = vou_dev->rect.height; 859 vou_dev->pix.bytesperline = 860 vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpl; 861 vou_dev->pix.sizeimage = vou_dev->pix.height * 862 ((vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpp) >> 3); 863 vou_dev->std = std_id; 864 sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); 865 866 return 0; 867} 868 869static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) 870{ 871 struct sh_vou_device *vou_dev = video_drvdata(file); 872 873 dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); 874 875 *std = vou_dev->std; 876 877 return 0; 878} 879 880static int sh_vou_log_status(struct file *file, void *priv) 881{ 882 struct sh_vou_device *vou_dev = video_drvdata(file); 883 884 pr_info("VOUER: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUER)); 885 pr_info("VOUCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUCR)); 886 pr_info("VOUSTR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSTR)); 887 pr_info("VOUVCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVCR)); 888 pr_info("VOUISR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUISR)); 889 pr_info("VOUBCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUBCR)); 890 pr_info("VOUDPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDPR)); 891 pr_info("VOUDSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDSR)); 892 pr_info("VOUVPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVPR)); 893 pr_info("VOUIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUIR)); 894 pr_info("VOUSRR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSRR)); 895 pr_info("VOUMSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUMSR)); 896 pr_info("VOUHIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUHIR)); 897 pr_info("VOUDFR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDFR)); 898 pr_info("VOUAD1R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD1R)); 899 pr_info("VOUAD2R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD2R)); 900 pr_info("VOUAIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAIR)); 901 pr_info("VOUSWR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSWR)); 902 pr_info("VOURCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURCR)); 903 pr_info("VOURPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURPR)); 904 return 0; 905} 906 907static int sh_vou_g_selection(struct file *file, void *fh, 908 struct v4l2_selection *sel) 909{ 910 struct sh_vou_device *vou_dev = video_drvdata(file); 911 912 if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 913 return -EINVAL; 914 switch (sel->target) { 915 case V4L2_SEL_TGT_COMPOSE: 916 sel->r = vou_dev->rect; 917 break; 918 case V4L2_SEL_TGT_COMPOSE_DEFAULT: 919 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 920 sel->r.left = 0; 921 sel->r.top = 0; 922 sel->r.width = VOU_MAX_IMAGE_WIDTH; 923 if (vou_dev->std & V4L2_STD_525_60) 924 sel->r.height = 480; 925 else 926 sel->r.height = 576; 927 break; 928 default: 929 return -EINVAL; 930 } 931 return 0; 932} 933 934/* Assume a dull encoder, do all the work ourselves. */ 935static int sh_vou_s_selection(struct file *file, void *fh, 936 struct v4l2_selection *sel) 937{ 938 struct v4l2_rect *rect = &sel->r; 939 struct sh_vou_device *vou_dev = video_drvdata(file); 940 struct v4l2_subdev_selection sd_sel = { 941 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 942 .target = V4L2_SEL_TGT_COMPOSE, 943 }; 944 struct v4l2_pix_format *pix = &vou_dev->pix; 945 struct sh_vou_geometry geo; 946 struct v4l2_subdev_format format = { 947 .which = V4L2_SUBDEV_FORMAT_ACTIVE, 948 /* Revisit: is this the correct code? */ 949 .format.code = MEDIA_BUS_FMT_YUYV8_2X8, 950 .format.field = V4L2_FIELD_INTERLACED, 951 .format.colorspace = V4L2_COLORSPACE_SMPTE170M, 952 }; 953 unsigned int img_height_max; 954 int ret; 955 956 if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 957 sel->target != V4L2_SEL_TGT_COMPOSE) 958 return -EINVAL; 959 960 if (vb2_is_busy(&vou_dev->queue)) 961 return -EBUSY; 962 963 if (vou_dev->std & V4L2_STD_525_60) 964 img_height_max = 480; 965 else 966 img_height_max = 576; 967 968 v4l_bound_align_image(&rect->width, 969 VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 1, 970 &rect->height, 971 VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); 972 973 if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH) 974 rect->left = VOU_MAX_IMAGE_WIDTH - rect->width; 975 976 if (rect->height + rect->top > img_height_max) 977 rect->top = img_height_max - rect->height; 978 979 geo.output = *rect; 980 geo.in_width = pix->width; 981 geo.in_height = pix->height; 982 983 /* Configure the encoder one-to-one, position at 0, ignore errors */ 984 sd_sel.r.width = geo.output.width; 985 sd_sel.r.height = geo.output.height; 986 /* 987 * We first issue a S_SELECTION, so that the subsequent S_FMT delivers the 988 * final encoder configuration. 989 */ 990 v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, 991 set_selection, NULL, &sd_sel); 992 format.format.width = geo.output.width; 993 format.format.height = geo.output.height; 994 ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, 995 set_fmt, NULL, &format); 996 /* Must be implemented, so, don't check for -ENOIOCTLCMD */ 997 if (ret < 0) 998 return ret; 999 1000 /* Sanity checks */ 1001 if ((unsigned)format.format.width > VOU_MAX_IMAGE_WIDTH || 1002 (unsigned)format.format.height > img_height_max || 1003 format.format.code != MEDIA_BUS_FMT_YUYV8_2X8) 1004 return -EIO; 1005 1006 geo.output.width = format.format.width; 1007 geo.output.height = format.format.height; 1008 1009 /* 1010 * No down-scaling. According to the API, current call has precedence: 1011 * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two. 1012 */ 1013 vou_adjust_input(&geo, vou_dev->std); 1014 1015 /* We tried to preserve output rectangle, but it could have changed */ 1016 vou_dev->rect = geo.output; 1017 pix->width = geo.in_width; 1018 pix->height = geo.in_height; 1019 1020 sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx, 1021 geo.scale_idx_h, geo.scale_idx_v); 1022 1023 return 0; 1024} 1025 1026static irqreturn_t sh_vou_isr(int irq, void *dev_id) 1027{ 1028 struct sh_vou_device *vou_dev = dev_id; 1029 static unsigned long j; 1030 struct sh_vou_buffer *vb; 1031 static int cnt; 1032 u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; 1033 u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); 1034 1035 if (!(irq_status & 0x300)) { 1036 if (printk_timed_ratelimit(&j, 500)) 1037 dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n", 1038 irq_status); 1039 return IRQ_NONE; 1040 } 1041 1042 spin_lock(&vou_dev->lock); 1043 if (!vou_dev->active || list_empty(&vou_dev->buf_list)) { 1044 if (printk_timed_ratelimit(&j, 500)) 1045 dev_warn(vou_dev->v4l2_dev.dev, 1046 "IRQ without active buffer: %x!\n", irq_status); 1047 /* Just ack: buf_release will disable further interrupts */ 1048 sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300); 1049 spin_unlock(&vou_dev->lock); 1050 return IRQ_HANDLED; 1051 } 1052 1053 masked = ~(0x300 & irq_status) & irq_status & 0x30304; 1054 dev_dbg(vou_dev->v4l2_dev.dev, 1055 "IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n", 1056 irq_status, masked, vou_status, cnt); 1057 1058 cnt++; 1059 /* side = vou_status & 0x10000; */ 1060 1061 /* Clear only set interrupts */ 1062 sh_vou_reg_a_write(vou_dev, VOUIR, masked); 1063 1064 vb = vou_dev->active; 1065 if (list_is_singular(&vb->list)) { 1066 /* Keep cycling while no next buffer is available */ 1067 sh_vou_schedule_next(vou_dev, &vb->vb); 1068 spin_unlock(&vou_dev->lock); 1069 return IRQ_HANDLED; 1070 } 1071 1072 list_del(&vb->list); 1073 1074 vb->vb.vb2_buf.timestamp = ktime_get_ns(); 1075 vb->vb.sequence = vou_dev->sequence++; 1076 vb->vb.field = V4L2_FIELD_INTERLACED; 1077 vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE); 1078 1079 vou_dev->active = list_entry(vou_dev->buf_list.next, 1080 struct sh_vou_buffer, list); 1081 1082 if (list_is_singular(&vou_dev->buf_list)) { 1083 /* Keep cycling while no next buffer is available */ 1084 sh_vou_schedule_next(vou_dev, &vou_dev->active->vb); 1085 } else { 1086 struct sh_vou_buffer *new = list_entry(vou_dev->active->list.next, 1087 struct sh_vou_buffer, list); 1088 sh_vou_schedule_next(vou_dev, &new->vb); 1089 } 1090 1091 spin_unlock(&vou_dev->lock); 1092 1093 return IRQ_HANDLED; 1094} 1095 1096static int sh_vou_hw_init(struct sh_vou_device *vou_dev) 1097{ 1098 struct sh_vou_pdata *pdata = vou_dev->pdata; 1099 u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29; 1100 int i = 100; 1101 1102 /* Disable all IRQs */ 1103 sh_vou_reg_a_write(vou_dev, VOUIR, 0); 1104 1105 /* Reset VOU interfaces - registers unaffected */ 1106 sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101); 1107 while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101)) 1108 udelay(1); 1109 1110 if (!i) 1111 return -ETIMEDOUT; 1112 1113 dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i); 1114 1115 if (pdata->flags & SH_VOU_PCLK_FALLING) 1116 voucr |= 1 << 28; 1117 if (pdata->flags & SH_VOU_HSYNC_LOW) 1118 voucr |= 1 << 27; 1119 if (pdata->flags & SH_VOU_VSYNC_LOW) 1120 voucr |= 1 << 26; 1121 sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000); 1122 1123 /* Manual register side switching at first */ 1124 sh_vou_reg_a_write(vou_dev, VOURCR, 4); 1125 /* Default - fixed HSYNC length, can be made configurable is required */ 1126 sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000); 1127 1128 sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); 1129 1130 return 0; 1131} 1132 1133/* File operations */ 1134static int sh_vou_open(struct file *file) 1135{ 1136 struct sh_vou_device *vou_dev = video_drvdata(file); 1137 int err; 1138 1139 if (mutex_lock_interruptible(&vou_dev->fop_lock)) 1140 return -ERESTARTSYS; 1141 1142 err = v4l2_fh_open(file); 1143 if (err) 1144 goto done_open; 1145 if (v4l2_fh_is_singular_file(file) && 1146 vou_dev->status == SH_VOU_INITIALISING) { 1147 /* First open */ 1148 pm_runtime_get_sync(vou_dev->v4l2_dev.dev); 1149 err = sh_vou_hw_init(vou_dev); 1150 if (err < 0) { 1151 pm_runtime_put(vou_dev->v4l2_dev.dev); 1152 v4l2_fh_release(file); 1153 } else { 1154 vou_dev->status = SH_VOU_IDLE; 1155 } 1156 } 1157done_open: 1158 mutex_unlock(&vou_dev->fop_lock); 1159 return err; 1160} 1161 1162static int sh_vou_release(struct file *file) 1163{ 1164 struct sh_vou_device *vou_dev = video_drvdata(file); 1165 bool is_last; 1166 1167 mutex_lock(&vou_dev->fop_lock); 1168 is_last = v4l2_fh_is_singular_file(file); 1169 _vb2_fop_release(file, NULL); 1170 if (is_last) { 1171 /* Last close */ 1172 vou_dev->status = SH_VOU_INITIALISING; 1173 sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); 1174 pm_runtime_put(vou_dev->v4l2_dev.dev); 1175 } 1176 mutex_unlock(&vou_dev->fop_lock); 1177 return 0; 1178} 1179 1180/* sh_vou display ioctl operations */ 1181static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { 1182 .vidioc_querycap = sh_vou_querycap, 1183 .vidioc_enum_fmt_vid_out = sh_vou_enum_fmt_vid_out, 1184 .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out, 1185 .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out, 1186 .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out, 1187 .vidioc_reqbufs = vb2_ioctl_reqbufs, 1188 .vidioc_create_bufs = vb2_ioctl_create_bufs, 1189 .vidioc_querybuf = vb2_ioctl_querybuf, 1190 .vidioc_qbuf = vb2_ioctl_qbuf, 1191 .vidioc_dqbuf = vb2_ioctl_dqbuf, 1192 .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 1193 .vidioc_streamon = vb2_ioctl_streamon, 1194 .vidioc_streamoff = vb2_ioctl_streamoff, 1195 .vidioc_expbuf = vb2_ioctl_expbuf, 1196 .vidioc_g_output = sh_vou_g_output, 1197 .vidioc_s_output = sh_vou_s_output, 1198 .vidioc_enum_output = sh_vou_enum_output, 1199 .vidioc_s_std = sh_vou_s_std, 1200 .vidioc_g_std = sh_vou_g_std, 1201 .vidioc_g_selection = sh_vou_g_selection, 1202 .vidioc_s_selection = sh_vou_s_selection, 1203 .vidioc_log_status = sh_vou_log_status, 1204}; 1205 1206static const struct v4l2_file_operations sh_vou_fops = { 1207 .owner = THIS_MODULE, 1208 .open = sh_vou_open, 1209 .release = sh_vou_release, 1210 .unlocked_ioctl = video_ioctl2, 1211 .mmap = vb2_fop_mmap, 1212 .poll = vb2_fop_poll, 1213 .write = vb2_fop_write, 1214}; 1215 1216static const struct video_device sh_vou_video_template = { 1217 .name = "sh_vou", 1218 .fops = &sh_vou_fops, 1219 .ioctl_ops = &sh_vou_ioctl_ops, 1220 .tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */ 1221 .vfl_dir = VFL_DIR_TX, 1222}; 1223 1224static int sh_vou_probe(struct platform_device *pdev) 1225{ 1226 struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data; 1227 struct v4l2_rect *rect; 1228 struct v4l2_pix_format *pix; 1229 struct i2c_adapter *i2c_adap; 1230 struct video_device *vdev; 1231 struct sh_vou_device *vou_dev; 1232 struct resource *reg_res; 1233 struct v4l2_subdev *subdev; 1234 struct vb2_queue *q; 1235 int irq, ret; 1236 1237 reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1238 irq = platform_get_irq(pdev, 0); 1239 1240 if (!vou_pdata || !reg_res || irq <= 0) { 1241 dev_err(&pdev->dev, "Insufficient VOU platform information.\n"); 1242 return -ENODEV; 1243 } 1244 1245 vou_dev = devm_kzalloc(&pdev->dev, sizeof(*vou_dev), GFP_KERNEL); 1246 if (!vou_dev) 1247 return -ENOMEM; 1248 1249 INIT_LIST_HEAD(&vou_dev->buf_list); 1250 spin_lock_init(&vou_dev->lock); 1251 mutex_init(&vou_dev->fop_lock); 1252 vou_dev->pdata = vou_pdata; 1253 vou_dev->status = SH_VOU_INITIALISING; 1254 vou_dev->pix_idx = 1; 1255 1256 rect = &vou_dev->rect; 1257 pix = &vou_dev->pix; 1258 1259 /* Fill in defaults */ 1260 vou_dev->std = V4L2_STD_NTSC_M; 1261 rect->left = 0; 1262 rect->top = 0; 1263 rect->width = VOU_MAX_IMAGE_WIDTH; 1264 rect->height = 480; 1265 pix->width = VOU_MAX_IMAGE_WIDTH; 1266 pix->height = 480; 1267 pix->pixelformat = V4L2_PIX_FMT_NV16; 1268 pix->field = V4L2_FIELD_INTERLACED; 1269 pix->bytesperline = VOU_MAX_IMAGE_WIDTH; 1270 pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; 1271 pix->colorspace = V4L2_COLORSPACE_SMPTE170M; 1272 1273 vou_dev->base = devm_ioremap_resource(&pdev->dev, reg_res); 1274 if (IS_ERR(vou_dev->base)) 1275 return PTR_ERR(vou_dev->base); 1276 1277 ret = devm_request_irq(&pdev->dev, irq, sh_vou_isr, 0, "vou", vou_dev); 1278 if (ret < 0) 1279 return ret; 1280 1281 ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev); 1282 if (ret < 0) { 1283 dev_err(&pdev->dev, "Error registering v4l2 device\n"); 1284 return ret; 1285 } 1286 1287 vdev = &vou_dev->vdev; 1288 *vdev = sh_vou_video_template; 1289 if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT) 1290 vdev->tvnorms |= V4L2_STD_PAL; 1291 vdev->v4l2_dev = &vou_dev->v4l2_dev; 1292 vdev->release = video_device_release_empty; 1293 vdev->lock = &vou_dev->fop_lock; 1294 1295 video_set_drvdata(vdev, vou_dev); 1296 1297 /* Initialize the vb2 queue */ 1298 q = &vou_dev->queue; 1299 q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 1300 q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; 1301 q->drv_priv = vou_dev; 1302 q->buf_struct_size = sizeof(struct sh_vou_buffer); 1303 q->ops = &sh_vou_qops; 1304 q->mem_ops = &vb2_dma_contig_memops; 1305 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1306 q->min_buffers_needed = 2; 1307 q->lock = &vou_dev->fop_lock; 1308 q->dev = &pdev->dev; 1309 ret = vb2_queue_init(q); 1310 if (ret) 1311 goto ei2cgadap; 1312 1313 vdev->queue = q; 1314 INIT_LIST_HEAD(&vou_dev->buf_list); 1315 1316 pm_runtime_enable(&pdev->dev); 1317 pm_runtime_resume(&pdev->dev); 1318 1319 i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap); 1320 if (!i2c_adap) { 1321 ret = -ENODEV; 1322 goto ei2cgadap; 1323 } 1324 1325 ret = sh_vou_hw_init(vou_dev); 1326 if (ret < 0) 1327 goto ereset; 1328 1329 subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap, 1330 vou_pdata->board_info, NULL); 1331 if (!subdev) { 1332 ret = -ENOMEM; 1333 goto ei2cnd; 1334 } 1335 1336 ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); 1337 if (ret < 0) 1338 goto evregdev; 1339 1340 return 0; 1341 1342evregdev: 1343ei2cnd: 1344ereset: 1345 i2c_put_adapter(i2c_adap); 1346ei2cgadap: 1347 pm_runtime_disable(&pdev->dev); 1348 v4l2_device_unregister(&vou_dev->v4l2_dev); 1349 return ret; 1350} 1351 1352static int sh_vou_remove(struct platform_device *pdev) 1353{ 1354 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 1355 struct sh_vou_device *vou_dev = container_of(v4l2_dev, 1356 struct sh_vou_device, v4l2_dev); 1357 struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, 1358 struct v4l2_subdev, list); 1359 struct i2c_client *client = v4l2_get_subdevdata(sd); 1360 1361 pm_runtime_disable(&pdev->dev); 1362 video_unregister_device(&vou_dev->vdev); 1363 i2c_put_adapter(client->adapter); 1364 v4l2_device_unregister(&vou_dev->v4l2_dev); 1365 return 0; 1366} 1367 1368static struct platform_driver __refdata sh_vou = { 1369 .remove = sh_vou_remove, 1370 .driver = { 1371 .name = "sh-vou", 1372 }, 1373}; 1374 1375module_platform_driver_probe(sh_vou, sh_vou_probe); 1376 1377MODULE_DESCRIPTION("SuperH VOU driver"); 1378MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); 1379MODULE_LICENSE("GPL v2"); 1380MODULE_VERSION("0.1.0"); 1381MODULE_ALIAS("platform:sh-vou");