162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  TW5864 driver - video encoding functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <media/v4l2-common.h>
1062306a36Sopenharmony_ci#include <media/v4l2-event.h>
1162306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "tw5864.h"
1462306a36Sopenharmony_ci#include "tw5864-reg.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define QUANTIZATION_TABLE_LEN 96
1762306a36Sopenharmony_ci#define VLC_LOOKUP_TABLE_LEN 1024
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const u16 forward_quantization_table[QUANTIZATION_TABLE_LEN] = {
2062306a36Sopenharmony_ci	0x3333, 0x1f82, 0x3333, 0x1f82, 0x1f82, 0x147b, 0x1f82, 0x147b,
2162306a36Sopenharmony_ci	0x3333, 0x1f82, 0x3333, 0x1f82, 0x1f82, 0x147b, 0x1f82, 0x147b,
2262306a36Sopenharmony_ci	0x2e8c, 0x1d42, 0x2e8c, 0x1d42, 0x1d42, 0x1234, 0x1d42, 0x1234,
2362306a36Sopenharmony_ci	0x2e8c, 0x1d42, 0x2e8c, 0x1d42, 0x1d42, 0x1234, 0x1d42, 0x1234,
2462306a36Sopenharmony_ci	0x2762, 0x199a, 0x2762, 0x199a, 0x199a, 0x1062, 0x199a, 0x1062,
2562306a36Sopenharmony_ci	0x2762, 0x199a, 0x2762, 0x199a, 0x199a, 0x1062, 0x199a, 0x1062,
2662306a36Sopenharmony_ci	0x2492, 0x16c1, 0x2492, 0x16c1, 0x16c1, 0x0e3f, 0x16c1, 0x0e3f,
2762306a36Sopenharmony_ci	0x2492, 0x16c1, 0x2492, 0x16c1, 0x16c1, 0x0e3f, 0x16c1, 0x0e3f,
2862306a36Sopenharmony_ci	0x2000, 0x147b, 0x2000, 0x147b, 0x147b, 0x0d1b, 0x147b, 0x0d1b,
2962306a36Sopenharmony_ci	0x2000, 0x147b, 0x2000, 0x147b, 0x147b, 0x0d1b, 0x147b, 0x0d1b,
3062306a36Sopenharmony_ci	0x1c72, 0x11cf, 0x1c72, 0x11cf, 0x11cf, 0x0b4d, 0x11cf, 0x0b4d,
3162306a36Sopenharmony_ci	0x1c72, 0x11cf, 0x1c72, 0x11cf, 0x11cf, 0x0b4d, 0x11cf, 0x0b4d
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const u16 inverse_quantization_table[QUANTIZATION_TABLE_LEN] = {
3562306a36Sopenharmony_ci	0x800a, 0x800d, 0x800a, 0x800d, 0x800d, 0x8010, 0x800d, 0x8010,
3662306a36Sopenharmony_ci	0x800a, 0x800d, 0x800a, 0x800d, 0x800d, 0x8010, 0x800d, 0x8010,
3762306a36Sopenharmony_ci	0x800b, 0x800e, 0x800b, 0x800e, 0x800e, 0x8012, 0x800e, 0x8012,
3862306a36Sopenharmony_ci	0x800b, 0x800e, 0x800b, 0x800e, 0x800e, 0x8012, 0x800e, 0x8012,
3962306a36Sopenharmony_ci	0x800d, 0x8010, 0x800d, 0x8010, 0x8010, 0x8014, 0x8010, 0x8014,
4062306a36Sopenharmony_ci	0x800d, 0x8010, 0x800d, 0x8010, 0x8010, 0x8014, 0x8010, 0x8014,
4162306a36Sopenharmony_ci	0x800e, 0x8012, 0x800e, 0x8012, 0x8012, 0x8017, 0x8012, 0x8017,
4262306a36Sopenharmony_ci	0x800e, 0x8012, 0x800e, 0x8012, 0x8012, 0x8017, 0x8012, 0x8017,
4362306a36Sopenharmony_ci	0x8010, 0x8014, 0x8010, 0x8014, 0x8014, 0x8019, 0x8014, 0x8019,
4462306a36Sopenharmony_ci	0x8010, 0x8014, 0x8010, 0x8014, 0x8014, 0x8019, 0x8014, 0x8019,
4562306a36Sopenharmony_ci	0x8012, 0x8017, 0x8012, 0x8017, 0x8017, 0x801d, 0x8017, 0x801d,
4662306a36Sopenharmony_ci	0x8012, 0x8017, 0x8012, 0x8017, 0x8017, 0x801d, 0x8017, 0x801d
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic const u16 encoder_vlc_lookup_table[VLC_LOOKUP_TABLE_LEN] = {
5062306a36Sopenharmony_ci	0x011, 0x000, 0x000, 0x000, 0x065, 0x021, 0x000, 0x000, 0x087, 0x064,
5162306a36Sopenharmony_ci	0x031, 0x000, 0x097, 0x086, 0x075, 0x053, 0x0a7, 0x096, 0x085, 0x063,
5262306a36Sopenharmony_ci	0x0b7, 0x0a6, 0x095, 0x074, 0x0df, 0x0b6, 0x0a5, 0x084, 0x0db, 0x0de,
5362306a36Sopenharmony_ci	0x0b5, 0x094, 0x0d8, 0x0da, 0x0dd, 0x0a4, 0x0ef, 0x0ee, 0x0d9, 0x0b4,
5462306a36Sopenharmony_ci	0x0eb, 0x0ea, 0x0ed, 0x0dc, 0x0ff, 0x0fe, 0x0e9, 0x0ec, 0x0fb, 0x0fa,
5562306a36Sopenharmony_ci	0x0fd, 0x0e8, 0x10f, 0x0f1, 0x0f9, 0x0fc, 0x10b, 0x10e, 0x10d, 0x0f8,
5662306a36Sopenharmony_ci	0x107, 0x10a, 0x109, 0x10c, 0x104, 0x106, 0x105, 0x108, 0x023, 0x000,
5762306a36Sopenharmony_ci	0x000, 0x000, 0x06b, 0x022, 0x000, 0x000, 0x067, 0x057, 0x033, 0x000,
5862306a36Sopenharmony_ci	0x077, 0x06a, 0x069, 0x045, 0x087, 0x066, 0x065, 0x044, 0x084, 0x076,
5962306a36Sopenharmony_ci	0x075, 0x056, 0x097, 0x086, 0x085, 0x068, 0x0bf, 0x096, 0x095, 0x064,
6062306a36Sopenharmony_ci	0x0bb, 0x0be, 0x0bd, 0x074, 0x0cf, 0x0ba, 0x0b9, 0x094, 0x0cb, 0x0ce,
6162306a36Sopenharmony_ci	0x0cd, 0x0bc, 0x0c8, 0x0ca, 0x0c9, 0x0b8, 0x0df, 0x0de, 0x0dd, 0x0cc,
6262306a36Sopenharmony_ci	0x0db, 0x0da, 0x0d9, 0x0dc, 0x0d7, 0x0eb, 0x0d6, 0x0d8, 0x0e9, 0x0e8,
6362306a36Sopenharmony_ci	0x0ea, 0x0d1, 0x0e7, 0x0e6, 0x0e5, 0x0e4, 0x04f, 0x000, 0x000, 0x000,
6462306a36Sopenharmony_ci	0x06f, 0x04e, 0x000, 0x000, 0x06b, 0x05f, 0x04d, 0x000, 0x068, 0x05c,
6562306a36Sopenharmony_ci	0x05e, 0x04c, 0x07f, 0x05a, 0x05b, 0x04b, 0x07b, 0x058, 0x059, 0x04a,
6662306a36Sopenharmony_ci	0x079, 0x06e, 0x06d, 0x049, 0x078, 0x06a, 0x069, 0x048, 0x08f, 0x07e,
6762306a36Sopenharmony_ci	0x07d, 0x05d, 0x08b, 0x08e, 0x07a, 0x06c, 0x09f, 0x08a, 0x08d, 0x07c,
6862306a36Sopenharmony_ci	0x09b, 0x09e, 0x089, 0x08c, 0x098, 0x09a, 0x09d, 0x088, 0x0ad, 0x097,
6962306a36Sopenharmony_ci	0x099, 0x09c, 0x0a9, 0x0ac, 0x0ab, 0x0aa, 0x0a5, 0x0a8, 0x0a7, 0x0a6,
7062306a36Sopenharmony_ci	0x0a1, 0x0a4, 0x0a3, 0x0a2, 0x021, 0x000, 0x000, 0x000, 0x067, 0x011,
7162306a36Sopenharmony_ci	0x000, 0x000, 0x064, 0x066, 0x031, 0x000, 0x063, 0x073, 0x072, 0x065,
7262306a36Sopenharmony_ci	0x062, 0x083, 0x082, 0x070, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7362306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7462306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7562306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7662306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7762306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7862306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
7962306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8062306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8162306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8262306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8362306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8462306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8562306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8662306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8762306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8862306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
8962306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9062306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9162306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9262306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9362306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9462306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9562306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9662306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9762306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9862306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
9962306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10062306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10162306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10262306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x011, 0x010,
10362306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10462306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x011, 0x021, 0x020, 0x000, 0x000, 0x000,
10562306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10662306a36Sopenharmony_ci	0x023, 0x022, 0x021, 0x020, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10762306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x023, 0x022, 0x021, 0x031,
10862306a36Sopenharmony_ci	0x030, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
10962306a36Sopenharmony_ci	0x000, 0x000, 0x023, 0x022, 0x033, 0x032, 0x031, 0x030, 0x000, 0x000,
11062306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x023, 0x030,
11162306a36Sopenharmony_ci	0x031, 0x033, 0x032, 0x035, 0x034, 0x000, 0x000, 0x000, 0x000, 0x000,
11262306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x037, 0x036, 0x035, 0x034, 0x033, 0x032,
11362306a36Sopenharmony_ci	0x031, 0x041, 0x051, 0x061, 0x071, 0x081, 0x091, 0x0a1, 0x0b1, 0x000,
11462306a36Sopenharmony_ci	0x002, 0x000, 0x0e4, 0x011, 0x0f4, 0x002, 0x024, 0x003, 0x005, 0x012,
11562306a36Sopenharmony_ci	0x034, 0x013, 0x065, 0x024, 0x013, 0x063, 0x015, 0x022, 0x075, 0x034,
11662306a36Sopenharmony_ci	0x044, 0x023, 0x023, 0x073, 0x054, 0x033, 0x033, 0x004, 0x043, 0x014,
11762306a36Sopenharmony_ci	0x011, 0x043, 0x014, 0x001, 0x025, 0x015, 0x035, 0x025, 0x064, 0x055,
11862306a36Sopenharmony_ci	0x045, 0x035, 0x074, 0x065, 0x085, 0x0d5, 0x012, 0x095, 0x055, 0x045,
11962306a36Sopenharmony_ci	0x095, 0x0e5, 0x084, 0x075, 0x022, 0x0a5, 0x094, 0x085, 0x032, 0x0b5,
12062306a36Sopenharmony_ci	0x003, 0x0c5, 0x001, 0x044, 0x0a5, 0x032, 0x0b5, 0x094, 0x0c5, 0x0a4,
12162306a36Sopenharmony_ci	0x0a4, 0x054, 0x0d5, 0x0b4, 0x0b4, 0x064, 0x0f5, 0x0f5, 0x053, 0x0d4,
12262306a36Sopenharmony_ci	0x0e5, 0x0c4, 0x105, 0x105, 0x0c4, 0x074, 0x063, 0x0e4, 0x0d4, 0x084,
12362306a36Sopenharmony_ci	0x073, 0x0f4, 0x004, 0x005, 0x000, 0x053, 0x000, 0x000, 0x000, 0x000,
12462306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
12562306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
12662306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
12762306a36Sopenharmony_ci	0x000, 0x000, 0x011, 0x021, 0x031, 0x030, 0x011, 0x021, 0x020, 0x000,
12862306a36Sopenharmony_ci	0x011, 0x010, 0x000, 0x000, 0x011, 0x033, 0x032, 0x043, 0x042, 0x053,
12962306a36Sopenharmony_ci	0x052, 0x063, 0x062, 0x073, 0x072, 0x083, 0x082, 0x093, 0x092, 0x091,
13062306a36Sopenharmony_ci	0x037, 0x036, 0x035, 0x034, 0x033, 0x045, 0x044, 0x043, 0x042, 0x053,
13162306a36Sopenharmony_ci	0x052, 0x063, 0x062, 0x061, 0x060, 0x000, 0x045, 0x037, 0x036, 0x035,
13262306a36Sopenharmony_ci	0x044, 0x043, 0x034, 0x033, 0x042, 0x053, 0x052, 0x061, 0x051, 0x060,
13362306a36Sopenharmony_ci	0x000, 0x000, 0x053, 0x037, 0x045, 0x044, 0x036, 0x035, 0x034, 0x043,
13462306a36Sopenharmony_ci	0x033, 0x042, 0x052, 0x051, 0x050, 0x000, 0x000, 0x000, 0x045, 0x044,
13562306a36Sopenharmony_ci	0x043, 0x037, 0x036, 0x035, 0x034, 0x033, 0x042, 0x051, 0x041, 0x050,
13662306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x061, 0x051, 0x037, 0x036, 0x035, 0x034,
13762306a36Sopenharmony_ci	0x033, 0x032, 0x041, 0x031, 0x060, 0x000, 0x000, 0x000, 0x000, 0x000,
13862306a36Sopenharmony_ci	0x061, 0x051, 0x035, 0x034, 0x033, 0x023, 0x032, 0x041, 0x031, 0x060,
13962306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x061, 0x041, 0x051, 0x033,
14062306a36Sopenharmony_ci	0x023, 0x022, 0x032, 0x031, 0x060, 0x000, 0x000, 0x000, 0x000, 0x000,
14162306a36Sopenharmony_ci	0x000, 0x000, 0x061, 0x060, 0x041, 0x023, 0x022, 0x031, 0x021, 0x051,
14262306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x051, 0x050,
14362306a36Sopenharmony_ci	0x031, 0x023, 0x022, 0x021, 0x041, 0x000, 0x000, 0x000, 0x000, 0x000,
14462306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x040, 0x041, 0x031, 0x032, 0x011, 0x033,
14562306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
14662306a36Sopenharmony_ci	0x040, 0x041, 0x021, 0x011, 0x031, 0x000, 0x000, 0x000, 0x000, 0x000,
14762306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x030, 0x031, 0x011, 0x021,
14862306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
14962306a36Sopenharmony_ci	0x000, 0x000, 0x020, 0x021, 0x011, 0x000, 0x000, 0x000, 0x000, 0x000,
15062306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x010, 0x011,
15162306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
15262306a36Sopenharmony_ci	0x000, 0x000, 0x000, 0x000
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const unsigned int lambda_lookup_table[] = {
15662306a36Sopenharmony_ci	0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
15762306a36Sopenharmony_ci	0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
15862306a36Sopenharmony_ci	0x0040, 0x0040, 0x0040, 0x0040, 0x0060, 0x0060, 0x0060, 0x0080,
15962306a36Sopenharmony_ci	0x0080, 0x0080, 0x00a0, 0x00c0, 0x00c0, 0x00e0, 0x0100, 0x0120,
16062306a36Sopenharmony_ci	0x0140, 0x0160, 0x01a0, 0x01c0, 0x0200, 0x0240, 0x0280, 0x02e0,
16162306a36Sopenharmony_ci	0x0320, 0x03a0, 0x0400, 0x0480, 0x0500, 0x05a0, 0x0660, 0x0720,
16262306a36Sopenharmony_ci	0x0800, 0x0900, 0x0a20, 0x0b60
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic const unsigned int intra4x4_lambda3[] = {
16662306a36Sopenharmony_ci	1, 1, 1, 1, 1, 1, 1, 1,
16762306a36Sopenharmony_ci	1, 1, 1, 1, 1, 1, 1, 1,
16862306a36Sopenharmony_ci	2, 2, 2, 2, 3, 3, 3, 4,
16962306a36Sopenharmony_ci	4, 4, 5, 6, 6, 7, 8, 9,
17062306a36Sopenharmony_ci	10, 11, 13, 14, 16, 18, 20, 23,
17162306a36Sopenharmony_ci	25, 29, 32, 36, 40, 45, 51, 57,
17262306a36Sopenharmony_ci	64, 72, 81, 91
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std);
17662306a36Sopenharmony_cistatic enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void tw5864_handle_frame_task(struct tasklet_struct *t);
17962306a36Sopenharmony_cistatic void tw5864_handle_frame(struct tw5864_h264_frame *frame);
18062306a36Sopenharmony_cistatic void tw5864_frame_interval_set(struct tw5864_input *input);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int tw5864_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
18362306a36Sopenharmony_ci			      unsigned int *num_planes, unsigned int sizes[],
18462306a36Sopenharmony_ci			      struct device *alloc_ctxs[])
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	if (*num_planes)
18762306a36Sopenharmony_ci		return sizes[0] < H264_VLC_BUF_SIZE ? -EINVAL : 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	sizes[0] = H264_VLC_BUF_SIZE;
19062306a36Sopenharmony_ci	*num_planes = 1;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic void tw5864_buf_queue(struct vb2_buffer *vb)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
19862306a36Sopenharmony_ci	struct vb2_queue *vq = vb->vb2_queue;
19962306a36Sopenharmony_ci	struct tw5864_input *dev = vb2_get_drv_priv(vq);
20062306a36Sopenharmony_ci	struct tw5864_buf *buf = container_of(vbuf, struct tw5864_buf, vb);
20162306a36Sopenharmony_ci	unsigned long flags;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->slock, flags);
20462306a36Sopenharmony_ci	list_add_tail(&buf->list, &dev->active);
20562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->slock, flags);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int tw5864_input_std_get(struct tw5864_input *input,
20962306a36Sopenharmony_ci				enum tw5864_vid_std *std)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
21262306a36Sopenharmony_ci	u8 std_reg = tw_indir_readb(TW5864_INDIR_VIN_E(input->nr));
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	*std = (std_reg & 0x70) >> 4;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (std_reg & 0x80) {
21762306a36Sopenharmony_ci		dev_dbg(&dev->pci->dev,
21862306a36Sopenharmony_ci			"Video format detection is in progress, please wait\n");
21962306a36Sopenharmony_ci		return -EAGAIN;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return 0;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int tw5864_enable_input(struct tw5864_input *input)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
22862306a36Sopenharmony_ci	int nr = input->nr;
22962306a36Sopenharmony_ci	unsigned long flags;
23062306a36Sopenharmony_ci	int d1_width = 720;
23162306a36Sopenharmony_ci	int d1_height;
23262306a36Sopenharmony_ci	int frame_width_bus_value = 0;
23362306a36Sopenharmony_ci	int frame_height_bus_value = 0;
23462306a36Sopenharmony_ci	int reg_frame_bus = 0x1c;
23562306a36Sopenharmony_ci	int fmt_reg_value = 0;
23662306a36Sopenharmony_ci	int downscale_enabled = 0;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	dev_dbg(&dev->pci->dev, "Enabling channel %d\n", nr);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	input->frame_seqno = 0;
24162306a36Sopenharmony_ci	input->frame_gop_seqno = 0;
24262306a36Sopenharmony_ci	input->h264_idr_pic_id = 0;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	input->reg_dsp_qp = input->qp;
24562306a36Sopenharmony_ci	input->reg_dsp_ref_mvp_lambda = lambda_lookup_table[input->qp];
24662306a36Sopenharmony_ci	input->reg_dsp_i4x4_weight = intra4x4_lambda3[input->qp];
24762306a36Sopenharmony_ci	input->reg_emu = TW5864_EMU_EN_LPF | TW5864_EMU_EN_BHOST
24862306a36Sopenharmony_ci		| TW5864_EMU_EN_SEN | TW5864_EMU_EN_ME | TW5864_EMU_EN_DDR;
24962306a36Sopenharmony_ci	input->reg_dsp = nr /* channel id */
25062306a36Sopenharmony_ci		| TW5864_DSP_CHROM_SW
25162306a36Sopenharmony_ci		| ((0xa << 8) & TW5864_DSP_MB_DELAY)
25262306a36Sopenharmony_ci		;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	input->resolution = D1;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	d1_height = (input->std == STD_NTSC) ? 480 : 576;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	input->width = d1_width;
25962306a36Sopenharmony_ci	input->height = d1_height;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	input->reg_interlacing = 0x4;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	switch (input->resolution) {
26462306a36Sopenharmony_ci	case D1:
26562306a36Sopenharmony_ci		frame_width_bus_value = 0x2cf;
26662306a36Sopenharmony_ci		frame_height_bus_value = input->height - 1;
26762306a36Sopenharmony_ci		reg_frame_bus = 0x1c;
26862306a36Sopenharmony_ci		fmt_reg_value = 0;
26962306a36Sopenharmony_ci		downscale_enabled = 0;
27062306a36Sopenharmony_ci		input->reg_dsp_codec |= TW5864_CIF_MAP_MD | TW5864_HD1_MAP_MD;
27162306a36Sopenharmony_ci		input->reg_emu |= TW5864_DSP_FRAME_TYPE_D1;
27262306a36Sopenharmony_ci		input->reg_interlacing = TW5864_DI_EN | TW5864_DSP_INTER_ST;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		tw_setl(TW5864_FULL_HALF_FLAG, 1 << nr);
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	case HD1:
27762306a36Sopenharmony_ci		input->height /= 2;
27862306a36Sopenharmony_ci		input->width /= 2;
27962306a36Sopenharmony_ci		frame_width_bus_value = 0x2cf;
28062306a36Sopenharmony_ci		frame_height_bus_value = input->height * 2 - 1;
28162306a36Sopenharmony_ci		reg_frame_bus = 0x1c;
28262306a36Sopenharmony_ci		fmt_reg_value = 0;
28362306a36Sopenharmony_ci		downscale_enabled = 0;
28462306a36Sopenharmony_ci		input->reg_dsp_codec |= TW5864_HD1_MAP_MD;
28562306a36Sopenharmony_ci		input->reg_emu |= TW5864_DSP_FRAME_TYPE_D1;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		break;
29062306a36Sopenharmony_ci	case CIF:
29162306a36Sopenharmony_ci		input->height /= 4;
29262306a36Sopenharmony_ci		input->width /= 2;
29362306a36Sopenharmony_ci		frame_width_bus_value = 0x15f;
29462306a36Sopenharmony_ci		frame_height_bus_value = input->height * 2 - 1;
29562306a36Sopenharmony_ci		reg_frame_bus = 0x07;
29662306a36Sopenharmony_ci		fmt_reg_value = 1;
29762306a36Sopenharmony_ci		downscale_enabled = 1;
29862306a36Sopenharmony_ci		input->reg_dsp_codec |= TW5864_CIF_MAP_MD;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr);
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	case QCIF:
30362306a36Sopenharmony_ci		input->height /= 4;
30462306a36Sopenharmony_ci		input->width /= 4;
30562306a36Sopenharmony_ci		frame_width_bus_value = 0x15f;
30662306a36Sopenharmony_ci		frame_height_bus_value = input->height * 2 - 1;
30762306a36Sopenharmony_ci		reg_frame_bus = 0x07;
30862306a36Sopenharmony_ci		fmt_reg_value = 1;
30962306a36Sopenharmony_ci		downscale_enabled = 1;
31062306a36Sopenharmony_ci		input->reg_dsp_codec |= TW5864_CIF_MAP_MD;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr);
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* analog input width / 4 */
31762306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_IN_PIC_WIDTH(nr), d1_width / 4);
31862306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_IN_PIC_HEIGHT(nr), d1_height / 4);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* output width / 4 */
32162306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_OUT_PIC_WIDTH(nr), input->width / 4);
32262306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_OUT_PIC_HEIGHT(nr), input->height / 4);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/*
32562306a36Sopenharmony_ci	 * Crop width from 720 to 704.
32662306a36Sopenharmony_ci	 * Above register settings need value 720 involved.
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	input->width = 704;
32962306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_CROP_ETC,
33062306a36Sopenharmony_ci			tw_indir_readb(TW5864_INDIR_CROP_ETC) |
33162306a36Sopenharmony_ci			TW5864_INDIR_CROP_ETC_CROP_EN);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	tw_writel(TW5864_DSP_PIC_MAX_MB,
33462306a36Sopenharmony_ci		  ((input->width / 16) << 8) | (input->height / 16));
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	tw_writel(TW5864_FRAME_WIDTH_BUS_A(nr),
33762306a36Sopenharmony_ci		  frame_width_bus_value);
33862306a36Sopenharmony_ci	tw_writel(TW5864_FRAME_WIDTH_BUS_B(nr),
33962306a36Sopenharmony_ci		  frame_width_bus_value);
34062306a36Sopenharmony_ci	tw_writel(TW5864_FRAME_HEIGHT_BUS_A(nr),
34162306a36Sopenharmony_ci		  frame_height_bus_value);
34262306a36Sopenharmony_ci	tw_writel(TW5864_FRAME_HEIGHT_BUS_B(nr),
34362306a36Sopenharmony_ci		  (frame_height_bus_value + 1) / 2 - 1);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	tw5864_frame_interval_set(input);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (downscale_enabled)
34862306a36Sopenharmony_ci		tw_setl(TW5864_H264EN_CH_DNS, 1 << nr);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	tw_mask_shift_writel(TW5864_H264EN_CH_FMT_REG1, 0x3, 2 * nr,
35162306a36Sopenharmony_ci			     fmt_reg_value);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	tw_mask_shift_writel((nr < 2
35462306a36Sopenharmony_ci			      ? TW5864_H264EN_RATE_MAX_LINE_REG1
35562306a36Sopenharmony_ci			      : TW5864_H264EN_RATE_MAX_LINE_REG2),
35662306a36Sopenharmony_ci			     0x1f, 5 * (nr % 2),
35762306a36Sopenharmony_ci			     input->std == STD_NTSC ? 29 : 24);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	tw_mask_shift_writel((nr < 2) ? TW5864_FRAME_BUS1 :
36062306a36Sopenharmony_ci			     TW5864_FRAME_BUS2, 0xff, (nr % 2) * 8,
36162306a36Sopenharmony_ci			     reg_frame_bus);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->slock, flags);
36462306a36Sopenharmony_ci	input->enabled = 1;
36562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->slock, flags);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid tw5864_request_encoded_frame(struct tw5864_input *input)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
37362306a36Sopenharmony_ci	u32 enc_buf_id_new;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	tw_setl(TW5864_DSP_CODEC, TW5864_CIF_MAP_MD | TW5864_HD1_MAP_MD);
37662306a36Sopenharmony_ci	tw_writel(TW5864_EMU, input->reg_emu);
37762306a36Sopenharmony_ci	tw_writel(TW5864_INTERLACING, input->reg_interlacing);
37862306a36Sopenharmony_ci	tw_writel(TW5864_DSP, input->reg_dsp);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	tw_writel(TW5864_DSP_QP, input->reg_dsp_qp);
38162306a36Sopenharmony_ci	tw_writel(TW5864_DSP_REF_MVP_LAMBDA, input->reg_dsp_ref_mvp_lambda);
38262306a36Sopenharmony_ci	tw_writel(TW5864_DSP_I4x4_WEIGHT, input->reg_dsp_i4x4_weight);
38362306a36Sopenharmony_ci	tw_mask_shift_writel(TW5864_DSP_INTRA_MODE, TW5864_DSP_INTRA_MODE_MASK,
38462306a36Sopenharmony_ci			     TW5864_DSP_INTRA_MODE_SHIFT,
38562306a36Sopenharmony_ci			     TW5864_DSP_INTRA_MODE_16x16);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (input->frame_gop_seqno == 0) {
38862306a36Sopenharmony_ci		/* Produce I-frame */
38962306a36Sopenharmony_ci		tw_writel(TW5864_MOTION_SEARCH_ETC, TW5864_INTRA_EN);
39062306a36Sopenharmony_ci		input->h264_idr_pic_id++;
39162306a36Sopenharmony_ci		input->h264_idr_pic_id &= TW5864_DSP_REF_FRM;
39262306a36Sopenharmony_ci	} else {
39362306a36Sopenharmony_ci		/* Produce P-frame */
39462306a36Sopenharmony_ci		tw_writel(TW5864_MOTION_SEARCH_ETC, TW5864_INTRA_EN |
39562306a36Sopenharmony_ci			  TW5864_ME_EN | BIT(5) /* SRCH_OPT default */);
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci	tw5864_prepare_frame_headers(input);
39862306a36Sopenharmony_ci	tw_writel(TW5864_VLC,
39962306a36Sopenharmony_ci		  TW5864_VLC_PCI_SEL |
40062306a36Sopenharmony_ci		  ((input->tail_nb_bits + 24) << TW5864_VLC_BIT_ALIGN_SHIFT) |
40162306a36Sopenharmony_ci		  input->reg_dsp_qp);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	enc_buf_id_new = tw_mask_shift_readl(TW5864_ENC_BUF_PTR_REC1, 0x3,
40462306a36Sopenharmony_ci					     2 * input->nr);
40562306a36Sopenharmony_ci	tw_writel(TW5864_DSP_ENC_ORG_PTR_REG,
40662306a36Sopenharmony_ci		  enc_buf_id_new << TW5864_DSP_ENC_ORG_PTR_SHIFT);
40762306a36Sopenharmony_ci	tw_writel(TW5864_DSP_ENC_REC,
40862306a36Sopenharmony_ci		  enc_buf_id_new << 12 | ((enc_buf_id_new + 3) & 3));
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	tw_writel(TW5864_SLICE, TW5864_START_NSLICE);
41162306a36Sopenharmony_ci	tw_writel(TW5864_SLICE, 0);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic int tw5864_disable_input(struct tw5864_input *input)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
41762306a36Sopenharmony_ci	unsigned long flags;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	dev_dbg(&dev->pci->dev, "Disabling channel %d\n", input->nr);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	spin_lock_irqsave(&dev->slock, flags);
42262306a36Sopenharmony_ci	input->enabled = 0;
42362306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->slock, flags);
42462306a36Sopenharmony_ci	return 0;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int tw5864_start_streaming(struct vb2_queue *q, unsigned int count)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct tw5864_input *input = vb2_get_drv_priv(q);
43062306a36Sopenharmony_ci	int ret;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	ret = tw5864_enable_input(input);
43362306a36Sopenharmony_ci	if (!ret)
43462306a36Sopenharmony_ci		return 0;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	while (!list_empty(&input->active)) {
43762306a36Sopenharmony_ci		struct tw5864_buf *buf = list_entry(input->active.next,
43862306a36Sopenharmony_ci						    struct tw5864_buf, list);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		list_del(&buf->list);
44162306a36Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci	return ret;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic void tw5864_stop_streaming(struct vb2_queue *q)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	unsigned long flags;
44962306a36Sopenharmony_ci	struct tw5864_input *input = vb2_get_drv_priv(q);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	tw5864_disable_input(input);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	spin_lock_irqsave(&input->slock, flags);
45462306a36Sopenharmony_ci	if (input->vb) {
45562306a36Sopenharmony_ci		vb2_buffer_done(&input->vb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
45662306a36Sopenharmony_ci		input->vb = NULL;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci	while (!list_empty(&input->active)) {
45962306a36Sopenharmony_ci		struct tw5864_buf *buf = list_entry(input->active.next,
46062306a36Sopenharmony_ci						    struct tw5864_buf, list);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		list_del(&buf->list);
46362306a36Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci	spin_unlock_irqrestore(&input->slock, flags);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic const struct vb2_ops tw5864_video_qops = {
46962306a36Sopenharmony_ci	.queue_setup = tw5864_queue_setup,
47062306a36Sopenharmony_ci	.buf_queue = tw5864_buf_queue,
47162306a36Sopenharmony_ci	.start_streaming = tw5864_start_streaming,
47262306a36Sopenharmony_ci	.stop_streaming = tw5864_stop_streaming,
47362306a36Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
47462306a36Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int tw5864_s_ctrl(struct v4l2_ctrl *ctrl)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct tw5864_input *input =
48062306a36Sopenharmony_ci		container_of(ctrl->handler, struct tw5864_input, hdl);
48162306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
48262306a36Sopenharmony_ci	unsigned long flags;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	switch (ctrl->id) {
48562306a36Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
48662306a36Sopenharmony_ci		tw_indir_writeb(TW5864_INDIR_VIN_A_BRIGHT(input->nr),
48762306a36Sopenharmony_ci				(u8)ctrl->val);
48862306a36Sopenharmony_ci		break;
48962306a36Sopenharmony_ci	case V4L2_CID_HUE:
49062306a36Sopenharmony_ci		tw_indir_writeb(TW5864_INDIR_VIN_7_HUE(input->nr),
49162306a36Sopenharmony_ci				(u8)ctrl->val);
49262306a36Sopenharmony_ci		break;
49362306a36Sopenharmony_ci	case V4L2_CID_CONTRAST:
49462306a36Sopenharmony_ci		tw_indir_writeb(TW5864_INDIR_VIN_9_CNTRST(input->nr),
49562306a36Sopenharmony_ci				(u8)ctrl->val);
49662306a36Sopenharmony_ci		break;
49762306a36Sopenharmony_ci	case V4L2_CID_SATURATION:
49862306a36Sopenharmony_ci		tw_indir_writeb(TW5864_INDIR_VIN_B_SAT_U(input->nr),
49962306a36Sopenharmony_ci				(u8)ctrl->val);
50062306a36Sopenharmony_ci		tw_indir_writeb(TW5864_INDIR_VIN_C_SAT_V(input->nr),
50162306a36Sopenharmony_ci				(u8)ctrl->val);
50262306a36Sopenharmony_ci		break;
50362306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
50462306a36Sopenharmony_ci		input->gop = ctrl->val;
50562306a36Sopenharmony_ci		return 0;
50662306a36Sopenharmony_ci	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
50762306a36Sopenharmony_ci		spin_lock_irqsave(&input->slock, flags);
50862306a36Sopenharmony_ci		input->qp = ctrl->val;
50962306a36Sopenharmony_ci		input->reg_dsp_qp = input->qp;
51062306a36Sopenharmony_ci		input->reg_dsp_ref_mvp_lambda = lambda_lookup_table[input->qp];
51162306a36Sopenharmony_ci		input->reg_dsp_i4x4_weight = intra4x4_lambda3[input->qp];
51262306a36Sopenharmony_ci		spin_unlock_irqrestore(&input->slock, flags);
51362306a36Sopenharmony_ci		return 0;
51462306a36Sopenharmony_ci	case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
51562306a36Sopenharmony_ci		memset(input->md_threshold_grid_values, ctrl->val,
51662306a36Sopenharmony_ci		       sizeof(input->md_threshold_grid_values));
51762306a36Sopenharmony_ci		return 0;
51862306a36Sopenharmony_ci	case V4L2_CID_DETECT_MD_MODE:
51962306a36Sopenharmony_ci		return 0;
52062306a36Sopenharmony_ci	case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
52162306a36Sopenharmony_ci		/* input->md_threshold_grid_ctrl->p_new.p_u16 contains data */
52262306a36Sopenharmony_ci		memcpy(input->md_threshold_grid_values,
52362306a36Sopenharmony_ci		       input->md_threshold_grid_ctrl->p_new.p_u16,
52462306a36Sopenharmony_ci		       sizeof(input->md_threshold_grid_values));
52562306a36Sopenharmony_ci		return 0;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int tw5864_fmt_vid_cap(struct file *file, void *priv,
53162306a36Sopenharmony_ci			      struct v4l2_format *f)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	f->fmt.pix.width = 704;
53662306a36Sopenharmony_ci	switch (input->std) {
53762306a36Sopenharmony_ci	default:
53862306a36Sopenharmony_ci		WARN_ON_ONCE(1);
53962306a36Sopenharmony_ci		return -EINVAL;
54062306a36Sopenharmony_ci	case STD_NTSC:
54162306a36Sopenharmony_ci		f->fmt.pix.height = 480;
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci	case STD_PAL:
54462306a36Sopenharmony_ci	case STD_SECAM:
54562306a36Sopenharmony_ci		f->fmt.pix.height = 576;
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
54962306a36Sopenharmony_ci	f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
55062306a36Sopenharmony_ci	f->fmt.pix.sizeimage = H264_VLC_BUF_SIZE;
55162306a36Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
55262306a36Sopenharmony_ci	return 0;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic int tw5864_enum_input(struct file *file, void *priv,
55662306a36Sopenharmony_ci			     struct v4l2_input *i)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
55962306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	u8 indir_0x000 = tw_indir_readb(TW5864_INDIR_VIN_0(input->nr));
56262306a36Sopenharmony_ci	u8 indir_0x00d = tw_indir_readb(TW5864_INDIR_VIN_D(input->nr));
56362306a36Sopenharmony_ci	u8 v1 = indir_0x000;
56462306a36Sopenharmony_ci	u8 v2 = indir_0x00d;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (i->index)
56762306a36Sopenharmony_ci		return -EINVAL;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	i->type = V4L2_INPUT_TYPE_CAMERA;
57062306a36Sopenharmony_ci	snprintf(i->name, sizeof(i->name), "Encoder %d", input->nr);
57162306a36Sopenharmony_ci	i->std = TW5864_NORMS;
57262306a36Sopenharmony_ci	if (v1 & (1 << 7))
57362306a36Sopenharmony_ci		i->status |= V4L2_IN_ST_NO_SYNC;
57462306a36Sopenharmony_ci	if (!(v1 & (1 << 6)))
57562306a36Sopenharmony_ci		i->status |= V4L2_IN_ST_NO_H_LOCK;
57662306a36Sopenharmony_ci	if (v1 & (1 << 2))
57762306a36Sopenharmony_ci		i->status |= V4L2_IN_ST_NO_SIGNAL;
57862306a36Sopenharmony_ci	if (v1 & (1 << 1))
57962306a36Sopenharmony_ci		i->status |= V4L2_IN_ST_NO_COLOR;
58062306a36Sopenharmony_ci	if (v2 & (1 << 2))
58162306a36Sopenharmony_ci		i->status |= V4L2_IN_ST_MACROVISION;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic int tw5864_g_input(struct file *file, void *priv, unsigned int *i)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	*i = 0;
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic int tw5864_s_input(struct file *file, void *priv, unsigned int i)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	if (i)
59562306a36Sopenharmony_ci		return -EINVAL;
59662306a36Sopenharmony_ci	return 0;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic int tw5864_querycap(struct file *file, void *priv,
60062306a36Sopenharmony_ci			   struct v4l2_capability *cap)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	strscpy(cap->driver, "tw5864", sizeof(cap->driver));
60562306a36Sopenharmony_ci	snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d",
60662306a36Sopenharmony_ci		 input->nr);
60762306a36Sopenharmony_ci	return 0;
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic int tw5864_querystd(struct file *file, void *priv, v4l2_std_id *std)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
61362306a36Sopenharmony_ci	enum tw5864_vid_std tw_std;
61462306a36Sopenharmony_ci	int ret;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	ret = tw5864_input_std_get(input, &tw_std);
61762306a36Sopenharmony_ci	if (ret)
61862306a36Sopenharmony_ci		return ret;
61962306a36Sopenharmony_ci	*std = tw5864_get_v4l2_std(tw_std);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	return 0;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic int tw5864_g_std(struct file *file, void *priv, v4l2_std_id *std)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	*std = input->v4l2_std;
62962306a36Sopenharmony_ci	return 0;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic int tw5864_s_std(struct file *file, void *priv, v4l2_std_id std)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
63562306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	input->v4l2_std = std;
63862306a36Sopenharmony_ci	input->std = tw5864_from_v4l2_std(std);
63962306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_VIN_E(input->nr), input->std);
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic int tw5864_enum_fmt_vid_cap(struct file *file, void *priv,
64462306a36Sopenharmony_ci				   struct v4l2_fmtdesc *f)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	if (f->index)
64762306a36Sopenharmony_ci		return -EINVAL;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	f->pixelformat = V4L2_PIX_FMT_H264;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return 0;
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic int tw5864_subscribe_event(struct v4l2_fh *fh,
65562306a36Sopenharmony_ci				  const struct v4l2_event_subscription *sub)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	switch (sub->type) {
65862306a36Sopenharmony_ci	case V4L2_EVENT_MOTION_DET:
65962306a36Sopenharmony_ci		/*
66062306a36Sopenharmony_ci		 * Allow for up to 30 events (1 second for NTSC) to be stored.
66162306a36Sopenharmony_ci		 */
66262306a36Sopenharmony_ci		return v4l2_event_subscribe(fh, sub, 30, NULL);
66362306a36Sopenharmony_ci	default:
66462306a36Sopenharmony_ci		return v4l2_ctrl_subscribe_event(fh, sub);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic void tw5864_frame_interval_set(struct tw5864_input *input)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	/*
67162306a36Sopenharmony_ci	 * This register value seems to follow such approach: In each second
67262306a36Sopenharmony_ci	 * interval, when processing Nth frame, it checks Nth bit of register
67362306a36Sopenharmony_ci	 * value and, if the bit is 1, it processes the frame, otherwise the
67462306a36Sopenharmony_ci	 * frame is discarded.
67562306a36Sopenharmony_ci	 * So unary representation would work, but more or less equal gaps
67662306a36Sopenharmony_ci	 * between the frames should be preserved.
67762306a36Sopenharmony_ci	 *
67862306a36Sopenharmony_ci	 * For 1 FPS - 0x00000001
67962306a36Sopenharmony_ci	 * 00000000 00000000 00000000 00000001
68062306a36Sopenharmony_ci	 *
68162306a36Sopenharmony_ci	 * For max FPS - set all 25/30 lower bits:
68262306a36Sopenharmony_ci	 * 00111111 11111111 11111111 11111111 (NTSC)
68362306a36Sopenharmony_ci	 * 00000001 11111111 11111111 11111111 (PAL)
68462306a36Sopenharmony_ci	 *
68562306a36Sopenharmony_ci	 * For half of max FPS - use such pattern:
68662306a36Sopenharmony_ci	 * 00010101 01010101 01010101 01010101 (NTSC)
68762306a36Sopenharmony_ci	 * 00000001 01010101 01010101 01010101 (PAL)
68862306a36Sopenharmony_ci	 *
68962306a36Sopenharmony_ci	 * Et cetera.
69062306a36Sopenharmony_ci	 *
69162306a36Sopenharmony_ci	 * The value supplied to hardware is capped by mask of 25/30 lower bits.
69262306a36Sopenharmony_ci	 */
69362306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
69462306a36Sopenharmony_ci	u32 unary_framerate = 0;
69562306a36Sopenharmony_ci	int shift = 0;
69662306a36Sopenharmony_ci	int std_max_fps = input->std == STD_NTSC ? 30 : 25;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	for (shift = 0; shift < std_max_fps; shift += input->frame_interval)
69962306a36Sopenharmony_ci		unary_framerate |= 0x00000001 << shift;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_RATE_CNTL_LO_WORD(input->nr, 0),
70262306a36Sopenharmony_ci		  unary_framerate >> 16);
70362306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_RATE_CNTL_HI_WORD(input->nr, 0),
70462306a36Sopenharmony_ci		  unary_framerate & 0xffff);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic int tw5864_frameinterval_get(struct tw5864_input *input,
70862306a36Sopenharmony_ci				    struct v4l2_fract *frameinterval)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	switch (input->std) {
71362306a36Sopenharmony_ci	case STD_NTSC:
71462306a36Sopenharmony_ci		frameinterval->numerator = 1001;
71562306a36Sopenharmony_ci		frameinterval->denominator = 30000;
71662306a36Sopenharmony_ci		break;
71762306a36Sopenharmony_ci	case STD_PAL:
71862306a36Sopenharmony_ci	case STD_SECAM:
71962306a36Sopenharmony_ci		frameinterval->numerator = 1;
72062306a36Sopenharmony_ci		frameinterval->denominator = 25;
72162306a36Sopenharmony_ci		break;
72262306a36Sopenharmony_ci	default:
72362306a36Sopenharmony_ci		dev_warn(&dev->pci->dev, "tw5864_frameinterval_get requested for unknown std %d\n",
72462306a36Sopenharmony_ci			 input->std);
72562306a36Sopenharmony_ci		return -EINVAL;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	return 0;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic int tw5864_enum_framesizes(struct file *file, void *priv,
73262306a36Sopenharmony_ci				  struct v4l2_frmsizeenum *fsize)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (fsize->index > 0)
73762306a36Sopenharmony_ci		return -EINVAL;
73862306a36Sopenharmony_ci	if (fsize->pixel_format != V4L2_PIX_FMT_H264)
73962306a36Sopenharmony_ci		return -EINVAL;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
74262306a36Sopenharmony_ci	fsize->discrete.width = 704;
74362306a36Sopenharmony_ci	fsize->discrete.height = input->std == STD_NTSC ? 480 : 576;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return 0;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic int tw5864_enum_frameintervals(struct file *file, void *priv,
74962306a36Sopenharmony_ci				      struct v4l2_frmivalenum *fintv)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
75262306a36Sopenharmony_ci	struct v4l2_fract frameinterval;
75362306a36Sopenharmony_ci	int std_max_fps = input->std == STD_NTSC ? 30 : 25;
75462306a36Sopenharmony_ci	struct v4l2_frmsizeenum fsize = { .index = fintv->index,
75562306a36Sopenharmony_ci		.pixel_format = fintv->pixel_format };
75662306a36Sopenharmony_ci	int ret;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	ret = tw5864_enum_framesizes(file, priv, &fsize);
75962306a36Sopenharmony_ci	if (ret)
76062306a36Sopenharmony_ci		return ret;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (fintv->width != fsize.discrete.width ||
76362306a36Sopenharmony_ci	    fintv->height != fsize.discrete.height)
76462306a36Sopenharmony_ci		return -EINVAL;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	ret = tw5864_frameinterval_get(input, &frameinterval);
76962306a36Sopenharmony_ci	if (ret)
77062306a36Sopenharmony_ci		return ret;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	fintv->stepwise.step = frameinterval;
77362306a36Sopenharmony_ci	fintv->stepwise.min = frameinterval;
77462306a36Sopenharmony_ci	fintv->stepwise.max = frameinterval;
77562306a36Sopenharmony_ci	fintv->stepwise.max.numerator *= std_max_fps;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int tw5864_g_parm(struct file *file, void *priv,
78162306a36Sopenharmony_ci			 struct v4l2_streamparm *sp)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
78462306a36Sopenharmony_ci	struct v4l2_captureparm *cp = &sp->parm.capture;
78562306a36Sopenharmony_ci	int ret;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	cp->capability = V4L2_CAP_TIMEPERFRAME;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	ret = tw5864_frameinterval_get(input, &cp->timeperframe);
79062306a36Sopenharmony_ci	if (ret)
79162306a36Sopenharmony_ci		return ret;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	cp->timeperframe.numerator *= input->frame_interval;
79462306a36Sopenharmony_ci	cp->capturemode = 0;
79562306a36Sopenharmony_ci	cp->readbuffers = 2;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return ret;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic int tw5864_s_parm(struct file *file, void *priv,
80162306a36Sopenharmony_ci			 struct v4l2_streamparm *sp)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
80462306a36Sopenharmony_ci	struct v4l2_fract *t = &sp->parm.capture.timeperframe;
80562306a36Sopenharmony_ci	struct v4l2_fract time_base;
80662306a36Sopenharmony_ci	int ret;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	ret = tw5864_frameinterval_get(input, &time_base);
80962306a36Sopenharmony_ci	if (ret)
81062306a36Sopenharmony_ci		return ret;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if (!t->numerator || !t->denominator) {
81362306a36Sopenharmony_ci		t->numerator = time_base.numerator * input->frame_interval;
81462306a36Sopenharmony_ci		t->denominator = time_base.denominator;
81562306a36Sopenharmony_ci	} else if (t->denominator != time_base.denominator) {
81662306a36Sopenharmony_ci		t->numerator = t->numerator * time_base.denominator /
81762306a36Sopenharmony_ci			t->denominator;
81862306a36Sopenharmony_ci		t->denominator = time_base.denominator;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	input->frame_interval = t->numerator / time_base.numerator;
82262306a36Sopenharmony_ci	if (input->frame_interval < 1)
82362306a36Sopenharmony_ci		input->frame_interval = 1;
82462306a36Sopenharmony_ci	tw5864_frame_interval_set(input);
82562306a36Sopenharmony_ci	return tw5864_g_parm(file, priv, sp);
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops tw5864_ctrl_ops = {
82962306a36Sopenharmony_ci	.s_ctrl = tw5864_s_ctrl,
83062306a36Sopenharmony_ci};
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic const struct v4l2_file_operations video_fops = {
83362306a36Sopenharmony_ci	.owner = THIS_MODULE,
83462306a36Sopenharmony_ci	.open = v4l2_fh_open,
83562306a36Sopenharmony_ci	.release = vb2_fop_release,
83662306a36Sopenharmony_ci	.read = vb2_fop_read,
83762306a36Sopenharmony_ci	.poll = vb2_fop_poll,
83862306a36Sopenharmony_ci	.mmap = vb2_fop_mmap,
83962306a36Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
84062306a36Sopenharmony_ci};
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci#define INDIR_SPACE_MAP_SHIFT 0x100000
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic int tw5864_g_reg(struct file *file, void *fh,
84762306a36Sopenharmony_ci			struct v4l2_dbg_register *reg)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
85062306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (reg->reg < INDIR_SPACE_MAP_SHIFT) {
85362306a36Sopenharmony_ci		if (reg->reg > 0x87fff)
85462306a36Sopenharmony_ci			return -EINVAL;
85562306a36Sopenharmony_ci		reg->size = 4;
85662306a36Sopenharmony_ci		reg->val = tw_readl(reg->reg);
85762306a36Sopenharmony_ci	} else {
85862306a36Sopenharmony_ci		__u64 indir_addr = reg->reg - INDIR_SPACE_MAP_SHIFT;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci		if (indir_addr > 0xefe)
86162306a36Sopenharmony_ci			return -EINVAL;
86262306a36Sopenharmony_ci		reg->size = 1;
86362306a36Sopenharmony_ci		reg->val = tw_indir_readb(reg->reg);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	return 0;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic int tw5864_s_reg(struct file *file, void *fh,
86962306a36Sopenharmony_ci			const struct v4l2_dbg_register *reg)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct tw5864_input *input = video_drvdata(file);
87262306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (reg->reg < INDIR_SPACE_MAP_SHIFT) {
87562306a36Sopenharmony_ci		if (reg->reg > 0x87fff)
87662306a36Sopenharmony_ci			return -EINVAL;
87762306a36Sopenharmony_ci		tw_writel(reg->reg, reg->val);
87862306a36Sopenharmony_ci	} else {
87962306a36Sopenharmony_ci		__u64 indir_addr = reg->reg - INDIR_SPACE_MAP_SHIFT;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		if (indir_addr > 0xefe)
88262306a36Sopenharmony_ci			return -EINVAL;
88362306a36Sopenharmony_ci		tw_indir_writeb(reg->reg, reg->val);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci	return 0;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci#endif
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops video_ioctl_ops = {
89062306a36Sopenharmony_ci	.vidioc_querycap = tw5864_querycap,
89162306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap = tw5864_enum_fmt_vid_cap,
89262306a36Sopenharmony_ci	.vidioc_reqbufs = vb2_ioctl_reqbufs,
89362306a36Sopenharmony_ci	.vidioc_create_bufs = vb2_ioctl_create_bufs,
89462306a36Sopenharmony_ci	.vidioc_querybuf = vb2_ioctl_querybuf,
89562306a36Sopenharmony_ci	.vidioc_qbuf = vb2_ioctl_qbuf,
89662306a36Sopenharmony_ci	.vidioc_dqbuf = vb2_ioctl_dqbuf,
89762306a36Sopenharmony_ci	.vidioc_expbuf = vb2_ioctl_expbuf,
89862306a36Sopenharmony_ci	.vidioc_querystd = tw5864_querystd,
89962306a36Sopenharmony_ci	.vidioc_s_std = tw5864_s_std,
90062306a36Sopenharmony_ci	.vidioc_g_std = tw5864_g_std,
90162306a36Sopenharmony_ci	.vidioc_enum_input = tw5864_enum_input,
90262306a36Sopenharmony_ci	.vidioc_g_input = tw5864_g_input,
90362306a36Sopenharmony_ci	.vidioc_s_input = tw5864_s_input,
90462306a36Sopenharmony_ci	.vidioc_streamon = vb2_ioctl_streamon,
90562306a36Sopenharmony_ci	.vidioc_streamoff = vb2_ioctl_streamoff,
90662306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap = tw5864_fmt_vid_cap,
90762306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap = tw5864_fmt_vid_cap,
90862306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap = tw5864_fmt_vid_cap,
90962306a36Sopenharmony_ci	.vidioc_log_status = v4l2_ctrl_log_status,
91062306a36Sopenharmony_ci	.vidioc_subscribe_event = tw5864_subscribe_event,
91162306a36Sopenharmony_ci	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
91262306a36Sopenharmony_ci	.vidioc_enum_framesizes = tw5864_enum_framesizes,
91362306a36Sopenharmony_ci	.vidioc_enum_frameintervals = tw5864_enum_frameintervals,
91462306a36Sopenharmony_ci	.vidioc_s_parm = tw5864_s_parm,
91562306a36Sopenharmony_ci	.vidioc_g_parm = tw5864_g_parm,
91662306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
91762306a36Sopenharmony_ci	.vidioc_g_register = tw5864_g_reg,
91862306a36Sopenharmony_ci	.vidioc_s_register = tw5864_s_reg,
91962306a36Sopenharmony_ci#endif
92062306a36Sopenharmony_ci};
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic const struct video_device tw5864_video_template = {
92362306a36Sopenharmony_ci	.name = "tw5864_video",
92462306a36Sopenharmony_ci	.fops = &video_fops,
92562306a36Sopenharmony_ci	.ioctl_ops = &video_ioctl_ops,
92662306a36Sopenharmony_ci	.release = video_device_release_empty,
92762306a36Sopenharmony_ci	.tvnorms = TW5864_NORMS,
92862306a36Sopenharmony_ci	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
92962306a36Sopenharmony_ci		V4L2_CAP_STREAMING,
93062306a36Sopenharmony_ci};
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/* Motion Detection Threshold matrix */
93362306a36Sopenharmony_cistatic const struct v4l2_ctrl_config tw5864_md_thresholds = {
93462306a36Sopenharmony_ci	.ops = &tw5864_ctrl_ops,
93562306a36Sopenharmony_ci	.id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
93662306a36Sopenharmony_ci	.dims = {MD_CELLS_HOR, MD_CELLS_VERT},
93762306a36Sopenharmony_ci	.def = 14,
93862306a36Sopenharmony_ci	/* See tw5864_md_metric_from_mvd() */
93962306a36Sopenharmony_ci	.max = 2 * 0x0f,
94062306a36Sopenharmony_ci	.step = 1,
94162306a36Sopenharmony_ci};
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic int tw5864_video_input_init(struct tw5864_input *dev, int video_nr);
94462306a36Sopenharmony_cistatic void tw5864_video_input_fini(struct tw5864_input *dev);
94562306a36Sopenharmony_cistatic void tw5864_encoder_tables_upload(struct tw5864_dev *dev);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ciint tw5864_video_init(struct tw5864_dev *dev, int *video_nr)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	int i;
95062306a36Sopenharmony_ci	int ret;
95162306a36Sopenharmony_ci	unsigned long flags;
95262306a36Sopenharmony_ci	int last_dma_allocated = -1;
95362306a36Sopenharmony_ci	int last_input_nr_registered = -1;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	for (i = 0; i < H264_BUF_CNT; i++) {
95662306a36Sopenharmony_ci		struct tw5864_h264_frame *frame = &dev->h264_buf[i];
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		frame->vlc.addr = dma_alloc_coherent(&dev->pci->dev,
95962306a36Sopenharmony_ci						     H264_VLC_BUF_SIZE,
96062306a36Sopenharmony_ci						     &frame->vlc.dma_addr,
96162306a36Sopenharmony_ci						     GFP_KERNEL | GFP_DMA32);
96262306a36Sopenharmony_ci		if (!frame->vlc.addr) {
96362306a36Sopenharmony_ci			dev_err(&dev->pci->dev, "dma alloc fail\n");
96462306a36Sopenharmony_ci			ret = -ENOMEM;
96562306a36Sopenharmony_ci			goto free_dma;
96662306a36Sopenharmony_ci		}
96762306a36Sopenharmony_ci		frame->mv.addr = dma_alloc_coherent(&dev->pci->dev,
96862306a36Sopenharmony_ci						    H264_MV_BUF_SIZE,
96962306a36Sopenharmony_ci						    &frame->mv.dma_addr,
97062306a36Sopenharmony_ci						    GFP_KERNEL | GFP_DMA32);
97162306a36Sopenharmony_ci		if (!frame->mv.addr) {
97262306a36Sopenharmony_ci			dev_err(&dev->pci->dev, "dma alloc fail\n");
97362306a36Sopenharmony_ci			ret = -ENOMEM;
97462306a36Sopenharmony_ci			dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE,
97562306a36Sopenharmony_ci					  frame->vlc.addr, frame->vlc.dma_addr);
97662306a36Sopenharmony_ci			goto free_dma;
97762306a36Sopenharmony_ci		}
97862306a36Sopenharmony_ci		last_dma_allocated = i;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	tw5864_encoder_tables_upload(dev);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* Picture is distorted without this block */
98462306a36Sopenharmony_ci	/* use falling edge to sample 54M to 108M */
98562306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_VD_108_POL, TW5864_INDIR_VD_108_POL_BOTH);
98662306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_CLK0_SEL, 0x00);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_DDRA_DLL_DQS_SEL0, 0x02);
98962306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_DDRA_DLL_DQS_SEL1, 0x02);
99062306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_DDRA_DLL_CLK90_SEL, 0x02);
99162306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_DDRB_DLL_DQS_SEL0, 0x02);
99262306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_DDRB_DLL_DQS_SEL1, 0x02);
99362306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_DDRB_DLL_CLK90_SEL, 0x02);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* video input reset */
99662306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_RESET, 0);
99762306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_RESET, TW5864_INDIR_RESET_VD |
99862306a36Sopenharmony_ci			TW5864_INDIR_RESET_DLL | TW5864_INDIR_RESET_MUX_CORE);
99962306a36Sopenharmony_ci	msleep(20);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	/*
100262306a36Sopenharmony_ci	 * Select Part A mode for all channels.
100362306a36Sopenharmony_ci	 * tw_setl instead of tw_clearl for Part B mode.
100462306a36Sopenharmony_ci	 *
100562306a36Sopenharmony_ci	 * I guess "Part B" is primarily for downscaled version of same channel
100662306a36Sopenharmony_ci	 * which goes in Part A of same bus
100762306a36Sopenharmony_ci	 */
100862306a36Sopenharmony_ci	tw_writel(TW5864_FULL_HALF_MODE_SEL, 0);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_PV_VD_CK_POL,
101162306a36Sopenharmony_ci			TW5864_INDIR_PV_VD_CK_POL_VD(0) |
101262306a36Sopenharmony_ci			TW5864_INDIR_PV_VD_CK_POL_VD(1) |
101362306a36Sopenharmony_ci			TW5864_INDIR_PV_VD_CK_POL_VD(2) |
101462306a36Sopenharmony_ci			TW5864_INDIR_PV_VD_CK_POL_VD(3));
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	spin_lock_irqsave(&dev->slock, flags);
101762306a36Sopenharmony_ci	dev->encoder_busy = 0;
101862306a36Sopenharmony_ci	dev->h264_buf_r_index = 0;
101962306a36Sopenharmony_ci	dev->h264_buf_w_index = 0;
102062306a36Sopenharmony_ci	tw_writel(TW5864_VLC_STREAM_BASE_ADDR,
102162306a36Sopenharmony_ci		  dev->h264_buf[dev->h264_buf_w_index].vlc.dma_addr);
102262306a36Sopenharmony_ci	tw_writel(TW5864_MV_STREAM_BASE_ADDR,
102362306a36Sopenharmony_ci		  dev->h264_buf[dev->h264_buf_w_index].mv.dma_addr);
102462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->slock, flags);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	tw_writel(TW5864_SEN_EN_CH, 0x000f);
102762306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_CH_EN, 0x000f);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_BUS0_MAP, 0x00000000);
103062306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_BUS1_MAP, 0x00001111);
103162306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_BUS2_MAP, 0x00002222);
103262306a36Sopenharmony_ci	tw_writel(TW5864_H264EN_BUS3_MAP, 0x00003333);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/*
103562306a36Sopenharmony_ci	 * Quote from Intersil (manufacturer):
103662306a36Sopenharmony_ci	 * 0x0038 is managed by HW, and by default it won't pass the pointer set
103762306a36Sopenharmony_ci	 * at 0x0010. So if you don't do encoding, 0x0038 should stay at '3'
103862306a36Sopenharmony_ci	 * (with 4 frames in buffer). If you encode one frame and then move
103962306a36Sopenharmony_ci	 * 0x0010 to '1' for example, HW will take one more frame and set it to
104062306a36Sopenharmony_ci	 * buffer #0, and then you should see 0x0038 is set to '0'.  There is
104162306a36Sopenharmony_ci	 * only one HW encoder engine, so 4 channels cannot get encoded
104262306a36Sopenharmony_ci	 * simultaneously. But each channel does have its own buffer (for
104362306a36Sopenharmony_ci	 * original frames and reconstructed frames). So there is no problem to
104462306a36Sopenharmony_ci	 * manage encoding for 4 channels at same time and no need to force
104562306a36Sopenharmony_ci	 * I-frames in switching channels.
104662306a36Sopenharmony_ci	 * End of quote.
104762306a36Sopenharmony_ci	 *
104862306a36Sopenharmony_ci	 * If we set 0x0010 (TW5864_ENC_BUF_PTR_REC1) to 0 (for any channel), we
104962306a36Sopenharmony_ci	 * have no "rolling" (until we change this value).
105062306a36Sopenharmony_ci	 * If we set 0x0010 (TW5864_ENC_BUF_PTR_REC1) to 0x3, it starts to roll
105162306a36Sopenharmony_ci	 * continuously together with 0x0038.
105262306a36Sopenharmony_ci	 */
105362306a36Sopenharmony_ci	tw_writel(TW5864_ENC_BUF_PTR_REC1, 0x00ff);
105462306a36Sopenharmony_ci	tw_writel(TW5864_PCI_INTTM_SCALE, 0);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	tw_writel(TW5864_INTERLACING, TW5864_DI_EN);
105762306a36Sopenharmony_ci	tw_writel(TW5864_MASTER_ENB_REG, TW5864_PCI_VLC_INTR_ENB);
105862306a36Sopenharmony_ci	tw_writel(TW5864_PCI_INTR_CTL,
105962306a36Sopenharmony_ci		  TW5864_TIMER_INTR_ENB | TW5864_PCI_MAST_ENB |
106062306a36Sopenharmony_ci		  TW5864_MVD_VLC_MAST_ENB);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER;
106362306a36Sopenharmony_ci	tw5864_irqmask_apply(dev);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	tasklet_setup(&dev->tasklet, tw5864_handle_frame_task);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	for (i = 0; i < TW5864_INPUTS; i++) {
106862306a36Sopenharmony_ci		dev->inputs[i].root = dev;
106962306a36Sopenharmony_ci		dev->inputs[i].nr = i;
107062306a36Sopenharmony_ci		ret = tw5864_video_input_init(&dev->inputs[i], video_nr[i]);
107162306a36Sopenharmony_ci		if (ret)
107262306a36Sopenharmony_ci			goto fini_video_inputs;
107362306a36Sopenharmony_ci		last_input_nr_registered = i;
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cifini_video_inputs:
107962306a36Sopenharmony_ci	for (i = last_input_nr_registered; i >= 0; i--)
108062306a36Sopenharmony_ci		tw5864_video_input_fini(&dev->inputs[i]);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	tasklet_kill(&dev->tasklet);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cifree_dma:
108562306a36Sopenharmony_ci	for (i = last_dma_allocated; i >= 0; i--) {
108662306a36Sopenharmony_ci		dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE,
108762306a36Sopenharmony_ci				  dev->h264_buf[i].vlc.addr,
108862306a36Sopenharmony_ci				  dev->h264_buf[i].vlc.dma_addr);
108962306a36Sopenharmony_ci		dma_free_coherent(&dev->pci->dev, H264_MV_BUF_SIZE,
109062306a36Sopenharmony_ci				  dev->h264_buf[i].mv.addr,
109162306a36Sopenharmony_ci				  dev->h264_buf[i].mv.dma_addr);
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return ret;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_cistatic int tw5864_video_input_init(struct tw5864_input *input, int video_nr)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
110062306a36Sopenharmony_ci	int ret;
110162306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &input->hdl;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	mutex_init(&input->lock);
110462306a36Sopenharmony_ci	spin_lock_init(&input->slock);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	/* setup video buffers queue */
110762306a36Sopenharmony_ci	INIT_LIST_HEAD(&input->active);
110862306a36Sopenharmony_ci	input->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
110962306a36Sopenharmony_ci	input->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
111062306a36Sopenharmony_ci	input->vidq.io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
111162306a36Sopenharmony_ci	input->vidq.ops = &tw5864_video_qops;
111262306a36Sopenharmony_ci	input->vidq.mem_ops = &vb2_dma_contig_memops;
111362306a36Sopenharmony_ci	input->vidq.drv_priv = input;
111462306a36Sopenharmony_ci	input->vidq.gfp_flags = 0;
111562306a36Sopenharmony_ci	input->vidq.buf_struct_size = sizeof(struct tw5864_buf);
111662306a36Sopenharmony_ci	input->vidq.lock = &input->lock;
111762306a36Sopenharmony_ci	input->vidq.min_buffers_needed = 2;
111862306a36Sopenharmony_ci	input->vidq.dev = &input->root->pci->dev;
111962306a36Sopenharmony_ci	ret = vb2_queue_init(&input->vidq);
112062306a36Sopenharmony_ci	if (ret)
112162306a36Sopenharmony_ci		goto free_mutex;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	input->vdev = tw5864_video_template;
112462306a36Sopenharmony_ci	input->vdev.v4l2_dev = &input->root->v4l2_dev;
112562306a36Sopenharmony_ci	input->vdev.lock = &input->lock;
112662306a36Sopenharmony_ci	input->vdev.queue = &input->vidq;
112762306a36Sopenharmony_ci	video_set_drvdata(&input->vdev, input);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* Initialize the device control structures */
113062306a36Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 6);
113162306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops,
113262306a36Sopenharmony_ci			  V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
113362306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops,
113462306a36Sopenharmony_ci			  V4L2_CID_CONTRAST, 0, 255, 1, 100);
113562306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops,
113662306a36Sopenharmony_ci			  V4L2_CID_SATURATION, 0, 255, 1, 128);
113762306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, V4L2_CID_HUE, -128, 127, 1, 0);
113862306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
113962306a36Sopenharmony_ci			  1, MAX_GOP_SIZE, 1, GOP_SIZE);
114062306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops,
114162306a36Sopenharmony_ci			  V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 28, 51, 1, QP_VALUE);
114262306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu(hdl, &tw5864_ctrl_ops,
114362306a36Sopenharmony_ci			       V4L2_CID_DETECT_MD_MODE,
114462306a36Sopenharmony_ci			       V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
114562306a36Sopenharmony_ci			       V4L2_DETECT_MD_MODE_DISABLED);
114662306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops,
114762306a36Sopenharmony_ci			  V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD,
114862306a36Sopenharmony_ci			  tw5864_md_thresholds.min, tw5864_md_thresholds.max,
114962306a36Sopenharmony_ci			  tw5864_md_thresholds.step, tw5864_md_thresholds.def);
115062306a36Sopenharmony_ci	input->md_threshold_grid_ctrl =
115162306a36Sopenharmony_ci		v4l2_ctrl_new_custom(hdl, &tw5864_md_thresholds, NULL);
115262306a36Sopenharmony_ci	if (hdl->error) {
115362306a36Sopenharmony_ci		ret = hdl->error;
115462306a36Sopenharmony_ci		goto free_v4l2_hdl;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci	input->vdev.ctrl_handler = hdl;
115762306a36Sopenharmony_ci	v4l2_ctrl_handler_setup(hdl);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	input->qp = QP_VALUE;
116062306a36Sopenharmony_ci	input->gop = GOP_SIZE;
116162306a36Sopenharmony_ci	input->frame_interval = 1;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	ret = video_register_device(&input->vdev, VFL_TYPE_VIDEO, video_nr);
116462306a36Sopenharmony_ci	if (ret)
116562306a36Sopenharmony_ci		goto free_v4l2_hdl;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	dev_info(&input->root->pci->dev, "Registered video device %s\n",
116862306a36Sopenharmony_ci		 video_device_node_name(&input->vdev));
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	/*
117162306a36Sopenharmony_ci	 * Set default video standard. Doesn't matter which, the detected value
117262306a36Sopenharmony_ci	 * will be found out by VIDIOC_QUERYSTD handler.
117362306a36Sopenharmony_ci	 */
117462306a36Sopenharmony_ci	input->v4l2_std = V4L2_STD_NTSC_M;
117562306a36Sopenharmony_ci	input->std = STD_NTSC;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_VIN_E(video_nr), 0x07);
117862306a36Sopenharmony_ci	/* to initiate auto format recognition */
117962306a36Sopenharmony_ci	tw_indir_writeb(TW5864_INDIR_VIN_F(video_nr), 0xff);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	return 0;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cifree_v4l2_hdl:
118462306a36Sopenharmony_ci	v4l2_ctrl_handler_free(hdl);
118562306a36Sopenharmony_cifree_mutex:
118662306a36Sopenharmony_ci	mutex_destroy(&input->lock);
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return ret;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic void tw5864_video_input_fini(struct tw5864_input *dev)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	vb2_video_unregister_device(&dev->vdev);
119462306a36Sopenharmony_ci	v4l2_ctrl_handler_free(&dev->hdl);
119562306a36Sopenharmony_ci}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_civoid tw5864_video_fini(struct tw5864_dev *dev)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	int i;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	tasklet_kill(&dev->tasklet);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	for (i = 0; i < TW5864_INPUTS; i++)
120462306a36Sopenharmony_ci		tw5864_video_input_fini(&dev->inputs[i]);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	for (i = 0; i < H264_BUF_CNT; i++) {
120762306a36Sopenharmony_ci		dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE,
120862306a36Sopenharmony_ci				  dev->h264_buf[i].vlc.addr,
120962306a36Sopenharmony_ci				  dev->h264_buf[i].vlc.dma_addr);
121062306a36Sopenharmony_ci		dma_free_coherent(&dev->pci->dev, H264_MV_BUF_SIZE,
121162306a36Sopenharmony_ci				  dev->h264_buf[i].mv.addr,
121262306a36Sopenharmony_ci				  dev->h264_buf[i].mv.dma_addr);
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_civoid tw5864_prepare_frame_headers(struct tw5864_input *input)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	struct tw5864_buf *vb = input->vb;
121962306a36Sopenharmony_ci	u8 *dst;
122062306a36Sopenharmony_ci	size_t dst_space;
122162306a36Sopenharmony_ci	unsigned long flags;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (!vb) {
122462306a36Sopenharmony_ci		spin_lock_irqsave(&input->slock, flags);
122562306a36Sopenharmony_ci		if (list_empty(&input->active)) {
122662306a36Sopenharmony_ci			spin_unlock_irqrestore(&input->slock, flags);
122762306a36Sopenharmony_ci			input->vb = NULL;
122862306a36Sopenharmony_ci			return;
122962306a36Sopenharmony_ci		}
123062306a36Sopenharmony_ci		vb = list_first_entry(&input->active, struct tw5864_buf, list);
123162306a36Sopenharmony_ci		list_del(&vb->list);
123262306a36Sopenharmony_ci		spin_unlock_irqrestore(&input->slock, flags);
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	dst = vb2_plane_vaddr(&vb->vb.vb2_buf, 0);
123662306a36Sopenharmony_ci	dst_space = vb2_plane_size(&vb->vb.vb2_buf, 0);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	/*
123962306a36Sopenharmony_ci	 * Low-level bitstream writing functions don't have a fine way to say
124062306a36Sopenharmony_ci	 * correctly that supplied buffer is too small. So we just check there
124162306a36Sopenharmony_ci	 * and warn, and don't care at lower level.
124262306a36Sopenharmony_ci	 * Currently all headers take below 32 bytes.
124362306a36Sopenharmony_ci	 * The buffer is supposed to have plenty of free space at this point,
124462306a36Sopenharmony_ci	 * anyway.
124562306a36Sopenharmony_ci	 */
124662306a36Sopenharmony_ci	if (WARN_ON_ONCE(dst_space < 128))
124762306a36Sopenharmony_ci		return;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/*
125062306a36Sopenharmony_ci	 * Generate H264 headers:
125162306a36Sopenharmony_ci	 * If this is first frame, put SPS and PPS
125262306a36Sopenharmony_ci	 */
125362306a36Sopenharmony_ci	if (input->frame_gop_seqno == 0)
125462306a36Sopenharmony_ci		tw5864_h264_put_stream_header(&dst, &dst_space, input->qp,
125562306a36Sopenharmony_ci					      input->width, input->height);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	/* Put slice header */
125862306a36Sopenharmony_ci	tw5864_h264_put_slice_header(&dst, &dst_space, input->h264_idr_pic_id,
125962306a36Sopenharmony_ci				     input->frame_gop_seqno,
126062306a36Sopenharmony_ci				     &input->tail_nb_bits, &input->tail);
126162306a36Sopenharmony_ci	input->vb = vb;
126262306a36Sopenharmony_ci	input->buf_cur_ptr = dst;
126362306a36Sopenharmony_ci	input->buf_cur_space_left = dst_space;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci/*
126762306a36Sopenharmony_ci * Returns heuristic motion detection metric value from known components of
126862306a36Sopenharmony_ci * hardware-provided Motion Vector Data.
126962306a36Sopenharmony_ci */
127062306a36Sopenharmony_cistatic unsigned int tw5864_md_metric_from_mvd(u32 mvd)
127162306a36Sopenharmony_ci{
127262306a36Sopenharmony_ci	/*
127362306a36Sopenharmony_ci	 * Format of motion vector data exposed by tw5864, according to
127462306a36Sopenharmony_ci	 * manufacturer:
127562306a36Sopenharmony_ci	 * mv_x 10 bits
127662306a36Sopenharmony_ci	 * mv_y 10 bits
127762306a36Sopenharmony_ci	 * non_zero_members 8 bits
127862306a36Sopenharmony_ci	 * mb_type 3 bits
127962306a36Sopenharmony_ci	 * reserved 1 bit
128062306a36Sopenharmony_ci	 *
128162306a36Sopenharmony_ci	 * non_zero_members: number of non-zero residuals in each macro block
128262306a36Sopenharmony_ci	 * after quantization
128362306a36Sopenharmony_ci	 *
128462306a36Sopenharmony_ci	 * unsigned int reserved = mvd >> 31;
128562306a36Sopenharmony_ci	 * unsigned int mb_type = (mvd >> 28) & 0x7;
128662306a36Sopenharmony_ci	 * unsigned int non_zero_members = (mvd >> 20) & 0xff;
128762306a36Sopenharmony_ci	 */
128862306a36Sopenharmony_ci	unsigned int mv_y = (mvd >> 10) & 0x3ff;
128962306a36Sopenharmony_ci	unsigned int mv_x = mvd & 0x3ff;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	/* heuristic: */
129262306a36Sopenharmony_ci	mv_x &= 0x0f;
129362306a36Sopenharmony_ci	mv_y &= 0x0f;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	return mv_y + mv_x;
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct tw5864_input *input = frame->input;
130162306a36Sopenharmony_ci	u32 *mv = (u32 *)frame->mv.addr;
130262306a36Sopenharmony_ci	int i;
130362306a36Sopenharmony_ci	int detected = 0;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	for (i = 0; i < MD_CELLS; i++) {
130662306a36Sopenharmony_ci		const u16 thresh = input->md_threshold_grid_values[i];
130762306a36Sopenharmony_ci		const unsigned int metric = tw5864_md_metric_from_mvd(mv[i]);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci		if (metric > thresh)
131062306a36Sopenharmony_ci			detected = 1;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci		if (detected)
131362306a36Sopenharmony_ci			break;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci	return detected;
131662306a36Sopenharmony_ci}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic void tw5864_handle_frame_task(struct tasklet_struct *t)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct tw5864_dev *dev = from_tasklet(dev, t, tasklet);
132162306a36Sopenharmony_ci	unsigned long flags;
132262306a36Sopenharmony_ci	int batch_size = H264_BUF_CNT;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	spin_lock_irqsave(&dev->slock, flags);
132562306a36Sopenharmony_ci	while (dev->h264_buf_r_index != dev->h264_buf_w_index && batch_size--) {
132662306a36Sopenharmony_ci		struct tw5864_h264_frame *frame =
132762306a36Sopenharmony_ci			&dev->h264_buf[dev->h264_buf_r_index];
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci		spin_unlock_irqrestore(&dev->slock, flags);
133062306a36Sopenharmony_ci		dma_sync_single_for_cpu(&dev->pci->dev, frame->vlc.dma_addr,
133162306a36Sopenharmony_ci					H264_VLC_BUF_SIZE, DMA_FROM_DEVICE);
133262306a36Sopenharmony_ci		dma_sync_single_for_cpu(&dev->pci->dev, frame->mv.dma_addr,
133362306a36Sopenharmony_ci					H264_MV_BUF_SIZE, DMA_FROM_DEVICE);
133462306a36Sopenharmony_ci		tw5864_handle_frame(frame);
133562306a36Sopenharmony_ci		dma_sync_single_for_device(&dev->pci->dev, frame->vlc.dma_addr,
133662306a36Sopenharmony_ci					   H264_VLC_BUF_SIZE, DMA_FROM_DEVICE);
133762306a36Sopenharmony_ci		dma_sync_single_for_device(&dev->pci->dev, frame->mv.dma_addr,
133862306a36Sopenharmony_ci					   H264_MV_BUF_SIZE, DMA_FROM_DEVICE);
133962306a36Sopenharmony_ci		spin_lock_irqsave(&dev->slock, flags);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci		dev->h264_buf_r_index++;
134262306a36Sopenharmony_ci		dev->h264_buf_r_index %= H264_BUF_CNT;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->slock, flags);
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci#ifdef DEBUG
134862306a36Sopenharmony_cistatic u32 tw5864_vlc_checksum(u32 *data, int len)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	u32 val, count_len = len;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	val = *data++;
135362306a36Sopenharmony_ci	while (((count_len >> 2) - 1) > 0) {
135462306a36Sopenharmony_ci		val ^= *data++;
135562306a36Sopenharmony_ci		count_len -= 4;
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci	val ^= htonl((len >> 2));
135862306a36Sopenharmony_ci	return val;
135962306a36Sopenharmony_ci}
136062306a36Sopenharmony_ci#endif
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cistatic void tw5864_handle_frame(struct tw5864_h264_frame *frame)
136362306a36Sopenharmony_ci{
136462306a36Sopenharmony_ci#define SKIP_VLCBUF_BYTES 3
136562306a36Sopenharmony_ci	struct tw5864_input *input = frame->input;
136662306a36Sopenharmony_ci	struct tw5864_dev *dev = input->root;
136762306a36Sopenharmony_ci	struct tw5864_buf *vb;
136862306a36Sopenharmony_ci	struct vb2_v4l2_buffer *v4l2_buf;
136962306a36Sopenharmony_ci	int frame_len = frame->vlc_len - SKIP_VLCBUF_BYTES;
137062306a36Sopenharmony_ci	u8 *dst = input->buf_cur_ptr;
137162306a36Sopenharmony_ci	u8 tail_mask, vlc_mask = 0;
137262306a36Sopenharmony_ci	int i;
137362306a36Sopenharmony_ci	u8 vlc_first_byte = ((u8 *)(frame->vlc.addr + SKIP_VLCBUF_BYTES))[0];
137462306a36Sopenharmony_ci	unsigned long flags;
137562306a36Sopenharmony_ci	int zero_run;
137662306a36Sopenharmony_ci	u8 *src;
137762306a36Sopenharmony_ci	u8 *src_end;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci#ifdef DEBUG
138062306a36Sopenharmony_ci	if (frame->checksum !=
138162306a36Sopenharmony_ci	    tw5864_vlc_checksum((u32 *)frame->vlc.addr, frame_len))
138262306a36Sopenharmony_ci		dev_err(&dev->pci->dev,
138362306a36Sopenharmony_ci			"Checksum of encoded frame doesn't match!\n");
138462306a36Sopenharmony_ci#endif
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	spin_lock_irqsave(&input->slock, flags);
138762306a36Sopenharmony_ci	vb = input->vb;
138862306a36Sopenharmony_ci	input->vb = NULL;
138962306a36Sopenharmony_ci	spin_unlock_irqrestore(&input->slock, flags);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	if (!vb) { /* Gone because of disabling */
139262306a36Sopenharmony_ci		dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n");
139362306a36Sopenharmony_ci		return;
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/*
139962306a36Sopenharmony_ci	 * Check for space.
140062306a36Sopenharmony_ci	 * Mind the overhead of startcode emulation prevention.
140162306a36Sopenharmony_ci	 */
140262306a36Sopenharmony_ci	if (input->buf_cur_space_left < frame_len * 5 / 4) {
140362306a36Sopenharmony_ci		dev_err_once(&dev->pci->dev,
140462306a36Sopenharmony_ci			     "Left space in vb2 buffer, %d bytes, is less than considered safely enough to put frame of length %d. Dropping this frame.\n",
140562306a36Sopenharmony_ci			     input->buf_cur_space_left, frame_len);
140662306a36Sopenharmony_ci		return;
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	for (i = 0; i < 8 - input->tail_nb_bits; i++)
141062306a36Sopenharmony_ci		vlc_mask |= 1 << i;
141162306a36Sopenharmony_ci	tail_mask = (~vlc_mask) & 0xff;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	dst[0] = (input->tail & tail_mask) | (vlc_first_byte & vlc_mask);
141462306a36Sopenharmony_ci	frame_len--;
141562306a36Sopenharmony_ci	dst++;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	/* H.264 startcode emulation prevention */
141862306a36Sopenharmony_ci	src = frame->vlc.addr + SKIP_VLCBUF_BYTES + 1;
141962306a36Sopenharmony_ci	src_end = src + frame_len;
142062306a36Sopenharmony_ci	zero_run = 0;
142162306a36Sopenharmony_ci	for (; src < src_end; src++) {
142262306a36Sopenharmony_ci		if (zero_run < 2) {
142362306a36Sopenharmony_ci			if (*src == 0)
142462306a36Sopenharmony_ci				++zero_run;
142562306a36Sopenharmony_ci			else
142662306a36Sopenharmony_ci				zero_run = 0;
142762306a36Sopenharmony_ci		} else {
142862306a36Sopenharmony_ci			if ((*src & ~0x03) == 0)
142962306a36Sopenharmony_ci				*dst++ = 0x03;
143062306a36Sopenharmony_ci			zero_run = *src == 0;
143162306a36Sopenharmony_ci		}
143262306a36Sopenharmony_ci		*dst++ = *src;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	vb2_set_plane_payload(&vb->vb.vb2_buf, 0,
143662306a36Sopenharmony_ci			      dst - (u8 *)vb2_plane_vaddr(&vb->vb.vb2_buf, 0));
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	vb->vb.vb2_buf.timestamp = frame->timestamp;
143962306a36Sopenharmony_ci	v4l2_buf->field = V4L2_FIELD_INTERLACED;
144062306a36Sopenharmony_ci	v4l2_buf->sequence = frame->seqno;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	/* Check for motion flags */
144362306a36Sopenharmony_ci	if (frame->gop_seqno /* P-frame */ &&
144462306a36Sopenharmony_ci	    tw5864_is_motion_triggered(frame)) {
144562306a36Sopenharmony_ci		struct v4l2_event ev = {
144662306a36Sopenharmony_ci			.type = V4L2_EVENT_MOTION_DET,
144762306a36Sopenharmony_ci			.u.motion_det = {
144862306a36Sopenharmony_ci				.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
144962306a36Sopenharmony_ci				.frame_sequence = v4l2_buf->sequence,
145062306a36Sopenharmony_ci			},
145162306a36Sopenharmony_ci		};
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci		v4l2_event_queue(&input->vdev, &ev);
145462306a36Sopenharmony_ci	}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	switch (std) {
146262306a36Sopenharmony_ci	case STD_NTSC:    return V4L2_STD_NTSC_M;
146362306a36Sopenharmony_ci	case STD_PAL:     return V4L2_STD_PAL_B;
146462306a36Sopenharmony_ci	case STD_SECAM:   return V4L2_STD_SECAM_B;
146562306a36Sopenharmony_ci	case STD_NTSC443: return V4L2_STD_NTSC_443;
146662306a36Sopenharmony_ci	case STD_PAL_M:   return V4L2_STD_PAL_M;
146762306a36Sopenharmony_ci	case STD_PAL_CN:  return V4L2_STD_PAL_Nc;
146862306a36Sopenharmony_ci	case STD_PAL_60:  return V4L2_STD_PAL_60;
146962306a36Sopenharmony_ci	case STD_INVALID: return V4L2_STD_UNKNOWN;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci	return 0;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_NTSC_M)
147762306a36Sopenharmony_ci		return STD_NTSC;
147862306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_PAL_B)
147962306a36Sopenharmony_ci		return STD_PAL;
148062306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_SECAM_B)
148162306a36Sopenharmony_ci		return STD_SECAM;
148262306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_NTSC_443)
148362306a36Sopenharmony_ci		return STD_NTSC443;
148462306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_PAL_M)
148562306a36Sopenharmony_ci		return STD_PAL_M;
148662306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_PAL_Nc)
148762306a36Sopenharmony_ci		return STD_PAL_CN;
148862306a36Sopenharmony_ci	if (v4l2_std & V4L2_STD_PAL_60)
148962306a36Sopenharmony_ci		return STD_PAL_60;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	return STD_INVALID;
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic void tw5864_encoder_tables_upload(struct tw5864_dev *dev)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	int i;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	tw_writel(TW5864_VLC_RD, 0x1);
149962306a36Sopenharmony_ci	for (i = 0; i < VLC_LOOKUP_TABLE_LEN; i++) {
150062306a36Sopenharmony_ci		tw_writel((TW5864_VLC_STREAM_MEM_START + i * 4),
150162306a36Sopenharmony_ci			  encoder_vlc_lookup_table[i]);
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci	tw_writel(TW5864_VLC_RD, 0x0);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	for (i = 0; i < QUANTIZATION_TABLE_LEN; i++) {
150662306a36Sopenharmony_ci		tw_writel((TW5864_QUAN_TAB + i * 4),
150762306a36Sopenharmony_ci			  forward_quantization_table[i]);
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	for (i = 0; i < QUANTIZATION_TABLE_LEN; i++) {
151162306a36Sopenharmony_ci		tw_writel((TW5864_QUAN_TAB + i * 4),
151262306a36Sopenharmony_ci			  inverse_quantization_table[i]);
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci}
1515