1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Zoran ZR36016 basic configuration functions 4 * 5 * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> 6 */ 7 8 #include <linux/module.h> 9 #include <linux/init.h> 10 #include <linux/slab.h> 11 12 /* headerfile of this module */ 13 #include "zr36016.h" 14 15 /* codec io API */ 16 #include "videocodec.h" 17 18 /* 19 * it doesn't make sense to have more than 20 or so, 20 * just to prevent some unwanted loops 21 */ 22 #define MAX_CODECS 20 23 24 /* amount of chips attached via this driver */ 25 static int zr36016_codecs; 26 27 /* 28 * Local hardware I/O functions: read/write via codec layer 29 * (registers are located in the master device) 30 */ 31 32 /* read and write functions */ 33 static u8 zr36016_read(struct zr36016 *ptr, u16 reg) 34 { 35 u8 value = 0; 36 struct zoran *zr = videocodec_to_zoran(ptr->codec); 37 38 /* just in case something is wrong... */ 39 if (ptr->codec->master_data->readreg) 40 value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF; 41 else 42 zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); 43 44 zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); 45 46 return value; 47 } 48 49 static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value) 50 { 51 struct zoran *zr = videocodec_to_zoran(ptr->codec); 52 53 zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); 54 55 // just in case something is wrong... 56 if (ptr->codec->master_data->writereg) 57 ptr->codec->master_data->writereg(ptr->codec, reg, value); 58 else 59 zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name); 60 } 61 62 /* 63 * indirect read and write functions 64 * 65 * the 016 supports auto-addr-increment, but 66 * writing it all time cost not much and is safer... 67 */ 68 static u8 zr36016_readi(struct zr36016 *ptr, u16 reg) 69 { 70 u8 value = 0; 71 struct zoran *zr = videocodec_to_zoran(ptr->codec); 72 73 /* just in case something is wrong... */ 74 if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) { 75 ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); 76 value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; 77 } else { 78 zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name); 79 } 80 81 zrdev_dbg(zr, "%s: reading indirect from 0x%04x: %02x\n", 82 ptr->name, reg, value); 83 return value; 84 } 85 86 static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value) 87 { 88 struct zoran *zr = videocodec_to_zoran(ptr->codec); 89 90 zrdev_dbg(zr, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, 91 value, reg); 92 93 /* just in case something is wrong... */ 94 if (ptr->codec->master_data->writereg) { 95 ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); 96 ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); 97 } else { 98 zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name); 99 } 100 } 101 102 /* Local helper function: version read */ 103 104 /* version kept in datastructure */ 105 static u8 zr36016_read_version(struct zr36016 *ptr) 106 { 107 ptr->version = zr36016_read(ptr, 0) >> 4; 108 return ptr->version; 109 } 110 111 /* 112 * Local helper function: basic test of "connectivity", writes/reads 113 * to/from PAX-Lo register 114 */ 115 116 static int zr36016_basic_test(struct zr36016 *ptr) 117 { 118 struct zoran *zr = videocodec_to_zoran(ptr->codec); 119 120 if (*KERN_INFO <= CONSOLE_LOGLEVEL_DEFAULT) { 121 int i; 122 123 zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); 124 zrdev_dbg(zr, "%s: registers: ", ptr->name); 125 for (i = 0; i <= 0x0b; i++) 126 zrdev_dbg(zr, "%02x ", zr36016_readi(ptr, i)); 127 zrdev_dbg(zr, "\n"); 128 } 129 // for testing just write 0, then the default value to a register and read 130 // it back in both cases 131 zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); 132 if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { 133 zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name); 134 return -ENXIO; 135 } 136 zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); 137 if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { 138 zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name); 139 return -ENXIO; 140 } 141 // we allow version numbers from 0-3, should be enough, though 142 zr36016_read_version(ptr); 143 if (ptr->version & 0x0c) { 144 zrdev_err(zr, "%s: attach failed, suspicious version %d found...\n", ptr->name, 145 ptr->version); 146 return -ENXIO; 147 } 148 149 return 0; /* looks good! */ 150 } 151 152 /* Basic datasets & init */ 153 154 static void zr36016_init(struct zr36016 *ptr) 155 { 156 // stop any processing 157 zr36016_write(ptr, ZR016_GOSTOP, 0); 158 159 // mode setup (yuv422 in and out, compression/expansuon due to mode) 160 zr36016_write(ptr, ZR016_MODE, 161 ZR016_YUV422 | ZR016_YUV422_YUV422 | 162 (ptr->mode == CODEC_DO_COMPRESSION ? 163 ZR016_COMPRESSION : ZR016_EXPANSION)); 164 165 // misc setup 166 zr36016_writei(ptr, ZR016I_SETUP1, 167 (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) | 168 (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI); 169 zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR); 170 171 // Window setup 172 // (no extra offset for now, norm defines offset, default width height) 173 zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8); 174 zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF); 175 zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8); 176 zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF); 177 zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8); 178 zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF); 179 zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8); 180 zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF); 181 182 /* shall we continue now, please? */ 183 zr36016_write(ptr, ZR016_GOSTOP, 1); 184 } 185 186 /* 187 * CODEC API FUNCTIONS 188 * 189 * These functions are accessed by the master via the API structure 190 */ 191 192 /* 193 * set compression/expansion mode and launches codec - 194 * this should be the last call from the master before starting processing 195 */ 196 static int zr36016_set_mode(struct videocodec *codec, int mode) 197 { 198 struct zr36016 *ptr = (struct zr36016 *)codec->data; 199 struct zoran *zr = videocodec_to_zoran(codec); 200 201 zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); 202 203 if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) 204 return -EINVAL; 205 206 ptr->mode = mode; 207 zr36016_init(ptr); 208 209 return 0; 210 } 211 212 /* set picture size */ 213 static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm, 214 struct vfe_settings *cap, struct vfe_polarity *pol) 215 { 216 struct zr36016 *ptr = (struct zr36016 *)codec->data; 217 struct zoran *zr = videocodec_to_zoran(codec); 218 219 zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", 220 ptr->name, norm->h_start, norm->v_start, 221 cap->x, cap->y, cap->width, cap->height, 222 cap->decimation); 223 224 /* 225 * if () return -EINVAL; 226 * trust the master driver that it knows what it does - so 227 * we allow invalid startx/y for now ... 228 */ 229 ptr->width = cap->width; 230 ptr->height = cap->height; 231 /* 232 * (Ronald) This is ugly. zoran_device.c, line 387 233 * already mentions what happens if h_start is even 234 * (blue faces, etc., cr/cb inversed). There's probably 235 * some good reason why h_start is 0 instead of 1, so I'm 236 * leaving it to this for now, but really... This can be 237 * done a lot simpler 238 */ 239 ptr->xoff = (norm->h_start ? norm->h_start : 1) + cap->x; 240 /* 241 * Something to note here (I don't understand it), setting 242 * v_start too high will cause the codec to 'not work'. I 243 * really don't get it. values of 16 (v_start) already break 244 * it here. Just '0' seems to work. More testing needed! 245 */ 246 ptr->yoff = norm->v_start + cap->y; 247 /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ 248 ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; 249 ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1; 250 251 return 0; 252 } 253 254 /* additional control functions */ 255 static int zr36016_control(struct videocodec *codec, int type, int size, void *data) 256 { 257 struct zr36016 *ptr = (struct zr36016 *)codec->data; 258 struct zoran *zr = videocodec_to_zoran(codec); 259 int *ival = (int *)data; 260 261 zrdev_dbg(zr, "%s: control %d call with %d byte\n", 262 ptr->name, type, size); 263 264 switch (type) { 265 case CODEC_G_STATUS: /* get last status - we don't know it ... */ 266 if (size != sizeof(int)) 267 return -EFAULT; 268 *ival = 0; 269 break; 270 271 case CODEC_G_CODEC_MODE: 272 if (size != sizeof(int)) 273 return -EFAULT; 274 *ival = 0; 275 break; 276 277 case CODEC_S_CODEC_MODE: 278 if (size != sizeof(int)) 279 return -EFAULT; 280 if (*ival != 0) 281 return -EINVAL; 282 /* not needed, do nothing */ 283 return 0; 284 285 case CODEC_G_VFE: 286 case CODEC_S_VFE: 287 return 0; 288 289 case CODEC_S_MMAP: 290 /* not available, give an error */ 291 return -ENXIO; 292 293 default: 294 return -EINVAL; 295 } 296 297 return size; 298 } 299 300 /* 301 * Exit and unregister function: 302 * 303 * Deinitializes Zoran's JPEG processor 304 */ 305 306 static int zr36016_unset(struct videocodec *codec) 307 { 308 struct zr36016 *ptr = codec->data; 309 struct zoran *zr = videocodec_to_zoran(codec); 310 311 if (ptr) { 312 /* do wee need some codec deinit here, too ???? */ 313 314 zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num); 315 kfree(ptr); 316 codec->data = NULL; 317 318 zr36016_codecs--; 319 return 0; 320 } 321 322 return -EFAULT; 323 } 324 325 /* 326 * Setup and registry function: 327 * 328 * Initializes Zoran's JPEG processor 329 * 330 * Also sets pixel size, average code size, mode (compr./decompr.) 331 * (the given size is determined by the processor with the video interface) 332 */ 333 334 static int zr36016_setup(struct videocodec *codec) 335 { 336 struct zr36016 *ptr; 337 struct zoran *zr = videocodec_to_zoran(codec); 338 int res; 339 340 zrdev_dbg(zr, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs); 341 342 if (zr36016_codecs == MAX_CODECS) { 343 zrdev_err(zr, "zr36016: Can't attach more codecs!\n"); 344 return -ENOSPC; 345 } 346 //mem structure init 347 ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); 348 codec->data = ptr; 349 if (!ptr) 350 return -ENOMEM; 351 352 snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", zr36016_codecs); 353 ptr->num = zr36016_codecs++; 354 ptr->codec = codec; 355 356 //testing 357 res = zr36016_basic_test(ptr); 358 if (res < 0) { 359 zr36016_unset(codec); 360 return res; 361 } 362 //final setup 363 ptr->mode = CODEC_DO_COMPRESSION; 364 ptr->width = 768; 365 ptr->height = 288; 366 ptr->xdec = 1; 367 ptr->ydec = 0; 368 zr36016_init(ptr); 369 370 zrdev_dbg(zr, "%s: codec v%d attached and running\n", 371 ptr->name, ptr->version); 372 373 return 0; 374 } 375 376 static const struct videocodec zr36016_codec = { 377 .name = "zr36016", 378 .magic = 0L, /* magic not used */ 379 .flags = 380 CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER | 381 CODEC_FLAG_DECODER, 382 .type = CODEC_TYPE_ZR36016, 383 .setup = zr36016_setup, /* functionality */ 384 .unset = zr36016_unset, 385 .set_mode = zr36016_set_mode, 386 .set_video = zr36016_set_video, 387 .control = zr36016_control, 388 /* others are not used */ 389 }; 390 391 /* HOOK IN DRIVER AS KERNEL MODULE */ 392 393 int zr36016_init_module(void) 394 { 395 zr36016_codecs = 0; 396 return videocodec_register(&zr36016_codec); 397 } 398 399 void zr36016_cleanup_module(void) 400 { 401 if (zr36016_codecs) { 402 pr_debug("zr36016: something's wrong - %d codecs left somehow.\n", 403 zr36016_codecs); 404 } 405 videocodec_unregister(&zr36016_codec); 406 } 407