18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TW5864 driver - video encoding functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 108c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 118c2ecf20Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "tw5864.h" 148c2ecf20Sopenharmony_ci#include "tw5864-reg.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define QUANTIZATION_TABLE_LEN 96 178c2ecf20Sopenharmony_ci#define VLC_LOOKUP_TABLE_LEN 1024 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const u16 forward_quantization_table[QUANTIZATION_TABLE_LEN] = { 208c2ecf20Sopenharmony_ci 0x3333, 0x1f82, 0x3333, 0x1f82, 0x1f82, 0x147b, 0x1f82, 0x147b, 218c2ecf20Sopenharmony_ci 0x3333, 0x1f82, 0x3333, 0x1f82, 0x1f82, 0x147b, 0x1f82, 0x147b, 228c2ecf20Sopenharmony_ci 0x2e8c, 0x1d42, 0x2e8c, 0x1d42, 0x1d42, 0x1234, 0x1d42, 0x1234, 238c2ecf20Sopenharmony_ci 0x2e8c, 0x1d42, 0x2e8c, 0x1d42, 0x1d42, 0x1234, 0x1d42, 0x1234, 248c2ecf20Sopenharmony_ci 0x2762, 0x199a, 0x2762, 0x199a, 0x199a, 0x1062, 0x199a, 0x1062, 258c2ecf20Sopenharmony_ci 0x2762, 0x199a, 0x2762, 0x199a, 0x199a, 0x1062, 0x199a, 0x1062, 268c2ecf20Sopenharmony_ci 0x2492, 0x16c1, 0x2492, 0x16c1, 0x16c1, 0x0e3f, 0x16c1, 0x0e3f, 278c2ecf20Sopenharmony_ci 0x2492, 0x16c1, 0x2492, 0x16c1, 0x16c1, 0x0e3f, 0x16c1, 0x0e3f, 288c2ecf20Sopenharmony_ci 0x2000, 0x147b, 0x2000, 0x147b, 0x147b, 0x0d1b, 0x147b, 0x0d1b, 298c2ecf20Sopenharmony_ci 0x2000, 0x147b, 0x2000, 0x147b, 0x147b, 0x0d1b, 0x147b, 0x0d1b, 308c2ecf20Sopenharmony_ci 0x1c72, 0x11cf, 0x1c72, 0x11cf, 0x11cf, 0x0b4d, 0x11cf, 0x0b4d, 318c2ecf20Sopenharmony_ci 0x1c72, 0x11cf, 0x1c72, 0x11cf, 0x11cf, 0x0b4d, 0x11cf, 0x0b4d 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const u16 inverse_quantization_table[QUANTIZATION_TABLE_LEN] = { 358c2ecf20Sopenharmony_ci 0x800a, 0x800d, 0x800a, 0x800d, 0x800d, 0x8010, 0x800d, 0x8010, 368c2ecf20Sopenharmony_ci 0x800a, 0x800d, 0x800a, 0x800d, 0x800d, 0x8010, 0x800d, 0x8010, 378c2ecf20Sopenharmony_ci 0x800b, 0x800e, 0x800b, 0x800e, 0x800e, 0x8012, 0x800e, 0x8012, 388c2ecf20Sopenharmony_ci 0x800b, 0x800e, 0x800b, 0x800e, 0x800e, 0x8012, 0x800e, 0x8012, 398c2ecf20Sopenharmony_ci 0x800d, 0x8010, 0x800d, 0x8010, 0x8010, 0x8014, 0x8010, 0x8014, 408c2ecf20Sopenharmony_ci 0x800d, 0x8010, 0x800d, 0x8010, 0x8010, 0x8014, 0x8010, 0x8014, 418c2ecf20Sopenharmony_ci 0x800e, 0x8012, 0x800e, 0x8012, 0x8012, 0x8017, 0x8012, 0x8017, 428c2ecf20Sopenharmony_ci 0x800e, 0x8012, 0x800e, 0x8012, 0x8012, 0x8017, 0x8012, 0x8017, 438c2ecf20Sopenharmony_ci 0x8010, 0x8014, 0x8010, 0x8014, 0x8014, 0x8019, 0x8014, 0x8019, 448c2ecf20Sopenharmony_ci 0x8010, 0x8014, 0x8010, 0x8014, 0x8014, 0x8019, 0x8014, 0x8019, 458c2ecf20Sopenharmony_ci 0x8012, 0x8017, 0x8012, 0x8017, 0x8017, 0x801d, 0x8017, 0x801d, 468c2ecf20Sopenharmony_ci 0x8012, 0x8017, 0x8012, 0x8017, 0x8017, 0x801d, 0x8017, 0x801d 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const u16 encoder_vlc_lookup_table[VLC_LOOKUP_TABLE_LEN] = { 508c2ecf20Sopenharmony_ci 0x011, 0x000, 0x000, 0x000, 0x065, 0x021, 0x000, 0x000, 0x087, 0x064, 518c2ecf20Sopenharmony_ci 0x031, 0x000, 0x097, 0x086, 0x075, 0x053, 0x0a7, 0x096, 0x085, 0x063, 528c2ecf20Sopenharmony_ci 0x0b7, 0x0a6, 0x095, 0x074, 0x0df, 0x0b6, 0x0a5, 0x084, 0x0db, 0x0de, 538c2ecf20Sopenharmony_ci 0x0b5, 0x094, 0x0d8, 0x0da, 0x0dd, 0x0a4, 0x0ef, 0x0ee, 0x0d9, 0x0b4, 548c2ecf20Sopenharmony_ci 0x0eb, 0x0ea, 0x0ed, 0x0dc, 0x0ff, 0x0fe, 0x0e9, 0x0ec, 0x0fb, 0x0fa, 558c2ecf20Sopenharmony_ci 0x0fd, 0x0e8, 0x10f, 0x0f1, 0x0f9, 0x0fc, 0x10b, 0x10e, 0x10d, 0x0f8, 568c2ecf20Sopenharmony_ci 0x107, 0x10a, 0x109, 0x10c, 0x104, 0x106, 0x105, 0x108, 0x023, 0x000, 578c2ecf20Sopenharmony_ci 0x000, 0x000, 0x06b, 0x022, 0x000, 0x000, 0x067, 0x057, 0x033, 0x000, 588c2ecf20Sopenharmony_ci 0x077, 0x06a, 0x069, 0x045, 0x087, 0x066, 0x065, 0x044, 0x084, 0x076, 598c2ecf20Sopenharmony_ci 0x075, 0x056, 0x097, 0x086, 0x085, 0x068, 0x0bf, 0x096, 0x095, 0x064, 608c2ecf20Sopenharmony_ci 0x0bb, 0x0be, 0x0bd, 0x074, 0x0cf, 0x0ba, 0x0b9, 0x094, 0x0cb, 0x0ce, 618c2ecf20Sopenharmony_ci 0x0cd, 0x0bc, 0x0c8, 0x0ca, 0x0c9, 0x0b8, 0x0df, 0x0de, 0x0dd, 0x0cc, 628c2ecf20Sopenharmony_ci 0x0db, 0x0da, 0x0d9, 0x0dc, 0x0d7, 0x0eb, 0x0d6, 0x0d8, 0x0e9, 0x0e8, 638c2ecf20Sopenharmony_ci 0x0ea, 0x0d1, 0x0e7, 0x0e6, 0x0e5, 0x0e4, 0x04f, 0x000, 0x000, 0x000, 648c2ecf20Sopenharmony_ci 0x06f, 0x04e, 0x000, 0x000, 0x06b, 0x05f, 0x04d, 0x000, 0x068, 0x05c, 658c2ecf20Sopenharmony_ci 0x05e, 0x04c, 0x07f, 0x05a, 0x05b, 0x04b, 0x07b, 0x058, 0x059, 0x04a, 668c2ecf20Sopenharmony_ci 0x079, 0x06e, 0x06d, 0x049, 0x078, 0x06a, 0x069, 0x048, 0x08f, 0x07e, 678c2ecf20Sopenharmony_ci 0x07d, 0x05d, 0x08b, 0x08e, 0x07a, 0x06c, 0x09f, 0x08a, 0x08d, 0x07c, 688c2ecf20Sopenharmony_ci 0x09b, 0x09e, 0x089, 0x08c, 0x098, 0x09a, 0x09d, 0x088, 0x0ad, 0x097, 698c2ecf20Sopenharmony_ci 0x099, 0x09c, 0x0a9, 0x0ac, 0x0ab, 0x0aa, 0x0a5, 0x0a8, 0x0a7, 0x0a6, 708c2ecf20Sopenharmony_ci 0x0a1, 0x0a4, 0x0a3, 0x0a2, 0x021, 0x000, 0x000, 0x000, 0x067, 0x011, 718c2ecf20Sopenharmony_ci 0x000, 0x000, 0x064, 0x066, 0x031, 0x000, 0x063, 0x073, 0x072, 0x065, 728c2ecf20Sopenharmony_ci 0x062, 0x083, 0x082, 0x070, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 738c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 748c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 758c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 768c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 778c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 788c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 798c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 808c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 818c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 828c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 838c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 848c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 858c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 868c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 878c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 888c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 898c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 908c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 918c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 928c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 938c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 948c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 958c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 968c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 978c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 988c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 998c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1008c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1018c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1028c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x011, 0x010, 1038c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1048c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x011, 0x021, 0x020, 0x000, 0x000, 0x000, 1058c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1068c2ecf20Sopenharmony_ci 0x023, 0x022, 0x021, 0x020, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1078c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x023, 0x022, 0x021, 0x031, 1088c2ecf20Sopenharmony_ci 0x030, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1098c2ecf20Sopenharmony_ci 0x000, 0x000, 0x023, 0x022, 0x033, 0x032, 0x031, 0x030, 0x000, 0x000, 1108c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x023, 0x030, 1118c2ecf20Sopenharmony_ci 0x031, 0x033, 0x032, 0x035, 0x034, 0x000, 0x000, 0x000, 0x000, 0x000, 1128c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x037, 0x036, 0x035, 0x034, 0x033, 0x032, 1138c2ecf20Sopenharmony_ci 0x031, 0x041, 0x051, 0x061, 0x071, 0x081, 0x091, 0x0a1, 0x0b1, 0x000, 1148c2ecf20Sopenharmony_ci 0x002, 0x000, 0x0e4, 0x011, 0x0f4, 0x002, 0x024, 0x003, 0x005, 0x012, 1158c2ecf20Sopenharmony_ci 0x034, 0x013, 0x065, 0x024, 0x013, 0x063, 0x015, 0x022, 0x075, 0x034, 1168c2ecf20Sopenharmony_ci 0x044, 0x023, 0x023, 0x073, 0x054, 0x033, 0x033, 0x004, 0x043, 0x014, 1178c2ecf20Sopenharmony_ci 0x011, 0x043, 0x014, 0x001, 0x025, 0x015, 0x035, 0x025, 0x064, 0x055, 1188c2ecf20Sopenharmony_ci 0x045, 0x035, 0x074, 0x065, 0x085, 0x0d5, 0x012, 0x095, 0x055, 0x045, 1198c2ecf20Sopenharmony_ci 0x095, 0x0e5, 0x084, 0x075, 0x022, 0x0a5, 0x094, 0x085, 0x032, 0x0b5, 1208c2ecf20Sopenharmony_ci 0x003, 0x0c5, 0x001, 0x044, 0x0a5, 0x032, 0x0b5, 0x094, 0x0c5, 0x0a4, 1218c2ecf20Sopenharmony_ci 0x0a4, 0x054, 0x0d5, 0x0b4, 0x0b4, 0x064, 0x0f5, 0x0f5, 0x053, 0x0d4, 1228c2ecf20Sopenharmony_ci 0x0e5, 0x0c4, 0x105, 0x105, 0x0c4, 0x074, 0x063, 0x0e4, 0x0d4, 0x084, 1238c2ecf20Sopenharmony_ci 0x073, 0x0f4, 0x004, 0x005, 0x000, 0x053, 0x000, 0x000, 0x000, 0x000, 1248c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1258c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1268c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1278c2ecf20Sopenharmony_ci 0x000, 0x000, 0x011, 0x021, 0x031, 0x030, 0x011, 0x021, 0x020, 0x000, 1288c2ecf20Sopenharmony_ci 0x011, 0x010, 0x000, 0x000, 0x011, 0x033, 0x032, 0x043, 0x042, 0x053, 1298c2ecf20Sopenharmony_ci 0x052, 0x063, 0x062, 0x073, 0x072, 0x083, 0x082, 0x093, 0x092, 0x091, 1308c2ecf20Sopenharmony_ci 0x037, 0x036, 0x035, 0x034, 0x033, 0x045, 0x044, 0x043, 0x042, 0x053, 1318c2ecf20Sopenharmony_ci 0x052, 0x063, 0x062, 0x061, 0x060, 0x000, 0x045, 0x037, 0x036, 0x035, 1328c2ecf20Sopenharmony_ci 0x044, 0x043, 0x034, 0x033, 0x042, 0x053, 0x052, 0x061, 0x051, 0x060, 1338c2ecf20Sopenharmony_ci 0x000, 0x000, 0x053, 0x037, 0x045, 0x044, 0x036, 0x035, 0x034, 0x043, 1348c2ecf20Sopenharmony_ci 0x033, 0x042, 0x052, 0x051, 0x050, 0x000, 0x000, 0x000, 0x045, 0x044, 1358c2ecf20Sopenharmony_ci 0x043, 0x037, 0x036, 0x035, 0x034, 0x033, 0x042, 0x051, 0x041, 0x050, 1368c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x061, 0x051, 0x037, 0x036, 0x035, 0x034, 1378c2ecf20Sopenharmony_ci 0x033, 0x032, 0x041, 0x031, 0x060, 0x000, 0x000, 0x000, 0x000, 0x000, 1388c2ecf20Sopenharmony_ci 0x061, 0x051, 0x035, 0x034, 0x033, 0x023, 0x032, 0x041, 0x031, 0x060, 1398c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x061, 0x041, 0x051, 0x033, 1408c2ecf20Sopenharmony_ci 0x023, 0x022, 0x032, 0x031, 0x060, 0x000, 0x000, 0x000, 0x000, 0x000, 1418c2ecf20Sopenharmony_ci 0x000, 0x000, 0x061, 0x060, 0x041, 0x023, 0x022, 0x031, 0x021, 0x051, 1428c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x051, 0x050, 1438c2ecf20Sopenharmony_ci 0x031, 0x023, 0x022, 0x021, 0x041, 0x000, 0x000, 0x000, 0x000, 0x000, 1448c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x040, 0x041, 0x031, 0x032, 0x011, 0x033, 1458c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1468c2ecf20Sopenharmony_ci 0x040, 0x041, 0x021, 0x011, 0x031, 0x000, 0x000, 0x000, 0x000, 0x000, 1478c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x030, 0x031, 0x011, 0x021, 1488c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1498c2ecf20Sopenharmony_ci 0x000, 0x000, 0x020, 0x021, 0x011, 0x000, 0x000, 0x000, 0x000, 0x000, 1508c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x010, 0x011, 1518c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 1528c2ecf20Sopenharmony_ci 0x000, 0x000, 0x000, 0x000 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const unsigned int lambda_lookup_table[] = { 1568c2ecf20Sopenharmony_ci 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 1578c2ecf20Sopenharmony_ci 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 1588c2ecf20Sopenharmony_ci 0x0040, 0x0040, 0x0040, 0x0040, 0x0060, 0x0060, 0x0060, 0x0080, 1598c2ecf20Sopenharmony_ci 0x0080, 0x0080, 0x00a0, 0x00c0, 0x00c0, 0x00e0, 0x0100, 0x0120, 1608c2ecf20Sopenharmony_ci 0x0140, 0x0160, 0x01a0, 0x01c0, 0x0200, 0x0240, 0x0280, 0x02e0, 1618c2ecf20Sopenharmony_ci 0x0320, 0x03a0, 0x0400, 0x0480, 0x0500, 0x05a0, 0x0660, 0x0720, 1628c2ecf20Sopenharmony_ci 0x0800, 0x0900, 0x0a20, 0x0b60 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const unsigned int intra4x4_lambda3[] = { 1668c2ecf20Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1678c2ecf20Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1688c2ecf20Sopenharmony_ci 2, 2, 2, 2, 3, 3, 3, 4, 1698c2ecf20Sopenharmony_ci 4, 4, 5, 6, 6, 7, 8, 9, 1708c2ecf20Sopenharmony_ci 10, 11, 13, 14, 16, 18, 20, 23, 1718c2ecf20Sopenharmony_ci 25, 29, 32, 36, 40, 45, 51, 57, 1728c2ecf20Sopenharmony_ci 64, 72, 81, 91 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std); 1768c2ecf20Sopenharmony_cistatic enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void tw5864_handle_frame_task(struct tasklet_struct *t); 1798c2ecf20Sopenharmony_cistatic void tw5864_handle_frame(struct tw5864_h264_frame *frame); 1808c2ecf20Sopenharmony_cistatic void tw5864_frame_interval_set(struct tw5864_input *input); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int tw5864_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, 1838c2ecf20Sopenharmony_ci unsigned int *num_planes, unsigned int sizes[], 1848c2ecf20Sopenharmony_ci struct device *alloc_ctxs[]) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci if (*num_planes) 1878c2ecf20Sopenharmony_ci return sizes[0] < H264_VLC_BUF_SIZE ? -EINVAL : 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci sizes[0] = H264_VLC_BUF_SIZE; 1908c2ecf20Sopenharmony_ci *num_planes = 1; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void tw5864_buf_queue(struct vb2_buffer *vb) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1988c2ecf20Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 1998c2ecf20Sopenharmony_ci struct tw5864_input *dev = vb2_get_drv_priv(vq); 2008c2ecf20Sopenharmony_ci struct tw5864_buf *buf = container_of(vbuf, struct tw5864_buf, vb); 2018c2ecf20Sopenharmony_ci unsigned long flags; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 2048c2ecf20Sopenharmony_ci list_add_tail(&buf->list, &dev->active); 2058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int tw5864_input_std_get(struct tw5864_input *input, 2098c2ecf20Sopenharmony_ci enum tw5864_vid_std *std) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 2128c2ecf20Sopenharmony_ci u8 std_reg = tw_indir_readb(TW5864_INDIR_VIN_E(input->nr)); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci *std = (std_reg & 0x70) >> 4; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (std_reg & 0x80) { 2178c2ecf20Sopenharmony_ci dev_dbg(&dev->pci->dev, 2188c2ecf20Sopenharmony_ci "Video format detection is in progress, please wait\n"); 2198c2ecf20Sopenharmony_ci return -EAGAIN; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int tw5864_enable_input(struct tw5864_input *input) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 2288c2ecf20Sopenharmony_ci int nr = input->nr; 2298c2ecf20Sopenharmony_ci unsigned long flags; 2308c2ecf20Sopenharmony_ci int d1_width = 720; 2318c2ecf20Sopenharmony_ci int d1_height; 2328c2ecf20Sopenharmony_ci int frame_width_bus_value = 0; 2338c2ecf20Sopenharmony_ci int frame_height_bus_value = 0; 2348c2ecf20Sopenharmony_ci int reg_frame_bus = 0x1c; 2358c2ecf20Sopenharmony_ci int fmt_reg_value = 0; 2368c2ecf20Sopenharmony_ci int downscale_enabled = 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci dev_dbg(&dev->pci->dev, "Enabling channel %d\n", nr); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci input->frame_seqno = 0; 2418c2ecf20Sopenharmony_ci input->frame_gop_seqno = 0; 2428c2ecf20Sopenharmony_ci input->h264_idr_pic_id = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci input->reg_dsp_qp = input->qp; 2458c2ecf20Sopenharmony_ci input->reg_dsp_ref_mvp_lambda = lambda_lookup_table[input->qp]; 2468c2ecf20Sopenharmony_ci input->reg_dsp_i4x4_weight = intra4x4_lambda3[input->qp]; 2478c2ecf20Sopenharmony_ci input->reg_emu = TW5864_EMU_EN_LPF | TW5864_EMU_EN_BHOST 2488c2ecf20Sopenharmony_ci | TW5864_EMU_EN_SEN | TW5864_EMU_EN_ME | TW5864_EMU_EN_DDR; 2498c2ecf20Sopenharmony_ci input->reg_dsp = nr /* channel id */ 2508c2ecf20Sopenharmony_ci | TW5864_DSP_CHROM_SW 2518c2ecf20Sopenharmony_ci | ((0xa << 8) & TW5864_DSP_MB_DELAY) 2528c2ecf20Sopenharmony_ci ; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci input->resolution = D1; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci d1_height = (input->std == STD_NTSC) ? 480 : 576; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci input->width = d1_width; 2598c2ecf20Sopenharmony_ci input->height = d1_height; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci input->reg_interlacing = 0x4; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci switch (input->resolution) { 2648c2ecf20Sopenharmony_ci case D1: 2658c2ecf20Sopenharmony_ci frame_width_bus_value = 0x2cf; 2668c2ecf20Sopenharmony_ci frame_height_bus_value = input->height - 1; 2678c2ecf20Sopenharmony_ci reg_frame_bus = 0x1c; 2688c2ecf20Sopenharmony_ci fmt_reg_value = 0; 2698c2ecf20Sopenharmony_ci downscale_enabled = 0; 2708c2ecf20Sopenharmony_ci input->reg_dsp_codec |= TW5864_CIF_MAP_MD | TW5864_HD1_MAP_MD; 2718c2ecf20Sopenharmony_ci input->reg_emu |= TW5864_DSP_FRAME_TYPE_D1; 2728c2ecf20Sopenharmony_ci input->reg_interlacing = TW5864_DI_EN | TW5864_DSP_INTER_ST; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci tw_setl(TW5864_FULL_HALF_FLAG, 1 << nr); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case HD1: 2778c2ecf20Sopenharmony_ci input->height /= 2; 2788c2ecf20Sopenharmony_ci input->width /= 2; 2798c2ecf20Sopenharmony_ci frame_width_bus_value = 0x2cf; 2808c2ecf20Sopenharmony_ci frame_height_bus_value = input->height * 2 - 1; 2818c2ecf20Sopenharmony_ci reg_frame_bus = 0x1c; 2828c2ecf20Sopenharmony_ci fmt_reg_value = 0; 2838c2ecf20Sopenharmony_ci downscale_enabled = 0; 2848c2ecf20Sopenharmony_ci input->reg_dsp_codec |= TW5864_HD1_MAP_MD; 2858c2ecf20Sopenharmony_ci input->reg_emu |= TW5864_DSP_FRAME_TYPE_D1; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci case CIF: 2918c2ecf20Sopenharmony_ci input->height /= 4; 2928c2ecf20Sopenharmony_ci input->width /= 2; 2938c2ecf20Sopenharmony_ci frame_width_bus_value = 0x15f; 2948c2ecf20Sopenharmony_ci frame_height_bus_value = input->height * 2 - 1; 2958c2ecf20Sopenharmony_ci reg_frame_bus = 0x07; 2968c2ecf20Sopenharmony_ci fmt_reg_value = 1; 2978c2ecf20Sopenharmony_ci downscale_enabled = 1; 2988c2ecf20Sopenharmony_ci input->reg_dsp_codec |= TW5864_CIF_MAP_MD; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr); 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci case QCIF: 3038c2ecf20Sopenharmony_ci input->height /= 4; 3048c2ecf20Sopenharmony_ci input->width /= 4; 3058c2ecf20Sopenharmony_ci frame_width_bus_value = 0x15f; 3068c2ecf20Sopenharmony_ci frame_height_bus_value = input->height * 2 - 1; 3078c2ecf20Sopenharmony_ci reg_frame_bus = 0x07; 3088c2ecf20Sopenharmony_ci fmt_reg_value = 1; 3098c2ecf20Sopenharmony_ci downscale_enabled = 1; 3108c2ecf20Sopenharmony_ci input->reg_dsp_codec |= TW5864_CIF_MAP_MD; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr); 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* analog input width / 4 */ 3178c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_IN_PIC_WIDTH(nr), d1_width / 4); 3188c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_IN_PIC_HEIGHT(nr), d1_height / 4); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* output width / 4 */ 3218c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_OUT_PIC_WIDTH(nr), input->width / 4); 3228c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_OUT_PIC_HEIGHT(nr), input->height / 4); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Crop width from 720 to 704. 3268c2ecf20Sopenharmony_ci * Above register settings need value 720 involved. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci input->width = 704; 3298c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_CROP_ETC, 3308c2ecf20Sopenharmony_ci tw_indir_readb(TW5864_INDIR_CROP_ETC) | 3318c2ecf20Sopenharmony_ci TW5864_INDIR_CROP_ETC_CROP_EN); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP_PIC_MAX_MB, 3348c2ecf20Sopenharmony_ci ((input->width / 16) << 8) | (input->height / 16)); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci tw_writel(TW5864_FRAME_WIDTH_BUS_A(nr), 3378c2ecf20Sopenharmony_ci frame_width_bus_value); 3388c2ecf20Sopenharmony_ci tw_writel(TW5864_FRAME_WIDTH_BUS_B(nr), 3398c2ecf20Sopenharmony_ci frame_width_bus_value); 3408c2ecf20Sopenharmony_ci tw_writel(TW5864_FRAME_HEIGHT_BUS_A(nr), 3418c2ecf20Sopenharmony_ci frame_height_bus_value); 3428c2ecf20Sopenharmony_ci tw_writel(TW5864_FRAME_HEIGHT_BUS_B(nr), 3438c2ecf20Sopenharmony_ci (frame_height_bus_value + 1) / 2 - 1); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci tw5864_frame_interval_set(input); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (downscale_enabled) 3488c2ecf20Sopenharmony_ci tw_setl(TW5864_H264EN_CH_DNS, 1 << nr); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci tw_mask_shift_writel(TW5864_H264EN_CH_FMT_REG1, 0x3, 2 * nr, 3518c2ecf20Sopenharmony_ci fmt_reg_value); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci tw_mask_shift_writel((nr < 2 3548c2ecf20Sopenharmony_ci ? TW5864_H264EN_RATE_MAX_LINE_REG1 3558c2ecf20Sopenharmony_ci : TW5864_H264EN_RATE_MAX_LINE_REG2), 3568c2ecf20Sopenharmony_ci 0x1f, 5 * (nr % 2), 3578c2ecf20Sopenharmony_ci input->std == STD_NTSC ? 29 : 24); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci tw_mask_shift_writel((nr < 2) ? TW5864_FRAME_BUS1 : 3608c2ecf20Sopenharmony_ci TW5864_FRAME_BUS2, 0xff, (nr % 2) * 8, 3618c2ecf20Sopenharmony_ci reg_frame_bus); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 3648c2ecf20Sopenharmony_ci input->enabled = 1; 3658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_civoid tw5864_request_encoded_frame(struct tw5864_input *input) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 3738c2ecf20Sopenharmony_ci u32 enc_buf_id_new; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci tw_setl(TW5864_DSP_CODEC, TW5864_CIF_MAP_MD | TW5864_HD1_MAP_MD); 3768c2ecf20Sopenharmony_ci tw_writel(TW5864_EMU, input->reg_emu); 3778c2ecf20Sopenharmony_ci tw_writel(TW5864_INTERLACING, input->reg_interlacing); 3788c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP, input->reg_dsp); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP_QP, input->reg_dsp_qp); 3818c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP_REF_MVP_LAMBDA, input->reg_dsp_ref_mvp_lambda); 3828c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP_I4x4_WEIGHT, input->reg_dsp_i4x4_weight); 3838c2ecf20Sopenharmony_ci tw_mask_shift_writel(TW5864_DSP_INTRA_MODE, TW5864_DSP_INTRA_MODE_MASK, 3848c2ecf20Sopenharmony_ci TW5864_DSP_INTRA_MODE_SHIFT, 3858c2ecf20Sopenharmony_ci TW5864_DSP_INTRA_MODE_16x16); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (input->frame_gop_seqno == 0) { 3888c2ecf20Sopenharmony_ci /* Produce I-frame */ 3898c2ecf20Sopenharmony_ci tw_writel(TW5864_MOTION_SEARCH_ETC, TW5864_INTRA_EN); 3908c2ecf20Sopenharmony_ci input->h264_idr_pic_id++; 3918c2ecf20Sopenharmony_ci input->h264_idr_pic_id &= TW5864_DSP_REF_FRM; 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci /* Produce P-frame */ 3948c2ecf20Sopenharmony_ci tw_writel(TW5864_MOTION_SEARCH_ETC, TW5864_INTRA_EN | 3958c2ecf20Sopenharmony_ci TW5864_ME_EN | BIT(5) /* SRCH_OPT default */); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci tw5864_prepare_frame_headers(input); 3988c2ecf20Sopenharmony_ci tw_writel(TW5864_VLC, 3998c2ecf20Sopenharmony_ci TW5864_VLC_PCI_SEL | 4008c2ecf20Sopenharmony_ci ((input->tail_nb_bits + 24) << TW5864_VLC_BIT_ALIGN_SHIFT) | 4018c2ecf20Sopenharmony_ci input->reg_dsp_qp); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci enc_buf_id_new = tw_mask_shift_readl(TW5864_ENC_BUF_PTR_REC1, 0x3, 4048c2ecf20Sopenharmony_ci 2 * input->nr); 4058c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP_ENC_ORG_PTR_REG, 4068c2ecf20Sopenharmony_ci enc_buf_id_new << TW5864_DSP_ENC_ORG_PTR_SHIFT); 4078c2ecf20Sopenharmony_ci tw_writel(TW5864_DSP_ENC_REC, 4088c2ecf20Sopenharmony_ci enc_buf_id_new << 12 | ((enc_buf_id_new + 3) & 3)); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci tw_writel(TW5864_SLICE, TW5864_START_NSLICE); 4118c2ecf20Sopenharmony_ci tw_writel(TW5864_SLICE, 0); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int tw5864_disable_input(struct tw5864_input *input) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 4178c2ecf20Sopenharmony_ci unsigned long flags; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci dev_dbg(&dev->pci->dev, "Disabling channel %d\n", input->nr); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 4228c2ecf20Sopenharmony_ci input->enabled = 0; 4238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int tw5864_start_streaming(struct vb2_queue *q, unsigned int count) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct tw5864_input *input = vb2_get_drv_priv(q); 4308c2ecf20Sopenharmony_ci int ret; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ret = tw5864_enable_input(input); 4338c2ecf20Sopenharmony_ci if (!ret) 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci while (!list_empty(&input->active)) { 4378c2ecf20Sopenharmony_ci struct tw5864_buf *buf = list_entry(input->active.next, 4388c2ecf20Sopenharmony_ci struct tw5864_buf, list); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci list_del(&buf->list); 4418c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci return ret; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic void tw5864_stop_streaming(struct vb2_queue *q) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci unsigned long flags; 4498c2ecf20Sopenharmony_ci struct tw5864_input *input = vb2_get_drv_priv(q); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci tw5864_disable_input(input); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci spin_lock_irqsave(&input->slock, flags); 4548c2ecf20Sopenharmony_ci if (input->vb) { 4558c2ecf20Sopenharmony_ci vb2_buffer_done(&input->vb->vb.vb2_buf, VB2_BUF_STATE_ERROR); 4568c2ecf20Sopenharmony_ci input->vb = NULL; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci while (!list_empty(&input->active)) { 4598c2ecf20Sopenharmony_ci struct tw5864_buf *buf = list_entry(input->active.next, 4608c2ecf20Sopenharmony_ci struct tw5864_buf, list); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci list_del(&buf->list); 4638c2ecf20Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&input->slock, flags); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic const struct vb2_ops tw5864_video_qops = { 4698c2ecf20Sopenharmony_ci .queue_setup = tw5864_queue_setup, 4708c2ecf20Sopenharmony_ci .buf_queue = tw5864_buf_queue, 4718c2ecf20Sopenharmony_ci .start_streaming = tw5864_start_streaming, 4728c2ecf20Sopenharmony_ci .stop_streaming = tw5864_stop_streaming, 4738c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 4748c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 4758c2ecf20Sopenharmony_ci}; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int tw5864_s_ctrl(struct v4l2_ctrl *ctrl) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct tw5864_input *input = 4808c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct tw5864_input, hdl); 4818c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 4828c2ecf20Sopenharmony_ci unsigned long flags; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci switch (ctrl->id) { 4858c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 4868c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_A_BRIGHT(input->nr), 4878c2ecf20Sopenharmony_ci (u8)ctrl->val); 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 4908c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_7_HUE(input->nr), 4918c2ecf20Sopenharmony_ci (u8)ctrl->val); 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 4948c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_9_CNTRST(input->nr), 4958c2ecf20Sopenharmony_ci (u8)ctrl->val); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 4988c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_B_SAT_U(input->nr), 4998c2ecf20Sopenharmony_ci (u8)ctrl->val); 5008c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_C_SAT_V(input->nr), 5018c2ecf20Sopenharmony_ci (u8)ctrl->val); 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 5048c2ecf20Sopenharmony_ci input->gop = ctrl->val; 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: 5078c2ecf20Sopenharmony_ci spin_lock_irqsave(&input->slock, flags); 5088c2ecf20Sopenharmony_ci input->qp = ctrl->val; 5098c2ecf20Sopenharmony_ci input->reg_dsp_qp = input->qp; 5108c2ecf20Sopenharmony_ci input->reg_dsp_ref_mvp_lambda = lambda_lookup_table[input->qp]; 5118c2ecf20Sopenharmony_ci input->reg_dsp_i4x4_weight = intra4x4_lambda3[input->qp]; 5128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&input->slock, flags); 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: 5158c2ecf20Sopenharmony_ci memset(input->md_threshold_grid_values, ctrl->val, 5168c2ecf20Sopenharmony_ci sizeof(input->md_threshold_grid_values)); 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci case V4L2_CID_DETECT_MD_MODE: 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci case V4L2_CID_DETECT_MD_THRESHOLD_GRID: 5218c2ecf20Sopenharmony_ci /* input->md_threshold_grid_ctrl->p_new.p_u16 contains data */ 5228c2ecf20Sopenharmony_ci memcpy(input->md_threshold_grid_values, 5238c2ecf20Sopenharmony_ci input->md_threshold_grid_ctrl->p_new.p_u16, 5248c2ecf20Sopenharmony_ci sizeof(input->md_threshold_grid_values)); 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int tw5864_fmt_vid_cap(struct file *file, void *priv, 5318c2ecf20Sopenharmony_ci struct v4l2_format *f) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci f->fmt.pix.width = 704; 5368c2ecf20Sopenharmony_ci switch (input->std) { 5378c2ecf20Sopenharmony_ci default: 5388c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 5398c2ecf20Sopenharmony_ci return -EINVAL; 5408c2ecf20Sopenharmony_ci case STD_NTSC: 5418c2ecf20Sopenharmony_ci f->fmt.pix.height = 480; 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci case STD_PAL: 5448c2ecf20Sopenharmony_ci case STD_SECAM: 5458c2ecf20Sopenharmony_ci f->fmt.pix.height = 576; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_INTERLACED; 5498c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264; 5508c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = H264_VLC_BUF_SIZE; 5518c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int tw5864_enum_input(struct file *file, void *priv, 5568c2ecf20Sopenharmony_ci struct v4l2_input *i) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 5598c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci u8 indir_0x000 = tw_indir_readb(TW5864_INDIR_VIN_0(input->nr)); 5628c2ecf20Sopenharmony_ci u8 indir_0x00d = tw_indir_readb(TW5864_INDIR_VIN_D(input->nr)); 5638c2ecf20Sopenharmony_ci u8 v1 = indir_0x000; 5648c2ecf20Sopenharmony_ci u8 v2 = indir_0x00d; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (i->index) 5678c2ecf20Sopenharmony_ci return -EINVAL; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 5708c2ecf20Sopenharmony_ci snprintf(i->name, sizeof(i->name), "Encoder %d", input->nr); 5718c2ecf20Sopenharmony_ci i->std = TW5864_NORMS; 5728c2ecf20Sopenharmony_ci if (v1 & (1 << 7)) 5738c2ecf20Sopenharmony_ci i->status |= V4L2_IN_ST_NO_SYNC; 5748c2ecf20Sopenharmony_ci if (!(v1 & (1 << 6))) 5758c2ecf20Sopenharmony_ci i->status |= V4L2_IN_ST_NO_H_LOCK; 5768c2ecf20Sopenharmony_ci if (v1 & (1 << 2)) 5778c2ecf20Sopenharmony_ci i->status |= V4L2_IN_ST_NO_SIGNAL; 5788c2ecf20Sopenharmony_ci if (v1 & (1 << 1)) 5798c2ecf20Sopenharmony_ci i->status |= V4L2_IN_ST_NO_COLOR; 5808c2ecf20Sopenharmony_ci if (v2 & (1 << 2)) 5818c2ecf20Sopenharmony_ci i->status |= V4L2_IN_ST_MACROVISION; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int tw5864_g_input(struct file *file, void *priv, unsigned int *i) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci *i = 0; 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int tw5864_s_input(struct file *file, void *priv, unsigned int i) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci if (i) 5958c2ecf20Sopenharmony_ci return -EINVAL; 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic int tw5864_querycap(struct file *file, void *priv, 6008c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci strscpy(cap->driver, "tw5864", sizeof(cap->driver)); 6058c2ecf20Sopenharmony_ci snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d", 6068c2ecf20Sopenharmony_ci input->nr); 6078c2ecf20Sopenharmony_ci sprintf(cap->bus_info, "PCI:%s", pci_name(input->root->pci)); 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int tw5864_querystd(struct file *file, void *priv, v4l2_std_id *std) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 6148c2ecf20Sopenharmony_ci enum tw5864_vid_std tw_std; 6158c2ecf20Sopenharmony_ci int ret; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci ret = tw5864_input_std_get(input, &tw_std); 6188c2ecf20Sopenharmony_ci if (ret) 6198c2ecf20Sopenharmony_ci return ret; 6208c2ecf20Sopenharmony_ci *std = tw5864_get_v4l2_std(tw_std); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int tw5864_g_std(struct file *file, void *priv, v4l2_std_id *std) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci *std = input->v4l2_std; 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int tw5864_s_std(struct file *file, void *priv, v4l2_std_id std) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 6368c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci input->v4l2_std = std; 6398c2ecf20Sopenharmony_ci input->std = tw5864_from_v4l2_std(std); 6408c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_E(input->nr), input->std); 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int tw5864_enum_fmt_vid_cap(struct file *file, void *priv, 6458c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci if (f->index) 6488c2ecf20Sopenharmony_ci return -EINVAL; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_H264; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int tw5864_subscribe_event(struct v4l2_fh *fh, 6568c2ecf20Sopenharmony_ci const struct v4l2_event_subscription *sub) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci switch (sub->type) { 6598c2ecf20Sopenharmony_ci case V4L2_EVENT_MOTION_DET: 6608c2ecf20Sopenharmony_ci /* 6618c2ecf20Sopenharmony_ci * Allow for up to 30 events (1 second for NTSC) to be stored. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 30, NULL); 6648c2ecf20Sopenharmony_ci default: 6658c2ecf20Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic void tw5864_frame_interval_set(struct tw5864_input *input) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * This register value seems to follow such approach: In each second 6738c2ecf20Sopenharmony_ci * interval, when processing Nth frame, it checks Nth bit of register 6748c2ecf20Sopenharmony_ci * value and, if the bit is 1, it processes the frame, otherwise the 6758c2ecf20Sopenharmony_ci * frame is discarded. 6768c2ecf20Sopenharmony_ci * So unary representation would work, but more or less equal gaps 6778c2ecf20Sopenharmony_ci * between the frames should be preserved. 6788c2ecf20Sopenharmony_ci * 6798c2ecf20Sopenharmony_ci * For 1 FPS - 0x00000001 6808c2ecf20Sopenharmony_ci * 00000000 00000000 00000000 00000001 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * For max FPS - set all 25/30 lower bits: 6838c2ecf20Sopenharmony_ci * 00111111 11111111 11111111 11111111 (NTSC) 6848c2ecf20Sopenharmony_ci * 00000001 11111111 11111111 11111111 (PAL) 6858c2ecf20Sopenharmony_ci * 6868c2ecf20Sopenharmony_ci * For half of max FPS - use such pattern: 6878c2ecf20Sopenharmony_ci * 00010101 01010101 01010101 01010101 (NTSC) 6888c2ecf20Sopenharmony_ci * 00000001 01010101 01010101 01010101 (PAL) 6898c2ecf20Sopenharmony_ci * 6908c2ecf20Sopenharmony_ci * Et cetera. 6918c2ecf20Sopenharmony_ci * 6928c2ecf20Sopenharmony_ci * The value supplied to hardware is capped by mask of 25/30 lower bits. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 6958c2ecf20Sopenharmony_ci u32 unary_framerate = 0; 6968c2ecf20Sopenharmony_ci int shift = 0; 6978c2ecf20Sopenharmony_ci int std_max_fps = input->std == STD_NTSC ? 30 : 25; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci for (shift = 0; shift < std_max_fps; shift += input->frame_interval) 7008c2ecf20Sopenharmony_ci unary_framerate |= 0x00000001 << shift; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_RATE_CNTL_LO_WORD(input->nr, 0), 7038c2ecf20Sopenharmony_ci unary_framerate >> 16); 7048c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_RATE_CNTL_HI_WORD(input->nr, 0), 7058c2ecf20Sopenharmony_ci unary_framerate & 0xffff); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int tw5864_frameinterval_get(struct tw5864_input *input, 7098c2ecf20Sopenharmony_ci struct v4l2_fract *frameinterval) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci switch (input->std) { 7148c2ecf20Sopenharmony_ci case STD_NTSC: 7158c2ecf20Sopenharmony_ci frameinterval->numerator = 1001; 7168c2ecf20Sopenharmony_ci frameinterval->denominator = 30000; 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci case STD_PAL: 7198c2ecf20Sopenharmony_ci case STD_SECAM: 7208c2ecf20Sopenharmony_ci frameinterval->numerator = 1; 7218c2ecf20Sopenharmony_ci frameinterval->denominator = 25; 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci default: 7248c2ecf20Sopenharmony_ci dev_warn(&dev->pci->dev, "tw5864_frameinterval_get requested for unknown std %d\n", 7258c2ecf20Sopenharmony_ci input->std); 7268c2ecf20Sopenharmony_ci return -EINVAL; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return 0; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int tw5864_enum_framesizes(struct file *file, void *priv, 7338c2ecf20Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (fsize->index > 0) 7388c2ecf20Sopenharmony_ci return -EINVAL; 7398c2ecf20Sopenharmony_ci if (fsize->pixel_format != V4L2_PIX_FMT_H264) 7408c2ecf20Sopenharmony_ci return -EINVAL; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 7438c2ecf20Sopenharmony_ci fsize->discrete.width = 704; 7448c2ecf20Sopenharmony_ci fsize->discrete.height = input->std == STD_NTSC ? 480 : 576; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int tw5864_enum_frameintervals(struct file *file, void *priv, 7508c2ecf20Sopenharmony_ci struct v4l2_frmivalenum *fintv) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 7538c2ecf20Sopenharmony_ci struct v4l2_fract frameinterval; 7548c2ecf20Sopenharmony_ci int std_max_fps = input->std == STD_NTSC ? 30 : 25; 7558c2ecf20Sopenharmony_ci struct v4l2_frmsizeenum fsize = { .index = fintv->index, 7568c2ecf20Sopenharmony_ci .pixel_format = fintv->pixel_format }; 7578c2ecf20Sopenharmony_ci int ret; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci ret = tw5864_enum_framesizes(file, priv, &fsize); 7608c2ecf20Sopenharmony_ci if (ret) 7618c2ecf20Sopenharmony_ci return ret; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (fintv->width != fsize.discrete.width || 7648c2ecf20Sopenharmony_ci fintv->height != fsize.discrete.height) 7658c2ecf20Sopenharmony_ci return -EINVAL; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci ret = tw5864_frameinterval_get(input, &frameinterval); 7708c2ecf20Sopenharmony_ci if (ret) 7718c2ecf20Sopenharmony_ci return ret; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci fintv->stepwise.step = frameinterval; 7748c2ecf20Sopenharmony_ci fintv->stepwise.min = frameinterval; 7758c2ecf20Sopenharmony_ci fintv->stepwise.max = frameinterval; 7768c2ecf20Sopenharmony_ci fintv->stepwise.max.numerator *= std_max_fps; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return ret; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int tw5864_g_parm(struct file *file, void *priv, 7828c2ecf20Sopenharmony_ci struct v4l2_streamparm *sp) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 7858c2ecf20Sopenharmony_ci struct v4l2_captureparm *cp = &sp->parm.capture; 7868c2ecf20Sopenharmony_ci int ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci cp->capability = V4L2_CAP_TIMEPERFRAME; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci ret = tw5864_frameinterval_get(input, &cp->timeperframe); 7918c2ecf20Sopenharmony_ci if (ret) 7928c2ecf20Sopenharmony_ci return ret; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci cp->timeperframe.numerator *= input->frame_interval; 7958c2ecf20Sopenharmony_ci cp->capturemode = 0; 7968c2ecf20Sopenharmony_ci cp->readbuffers = 2; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci return ret; 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic int tw5864_s_parm(struct file *file, void *priv, 8028c2ecf20Sopenharmony_ci struct v4l2_streamparm *sp) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 8058c2ecf20Sopenharmony_ci struct v4l2_fract *t = &sp->parm.capture.timeperframe; 8068c2ecf20Sopenharmony_ci struct v4l2_fract time_base; 8078c2ecf20Sopenharmony_ci int ret; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci ret = tw5864_frameinterval_get(input, &time_base); 8108c2ecf20Sopenharmony_ci if (ret) 8118c2ecf20Sopenharmony_ci return ret; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (!t->numerator || !t->denominator) { 8148c2ecf20Sopenharmony_ci t->numerator = time_base.numerator * input->frame_interval; 8158c2ecf20Sopenharmony_ci t->denominator = time_base.denominator; 8168c2ecf20Sopenharmony_ci } else if (t->denominator != time_base.denominator) { 8178c2ecf20Sopenharmony_ci t->numerator = t->numerator * time_base.denominator / 8188c2ecf20Sopenharmony_ci t->denominator; 8198c2ecf20Sopenharmony_ci t->denominator = time_base.denominator; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci input->frame_interval = t->numerator / time_base.numerator; 8238c2ecf20Sopenharmony_ci if (input->frame_interval < 1) 8248c2ecf20Sopenharmony_ci input->frame_interval = 1; 8258c2ecf20Sopenharmony_ci tw5864_frame_interval_set(input); 8268c2ecf20Sopenharmony_ci return tw5864_g_parm(file, priv, sp); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops tw5864_ctrl_ops = { 8308c2ecf20Sopenharmony_ci .s_ctrl = tw5864_s_ctrl, 8318c2ecf20Sopenharmony_ci}; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations video_fops = { 8348c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8358c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 8368c2ecf20Sopenharmony_ci .release = vb2_fop_release, 8378c2ecf20Sopenharmony_ci .read = vb2_fop_read, 8388c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 8398c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 8408c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 8418c2ecf20Sopenharmony_ci}; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci#define INDIR_SPACE_MAP_SHIFT 0x100000 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int tw5864_g_reg(struct file *file, void *fh, 8488c2ecf20Sopenharmony_ci struct v4l2_dbg_register *reg) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 8518c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (reg->reg < INDIR_SPACE_MAP_SHIFT) { 8548c2ecf20Sopenharmony_ci if (reg->reg > 0x87fff) 8558c2ecf20Sopenharmony_ci return -EINVAL; 8568c2ecf20Sopenharmony_ci reg->size = 4; 8578c2ecf20Sopenharmony_ci reg->val = tw_readl(reg->reg); 8588c2ecf20Sopenharmony_ci } else { 8598c2ecf20Sopenharmony_ci __u64 indir_addr = reg->reg - INDIR_SPACE_MAP_SHIFT; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (indir_addr > 0xefe) 8628c2ecf20Sopenharmony_ci return -EINVAL; 8638c2ecf20Sopenharmony_ci reg->size = 1; 8648c2ecf20Sopenharmony_ci reg->val = tw_indir_readb(reg->reg); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistatic int tw5864_s_reg(struct file *file, void *fh, 8708c2ecf20Sopenharmony_ci const struct v4l2_dbg_register *reg) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci struct tw5864_input *input = video_drvdata(file); 8738c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (reg->reg < INDIR_SPACE_MAP_SHIFT) { 8768c2ecf20Sopenharmony_ci if (reg->reg > 0x87fff) 8778c2ecf20Sopenharmony_ci return -EINVAL; 8788c2ecf20Sopenharmony_ci tw_writel(reg->reg, reg->val); 8798c2ecf20Sopenharmony_ci } else { 8808c2ecf20Sopenharmony_ci __u64 indir_addr = reg->reg - INDIR_SPACE_MAP_SHIFT; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (indir_addr > 0xefe) 8838c2ecf20Sopenharmony_ci return -EINVAL; 8848c2ecf20Sopenharmony_ci tw_indir_writeb(reg->reg, reg->val); 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci#endif 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops video_ioctl_ops = { 8918c2ecf20Sopenharmony_ci .vidioc_querycap = tw5864_querycap, 8928c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = tw5864_enum_fmt_vid_cap, 8938c2ecf20Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 8948c2ecf20Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 8958c2ecf20Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 8968c2ecf20Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 8978c2ecf20Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 8988c2ecf20Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 8998c2ecf20Sopenharmony_ci .vidioc_querystd = tw5864_querystd, 9008c2ecf20Sopenharmony_ci .vidioc_s_std = tw5864_s_std, 9018c2ecf20Sopenharmony_ci .vidioc_g_std = tw5864_g_std, 9028c2ecf20Sopenharmony_ci .vidioc_enum_input = tw5864_enum_input, 9038c2ecf20Sopenharmony_ci .vidioc_g_input = tw5864_g_input, 9048c2ecf20Sopenharmony_ci .vidioc_s_input = tw5864_s_input, 9058c2ecf20Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 9068c2ecf20Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 9078c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = tw5864_fmt_vid_cap, 9088c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = tw5864_fmt_vid_cap, 9098c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = tw5864_fmt_vid_cap, 9108c2ecf20Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 9118c2ecf20Sopenharmony_ci .vidioc_subscribe_event = tw5864_subscribe_event, 9128c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 9138c2ecf20Sopenharmony_ci .vidioc_enum_framesizes = tw5864_enum_framesizes, 9148c2ecf20Sopenharmony_ci .vidioc_enum_frameintervals = tw5864_enum_frameintervals, 9158c2ecf20Sopenharmony_ci .vidioc_s_parm = tw5864_s_parm, 9168c2ecf20Sopenharmony_ci .vidioc_g_parm = tw5864_g_parm, 9178c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 9188c2ecf20Sopenharmony_ci .vidioc_g_register = tw5864_g_reg, 9198c2ecf20Sopenharmony_ci .vidioc_s_register = tw5864_s_reg, 9208c2ecf20Sopenharmony_ci#endif 9218c2ecf20Sopenharmony_ci}; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic const struct video_device tw5864_video_template = { 9248c2ecf20Sopenharmony_ci .name = "tw5864_video", 9258c2ecf20Sopenharmony_ci .fops = &video_fops, 9268c2ecf20Sopenharmony_ci .ioctl_ops = &video_ioctl_ops, 9278c2ecf20Sopenharmony_ci .release = video_device_release_empty, 9288c2ecf20Sopenharmony_ci .tvnorms = TW5864_NORMS, 9298c2ecf20Sopenharmony_ci .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 9308c2ecf20Sopenharmony_ci V4L2_CAP_STREAMING, 9318c2ecf20Sopenharmony_ci}; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/* Motion Detection Threshold matrix */ 9348c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config tw5864_md_thresholds = { 9358c2ecf20Sopenharmony_ci .ops = &tw5864_ctrl_ops, 9368c2ecf20Sopenharmony_ci .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID, 9378c2ecf20Sopenharmony_ci .dims = {MD_CELLS_HOR, MD_CELLS_VERT}, 9388c2ecf20Sopenharmony_ci .def = 14, 9398c2ecf20Sopenharmony_ci /* See tw5864_md_metric_from_mvd() */ 9408c2ecf20Sopenharmony_ci .max = 2 * 0x0f, 9418c2ecf20Sopenharmony_ci .step = 1, 9428c2ecf20Sopenharmony_ci}; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic int tw5864_video_input_init(struct tw5864_input *dev, int video_nr); 9458c2ecf20Sopenharmony_cistatic void tw5864_video_input_fini(struct tw5864_input *dev); 9468c2ecf20Sopenharmony_cistatic void tw5864_encoder_tables_upload(struct tw5864_dev *dev); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ciint tw5864_video_init(struct tw5864_dev *dev, int *video_nr) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci int i; 9518c2ecf20Sopenharmony_ci int ret; 9528c2ecf20Sopenharmony_ci unsigned long flags; 9538c2ecf20Sopenharmony_ci int last_dma_allocated = -1; 9548c2ecf20Sopenharmony_ci int last_input_nr_registered = -1; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci for (i = 0; i < H264_BUF_CNT; i++) { 9578c2ecf20Sopenharmony_ci struct tw5864_h264_frame *frame = &dev->h264_buf[i]; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci frame->vlc.addr = dma_alloc_coherent(&dev->pci->dev, 9608c2ecf20Sopenharmony_ci H264_VLC_BUF_SIZE, 9618c2ecf20Sopenharmony_ci &frame->vlc.dma_addr, 9628c2ecf20Sopenharmony_ci GFP_KERNEL | GFP_DMA32); 9638c2ecf20Sopenharmony_ci if (!frame->vlc.addr) { 9648c2ecf20Sopenharmony_ci dev_err(&dev->pci->dev, "dma alloc fail\n"); 9658c2ecf20Sopenharmony_ci ret = -ENOMEM; 9668c2ecf20Sopenharmony_ci goto free_dma; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci frame->mv.addr = dma_alloc_coherent(&dev->pci->dev, 9698c2ecf20Sopenharmony_ci H264_MV_BUF_SIZE, 9708c2ecf20Sopenharmony_ci &frame->mv.dma_addr, 9718c2ecf20Sopenharmony_ci GFP_KERNEL | GFP_DMA32); 9728c2ecf20Sopenharmony_ci if (!frame->mv.addr) { 9738c2ecf20Sopenharmony_ci dev_err(&dev->pci->dev, "dma alloc fail\n"); 9748c2ecf20Sopenharmony_ci ret = -ENOMEM; 9758c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE, 9768c2ecf20Sopenharmony_ci frame->vlc.addr, frame->vlc.dma_addr); 9778c2ecf20Sopenharmony_ci goto free_dma; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci last_dma_allocated = i; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci tw5864_encoder_tables_upload(dev); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* Picture is distorted without this block */ 9858c2ecf20Sopenharmony_ci /* use falling edge to sample 54M to 108M */ 9868c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VD_108_POL, TW5864_INDIR_VD_108_POL_BOTH); 9878c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_CLK0_SEL, 0x00); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_DDRA_DLL_DQS_SEL0, 0x02); 9908c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_DDRA_DLL_DQS_SEL1, 0x02); 9918c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_DDRA_DLL_CLK90_SEL, 0x02); 9928c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_DDRB_DLL_DQS_SEL0, 0x02); 9938c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_DDRB_DLL_DQS_SEL1, 0x02); 9948c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_DDRB_DLL_CLK90_SEL, 0x02); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* video input reset */ 9978c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_RESET, 0); 9988c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_RESET, TW5864_INDIR_RESET_VD | 9998c2ecf20Sopenharmony_ci TW5864_INDIR_RESET_DLL | TW5864_INDIR_RESET_MUX_CORE); 10008c2ecf20Sopenharmony_ci msleep(20); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* 10038c2ecf20Sopenharmony_ci * Select Part A mode for all channels. 10048c2ecf20Sopenharmony_ci * tw_setl instead of tw_clearl for Part B mode. 10058c2ecf20Sopenharmony_ci * 10068c2ecf20Sopenharmony_ci * I guess "Part B" is primarily for downscaled version of same channel 10078c2ecf20Sopenharmony_ci * which goes in Part A of same bus 10088c2ecf20Sopenharmony_ci */ 10098c2ecf20Sopenharmony_ci tw_writel(TW5864_FULL_HALF_MODE_SEL, 0); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_PV_VD_CK_POL, 10128c2ecf20Sopenharmony_ci TW5864_INDIR_PV_VD_CK_POL_VD(0) | 10138c2ecf20Sopenharmony_ci TW5864_INDIR_PV_VD_CK_POL_VD(1) | 10148c2ecf20Sopenharmony_ci TW5864_INDIR_PV_VD_CK_POL_VD(2) | 10158c2ecf20Sopenharmony_ci TW5864_INDIR_PV_VD_CK_POL_VD(3)); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 10188c2ecf20Sopenharmony_ci dev->encoder_busy = 0; 10198c2ecf20Sopenharmony_ci dev->h264_buf_r_index = 0; 10208c2ecf20Sopenharmony_ci dev->h264_buf_w_index = 0; 10218c2ecf20Sopenharmony_ci tw_writel(TW5864_VLC_STREAM_BASE_ADDR, 10228c2ecf20Sopenharmony_ci dev->h264_buf[dev->h264_buf_w_index].vlc.dma_addr); 10238c2ecf20Sopenharmony_ci tw_writel(TW5864_MV_STREAM_BASE_ADDR, 10248c2ecf20Sopenharmony_ci dev->h264_buf[dev->h264_buf_w_index].mv.dma_addr); 10258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci tw_writel(TW5864_SEN_EN_CH, 0x000f); 10288c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_CH_EN, 0x000f); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_BUS0_MAP, 0x00000000); 10318c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_BUS1_MAP, 0x00001111); 10328c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_BUS2_MAP, 0x00002222); 10338c2ecf20Sopenharmony_ci tw_writel(TW5864_H264EN_BUS3_MAP, 0x00003333); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* 10368c2ecf20Sopenharmony_ci * Quote from Intersil (manufacturer): 10378c2ecf20Sopenharmony_ci * 0x0038 is managed by HW, and by default it won't pass the pointer set 10388c2ecf20Sopenharmony_ci * at 0x0010. So if you don't do encoding, 0x0038 should stay at '3' 10398c2ecf20Sopenharmony_ci * (with 4 frames in buffer). If you encode one frame and then move 10408c2ecf20Sopenharmony_ci * 0x0010 to '1' for example, HW will take one more frame and set it to 10418c2ecf20Sopenharmony_ci * buffer #0, and then you should see 0x0038 is set to '0'. There is 10428c2ecf20Sopenharmony_ci * only one HW encoder engine, so 4 channels cannot get encoded 10438c2ecf20Sopenharmony_ci * simultaneously. But each channel does have its own buffer (for 10448c2ecf20Sopenharmony_ci * original frames and reconstructed frames). So there is no problem to 10458c2ecf20Sopenharmony_ci * manage encoding for 4 channels at same time and no need to force 10468c2ecf20Sopenharmony_ci * I-frames in switching channels. 10478c2ecf20Sopenharmony_ci * End of quote. 10488c2ecf20Sopenharmony_ci * 10498c2ecf20Sopenharmony_ci * If we set 0x0010 (TW5864_ENC_BUF_PTR_REC1) to 0 (for any channel), we 10508c2ecf20Sopenharmony_ci * have no "rolling" (until we change this value). 10518c2ecf20Sopenharmony_ci * If we set 0x0010 (TW5864_ENC_BUF_PTR_REC1) to 0x3, it starts to roll 10528c2ecf20Sopenharmony_ci * continuously together with 0x0038. 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_ci tw_writel(TW5864_ENC_BUF_PTR_REC1, 0x00ff); 10558c2ecf20Sopenharmony_ci tw_writel(TW5864_PCI_INTTM_SCALE, 0); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci tw_writel(TW5864_INTERLACING, TW5864_DI_EN); 10588c2ecf20Sopenharmony_ci tw_writel(TW5864_MASTER_ENB_REG, TW5864_PCI_VLC_INTR_ENB); 10598c2ecf20Sopenharmony_ci tw_writel(TW5864_PCI_INTR_CTL, 10608c2ecf20Sopenharmony_ci TW5864_TIMER_INTR_ENB | TW5864_PCI_MAST_ENB | 10618c2ecf20Sopenharmony_ci TW5864_MVD_VLC_MAST_ENB); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER; 10648c2ecf20Sopenharmony_ci tw5864_irqmask_apply(dev); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci tasklet_setup(&dev->tasklet, tw5864_handle_frame_task); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci for (i = 0; i < TW5864_INPUTS; i++) { 10698c2ecf20Sopenharmony_ci dev->inputs[i].root = dev; 10708c2ecf20Sopenharmony_ci dev->inputs[i].nr = i; 10718c2ecf20Sopenharmony_ci ret = tw5864_video_input_init(&dev->inputs[i], video_nr[i]); 10728c2ecf20Sopenharmony_ci if (ret) 10738c2ecf20Sopenharmony_ci goto fini_video_inputs; 10748c2ecf20Sopenharmony_ci last_input_nr_registered = i; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return 0; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cifini_video_inputs: 10808c2ecf20Sopenharmony_ci for (i = last_input_nr_registered; i >= 0; i--) 10818c2ecf20Sopenharmony_ci tw5864_video_input_fini(&dev->inputs[i]); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci tasklet_kill(&dev->tasklet); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cifree_dma: 10868c2ecf20Sopenharmony_ci for (i = last_dma_allocated; i >= 0; i--) { 10878c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE, 10888c2ecf20Sopenharmony_ci dev->h264_buf[i].vlc.addr, 10898c2ecf20Sopenharmony_ci dev->h264_buf[i].vlc.dma_addr); 10908c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pci->dev, H264_MV_BUF_SIZE, 10918c2ecf20Sopenharmony_ci dev->h264_buf[i].mv.addr, 10928c2ecf20Sopenharmony_ci dev->h264_buf[i].mv.dma_addr); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return ret; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int tw5864_video_input_init(struct tw5864_input *input, int video_nr) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 11018c2ecf20Sopenharmony_ci int ret; 11028c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &input->hdl; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci mutex_init(&input->lock); 11058c2ecf20Sopenharmony_ci spin_lock_init(&input->slock); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* setup video buffers queue */ 11088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&input->active); 11098c2ecf20Sopenharmony_ci input->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 11108c2ecf20Sopenharmony_ci input->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 11118c2ecf20Sopenharmony_ci input->vidq.io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; 11128c2ecf20Sopenharmony_ci input->vidq.ops = &tw5864_video_qops; 11138c2ecf20Sopenharmony_ci input->vidq.mem_ops = &vb2_dma_contig_memops; 11148c2ecf20Sopenharmony_ci input->vidq.drv_priv = input; 11158c2ecf20Sopenharmony_ci input->vidq.gfp_flags = 0; 11168c2ecf20Sopenharmony_ci input->vidq.buf_struct_size = sizeof(struct tw5864_buf); 11178c2ecf20Sopenharmony_ci input->vidq.lock = &input->lock; 11188c2ecf20Sopenharmony_ci input->vidq.min_buffers_needed = 2; 11198c2ecf20Sopenharmony_ci input->vidq.dev = &input->root->pci->dev; 11208c2ecf20Sopenharmony_ci ret = vb2_queue_init(&input->vidq); 11218c2ecf20Sopenharmony_ci if (ret) 11228c2ecf20Sopenharmony_ci goto free_mutex; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci input->vdev = tw5864_video_template; 11258c2ecf20Sopenharmony_ci input->vdev.v4l2_dev = &input->root->v4l2_dev; 11268c2ecf20Sopenharmony_ci input->vdev.lock = &input->lock; 11278c2ecf20Sopenharmony_ci input->vdev.queue = &input->vidq; 11288c2ecf20Sopenharmony_ci video_set_drvdata(&input->vdev, input); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* Initialize the device control structures */ 11318c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 6); 11328c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, 11338c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 11348c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, 11358c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, 0, 255, 1, 100); 11368c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, 11378c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, 0, 255, 1, 128); 11388c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, V4L2_CID_HUE, -128, 127, 1, 0); 11398c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 11408c2ecf20Sopenharmony_ci 1, MAX_GOP_SIZE, 1, GOP_SIZE); 11418c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, 11428c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 28, 51, 1, QP_VALUE); 11438c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &tw5864_ctrl_ops, 11448c2ecf20Sopenharmony_ci V4L2_CID_DETECT_MD_MODE, 11458c2ecf20Sopenharmony_ci V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0, 11468c2ecf20Sopenharmony_ci V4L2_DETECT_MD_MODE_DISABLED); 11478c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, 11488c2ecf20Sopenharmony_ci V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 11498c2ecf20Sopenharmony_ci tw5864_md_thresholds.min, tw5864_md_thresholds.max, 11508c2ecf20Sopenharmony_ci tw5864_md_thresholds.step, tw5864_md_thresholds.def); 11518c2ecf20Sopenharmony_ci input->md_threshold_grid_ctrl = 11528c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &tw5864_md_thresholds, NULL); 11538c2ecf20Sopenharmony_ci if (hdl->error) { 11548c2ecf20Sopenharmony_ci ret = hdl->error; 11558c2ecf20Sopenharmony_ci goto free_v4l2_hdl; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci input->vdev.ctrl_handler = hdl; 11588c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(hdl); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci input->qp = QP_VALUE; 11618c2ecf20Sopenharmony_ci input->gop = GOP_SIZE; 11628c2ecf20Sopenharmony_ci input->frame_interval = 1; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci ret = video_register_device(&input->vdev, VFL_TYPE_VIDEO, video_nr); 11658c2ecf20Sopenharmony_ci if (ret) 11668c2ecf20Sopenharmony_ci goto free_v4l2_hdl; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci dev_info(&input->root->pci->dev, "Registered video device %s\n", 11698c2ecf20Sopenharmony_ci video_device_node_name(&input->vdev)); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci /* 11728c2ecf20Sopenharmony_ci * Set default video standard. Doesn't matter which, the detected value 11738c2ecf20Sopenharmony_ci * will be found out by VIDIOC_QUERYSTD handler. 11748c2ecf20Sopenharmony_ci */ 11758c2ecf20Sopenharmony_ci input->v4l2_std = V4L2_STD_NTSC_M; 11768c2ecf20Sopenharmony_ci input->std = STD_NTSC; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_E(video_nr), 0x07); 11798c2ecf20Sopenharmony_ci /* to initiate auto format recognition */ 11808c2ecf20Sopenharmony_ci tw_indir_writeb(TW5864_INDIR_VIN_F(video_nr), 0xff); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci return 0; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cifree_v4l2_hdl: 11858c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 11868c2ecf20Sopenharmony_cifree_mutex: 11878c2ecf20Sopenharmony_ci mutex_destroy(&input->lock); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci return ret; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic void tw5864_video_input_fini(struct tw5864_input *dev) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci vb2_video_unregister_device(&dev->vdev); 11958c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&dev->hdl); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_civoid tw5864_video_fini(struct tw5864_dev *dev) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci int i; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci tasklet_kill(&dev->tasklet); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci for (i = 0; i < TW5864_INPUTS; i++) 12058c2ecf20Sopenharmony_ci tw5864_video_input_fini(&dev->inputs[i]); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci for (i = 0; i < H264_BUF_CNT; i++) { 12088c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE, 12098c2ecf20Sopenharmony_ci dev->h264_buf[i].vlc.addr, 12108c2ecf20Sopenharmony_ci dev->h264_buf[i].vlc.dma_addr); 12118c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pci->dev, H264_MV_BUF_SIZE, 12128c2ecf20Sopenharmony_ci dev->h264_buf[i].mv.addr, 12138c2ecf20Sopenharmony_ci dev->h264_buf[i].mv.dma_addr); 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_civoid tw5864_prepare_frame_headers(struct tw5864_input *input) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct tw5864_buf *vb = input->vb; 12208c2ecf20Sopenharmony_ci u8 *dst; 12218c2ecf20Sopenharmony_ci size_t dst_space; 12228c2ecf20Sopenharmony_ci unsigned long flags; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (!vb) { 12258c2ecf20Sopenharmony_ci spin_lock_irqsave(&input->slock, flags); 12268c2ecf20Sopenharmony_ci if (list_empty(&input->active)) { 12278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&input->slock, flags); 12288c2ecf20Sopenharmony_ci input->vb = NULL; 12298c2ecf20Sopenharmony_ci return; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci vb = list_first_entry(&input->active, struct tw5864_buf, list); 12328c2ecf20Sopenharmony_ci list_del(&vb->list); 12338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&input->slock, flags); 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci dst = vb2_plane_vaddr(&vb->vb.vb2_buf, 0); 12378c2ecf20Sopenharmony_ci dst_space = vb2_plane_size(&vb->vb.vb2_buf, 0); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* 12408c2ecf20Sopenharmony_ci * Low-level bitstream writing functions don't have a fine way to say 12418c2ecf20Sopenharmony_ci * correctly that supplied buffer is too small. So we just check there 12428c2ecf20Sopenharmony_ci * and warn, and don't care at lower level. 12438c2ecf20Sopenharmony_ci * Currently all headers take below 32 bytes. 12448c2ecf20Sopenharmony_ci * The buffer is supposed to have plenty of free space at this point, 12458c2ecf20Sopenharmony_ci * anyway. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(dst_space < 128)) 12488c2ecf20Sopenharmony_ci return; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* 12518c2ecf20Sopenharmony_ci * Generate H264 headers: 12528c2ecf20Sopenharmony_ci * If this is first frame, put SPS and PPS 12538c2ecf20Sopenharmony_ci */ 12548c2ecf20Sopenharmony_ci if (input->frame_gop_seqno == 0) 12558c2ecf20Sopenharmony_ci tw5864_h264_put_stream_header(&dst, &dst_space, input->qp, 12568c2ecf20Sopenharmony_ci input->width, input->height); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* Put slice header */ 12598c2ecf20Sopenharmony_ci tw5864_h264_put_slice_header(&dst, &dst_space, input->h264_idr_pic_id, 12608c2ecf20Sopenharmony_ci input->frame_gop_seqno, 12618c2ecf20Sopenharmony_ci &input->tail_nb_bits, &input->tail); 12628c2ecf20Sopenharmony_ci input->vb = vb; 12638c2ecf20Sopenharmony_ci input->buf_cur_ptr = dst; 12648c2ecf20Sopenharmony_ci input->buf_cur_space_left = dst_space; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/* 12688c2ecf20Sopenharmony_ci * Returns heuristic motion detection metric value from known components of 12698c2ecf20Sopenharmony_ci * hardware-provided Motion Vector Data. 12708c2ecf20Sopenharmony_ci */ 12718c2ecf20Sopenharmony_cistatic unsigned int tw5864_md_metric_from_mvd(u32 mvd) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci /* 12748c2ecf20Sopenharmony_ci * Format of motion vector data exposed by tw5864, according to 12758c2ecf20Sopenharmony_ci * manufacturer: 12768c2ecf20Sopenharmony_ci * mv_x 10 bits 12778c2ecf20Sopenharmony_ci * mv_y 10 bits 12788c2ecf20Sopenharmony_ci * non_zero_members 8 bits 12798c2ecf20Sopenharmony_ci * mb_type 3 bits 12808c2ecf20Sopenharmony_ci * reserved 1 bit 12818c2ecf20Sopenharmony_ci * 12828c2ecf20Sopenharmony_ci * non_zero_members: number of non-zero residuals in each macro block 12838c2ecf20Sopenharmony_ci * after quantization 12848c2ecf20Sopenharmony_ci * 12858c2ecf20Sopenharmony_ci * unsigned int reserved = mvd >> 31; 12868c2ecf20Sopenharmony_ci * unsigned int mb_type = (mvd >> 28) & 0x7; 12878c2ecf20Sopenharmony_ci * unsigned int non_zero_members = (mvd >> 20) & 0xff; 12888c2ecf20Sopenharmony_ci */ 12898c2ecf20Sopenharmony_ci unsigned int mv_y = (mvd >> 10) & 0x3ff; 12908c2ecf20Sopenharmony_ci unsigned int mv_x = mvd & 0x3ff; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* heuristic: */ 12938c2ecf20Sopenharmony_ci mv_x &= 0x0f; 12948c2ecf20Sopenharmony_ci mv_y &= 0x0f; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return mv_y + mv_x; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci struct tw5864_input *input = frame->input; 13028c2ecf20Sopenharmony_ci u32 *mv = (u32 *)frame->mv.addr; 13038c2ecf20Sopenharmony_ci int i; 13048c2ecf20Sopenharmony_ci int detected = 0; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci for (i = 0; i < MD_CELLS; i++) { 13078c2ecf20Sopenharmony_ci const u16 thresh = input->md_threshold_grid_values[i]; 13088c2ecf20Sopenharmony_ci const unsigned int metric = tw5864_md_metric_from_mvd(mv[i]); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (metric > thresh) 13118c2ecf20Sopenharmony_ci detected = 1; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (detected) 13148c2ecf20Sopenharmony_ci break; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci return detected; 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic void tw5864_handle_frame_task(struct tasklet_struct *t) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct tw5864_dev *dev = from_tasklet(dev, t, tasklet); 13228c2ecf20Sopenharmony_ci unsigned long flags; 13238c2ecf20Sopenharmony_ci int batch_size = H264_BUF_CNT; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 13268c2ecf20Sopenharmony_ci while (dev->h264_buf_r_index != dev->h264_buf_w_index && batch_size--) { 13278c2ecf20Sopenharmony_ci struct tw5864_h264_frame *frame = 13288c2ecf20Sopenharmony_ci &dev->h264_buf[dev->h264_buf_r_index]; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 13318c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&dev->pci->dev, frame->vlc.dma_addr, 13328c2ecf20Sopenharmony_ci H264_VLC_BUF_SIZE, DMA_FROM_DEVICE); 13338c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&dev->pci->dev, frame->mv.dma_addr, 13348c2ecf20Sopenharmony_ci H264_MV_BUF_SIZE, DMA_FROM_DEVICE); 13358c2ecf20Sopenharmony_ci tw5864_handle_frame(frame); 13368c2ecf20Sopenharmony_ci dma_sync_single_for_device(&dev->pci->dev, frame->vlc.dma_addr, 13378c2ecf20Sopenharmony_ci H264_VLC_BUF_SIZE, DMA_FROM_DEVICE); 13388c2ecf20Sopenharmony_ci dma_sync_single_for_device(&dev->pci->dev, frame->mv.dma_addr, 13398c2ecf20Sopenharmony_ci H264_MV_BUF_SIZE, DMA_FROM_DEVICE); 13408c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci dev->h264_buf_r_index++; 13438c2ecf20Sopenharmony_ci dev->h264_buf_r_index %= H264_BUF_CNT; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci#ifdef DEBUG 13498c2ecf20Sopenharmony_cistatic u32 tw5864_vlc_checksum(u32 *data, int len) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci u32 val, count_len = len; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci val = *data++; 13548c2ecf20Sopenharmony_ci while (((count_len >> 2) - 1) > 0) { 13558c2ecf20Sopenharmony_ci val ^= *data++; 13568c2ecf20Sopenharmony_ci count_len -= 4; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci val ^= htonl((len >> 2)); 13598c2ecf20Sopenharmony_ci return val; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci#endif 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic void tw5864_handle_frame(struct tw5864_h264_frame *frame) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci#define SKIP_VLCBUF_BYTES 3 13668c2ecf20Sopenharmony_ci struct tw5864_input *input = frame->input; 13678c2ecf20Sopenharmony_ci struct tw5864_dev *dev = input->root; 13688c2ecf20Sopenharmony_ci struct tw5864_buf *vb; 13698c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *v4l2_buf; 13708c2ecf20Sopenharmony_ci int frame_len = frame->vlc_len - SKIP_VLCBUF_BYTES; 13718c2ecf20Sopenharmony_ci u8 *dst = input->buf_cur_ptr; 13728c2ecf20Sopenharmony_ci u8 tail_mask, vlc_mask = 0; 13738c2ecf20Sopenharmony_ci int i; 13748c2ecf20Sopenharmony_ci u8 vlc_first_byte = ((u8 *)(frame->vlc.addr + SKIP_VLCBUF_BYTES))[0]; 13758c2ecf20Sopenharmony_ci unsigned long flags; 13768c2ecf20Sopenharmony_ci int zero_run; 13778c2ecf20Sopenharmony_ci u8 *src; 13788c2ecf20Sopenharmony_ci u8 *src_end; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci#ifdef DEBUG 13818c2ecf20Sopenharmony_ci if (frame->checksum != 13828c2ecf20Sopenharmony_ci tw5864_vlc_checksum((u32 *)frame->vlc.addr, frame_len)) 13838c2ecf20Sopenharmony_ci dev_err(&dev->pci->dev, 13848c2ecf20Sopenharmony_ci "Checksum of encoded frame doesn't match!\n"); 13858c2ecf20Sopenharmony_ci#endif 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci spin_lock_irqsave(&input->slock, flags); 13888c2ecf20Sopenharmony_ci vb = input->vb; 13898c2ecf20Sopenharmony_ci input->vb = NULL; 13908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&input->slock, flags); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci if (!vb) { /* Gone because of disabling */ 13938c2ecf20Sopenharmony_ci dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n"); 13948c2ecf20Sopenharmony_ci return; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci /* 14008c2ecf20Sopenharmony_ci * Check for space. 14018c2ecf20Sopenharmony_ci * Mind the overhead of startcode emulation prevention. 14028c2ecf20Sopenharmony_ci */ 14038c2ecf20Sopenharmony_ci if (input->buf_cur_space_left < frame_len * 5 / 4) { 14048c2ecf20Sopenharmony_ci dev_err_once(&dev->pci->dev, 14058c2ecf20Sopenharmony_ci "Left space in vb2 buffer, %d bytes, is less than considered safely enough to put frame of length %d. Dropping this frame.\n", 14068c2ecf20Sopenharmony_ci input->buf_cur_space_left, frame_len); 14078c2ecf20Sopenharmony_ci return; 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci for (i = 0; i < 8 - input->tail_nb_bits; i++) 14118c2ecf20Sopenharmony_ci vlc_mask |= 1 << i; 14128c2ecf20Sopenharmony_ci tail_mask = (~vlc_mask) & 0xff; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci dst[0] = (input->tail & tail_mask) | (vlc_first_byte & vlc_mask); 14158c2ecf20Sopenharmony_ci frame_len--; 14168c2ecf20Sopenharmony_ci dst++; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* H.264 startcode emulation prevention */ 14198c2ecf20Sopenharmony_ci src = frame->vlc.addr + SKIP_VLCBUF_BYTES + 1; 14208c2ecf20Sopenharmony_ci src_end = src + frame_len; 14218c2ecf20Sopenharmony_ci zero_run = 0; 14228c2ecf20Sopenharmony_ci for (; src < src_end; src++) { 14238c2ecf20Sopenharmony_ci if (zero_run < 2) { 14248c2ecf20Sopenharmony_ci if (*src == 0) 14258c2ecf20Sopenharmony_ci ++zero_run; 14268c2ecf20Sopenharmony_ci else 14278c2ecf20Sopenharmony_ci zero_run = 0; 14288c2ecf20Sopenharmony_ci } else { 14298c2ecf20Sopenharmony_ci if ((*src & ~0x03) == 0) 14308c2ecf20Sopenharmony_ci *dst++ = 0x03; 14318c2ecf20Sopenharmony_ci zero_run = *src == 0; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci *dst++ = *src; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci vb2_set_plane_payload(&vb->vb.vb2_buf, 0, 14378c2ecf20Sopenharmony_ci dst - (u8 *)vb2_plane_vaddr(&vb->vb.vb2_buf, 0)); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci vb->vb.vb2_buf.timestamp = frame->timestamp; 14408c2ecf20Sopenharmony_ci v4l2_buf->field = V4L2_FIELD_INTERLACED; 14418c2ecf20Sopenharmony_ci v4l2_buf->sequence = frame->seqno; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci /* Check for motion flags */ 14448c2ecf20Sopenharmony_ci if (frame->gop_seqno /* P-frame */ && 14458c2ecf20Sopenharmony_ci tw5864_is_motion_triggered(frame)) { 14468c2ecf20Sopenharmony_ci struct v4l2_event ev = { 14478c2ecf20Sopenharmony_ci .type = V4L2_EVENT_MOTION_DET, 14488c2ecf20Sopenharmony_ci .u.motion_det = { 14498c2ecf20Sopenharmony_ci .flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ, 14508c2ecf20Sopenharmony_ci .frame_sequence = v4l2_buf->sequence, 14518c2ecf20Sopenharmony_ci }, 14528c2ecf20Sopenharmony_ci }; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci v4l2_event_queue(&input->vdev, &ev); 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE); 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_cistatic v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci switch (std) { 14638c2ecf20Sopenharmony_ci case STD_NTSC: return V4L2_STD_NTSC_M; 14648c2ecf20Sopenharmony_ci case STD_PAL: return V4L2_STD_PAL_B; 14658c2ecf20Sopenharmony_ci case STD_SECAM: return V4L2_STD_SECAM_B; 14668c2ecf20Sopenharmony_ci case STD_NTSC443: return V4L2_STD_NTSC_443; 14678c2ecf20Sopenharmony_ci case STD_PAL_M: return V4L2_STD_PAL_M; 14688c2ecf20Sopenharmony_ci case STD_PAL_CN: return V4L2_STD_PAL_Nc; 14698c2ecf20Sopenharmony_ci case STD_PAL_60: return V4L2_STD_PAL_60; 14708c2ecf20Sopenharmony_ci case STD_INVALID: return V4L2_STD_UNKNOWN; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci return 0; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_NTSC_M) 14788c2ecf20Sopenharmony_ci return STD_NTSC; 14798c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_PAL_B) 14808c2ecf20Sopenharmony_ci return STD_PAL; 14818c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_SECAM_B) 14828c2ecf20Sopenharmony_ci return STD_SECAM; 14838c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_NTSC_443) 14848c2ecf20Sopenharmony_ci return STD_NTSC443; 14858c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_PAL_M) 14868c2ecf20Sopenharmony_ci return STD_PAL_M; 14878c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_PAL_Nc) 14888c2ecf20Sopenharmony_ci return STD_PAL_CN; 14898c2ecf20Sopenharmony_ci if (v4l2_std & V4L2_STD_PAL_60) 14908c2ecf20Sopenharmony_ci return STD_PAL_60; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return STD_INVALID; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic void tw5864_encoder_tables_upload(struct tw5864_dev *dev) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci int i; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci tw_writel(TW5864_VLC_RD, 0x1); 15008c2ecf20Sopenharmony_ci for (i = 0; i < VLC_LOOKUP_TABLE_LEN; i++) { 15018c2ecf20Sopenharmony_ci tw_writel((TW5864_VLC_STREAM_MEM_START + i * 4), 15028c2ecf20Sopenharmony_ci encoder_vlc_lookup_table[i]); 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci tw_writel(TW5864_VLC_RD, 0x0); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci for (i = 0; i < QUANTIZATION_TABLE_LEN; i++) { 15078c2ecf20Sopenharmony_ci tw_writel((TW5864_QUAN_TAB + i * 4), 15088c2ecf20Sopenharmony_ci forward_quantization_table[i]); 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci for (i = 0; i < QUANTIZATION_TABLE_LEN; i++) { 15128c2ecf20Sopenharmony_ci tw_writel((TW5864_QUAN_TAB + i * 4), 15138c2ecf20Sopenharmony_ci inverse_quantization_table[i]); 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci} 1516