blob: 4cb365d4ffdcc9c4e12cde82f46d411cb86c7a13 [file] [log] [blame]
Hans Verkuil32db7752007-07-20 09:29:43 -03001/*
2 On Screen Display cx23415 Framebuffer driver
3
4 This module presents the cx23415 OSD (onscreen display) framebuffer memory
5 as a standard Linux /dev/fb style framebuffer device. The framebuffer has
Hans Verkuilbe383bd2007-07-20 10:16:03 -03006 support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
Hans Verkuil32db7752007-07-20 09:29:43 -03007 mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
8 local alpha. The colorspace is selectable between rgb & yuv.
9 Depending on the TV standard configured in the ivtv module at load time,
10 the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
11 Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
12 or 59.94 (NTSC)
13
14 Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
15
16 Derived from drivers/video/vesafb.c
17 Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
18
19 2.6 kernel port:
20 Copyright (C) 2004 Matthias Badaire
21
22 Copyright (C) 2004 Chris Kennedy <c@groovy.org>
23
24 Copyright (C) 2006 Ian Armstrong <ian@iarmst.demon.co.uk>
25
26 This program is free software; you can redistribute it and/or modify
27 it under the terms of the GNU General Public License as published by
28 the Free Software Foundation; either version 2 of the License, or
29 (at your option) any later version.
30
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
35
36 You should have received a copy of the GNU General Public License
37 along with this program; if not, write to the Free Software
38 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
39 */
40
41#include <linux/module.h>
42#include <linux/kernel.h>
Hans Verkuil32db7752007-07-20 09:29:43 -030043#include <linux/fb.h>
Hans Verkuil0f45b8c2007-08-26 06:04:10 -030044#include <linux/ivtvfb.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090045#include <linux/slab.h>
Hans Verkuil32db7752007-07-20 09:29:43 -030046
Luis R. Rodriguez1bf17352015-06-15 10:28:16 +020047#ifdef CONFIG_X86_64
48#include <asm/pat.h>
Hans Verkuil32db7752007-07-20 09:29:43 -030049#endif
50
51#include "ivtv-driver.h"
Hans Verkuil67ec09f2008-11-29 19:38:23 -030052#include "ivtv-cards.h"
Ian Armstrong4e7ca402008-10-19 18:58:26 -030053#include "ivtv-i2c.h"
Hans Verkuil32db7752007-07-20 09:29:43 -030054#include "ivtv-udma.h"
Hans Verkuil32db7752007-07-20 09:29:43 -030055#include "ivtv-mailbox.h"
Ian Armstrong215659d2010-06-12 13:41:57 -030056#include "ivtv-firmware.h"
Hans Verkuil32db7752007-07-20 09:29:43 -030057
58/* card parameters */
Hans Verkuil641ed492007-08-28 03:24:31 -030059static int ivtvfb_card_id = -1;
60static int ivtvfb_debug = 0;
Rusty Russell90ab5ee2012-01-13 09:32:20 +103061static bool osd_laced;
Hans Verkuil32db7752007-07-20 09:29:43 -030062static int osd_depth;
63static int osd_upper;
64static int osd_left;
65static int osd_yres;
66static int osd_xres;
67
Hans Verkuil641ed492007-08-28 03:24:31 -030068module_param(ivtvfb_card_id, int, 0444);
69module_param_named(debug,ivtvfb_debug, int, 0644);
Hans Verkuil32db7752007-07-20 09:29:43 -030070module_param(osd_laced, bool, 0444);
Hans Verkuil32db7752007-07-20 09:29:43 -030071module_param(osd_depth, int, 0444);
72module_param(osd_upper, int, 0444);
73module_param(osd_left, int, 0444);
74module_param(osd_yres, int, 0444);
75module_param(osd_xres, int, 0444);
76
Hans Verkuil641ed492007-08-28 03:24:31 -030077MODULE_PARM_DESC(ivtvfb_card_id,
Hans Verkuil32db7752007-07-20 09:29:43 -030078 "Only use framebuffer of the specified ivtv card (0-31)\n"
79 "\t\t\tdefault -1: initialize all available framebuffers");
80
81MODULE_PARM_DESC(debug,
82 "Debug level (bitmask). Default: errors only\n"
83 "\t\t\t(debug = 3 gives full debugging)");
84
Hans Verkuil32db7752007-07-20 09:29:43 -030085/* Why upper, left, xres, yres, depth, laced ? To match terminology used
86 by fbset.
87 Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
88
89MODULE_PARM_DESC(osd_laced,
90 "Interlaced mode\n"
91 "\t\t\t0=off\n"
92 "\t\t\t1=on\n"
93 "\t\t\tdefault off");
94
95MODULE_PARM_DESC(osd_depth,
Hans Verkuilbe383bd2007-07-20 10:16:03 -030096 "Bits per pixel - 8, 16, 32\n"
Hans Verkuil32db7752007-07-20 09:29:43 -030097 "\t\t\tdefault 8");
98
99MODULE_PARM_DESC(osd_upper,
100 "Vertical start position\n"
101 "\t\t\tdefault 0 (Centered)");
102
103MODULE_PARM_DESC(osd_left,
104 "Horizontal start position\n"
105 "\t\t\tdefault 0 (Centered)");
106
107MODULE_PARM_DESC(osd_yres,
108 "Display height\n"
109 "\t\t\tdefault 480 (PAL)\n"
110 "\t\t\t 400 (NTSC)");
111
112MODULE_PARM_DESC(osd_xres,
113 "Display width\n"
114 "\t\t\tdefault 640");
115
116MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
117MODULE_LICENSE("GPL");
118
119/* --------------------------------------------------------------------- */
120
Hans Verkuil641ed492007-08-28 03:24:31 -0300121#define IVTVFB_DBGFLG_WARN (1 << 0)
122#define IVTVFB_DBGFLG_INFO (1 << 1)
Hans Verkuil32db7752007-07-20 09:29:43 -0300123
Hans Verkuil641ed492007-08-28 03:24:31 -0300124#define IVTVFB_DEBUG(x, type, fmt, args...) \
Hans Verkuil32db7752007-07-20 09:29:43 -0300125 do { \
Hans Verkuil641ed492007-08-28 03:24:31 -0300126 if ((x) & ivtvfb_debug) \
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300127 printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
Hans Verkuil32db7752007-07-20 09:29:43 -0300128 } while (0)
Hans Verkuil641ed492007-08-28 03:24:31 -0300129#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
130#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
Hans Verkuil32db7752007-07-20 09:29:43 -0300131
132/* Standard kernel messages */
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300133#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args)
134#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args)
135#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
Hans Verkuil32db7752007-07-20 09:29:43 -0300136
137/* --------------------------------------------------------------------- */
138
139#define IVTV_OSD_MAX_WIDTH 720
140#define IVTV_OSD_MAX_HEIGHT 576
141
142#define IVTV_OSD_BPP_8 0x00
143#define IVTV_OSD_BPP_16_444 0x03
144#define IVTV_OSD_BPP_16_555 0x02
145#define IVTV_OSD_BPP_16_565 0x01
146#define IVTV_OSD_BPP_32 0x04
147
148struct osd_info {
Hans Verkuil32db7752007-07-20 09:29:43 -0300149 /* Physical base address */
150 unsigned long video_pbase;
151 /* Relative base address (relative to start of decoder memory) */
152 u32 video_rbase;
153 /* Mapped base address */
154 volatile char __iomem *video_vbase;
155 /* Buffer size */
156 u32 video_buffer_size;
157
Hans Verkuil32db7752007-07-20 09:29:43 -0300158 /* video_base rounded down as required by hardware MTRRs */
159 unsigned long fb_start_aligned_physaddr;
160 /* video_base rounded up as required by hardware MTRRs */
161 unsigned long fb_end_aligned_physaddr;
Luis R. Rodriguez1bf17352015-06-15 10:28:16 +0200162 int wc_cookie;
Hans Verkuil32db7752007-07-20 09:29:43 -0300163
164 /* Store the buffer offset */
165 int set_osd_coords_x;
166 int set_osd_coords_y;
167
168 /* Current dimensions (NOT VISIBLE SIZE!) */
169 int display_width;
170 int display_height;
171 int display_byte_stride;
172
173 /* Current bits per pixel */
174 int bits_per_pixel;
175 int bytes_per_pixel;
176
177 /* Frame buffer stuff */
178 struct fb_info ivtvfb_info;
179 struct fb_var_screeninfo ivtvfb_defined;
180 struct fb_fix_screeninfo ivtvfb_fix;
Ian Armstrong215659d2010-06-12 13:41:57 -0300181
182 /* Used for a warm start */
183 struct fb_var_screeninfo fbvar_cur;
184 int blank_cur;
185 u32 palette_cur[256];
186 u32 pan_cur;
Hans Verkuil32db7752007-07-20 09:29:43 -0300187};
188
189struct ivtv_osd_coords {
190 unsigned long offset;
191 unsigned long max_offset;
192 int pixel_stride;
193 int lines;
194 int x;
195 int y;
196};
197
198/* --------------------------------------------------------------------- */
199
200/* ivtv API calls for framebuffer related support */
201
Hans Verkuil641ed492007-08-28 03:24:31 -0300202static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
Hans Verkuil32db7752007-07-20 09:29:43 -0300203 u32 *fblength)
204{
205 u32 data[CX2341X_MBOX_MAX_DATA];
206 int rc;
207
Ian Armstrong215659d2010-06-12 13:41:57 -0300208 ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
Hans Verkuil32db7752007-07-20 09:29:43 -0300209 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
210 *fbbase = data[0];
211 *fblength = data[1];
212 return rc;
213}
214
Hans Verkuil641ed492007-08-28 03:24:31 -0300215static int ivtvfb_get_osd_coords(struct ivtv *itv,
Hans Verkuil32db7752007-07-20 09:29:43 -0300216 struct ivtv_osd_coords *osd)
217{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300218 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300219 u32 data[CX2341X_MBOX_MAX_DATA];
220
221 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
222
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300223 osd->offset = data[0] - oi->video_rbase;
224 osd->max_offset = oi->display_width * oi->display_height * 4;
Hans Verkuil32db7752007-07-20 09:29:43 -0300225 osd->pixel_stride = data[1];
226 osd->lines = data[2];
227 osd->x = data[3];
228 osd->y = data[4];
229 return 0;
230}
231
Hans Verkuil641ed492007-08-28 03:24:31 -0300232static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
Hans Verkuil32db7752007-07-20 09:29:43 -0300233{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300234 struct osd_info *oi = itv->osd_info;
235
236 oi->display_width = osd->pixel_stride;
237 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
238 oi->set_osd_coords_x += osd->x;
239 oi->set_osd_coords_y = osd->y;
Hans Verkuil32db7752007-07-20 09:29:43 -0300240
241 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300242 osd->offset + oi->video_rbase,
Hans Verkuil32db7752007-07-20 09:29:43 -0300243 osd->pixel_stride,
244 osd->lines, osd->x, osd->y);
245}
246
Hans Verkuil641ed492007-08-28 03:24:31 -0300247static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
Hans Verkuil32db7752007-07-20 09:29:43 -0300248{
Ian Armstrongc5874c92011-05-29 21:33:17 -0300249 int osd_height_limit = itv->is_out_50hz ? 576 : 480;
Hans Verkuil32db7752007-07-20 09:29:43 -0300250
251 /* Only fail if resolution too high, otherwise fudge the start coords. */
252 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
253 return -EINVAL;
254
255 /* Ensure we don't exceed display limits */
256 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300257 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300258 ivtv_window->top, ivtv_window->height);
259 ivtv_window->top = osd_height_limit - ivtv_window->height;
260 }
261
262 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300263 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300264 ivtv_window->left, ivtv_window->width);
265 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
266 }
267
268 /* Set the OSD origin */
269 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
270
271 /* How much to display */
272 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
273
274 /* Pass this info back the yuv handler */
275 itv->yuv_info.osd_vis_w = ivtv_window->width;
276 itv->yuv_info.osd_vis_h = ivtv_window->height;
277 itv->yuv_info.osd_x_offset = ivtv_window->left;
278 itv->yuv_info.osd_y_offset = ivtv_window->top;
279
280 return 0;
281}
282
Hans Verkuil641ed492007-08-28 03:24:31 -0300283static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
Hans Verkuil32db7752007-07-20 09:29:43 -0300284 unsigned long ivtv_dest_addr, void __user *userbuf,
285 int size_in_bytes)
286{
287 DEFINE_WAIT(wait);
Hans Verkuil32db7752007-07-20 09:29:43 -0300288 int got_sig = 0;
289
290 mutex_lock(&itv->udma.lock);
291 /* Map User DMA */
292 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
293 mutex_unlock(&itv->udma.lock);
Hans Verkuil641ed492007-08-28 03:24:31 -0300294 IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
Hans Verkuil32db7752007-07-20 09:29:43 -0300295 "Error with get_user_pages: %d bytes, %d pages returned\n",
296 size_in_bytes, itv->udma.page_count);
297
298 /* get_user_pages must have failed completely */
299 return -EIO;
300 }
301
Hans Verkuil641ed492007-08-28 03:24:31 -0300302 IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300303 size_in_bytes, itv->udma.page_count);
304
305 ivtv_udma_prepare(itv);
306 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
307 /* if no UDMA is pending and no UDMA is in progress, then the DMA
308 is finished */
Hans Verkuilec105a42009-05-02 11:10:23 -0300309 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
310 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
Hans Verkuil32db7752007-07-20 09:29:43 -0300311 /* don't interrupt if the DMA is in progress but break off
312 a still pending DMA. */
313 got_sig = signal_pending(current);
314 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
315 break;
316 got_sig = 0;
317 schedule();
318 }
319 finish_wait(&itv->dma_waitq, &wait);
320
321 /* Unmap Last DMA Xfer */
322 ivtv_udma_unmap(itv);
323 mutex_unlock(&itv->udma.lock);
324 if (got_sig) {
325 IVTV_DEBUG_INFO("User stopped OSD\n");
326 return -EINTR;
327 }
328
Ian Armstrongc7775492008-10-04 10:28:24 -0300329 return 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300330}
331
Hans Verkuil641ed492007-08-28 03:24:31 -0300332static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300333 unsigned long dest_offset, int count)
Hans Verkuil32db7752007-07-20 09:29:43 -0300334{
335 DEFINE_WAIT(wait);
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300336 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300337
338 /* Nothing to do */
339 if (count == 0) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300340 IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300341 return -EINVAL;
342 }
343
344 /* Check Total FB Size */
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300345 if ((dest_offset + count) > oi->video_buffer_size) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300346 IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300347 dest_offset + count, oi->video_buffer_size);
Hans Verkuil32db7752007-07-20 09:29:43 -0300348 return -E2BIG;
349 }
350
351 /* Not fatal, but will have undesirable results */
352 if ((unsigned long)source & 3)
Hans Verkuil641ed492007-08-28 03:24:31 -0300353 IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300354 (unsigned long)source);
Hans Verkuil32db7752007-07-20 09:29:43 -0300355
356 if (dest_offset & 3)
Hans Verkuil641ed492007-08-28 03:24:31 -0300357 IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
Hans Verkuil32db7752007-07-20 09:29:43 -0300358
359 if (count & 3)
Hans Verkuil641ed492007-08-28 03:24:31 -0300360 IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
Hans Verkuil32db7752007-07-20 09:29:43 -0300361
362 /* Check Source */
363 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300364 IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300365 (unsigned long)source);
366
Hans Verkuil641ed492007-08-28 03:24:31 -0300367 IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300368 dest_offset, (unsigned long)source,
369 count);
370 return -EINVAL;
371 }
372
373 /* OSD Address to send DMA to */
Hans Verkuil33c0fca2007-08-23 06:32:46 -0300374 dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
Hans Verkuil32db7752007-07-20 09:29:43 -0300375
376 /* Fill Buffers */
Hans Verkuil641ed492007-08-28 03:24:31 -0300377 return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
Hans Verkuil32db7752007-07-20 09:29:43 -0300378}
379
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300380static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
Ian Armstrong4ee0e422008-10-06 03:03:18 -0300381 size_t count, loff_t *ppos)
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300382{
383 unsigned long p = *ppos;
384 void *dst;
385 int err = 0;
Ian Armstrongc7775492008-10-04 10:28:24 -0300386 int dma_err;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300387 unsigned long total_size;
388 struct ivtv *itv = (struct ivtv *) info->par;
389 unsigned long dma_offset =
390 IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
391 unsigned long dma_size;
392 u16 lead = 0, tail = 0;
393
394 if (info->state != FBINFO_STATE_RUNNING)
395 return -EPERM;
396
397 total_size = info->screen_size;
398
399 if (total_size == 0)
400 total_size = info->fix.smem_len;
401
402 if (p > total_size)
403 return -EFBIG;
404
405 if (count > total_size) {
406 err = -EFBIG;
407 count = total_size;
408 }
409
410 if (count + p > total_size) {
411 if (!err)
412 err = -ENOSPC;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300413 count = total_size - p;
414 }
415
416 dst = (void __force *) (info->screen_base + p);
417
418 if (info->fbops->fb_sync)
419 info->fbops->fb_sync(info);
420
Ian Armstrongc7775492008-10-04 10:28:24 -0300421 /* If transfer size > threshold and both src/dst
422 addresses are aligned, use DMA */
423 if (count >= 4096 &&
424 ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
425 /* Odd address = can't DMA. Align */
426 if ((unsigned long)dst & 3) {
427 lead = 4 - ((unsigned long)dst & 3);
428 if (copy_from_user(dst, buf, lead))
429 return -EFAULT;
430 buf += lead;
431 dst += lead;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300432 }
Ian Armstrongc7775492008-10-04 10:28:24 -0300433 /* DMA resolution is 32 bits */
434 if ((count - lead) & 3)
435 tail = (count - lead) & 3;
436 /* DMA the data */
437 dma_size = count - lead - tail;
438 dma_err = ivtvfb_prep_dec_dma_to_device(itv,
439 p + lead + dma_offset, (void __user *)buf, dma_size);
440 if (dma_err)
441 return dma_err;
442 dst += dma_size;
443 buf += dma_size;
444 /* Copy any leftover data */
445 if (tail && copy_from_user(dst, buf, tail))
446 return -EFAULT;
447 } else if (copy_from_user(dst, buf, count)) {
448 return -EFAULT;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300449 }
450
451 if (!err)
452 *ppos += count;
453
454 return (err) ? err : count;
455}
456
Hans Verkuil32db7752007-07-20 09:29:43 -0300457static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
458{
459 DEFINE_WAIT(wait);
460 struct ivtv *itv = (struct ivtv *)info->par;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300461 int rc = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300462
463 switch (cmd) {
Hans Verkuil32db7752007-07-20 09:29:43 -0300464 case FBIOGET_VBLANK: {
465 struct fb_vblank vblank;
466 u32 trace;
467
Dan Rosenberg40570792010-09-15 18:44:22 -0300468 memset(&vblank, 0, sizeof(struct fb_vblank));
469
Hans Verkuil32db7752007-07-20 09:29:43 -0300470 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
471 FB_VBLANK_HAVE_VSYNC;
Andy Walls4e1af312010-03-13 20:37:25 -0300472 trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
Ian Armstrongc5874c92011-05-29 21:33:17 -0300473 if (itv->is_out_50hz && trace > 312)
Ian Armstrongc7775492008-10-04 10:28:24 -0300474 trace -= 312;
Ian Armstrongc5874c92011-05-29 21:33:17 -0300475 else if (itv->is_out_60hz && trace > 262)
Ian Armstrongc7775492008-10-04 10:28:24 -0300476 trace -= 262;
477 if (trace == 1)
478 vblank.flags |= FB_VBLANK_VSYNCING;
Hans Verkuila158f352007-08-23 11:31:57 -0300479 vblank.count = itv->last_vsync_field;
Hans Verkuil32db7752007-07-20 09:29:43 -0300480 vblank.vcount = trace;
481 vblank.hcount = 0;
482 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
483 return -EFAULT;
484 return 0;
485 }
486
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300487 case FBIO_WAITFORVSYNC:
Hans Verkuil32db7752007-07-20 09:29:43 -0300488 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
Ian Armstrongc7775492008-10-04 10:28:24 -0300489 if (!schedule_timeout(msecs_to_jiffies(50)))
490 rc = -ETIMEDOUT;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300491 finish_wait(&itv->vsync_waitq, &wait);
Hans Verkuil32db7752007-07-20 09:29:43 -0300492 return rc;
Hans Verkuil32db7752007-07-20 09:29:43 -0300493
Hans Verkuild715e762007-07-20 10:30:32 -0300494 case IVTVFB_IOC_DMA_FRAME: {
495 struct ivtvfb_dma_frame args;
Hans Verkuil32db7752007-07-20 09:29:43 -0300496
Hans Verkuil641ed492007-08-28 03:24:31 -0300497 IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300498 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
499 return -EFAULT;
500
Hans Verkuil641ed492007-08-28 03:24:31 -0300501 return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
Hans Verkuil32db7752007-07-20 09:29:43 -0300502 }
503
504 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300505 IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300506 return -EINVAL;
507 }
508 return 0;
509}
510
511/* Framebuffer device handling */
512
513static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
514{
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300515 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300516 struct ivtv_osd_coords ivtv_osd;
517 struct v4l2_rect ivtv_window;
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300518 int osd_mode = -1;
Hans Verkuil32db7752007-07-20 09:29:43 -0300519
Hans Verkuil641ed492007-08-28 03:24:31 -0300520 IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300521
522 /* Select color space */
523 if (var->nonstd) /* YUV */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300524 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
Hans Verkuil32db7752007-07-20 09:29:43 -0300525 else /* RGB */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300526 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
Hans Verkuil32db7752007-07-20 09:29:43 -0300527
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300528 /* Set the color mode */
Hans Verkuil32db7752007-07-20 09:29:43 -0300529 switch (var->bits_per_pixel) {
530 case 8:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300531 osd_mode = IVTV_OSD_BPP_8;
Hans Verkuil32db7752007-07-20 09:29:43 -0300532 break;
533 case 32:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300534 osd_mode = IVTV_OSD_BPP_32;
Hans Verkuil32db7752007-07-20 09:29:43 -0300535 break;
536 case 16:
537 switch (var->green.length) {
538 case 4:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300539 osd_mode = IVTV_OSD_BPP_16_444;
Hans Verkuil32db7752007-07-20 09:29:43 -0300540 break;
541 case 5:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300542 osd_mode = IVTV_OSD_BPP_16_555;
Hans Verkuil32db7752007-07-20 09:29:43 -0300543 break;
544 case 6:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300545 osd_mode = IVTV_OSD_BPP_16_565;
Hans Verkuil32db7752007-07-20 09:29:43 -0300546 break;
547 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300548 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300549 }
550 break;
551 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300552 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300553 }
554
Ian Armstrong6659e3e2007-10-12 08:15:41 -0300555 /* Set video mode. Although rare, the display can become scrambled even
556 if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
557 if (osd_mode != -1) {
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300558 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
559 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300560 }
561
562 oi->bits_per_pixel = var->bits_per_pixel;
563 oi->bytes_per_pixel = var->bits_per_pixel / 8;
Hans Verkuil32db7752007-07-20 09:29:43 -0300564
565 /* Set the flicker filter */
566 switch (var->vmode & FB_VMODE_MASK) {
567 case FB_VMODE_NONINTERLACED: /* Filter on */
568 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
569 break;
570 case FB_VMODE_INTERLACED: /* Filter off */
571 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
572 break;
573 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300574 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300575 }
576
577 /* Read the current osd info */
Hans Verkuil641ed492007-08-28 03:24:31 -0300578 ivtvfb_get_osd_coords(itv, &ivtv_osd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300579
580 /* Now set the OSD to the size we want */
581 ivtv_osd.pixel_stride = var->xres_virtual;
582 ivtv_osd.lines = var->yres_virtual;
583 ivtv_osd.x = 0;
584 ivtv_osd.y = 0;
Hans Verkuil641ed492007-08-28 03:24:31 -0300585 ivtvfb_set_osd_coords(itv, &ivtv_osd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300586
587 /* Can't seem to find the right API combo for this.
588 Use another function which does what we need through direct register access. */
589 ivtv_window.width = var->xres;
590 ivtv_window.height = var->yres;
591
592 /* Minimum margin cannot be 0, as X won't allow such a mode */
Ian Armstrong215659d2010-06-12 13:41:57 -0300593 if (!var->upper_margin)
594 var->upper_margin++;
595 if (!var->left_margin)
596 var->left_margin++;
Hans Verkuil32db7752007-07-20 09:29:43 -0300597 ivtv_window.top = var->upper_margin - 1;
598 ivtv_window.left = var->left_margin - 1;
599
Hans Verkuil641ed492007-08-28 03:24:31 -0300600 ivtvfb_set_display_window(itv, &ivtv_window);
Hans Verkuil32db7752007-07-20 09:29:43 -0300601
Ian Armstrong77aded62007-11-05 14:27:09 -0300602 /* Pass screen size back to yuv handler */
603 itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
604 itv->yuv_info.osd_full_h = ivtv_osd.lines;
605
Hans Verkuil32db7752007-07-20 09:29:43 -0300606 /* Force update of yuv registers */
607 itv->yuv_info.yuv_forced_update = 1;
608
Ian Armstrong215659d2010-06-12 13:41:57 -0300609 /* Keep a copy of these settings */
610 memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
611
Hans Verkuil641ed492007-08-28 03:24:31 -0300612 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300613 var->xres, var->yres,
614 var->xres_virtual, var->yres_virtual,
615 var->bits_per_pixel);
Hans Verkuil32db7752007-07-20 09:29:43 -0300616
Hans Verkuil641ed492007-08-28 03:24:31 -0300617 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300618 var->left_margin, var->upper_margin);
Hans Verkuil32db7752007-07-20 09:29:43 -0300619
Hans Verkuil641ed492007-08-28 03:24:31 -0300620 IVTVFB_DEBUG_INFO("Display filter: %s\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300621 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
Hans Verkuil641ed492007-08-28 03:24:31 -0300622 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
Hans Verkuil32db7752007-07-20 09:29:43 -0300623
624 return 0;
625}
626
627static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
628{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300629 struct osd_info *oi = itv->osd_info;
630
Hans Verkuil641ed492007-08-28 03:24:31 -0300631 IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300632 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
Hans Verkuilcebfadf2008-04-26 08:51:51 -0300633 strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300634 fix->smem_start = oi->video_pbase;
635 fix->smem_len = oi->video_buffer_size;
Hans Verkuil32db7752007-07-20 09:29:43 -0300636 fix->type = FB_TYPE_PACKED_PIXELS;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300637 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
Hans Verkuil32db7752007-07-20 09:29:43 -0300638 fix->xpanstep = 1;
639 fix->ypanstep = 1;
640 fix->ywrapstep = 0;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300641 fix->line_length = oi->display_byte_stride;
Hans Verkuil32db7752007-07-20 09:29:43 -0300642 fix->accel = FB_ACCEL_NONE;
643 return 0;
644}
645
646/* Check the requested display mode, returning -EINVAL if we can't
647 handle it. */
648
649static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
650{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300651 struct osd_info *oi = itv->osd_info;
Ian Armstrong68a341a2007-08-03 09:51:58 -0300652 int osd_height_limit;
653 u32 pixclock, hlimit, vlimit;
Hans Verkuil32db7752007-07-20 09:29:43 -0300654
Hans Verkuil641ed492007-08-28 03:24:31 -0300655 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300656
Ian Armstrong68a341a2007-08-03 09:51:58 -0300657 /* Set base references for mode calcs. */
Ian Armstrongc5874c92011-05-29 21:33:17 -0300658 if (itv->is_out_50hz) {
Ian Armstrong68a341a2007-08-03 09:51:58 -0300659 pixclock = 84316;
660 hlimit = 776;
661 vlimit = 591;
662 osd_height_limit = 576;
663 }
664 else {
665 pixclock = 83926;
666 hlimit = 776;
667 vlimit = 495;
668 osd_height_limit = 480;
669 }
670
Hans Verkuil32db7752007-07-20 09:29:43 -0300671 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
672 var->transp.offset = 24;
673 var->transp.length = 8;
674 var->red.offset = 16;
675 var->red.length = 8;
676 var->green.offset = 8;
677 var->green.length = 8;
678 var->blue.offset = 0;
679 var->blue.length = 8;
680 }
681 else if (var->bits_per_pixel == 16) {
682 /* To find out the true mode, check green length */
683 switch (var->green.length) {
684 case 4:
Hans Verkuil32db7752007-07-20 09:29:43 -0300685 var->red.offset = 8;
686 var->red.length = 4;
687 var->green.offset = 4;
688 var->green.length = 4;
689 var->blue.offset = 0;
690 var->blue.length = 4;
Hans Verkuil459a52f2007-08-22 08:58:47 -0300691 var->transp.offset = 12;
692 var->transp.length = 1;
Hans Verkuil32db7752007-07-20 09:29:43 -0300693 break;
694 case 5:
Hans Verkuil32db7752007-07-20 09:29:43 -0300695 var->red.offset = 10;
696 var->red.length = 5;
697 var->green.offset = 5;
698 var->green.length = 5;
699 var->blue.offset = 0;
700 var->blue.length = 5;
Hans Verkuil459a52f2007-08-22 08:58:47 -0300701 var->transp.offset = 15;
702 var->transp.length = 1;
Hans Verkuil32db7752007-07-20 09:29:43 -0300703 break;
704 default:
Hans Verkuil32db7752007-07-20 09:29:43 -0300705 var->red.offset = 11;
706 var->red.length = 5;
707 var->green.offset = 5;
708 var->green.length = 6;
709 var->blue.offset = 0;
710 var->blue.length = 5;
Hans Verkuil459a52f2007-08-22 08:58:47 -0300711 var->transp.offset = 0;
712 var->transp.length = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300713 break;
714 }
715 }
716 else {
Hans Verkuil641ed492007-08-28 03:24:31 -0300717 IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
Hans Verkuil32db7752007-07-20 09:29:43 -0300718 return -EINVAL;
719 }
720
721 /* Check the resolution */
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300722 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
723 IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
724 var->xres, var->yres);
725 return -EINVAL;
Hans Verkuil32db7752007-07-20 09:29:43 -0300726 }
Hans Verkuil32db7752007-07-20 09:29:43 -0300727
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300728 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
729 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
730 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
731 var->xres_virtual < var->xres ||
732 var->yres_virtual < var->yres) {
733 IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
734 var->xres_virtual, var->yres_virtual);
735 return -EINVAL;
Hans Verkuil32db7752007-07-20 09:29:43 -0300736 }
737
738 /* Some extra checks if in 8 bit mode */
739 if (var->bits_per_pixel == 8) {
740 /* Width must be a multiple of 4 */
741 if (var->xres & 3) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300742 IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
Hans Verkuil32db7752007-07-20 09:29:43 -0300743 return -EINVAL;
744 }
745 if (var->xres_virtual & 3) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300746 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
Hans Verkuil32db7752007-07-20 09:29:43 -0300747 return -EINVAL;
748 }
749 }
750 else if (var->bits_per_pixel == 16) {
751 /* Width must be a multiple of 2 */
752 if (var->xres & 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300753 IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
Hans Verkuil32db7752007-07-20 09:29:43 -0300754 return -EINVAL;
755 }
756 if (var->xres_virtual & 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300757 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
Hans Verkuil32db7752007-07-20 09:29:43 -0300758 return -EINVAL;
759 }
760 }
761
762 /* Now check the offsets */
763 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300764 IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300765 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
Hans Verkuil32db7752007-07-20 09:29:43 -0300766 return -EINVAL;
767 }
768
769 /* Check pixel format */
770 if (var->nonstd > 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300771 IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300772 return -EINVAL;
773 }
774
775 /* Check video mode */
776 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
777 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300778 IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
Hans Verkuil32db7752007-07-20 09:29:43 -0300779 return -EINVAL;
780 }
781
782 /* Check the left & upper margins
783 If the margins are too large, just center the screen
784 (enforcing margins causes too many problems) */
785
Ian Armstrongc5874c92011-05-29 21:33:17 -0300786 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1)
Hans Verkuil32db7752007-07-20 09:29:43 -0300787 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
Ian Armstrongc5874c92011-05-29 21:33:17 -0300788
789 if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481))
790 var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) -
791 var->yres) / 2);
Hans Verkuil32db7752007-07-20 09:29:43 -0300792
793 /* Maintain overall 'size' for a constant refresh rate */
Ian Armstrong68a341a2007-08-03 09:51:58 -0300794 var->right_margin = hlimit - var->left_margin - var->xres;
795 var->lower_margin = vlimit - var->upper_margin - var->yres;
Hans Verkuil32db7752007-07-20 09:29:43 -0300796
797 /* Fixed sync times */
798 var->hsync_len = 24;
799 var->vsync_len = 2;
800
801 /* Non-interlaced / interlaced mode is used to switch the OSD filter
802 on or off. Adjust the clock timings to maintain a constant
803 vertical refresh rate. */
Hans Verkuil32db7752007-07-20 09:29:43 -0300804 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
Ian Armstrong68a341a2007-08-03 09:51:58 -0300805 var->pixclock = pixclock / 2;
806 else
807 var->pixclock = pixclock;
Hans Verkuil32db7752007-07-20 09:29:43 -0300808
Hans Verkuil37f89f92008-06-22 11:57:31 -0300809 itv->osd_rect.width = var->xres;
810 itv->osd_rect.height = var->yres;
811
Hans Verkuil641ed492007-08-28 03:24:31 -0300812 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300813 var->xres, var->yres,
814 var->xres_virtual, var->yres_virtual,
Hans Verkuil32db7752007-07-20 09:29:43 -0300815 var->bits_per_pixel);
816
Hans Verkuil641ed492007-08-28 03:24:31 -0300817 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300818 var->left_margin, var->upper_margin);
Hans Verkuil32db7752007-07-20 09:29:43 -0300819
Hans Verkuil641ed492007-08-28 03:24:31 -0300820 IVTVFB_DEBUG_INFO("Display filter: %s\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300821 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
Hans Verkuil641ed492007-08-28 03:24:31 -0300822 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
Hans Verkuil32db7752007-07-20 09:29:43 -0300823 return 0;
824}
825
826static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
827{
828 struct ivtv *itv = (struct ivtv *) info->par;
Hans Verkuil641ed492007-08-28 03:24:31 -0300829 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300830 return _ivtvfb_check_var(var, itv);
Hans Verkuil32db7752007-07-20 09:29:43 -0300831}
832
833static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
834{
835 u32 osd_pan_index;
836 struct ivtv *itv = (struct ivtv *) info->par;
837
Ian Armstrong6600cc32011-05-28 22:15:41 -0300838 if (var->yoffset + info->var.yres > info->var.yres_virtual ||
839 var->xoffset + info->var.xres > info->var.xres_virtual)
840 return -EINVAL;
841
Laurent Pinchart5d9c08d2011-05-25 06:41:23 -0300842 osd_pan_index = var->yoffset * info->fix.line_length
843 + var->xoffset * info->var.bits_per_pixel / 8;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300844 write_reg(osd_pan_index, 0x02A0C);
Hans Verkuil32db7752007-07-20 09:29:43 -0300845
846 /* Pass this info back the yuv handler */
847 itv->yuv_info.osd_x_pan = var->xoffset;
848 itv->yuv_info.osd_y_pan = var->yoffset;
849 /* Force update of yuv registers */
850 itv->yuv_info.yuv_forced_update = 1;
Ian Armstrong215659d2010-06-12 13:41:57 -0300851 /* Remember this value */
852 itv->osd_info->pan_cur = osd_pan_index;
Hans Verkuil32db7752007-07-20 09:29:43 -0300853 return 0;
854}
855
856static int ivtvfb_set_par(struct fb_info *info)
857{
858 int rc = 0;
859 struct ivtv *itv = (struct ivtv *) info->par;
860
Hans Verkuil641ed492007-08-28 03:24:31 -0300861 IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300862
863 rc = ivtvfb_set_var(itv, &info->var);
864 ivtvfb_pan_display(&info->var, info);
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300865 ivtvfb_get_fix(itv, &info->fix);
Ian Armstrong215659d2010-06-12 13:41:57 -0300866 ivtv_firmware_check(itv, "ivtvfb_set_par");
Hans Verkuil32db7752007-07-20 09:29:43 -0300867 return rc;
868}
869
870static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
871 unsigned blue, unsigned transp,
872 struct fb_info *info)
873{
874 u32 color, *palette;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300875 struct ivtv *itv = (struct ivtv *)info->par;
Hans Verkuil32db7752007-07-20 09:29:43 -0300876
877 if (regno >= info->cmap.len)
878 return -EINVAL;
879
880 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
881 if (info->var.bits_per_pixel <= 8) {
882 write_reg(regno, 0x02a30);
883 write_reg(color, 0x02a34);
Ian Armstrong215659d2010-06-12 13:41:57 -0300884 itv->osd_info->palette_cur[regno] = color;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300885 return 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300886 }
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300887 if (regno >= 16)
888 return -EINVAL;
Hans Verkuil32db7752007-07-20 09:29:43 -0300889
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300890 palette = info->pseudo_palette;
891 if (info->var.bits_per_pixel == 16) {
892 switch (info->var.green.length) {
893 case 4:
894 color = ((red & 0xf000) >> 4) |
895 ((green & 0xf000) >> 8) |
896 ((blue & 0xf000) >> 12);
897 break;
898 case 5:
899 color = ((red & 0xf800) >> 1) |
900 ((green & 0xf800) >> 6) |
901 ((blue & 0xf800) >> 11);
902 break;
903 case 6:
904 color = (red & 0xf800 ) |
905 ((green & 0xfc00) >> 5) |
906 ((blue & 0xf800) >> 11);
907 break;
Hans Verkuil32db7752007-07-20 09:29:43 -0300908 }
Hans Verkuil32db7752007-07-20 09:29:43 -0300909 }
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300910 palette[regno] = color;
Hans Verkuil32db7752007-07-20 09:29:43 -0300911 return 0;
912}
913
914/* We don't really support blanking. All this does is enable or
915 disable the OSD. */
916static int ivtvfb_blank(int blank_mode, struct fb_info *info)
917{
918 struct ivtv *itv = (struct ivtv *)info->par;
919
Hans Verkuil641ed492007-08-28 03:24:31 -0300920 IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
Hans Verkuil32db7752007-07-20 09:29:43 -0300921 switch (blank_mode) {
922 case FB_BLANK_UNBLANK:
923 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300924 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
Hans Verkuil32db7752007-07-20 09:29:43 -0300925 break;
926 case FB_BLANK_NORMAL:
927 case FB_BLANK_HSYNC_SUSPEND:
928 case FB_BLANK_VSYNC_SUSPEND:
Ian Armstrong4e7ca402008-10-19 18:58:26 -0300929 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300930 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
Ian Armstrong4e7ca402008-10-19 18:58:26 -0300931 break;
Hans Verkuil32db7752007-07-20 09:29:43 -0300932 case FB_BLANK_POWERDOWN:
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300933 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
Hans Verkuil32db7752007-07-20 09:29:43 -0300934 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
935 break;
936 }
Ian Armstrong215659d2010-06-12 13:41:57 -0300937 itv->osd_info->blank_cur = blank_mode;
Hans Verkuil32db7752007-07-20 09:29:43 -0300938 return 0;
939}
940
941static struct fb_ops ivtvfb_ops = {
942 .owner = THIS_MODULE,
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300943 .fb_write = ivtvfb_write,
Hans Verkuil32db7752007-07-20 09:29:43 -0300944 .fb_check_var = ivtvfb_check_var,
945 .fb_set_par = ivtvfb_set_par,
946 .fb_setcolreg = ivtvfb_setcolreg,
947 .fb_fillrect = cfb_fillrect,
948 .fb_copyarea = cfb_copyarea,
949 .fb_imageblit = cfb_imageblit,
950 .fb_cursor = NULL,
951 .fb_ioctl = ivtvfb_ioctl,
952 .fb_pan_display = ivtvfb_pan_display,
953 .fb_blank = ivtvfb_blank,
954};
955
Ian Armstrong215659d2010-06-12 13:41:57 -0300956/* Restore hardware after firmware restart */
957static void ivtvfb_restore(struct ivtv *itv)
958{
959 struct osd_info *oi = itv->osd_info;
960 int i;
961
962 ivtvfb_set_var(itv, &oi->fbvar_cur);
963 ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
964 for (i = 0; i < 256; i++) {
965 write_reg(i, 0x02a30);
966 write_reg(oi->palette_cur[i], 0x02a34);
967 }
968 write_reg(oi->pan_cur, 0x02a0c);
969}
970
Hans Verkuil32db7752007-07-20 09:29:43 -0300971/* Initialization */
972
973
974/* Setup our initial video mode */
975static int ivtvfb_init_vidmode(struct ivtv *itv)
976{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300977 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300978 struct v4l2_rect start_window;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300979 int max_height;
Hans Verkuil32db7752007-07-20 09:29:43 -0300980
Hans Verkuil32db7752007-07-20 09:29:43 -0300981 /* Color mode */
982
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300983 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
984 osd_depth = 8;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300985 oi->bits_per_pixel = osd_depth;
986 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
Hans Verkuil32db7752007-07-20 09:29:43 -0300987
988 /* Horizontal size & position */
989
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300990 if (osd_xres > 720)
991 osd_xres = 720;
Hans Verkuil32db7752007-07-20 09:29:43 -0300992
993 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
994 if (osd_depth == 8)
995 osd_xres &= ~3;
996 else if (osd_depth == 16)
997 osd_xres &= ~1;
998
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300999 start_window.width = osd_xres ? osd_xres : 640;
Hans Verkuil32db7752007-07-20 09:29:43 -03001000
1001 /* Check horizontal start (osd_left). */
1002 if (osd_left && osd_left + start_window.width > 721) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001003 IVTVFB_ERR("Invalid osd_left - assuming default\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001004 osd_left = 0;
1005 }
1006
1007 /* Hardware coords start at 0, user coords start at 1. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001008 osd_left--;
Hans Verkuil32db7752007-07-20 09:29:43 -03001009
Ian Armstrongc5874c92011-05-29 21:33:17 -03001010 start_window.left = osd_left >= 0 ?
1011 osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
Hans Verkuil32db7752007-07-20 09:29:43 -03001012
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001013 oi->display_byte_stride =
1014 start_window.width * oi->bytes_per_pixel;
Hans Verkuil32db7752007-07-20 09:29:43 -03001015
1016 /* Vertical size & position */
1017
Ian Armstrongc5874c92011-05-29 21:33:17 -03001018 max_height = itv->is_out_50hz ? 576 : 480;
Hans Verkuil32db7752007-07-20 09:29:43 -03001019
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001020 if (osd_yres > max_height)
1021 osd_yres = max_height;
Hans Verkuil32db7752007-07-20 09:29:43 -03001022
Ian Armstrongc5874c92011-05-29 21:33:17 -03001023 start_window.height = osd_yres ?
1024 osd_yres : itv->is_out_50hz ? 480 : 400;
Hans Verkuil32db7752007-07-20 09:29:43 -03001025
1026 /* Check vertical start (osd_upper). */
1027 if (osd_upper + start_window.height > max_height + 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001028 IVTVFB_ERR("Invalid osd_upper - assuming default\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001029 osd_upper = 0;
1030 }
1031
1032 /* Hardware coords start at 0, user coords start at 1. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001033 osd_upper--;
Hans Verkuil32db7752007-07-20 09:29:43 -03001034
1035 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
1036
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001037 oi->display_width = start_window.width;
1038 oi->display_height = start_window.height;
Hans Verkuil32db7752007-07-20 09:29:43 -03001039
1040 /* Generate a valid fb_var_screeninfo */
1041
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001042 oi->ivtvfb_defined.xres = oi->display_width;
1043 oi->ivtvfb_defined.yres = oi->display_height;
1044 oi->ivtvfb_defined.xres_virtual = oi->display_width;
1045 oi->ivtvfb_defined.yres_virtual = oi->display_height;
1046 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
1047 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
1048 oi->ivtvfb_defined.left_margin = start_window.left + 1;
1049 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
1050 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
1051 oi->ivtvfb_defined.nonstd = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -03001052
1053 /* We've filled in the most data, let the usual mode check
1054 routine fill in the rest. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001055 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
Hans Verkuil32db7752007-07-20 09:29:43 -03001056
1057 /* Generate valid fb_fix_screeninfo */
1058
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001059 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
Hans Verkuil32db7752007-07-20 09:29:43 -03001060
1061 /* Generate valid fb_info */
1062
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001063 oi->ivtvfb_info.node = -1;
1064 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
1065 oi->ivtvfb_info.fbops = &ivtvfb_ops;
1066 oi->ivtvfb_info.par = itv;
1067 oi->ivtvfb_info.var = oi->ivtvfb_defined;
1068 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
1069 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
1070 oi->ivtvfb_info.fbops = &ivtvfb_ops;
Hans Verkuil32db7752007-07-20 09:29:43 -03001071
1072 /* Supply some monitor specs. Bogus values will do for now */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001073 oi->ivtvfb_info.monspecs.hfmin = 8000;
1074 oi->ivtvfb_info.monspecs.hfmax = 70000;
1075 oi->ivtvfb_info.monspecs.vfmin = 10;
1076 oi->ivtvfb_info.monspecs.vfmax = 100;
Hans Verkuil32db7752007-07-20 09:29:43 -03001077
1078 /* Allocate color map */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001079 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001080 IVTVFB_ERR("abort, unable to alloc cmap\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001081 return -ENOMEM;
1082 }
1083
1084 /* Allocate the pseudo palette */
Hans Verkuil3f983872008-05-01 10:31:12 -03001085 oi->ivtvfb_info.pseudo_palette =
1086 kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
Hans Verkuil32db7752007-07-20 09:29:43 -03001087
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001088 if (!oi->ivtvfb_info.pseudo_palette) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001089 IVTVFB_ERR("abort, unable to alloc pseudo palette\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001090 return -ENOMEM;
1091 }
1092
1093 return 0;
1094}
1095
1096/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1097
1098static int ivtvfb_init_io(struct ivtv *itv)
1099{
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001100 struct osd_info *oi = itv->osd_info;
Luis R. Rodriguez1bf17352015-06-15 10:28:16 +02001101 /* Find the largest power of two that maps the whole buffer */
1102 int size_shift = 31;
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001103
Hans Verkuil26e9d592007-08-25 05:41:52 -03001104 mutex_lock(&itv->serialize_lock);
Hans Verkuil6e5eb592007-07-25 12:55:52 -03001105 if (ivtv_init_on_first_open(itv)) {
Hans Verkuil26e9d592007-08-25 05:41:52 -03001106 mutex_unlock(&itv->serialize_lock);
Hans Verkuil641ed492007-08-28 03:24:31 -03001107 IVTVFB_ERR("Failed to initialize ivtv\n");
Hans Verkuil6e5eb592007-07-25 12:55:52 -03001108 return -ENXIO;
1109 }
Hans Verkuil26e9d592007-08-25 05:41:52 -03001110 mutex_unlock(&itv->serialize_lock);
Hans Verkuil6e5eb592007-07-25 12:55:52 -03001111
Ian Armstrong5f39b9f2010-05-23 22:10:30 -03001112 if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
1113 &oi->video_buffer_size) < 0) {
1114 IVTVFB_ERR("Firmware failed to respond\n");
1115 return -EIO;
1116 }
Hans Verkuil32db7752007-07-20 09:29:43 -03001117
1118 /* The osd buffer size depends on the number of video buffers allocated
1119 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1120 size to prevent any overlap. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001121 oi->video_buffer_size = 1704960;
Hans Verkuil32db7752007-07-20 09:29:43 -03001122
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001123 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1124 oi->video_vbase = itv->dec_mem + oi->video_rbase;
Hans Verkuil32db7752007-07-20 09:29:43 -03001125
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001126 if (!oi->video_vbase) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001127 IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001128 oi->video_buffer_size, oi->video_pbase);
Hans Verkuil32db7752007-07-20 09:29:43 -03001129 return -EIO;
1130 }
1131
Hans Verkuil641ed492007-08-28 03:24:31 -03001132 IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001133 oi->video_pbase, oi->video_vbase,
1134 oi->video_buffer_size / 1024);
Hans Verkuil32db7752007-07-20 09:29:43 -03001135
Luis R. Rodriguez1bf17352015-06-15 10:28:16 +02001136 while (!(oi->video_buffer_size & (1 << size_shift)))
1137 size_shift--;
1138 size_shift++;
1139 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1140 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1141 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1142 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1143 oi->wc_cookie = arch_phys_wc_add(oi->fb_start_aligned_physaddr,
1144 oi->fb_end_aligned_physaddr -
1145 oi->fb_start_aligned_physaddr);
Hans Verkuil32db7752007-07-20 09:29:43 -03001146 /* Blank the entire osd. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001147 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
Hans Verkuil32db7752007-07-20 09:29:43 -03001148
1149 return 0;
1150}
1151
1152/* Release any memory we've grabbed & remove mtrr entry */
1153static void ivtvfb_release_buffers (struct ivtv *itv)
1154{
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001155 struct osd_info *oi = itv->osd_info;
1156
Hans Verkuil32db7752007-07-20 09:29:43 -03001157 /* Release cmap */
Adrian Bunk13628032007-08-28 03:28:04 -03001158 if (oi->ivtvfb_info.cmap.len)
1159 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
Hans Verkuil32db7752007-07-20 09:29:43 -03001160
1161 /* Release pseudo palette */
Syam Sidhardhan18552ea2013-02-26 15:28:15 -03001162 kfree(oi->ivtvfb_info.pseudo_palette);
Luis R. Rodriguez1bf17352015-06-15 10:28:16 +02001163 arch_phys_wc_del(oi->wc_cookie);
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001164 kfree(oi);
Hans Verkuil32db7752007-07-20 09:29:43 -03001165 itv->osd_info = NULL;
1166}
1167
1168/* Initialize the specified card */
1169
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001170static int ivtvfb_init_card(struct ivtv *itv)
Hans Verkuil32db7752007-07-20 09:29:43 -03001171{
1172 int rc;
1173
1174 if (itv->osd_info) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001175 IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
Hans Verkuil32db7752007-07-20 09:29:43 -03001176 return -EBUSY;
1177 }
1178
Hans Verkuil3f983872008-05-01 10:31:12 -03001179 itv->osd_info = kzalloc(sizeof(struct osd_info),
1180 GFP_ATOMIC|__GFP_NOWARN);
Richard Knutsson14d5deb2007-12-08 10:35:06 -03001181 if (itv->osd_info == NULL) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001182 IVTVFB_ERR("Failed to allocate memory for osd_info\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001183 return -ENOMEM;
1184 }
1185
1186 /* Find & setup the OSD buffer */
Ian Armstrong5f39b9f2010-05-23 22:10:30 -03001187 rc = ivtvfb_init_io(itv);
1188 if (rc) {
1189 ivtvfb_release_buffers(itv);
Hans Verkuil32db7752007-07-20 09:29:43 -03001190 return rc;
Ian Armstrong5f39b9f2010-05-23 22:10:30 -03001191 }
Hans Verkuil32db7752007-07-20 09:29:43 -03001192
1193 /* Set the startup video mode information */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001194 if ((rc = ivtvfb_init_vidmode(itv))) {
Hans Verkuil32db7752007-07-20 09:29:43 -03001195 ivtvfb_release_buffers(itv);
1196 return rc;
1197 }
1198
1199 /* Register the framebuffer */
1200 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1201 ivtvfb_release_buffers(itv);
1202 return -EINVAL;
1203 }
1204
1205 itv->osd_video_pbase = itv->osd_info->video_pbase;
1206
1207 /* Set the card to the requested mode */
1208 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1209
1210 /* Set color 0 to black */
1211 write_reg(0, 0x02a30);
1212 write_reg(0, 0x02a34);
1213
1214 /* Enable the osd */
1215 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1216
Ian Armstrong215659d2010-06-12 13:41:57 -03001217 /* Enable restart */
1218 itv->ivtvfb_restore = ivtvfb_restore;
1219
Hans Verkuil32db7752007-07-20 09:29:43 -03001220 /* Allocate DMA */
1221 ivtv_udma_alloc(itv);
1222 return 0;
1223
1224}
1225
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001226static int __init ivtvfb_callback_init(struct device *dev, void *p)
1227{
1228 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001229 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001230
Jiri Slaby37b58bf2010-07-19 14:39:34 -03001231 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001232 if (ivtvfb_init_card(itv) == 0) {
1233 IVTVFB_INFO("Framebuffer registered on %s\n",
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001234 itv->v4l2_dev.name);
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001235 (*(int *)p)++;
1236 }
1237 }
1238 return 0;
1239}
1240
1241static int ivtvfb_callback_cleanup(struct device *dev, void *p)
1242{
1243 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001244 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
Ian Armstrong5f39b9f2010-05-23 22:10:30 -03001245 struct osd_info *oi = itv->osd_info;
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001246
Jiri Slaby37b58bf2010-07-19 14:39:34 -03001247 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001248 if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
1249 IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
1250 itv->instance);
1251 return 0;
1252 }
1253 IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
Ian Armstrong215659d2010-06-12 13:41:57 -03001254 itv->ivtvfb_restore = NULL;
Ian Armstrong5f39b9f2010-05-23 22:10:30 -03001255 ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001256 ivtvfb_release_buffers(itv);
1257 itv->osd_video_pbase = 0;
1258 }
1259 return 0;
1260}
1261
Hans Verkuil32db7752007-07-20 09:29:43 -03001262static int __init ivtvfb_init(void)
1263{
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001264 struct device_driver *drv;
1265 int registered = 0;
1266 int err;
Hans Verkuil32db7752007-07-20 09:29:43 -03001267
Luis R. Rodriguez1bf17352015-06-15 10:28:16 +02001268#ifdef CONFIG_X86_64
1269 if (WARN(pat_enabled(),
1270 "ivtvfb needs PAT disabled, boot with nopat kernel parameter\n")) {
1271 return -ENODEV;
1272 }
1273#endif
1274
Hans Verkuil641ed492007-08-28 03:24:31 -03001275 if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
1276 printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
Hans Verkuil32db7752007-07-20 09:29:43 -03001277 IVTV_MAX_CARDS - 1);
1278 return -EINVAL;
1279 }
1280
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001281 drv = driver_find("ivtv", &pci_bus_type);
1282 err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
Hans Verkuil932205a2012-04-23 08:25:20 -03001283 (void)err; /* suppress compiler warning */
Hans Verkuil32db7752007-07-20 09:29:43 -03001284 if (!registered) {
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001285 printk(KERN_ERR "ivtvfb: no cards found\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001286 return -ENODEV;
1287 }
1288 return 0;
1289}
1290
1291static void ivtvfb_cleanup(void)
1292{
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001293 struct device_driver *drv;
1294 int err;
Hans Verkuil32db7752007-07-20 09:29:43 -03001295
Hans Verkuil7b3a0d42007-08-26 06:11:07 -03001296 printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001297
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001298 drv = driver_find("ivtv", &pci_bus_type);
1299 err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
Hans Verkuil932205a2012-04-23 08:25:20 -03001300 (void)err; /* suppress compiler warning */
Hans Verkuil32db7752007-07-20 09:29:43 -03001301}
1302
1303module_init(ivtvfb_init);
1304module_exit(ivtvfb_cleanup);