1/* 2 * Zoran ZR36016 basic configuration functions 3 * 4 * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> 5 * 6 * $Id: zr36016.c,v 1.1.2.14 2003/08/20 19:46:55 Exp $ 7 * 8 * ------------------------------------------------------------------------ 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 * 24 * ------------------------------------------------------------------------ 25 */ 26 27#define ZR016_VERSION "v0.7" 28 29#include <linux/module.h> 30#include <linux/init.h> 31#include <linux/slab.h> 32#include <linux/delay.h> 33 34#include <linux/types.h> 35#include <linux/wait.h> 36 37/* I/O commands, error codes */ 38#include <asm/io.h> 39 40/* v4l API */ 41 42/* headerfile of this module */ 43#include"zr36016.h" 44 45/* codec io API */ 46#include"videocodec.h" 47 48/* it doesn't make sense to have more than 20 or so, 49 just to prevent some unwanted loops */ 50#define MAX_CODECS 20 51 52/* amount of chips attached via this driver */ 53static int zr36016_codecs; 54 55/* debugging is available via module parameter */ 56static int debug; 57module_param(debug, int, 0); 58MODULE_PARM_DESC(debug, "Debug level (0-4)"); 59 60#define dprintk(num, format, args...) \ 61 do { \ 62 if (debug >= num) \ 63 printk(format, ##args); \ 64 } while (0) 65 66/* ========================================================================= 67 Local hardware I/O functions: 68 69 read/write via codec layer (registers are located in the master device) 70 ========================================================================= */ 71 72/* read and write functions */ 73static u8 74zr36016_read (struct zr36016 *ptr, 75 u16 reg) 76{ 77 u8 value = 0; 78 79 // just in case something is wrong... 80 if (ptr->codec->master_data->readreg) 81 value = 82 (ptr->codec->master_data-> 83 readreg(ptr->codec, reg)) & 0xFF; 84 else 85 dprintk(1, 86 KERN_ERR "%s: invalid I/O setup, nothing read!\n", 87 ptr->name); 88 89 dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, 90 value); 91 92 return value; 93} 94 95static void 96zr36016_write (struct zr36016 *ptr, 97 u16 reg, 98 u8 value) 99{ 100 dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, 101 reg); 102 103 // just in case something is wrong... 104 if (ptr->codec->master_data->writereg) { 105 ptr->codec->master_data->writereg(ptr->codec, reg, value); 106 } else 107 dprintk(1, 108 KERN_ERR 109 "%s: invalid I/O setup, nothing written!\n", 110 ptr->name); 111} 112 113/* indirect read and write functions */ 114/* the 016 supports auto-addr-increment, but 115 * writing it all time cost not much and is safer... */ 116static u8 117zr36016_readi (struct zr36016 *ptr, 118 u16 reg) 119{ 120 u8 value = 0; 121 122 // just in case something is wrong... 123 if ((ptr->codec->master_data->writereg) && 124 (ptr->codec->master_data->readreg)) { 125 ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR 126 value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA 127 } else 128 dprintk(1, 129 KERN_ERR 130 "%s: invalid I/O setup, nothing read (i)!\n", 131 ptr->name); 132 133 dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name, 134 reg, value); 135 return value; 136} 137 138static void 139zr36016_writei (struct zr36016 *ptr, 140 u16 reg, 141 u8 value) 142{ 143 dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, 144 value, reg); 145 146 // just in case something is wrong... 147 if (ptr->codec->master_data->writereg) { 148 ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR 149 ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA 150 } else 151 dprintk(1, 152 KERN_ERR 153 "%s: invalid I/O setup, nothing written (i)!\n", 154 ptr->name); 155} 156 157/* ========================================================================= 158 Local helper function: 159 160 version read 161 ========================================================================= */ 162 163/* version kept in datastructure */ 164static u8 165zr36016_read_version (struct zr36016 *ptr) 166{ 167 ptr->version = zr36016_read(ptr, 0) >> 4; 168 return ptr->version; 169} 170 171/* ========================================================================= 172 Local helper function: 173 174 basic test of "connectivity", writes/reads to/from PAX-Lo register 175 ========================================================================= */ 176 177static int 178zr36016_basic_test (struct zr36016 *ptr) 179{ 180 if (debug) { 181 int i; 182 zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); 183 dprintk(1, KERN_INFO "%s: registers: ", ptr->name); 184 for (i = 0; i <= 0x0b; i++) 185 dprintk(1, "%02x ", zr36016_readi(ptr, i)); 186 dprintk(1, "\n"); 187 } 188 // for testing just write 0, then the default value to a register and read 189 // it back in both cases 190 zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); 191 if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { 192 dprintk(1, 193 KERN_ERR 194 "%s: attach failed, can't connect to vfe processor!\n", 195 ptr->name); 196 return -ENXIO; 197 } 198 zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); 199 if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { 200 dprintk(1, 201 KERN_ERR 202 "%s: attach failed, can't connect to vfe processor!\n", 203 ptr->name); 204 return -ENXIO; 205 } 206 // we allow version numbers from 0-3, should be enough, though 207 zr36016_read_version(ptr); 208 if (ptr->version & 0x0c) { 209 dprintk(1, 210 KERN_ERR 211 "%s: attach failed, suspicious version %d found...\n", 212 ptr->name, ptr->version); 213 return -ENXIO; 214 } 215 216 return 0; /* looks good! */ 217} 218 219/* ========================================================================= 220 Local helper function: 221 222 simple loop for pushing the init datasets - NO USE -- 223 ========================================================================= */ 224 225 226/* ========================================================================= 227 Basic datasets & init: 228 229 //TODO// 230 ========================================================================= */ 231 232// needed offset values PAL NTSC SECAM 233static const int zr016_xoff[] = { 20, 20, 20 }; 234static const int zr016_yoff[] = { 8, 9, 7 }; 235 236static void 237zr36016_init (struct zr36016 *ptr) 238{ 239 // stop any processing 240 zr36016_write(ptr, ZR016_GOSTOP, 0); 241 242 // mode setup (yuv422 in and out, compression/expansuon due to mode) 243 zr36016_write(ptr, ZR016_MODE, 244 ZR016_YUV422 | ZR016_YUV422_YUV422 | 245 (ptr->mode == CODEC_DO_COMPRESSION ? 246 ZR016_COMPRESSION : ZR016_EXPANSION)); 247 248 // misc setup 249 zr36016_writei(ptr, ZR016I_SETUP1, 250 (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) | 251 (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI); 252 zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR); 253 254 // Window setup 255 // (no extra offset for now, norm defines offset, default width height) 256 zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8); 257 zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF); 258 zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8); 259 zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF); 260 zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8); 261 zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF); 262 zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8); 263 zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF); 264 265 /* shall we continue now, please? */ 266 zr36016_write(ptr, ZR016_GOSTOP, 1); 267} 268 269/* ========================================================================= 270 CODEC API FUNCTIONS 271 272 this functions are accessed by the master via the API structure 273 ========================================================================= */ 274 275/* set compression/expansion mode and launches codec - 276 this should be the last call from the master before starting processing */ 277static int 278zr36016_set_mode (struct videocodec *codec, 279 int mode) 280{ 281 struct zr36016 *ptr = (struct zr36016 *) codec->data; 282 283 dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); 284 285 if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) 286 return -EINVAL; 287 288 ptr->mode = mode; 289 zr36016_init(ptr); 290 291 return 0; 292} 293 294/* set picture size */ 295static int 296zr36016_set_video (struct videocodec *codec, 297 struct tvnorm *norm, 298 struct vfe_settings *cap, 299 struct vfe_polarity *pol) 300{ 301 struct zr36016 *ptr = (struct zr36016 *) codec->data; 302 303 dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", 304 ptr->name, norm->HStart, norm->VStart, 305 cap->x, cap->y, cap->width, cap->height, 306 cap->decimation); 307 308 /* if () return -EINVAL; 309 * trust the master driver that it knows what it does - so 310 * we allow invalid startx/y for now ... */ 311 ptr->width = cap->width; 312 ptr->height = cap->height; 313 /* (Ronald) This is ugly. zoran_device.c, line 387 314 * already mentions what happens if HStart is even 315 * (blue faces, etc., cr/cb inversed). There's probably 316 * some good reason why HStart is 0 instead of 1, so I'm 317 * leaving it to this for now, but really... This can be 318 * done a lot simpler */ 319 ptr->xoff = (norm->HStart ? norm->HStart : 1) + cap->x; 320 /* Something to note here (I don't understand it), setting 321 * VStart too high will cause the codec to 'not work'. I 322 * really don't get it. values of 16 (VStart) already break 323 * it here. Just '0' seems to work. More testing needed! */ 324 ptr->yoff = norm->VStart + cap->y; 325 /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ 326 ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; 327 ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1; 328 329 return 0; 330} 331 332/* additional control functions */ 333static int 334zr36016_control (struct videocodec *codec, 335 int type, 336 int size, 337 void *data) 338{ 339 struct zr36016 *ptr = (struct zr36016 *) codec->data; 340 int *ival = (int *) data; 341 342 dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, 343 size); 344 345 switch (type) { 346 case CODEC_G_STATUS: /* get last status - we don't know it ... */ 347 if (size != sizeof(int)) 348 return -EFAULT; 349 *ival = 0; 350 break; 351 352 case CODEC_G_CODEC_MODE: 353 if (size != sizeof(int)) 354 return -EFAULT; 355 *ival = 0; 356 break; 357 358 case CODEC_S_CODEC_MODE: 359 if (size != sizeof(int)) 360 return -EFAULT; 361 if (*ival != 0) 362 return -EINVAL; 363 /* not needed, do nothing */ 364 return 0; 365 366 case CODEC_G_VFE: 367 case CODEC_S_VFE: 368 return 0; 369 370 case CODEC_S_MMAP: 371 /* not available, give an error */ 372 return -ENXIO; 373 374 default: 375 return -EINVAL; 376 } 377 378 return size; 379} 380 381/* ========================================================================= 382 Exit and unregister function: 383 384 Deinitializes Zoran's JPEG processor 385 ========================================================================= */ 386 387static int 388zr36016_unset (struct videocodec *codec) 389{ 390 struct zr36016 *ptr = codec->data; 391 392 if (ptr) { 393 /* do wee need some codec deinit here, too ???? */ 394 395 dprintk(1, "%s: finished codec #%d\n", ptr->name, 396 ptr->num); 397 kfree(ptr); 398 codec->data = NULL; 399 400 zr36016_codecs--; 401 return 0; 402 } 403 404 return -EFAULT; 405} 406 407/* ========================================================================= 408 Setup and registry function: 409 410 Initializes Zoran's JPEG processor 411 412 Also sets pixel size, average code size, mode (compr./decompr.) 413 (the given size is determined by the processor with the video interface) 414 ========================================================================= */ 415 416static int 417zr36016_setup (struct videocodec *codec) 418{ 419 struct zr36016 *ptr; 420 int res; 421 422 dprintk(2, "zr36016: initializing VFE subsystem #%d.\n", 423 zr36016_codecs); 424 425 if (zr36016_codecs == MAX_CODECS) { 426 dprintk(1, 427 KERN_ERR "zr36016: Can't attach more codecs!\n"); 428 return -ENOSPC; 429 } 430 //mem structure init 431 codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL); 432 if (NULL == ptr) { 433 dprintk(1, KERN_ERR "zr36016: Can't get enough memory!\n"); 434 return -ENOMEM; 435 } 436 437 snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", 438 zr36016_codecs); 439 ptr->num = zr36016_codecs++; 440 ptr->codec = codec; 441 442 //testing 443 res = zr36016_basic_test(ptr); 444 if (res < 0) { 445 zr36016_unset(codec); 446 return res; 447 } 448 //final setup 449 ptr->mode = CODEC_DO_COMPRESSION; 450 ptr->width = 768; 451 ptr->height = 288; 452 ptr->xdec = 1; 453 ptr->ydec = 0; 454 zr36016_init(ptr); 455 456 dprintk(1, KERN_INFO "%s: codec v%d attached and running\n", 457 ptr->name, ptr->version); 458 459 return 0; 460} 461 462static const struct videocodec zr36016_codec = { 463 .owner = THIS_MODULE, 464 .name = "zr36016", 465 .magic = 0L, // magic not used 466 .flags = 467 CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER | 468 CODEC_FLAG_DECODER, 469 .type = CODEC_TYPE_ZR36016, 470 .setup = zr36016_setup, // functionality 471 .unset = zr36016_unset, 472 .set_mode = zr36016_set_mode, 473 .set_video = zr36016_set_video, 474 .control = zr36016_control, 475 // others are not used 476}; 477 478/* ========================================================================= 479 HOOK IN DRIVER AS KERNEL MODULE 480 ========================================================================= */ 481 482static int __init 483zr36016_init_module (void) 484{ 485 //dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION); 486 zr36016_codecs = 0; 487 return videocodec_register(&zr36016_codec); 488} 489 490static void __exit 491zr36016_cleanup_module (void) 492{ 493 if (zr36016_codecs) { 494 dprintk(1, 495 "zr36016: something's wrong - %d codecs left somehow.\n", 496 zr36016_codecs); 497 } 498 videocodec_unregister(&zr36016_codec); 499} 500 501module_init(zr36016_init_module); 502module_exit(zr36016_cleanup_module); 503 504MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); 505MODULE_DESCRIPTION("Driver module for ZR36016 video frontends " 506 ZR016_VERSION); 507MODULE_LICENSE("GPL"); 508