File Index
Files and directories
Sign in
FILE

mali-c55-resizer.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ARM Mali-C55 ISP Driver - Image signal processor
   4 *
   5 * Copyright (C) 2025 Ideas on Board Oy
   6 */
   7
   8#include <linux/math.h>
   9#include <linux/minmax.h>
  10
  11#include <media/media-entity.h>
  12#include <media/v4l2-subdev.h>
  13
  14#include "mali-c55-common.h"
  15#include "mali-c55-registers.h"
  16
  17/* Scaling factor in Q4.20 format. */
  18#define MALI_C55_RSZ_SCALER_FACTOR	(1U << 20)
  19
  20#define MALI_C55_RSZ_COEFS_BANKS	8
  21#define MALI_C55_RSZ_COEFS_ENTRIES	64
  22
  23static inline struct mali_c55_resizer *
  24sd_to_mali_c55_rsz(struct v4l2_subdev *sd)
  25{
  26	return container_of(sd, struct mali_c55_resizer, sd);
  27}
  28
  29static const unsigned int
  30mali_c55_rsz_filter_coeffs_h[MALI_C55_RSZ_COEFS_BANKS]
  31			    [MALI_C55_RSZ_COEFS_ENTRIES] = {
  32	{	/* Bank 0 */
  33		0x24fc0000, 0x0000fc24, 0x27fc0000, 0x0000fc21,
  34		0x28fc0000, 0x0000fd1f, 0x2cfb0000, 0x0000fd1c,
  35		0x2efb0000, 0x0000fd1a, 0x30fb0000, 0x0000fe17,
  36		0x32fb0000, 0x0000fe15, 0x35fb0000, 0x0000fe12,
  37		0x35fc0000, 0x0000ff10, 0x37fc0000, 0x0000ff0e,
  38		0x39fc0000, 0x0000ff0c, 0x3afd0000, 0x0000ff0a,
  39		0x3afe0000, 0x00000008, 0x3cfe0000, 0x00000006,
  40		0x3dff0000, 0x00000004, 0x3d000000, 0x00000003,
  41		0x3c020000, 0x00000002, 0x3d030000, 0x00000000,
  42		0x3d040000, 0x000000ff, 0x3c060000, 0x000000fe,
  43		0x3a080000, 0x000000fe, 0x3a0aff00, 0x000000fd,
  44		0x390cff00, 0x000000fc, 0x370eff00, 0x000000fc,
  45		0x3510ff00, 0x000000fc, 0x3512fe00, 0x000000fb,
  46		0x3215fe00, 0x000000fb, 0x3017fe00, 0x000000fb,
  47		0x2e1afd00, 0x000000fb, 0x2c1cfd00, 0x000000fb,
  48		0x281ffd00, 0x000000fc, 0x2721fc00, 0x000000fc,
  49	},
  50	{	/* Bank 1 */
  51		0x25fb0000, 0x0000fb25, 0x27fb0000, 0x0000fb23,
  52		0x29fb0000, 0x0000fb21, 0x2afc0000, 0x0000fb1f,
  53		0x2cfc0000, 0x0000fb1d, 0x2efc0000, 0x0000fb1b,
  54		0x2ffd0000, 0x0000fb19, 0x2ffe0000, 0x0000fc17,
  55		0x31fe0000, 0x0000fc15, 0x32ff0000, 0x0000fc13,
  56		0x3400ff00, 0x0000fc11, 0x3301ff00, 0x0000fd10,
  57		0x3402ff00, 0x0000fd0e, 0x3503ff00, 0x0000fd0c,
  58		0x3505ff00, 0x0000fd0a, 0x3506fe00, 0x0000fe09,
  59		0x3607fe00, 0x0000fe07, 0x3509fe00, 0x0000fe06,
  60		0x350afd00, 0x0000ff05, 0x350cfd00, 0x0000ff03,
  61		0x340efd00, 0x0000ff02, 0x3310fd00, 0x0000ff01,
  62		0x3411fc00, 0x0000ff00, 0x3213fc00, 0x000000ff,
  63		0x3115fc00, 0x000000fe, 0x2f17fc00, 0x000000fe,
  64		0x2f19fb00, 0x000000fd, 0x2e1bfb00, 0x000000fc,
  65		0x2c1dfb00, 0x000000fc, 0x2a1ffb00, 0x000000fc,
  66		0x2921fb00, 0x000000fb, 0x2723fb00, 0x000000fb,
  67	},
  68	{	/* Bank 2 */
  69		0x1f010000, 0x0000011f, 0x21010000, 0x0000001e,
  70		0x21020000, 0x0000001d, 0x22020000, 0x0000001c,
  71		0x23030000, 0x0000ff1b, 0x2404ff00, 0x0000ff1a,
  72		0x2504ff00, 0x0000ff19, 0x2505ff00, 0x0000ff18,
  73		0x2606ff00, 0x0000fe17, 0x2607ff00, 0x0000fe16,
  74		0x2708ff00, 0x0000fe14, 0x2709ff00, 0x0000fe13,
  75		0x270aff00, 0x0000fe12, 0x280bfe00, 0x0000fe11,
  76		0x280cfe00, 0x0000fe10, 0x280dfe00, 0x0000fe0f,
  77		0x280efe00, 0x0000fe0e, 0x280ffe00, 0x0000fe0d,
  78		0x2810fe00, 0x0000fe0c, 0x2811fe00, 0x0000fe0b,
  79		0x2712fe00, 0x0000ff0a, 0x2713fe00, 0x0000ff09,
  80		0x2714fe00, 0x0000ff08, 0x2616fe00, 0x0000ff07,
  81		0x2617fe00, 0x0000ff06, 0x2518ff00, 0x0000ff05,
  82		0x2519ff00, 0x0000ff04, 0x241aff00, 0x0000ff04,
  83		0x231bff00, 0x00000003, 0x221c0000, 0x00000002,
  84		0x211d0000, 0x00000002, 0x211e0000, 0x00000001,
  85	},
  86	{	/* Bank 3 */
  87		0x1b06ff00, 0x00ff061b, 0x1b07ff00, 0x00ff061a,
  88		0x1c07ff00, 0x00ff051a, 0x1c08ff00, 0x00ff0519,
  89		0x1c09ff00, 0x00ff0419, 0x1d09ff00, 0x00ff0418,
  90		0x1e0aff00, 0x00ff0317, 0x1e0aff00, 0x00ff0317,
  91		0x1e0bff00, 0x00ff0316, 0x1f0cff00, 0x00ff0215,
  92		0x1e0cff00, 0x00000215, 0x1e0dff00, 0x00000214,
  93		0x1e0e0000, 0x00000113, 0x1e0e0000, 0x00000113,
  94		0x1e0f0000, 0x00000112, 0x1f100000, 0x00000011,
  95		0x20100000, 0x00000010, 0x1f110000, 0x00000010,
  96		0x1e120100, 0x0000000f, 0x1e130100, 0x0000000e,
  97		0x1e130100, 0x0000000e, 0x1e140200, 0x0000ff0d,
  98		0x1e150200, 0x0000ff0c, 0x1f1502ff, 0x0000ff0c,
  99		0x1e1603ff, 0x0000ff0b, 0x1e1703ff, 0x0000ff0a,
 100		0x1e1703ff, 0x0000ff0a, 0x1d1804ff, 0x0000ff09,
 101		0x1c1904ff, 0x0000ff09, 0x1c1905ff, 0x0000ff08,
 102		0x1c1a05ff, 0x0000ff07, 0x1b1a06ff, 0x0000ff07,
 103	},
 104	{	/* Bank 4 */
 105		0x17090000, 0x00000917, 0x18090000, 0x00000916,
 106		0x170a0100, 0x00000816, 0x170a0100, 0x00000816,
 107		0x180b0100, 0x00000715, 0x180b0100, 0x00000715,
 108		0x170c0100, 0x00000715, 0x190c0100, 0x00000614,
 109		0x180d0100, 0x00000614, 0x190d0200, 0x00000513,
 110		0x180e0200, 0x00000513, 0x180e0200, 0x00000513,
 111		0x1a0e0200, 0x00000412, 0x190f0200, 0x00000412,
 112		0x190f0300, 0x00000411, 0x18100300, 0x00000411,
 113		0x1a100300, 0x00000310, 0x18110400, 0x00000310,
 114		0x19110400, 0x0000030f, 0x19120400, 0x0000020f,
 115		0x1a120400, 0x0000020e, 0x18130500, 0x0000020e,
 116		0x18130500, 0x0000020e, 0x19130500, 0x0000020d,
 117		0x18140600, 0x0000010d, 0x19140600, 0x0000010c,
 118		0x17150700, 0x0000010c, 0x18150700, 0x0000010b,
 119		0x18150700, 0x0000010b, 0x17160800, 0x0000010a,
 120		0x17160800, 0x0000010a, 0x18160900, 0x00000009,
 121	},
 122	{	/* Bank 5 */
 123		0x120b0300, 0x00030b12, 0x120c0300, 0x00030b11,
 124		0x110c0400, 0x00030b11, 0x110c0400, 0x00030b11,
 125		0x130c0400, 0x00020a11, 0x120d0400, 0x00020a11,
 126		0x110d0500, 0x00020a11, 0x110d0500, 0x00020a11,
 127		0x130d0500, 0x00010911, 0x130e0500, 0x00010910,
 128		0x120e0600, 0x00010910, 0x120e0600, 0x00010910,
 129		0x130e0600, 0x00010810, 0x120f0600, 0x00010810,
 130		0x120f0700, 0x00000810, 0x130f0700, 0x0000080f,
 131		0x140f0700, 0x0000070f, 0x130f0800, 0x0000070f,
 132		0x12100800, 0x0000070f, 0x12100801, 0x0000060f,
 133		0x13100801, 0x0000060e, 0x12100901, 0x0000060e,
 134		0x12100901, 0x0000060e, 0x13100901, 0x0000050e,
 135		0x13110901, 0x0000050d, 0x11110a02, 0x0000050d,
 136		0x11110a02, 0x0000050d, 0x12110a02, 0x0000040d,
 137		0x13110a02, 0x0000040c, 0x11110b03, 0x0000040c,
 138		0x11110b03, 0x0000040c, 0x12110b03, 0x0000030c,
 139	},
 140	{	/* Bank 6 */
 141		0x0b0a0805, 0x00080a0c, 0x0b0a0805, 0x00080a0c,
 142		0x0c0a0805, 0x00080a0b, 0x0c0a0805, 0x00080a0b,
 143		0x0d0a0805, 0x00070a0b, 0x0d0a0805, 0x00070a0b,
 144		0x0d0a0805, 0x00070a0b, 0x0c0a0806, 0x00070a0b,
 145		0x0b0b0806, 0x00070a0b, 0x0c0b0806, 0x0007090b,
 146		0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b,
 147		0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b,
 148		0x0b0b0906, 0x0007090b, 0x0c0b0906, 0x0006090b,
 149		0x0c0b0906, 0x0006090b, 0x0c0b0906, 0x0006090b,
 150		0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b,
 151		0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b,
 152		0x0b0b0907, 0x0006090b, 0x0c0b0907, 0x0006080b,
 153		0x0b0b0a07, 0x0006080b, 0x0c0b0a07, 0x0006080a,
 154		0x0d0b0a07, 0x0005080a, 0x0d0b0a07, 0x0005080a,
 155		0x0d0b0a07, 0x0005080a, 0x0c0b0a08, 0x0005080a,
 156		0x0c0b0a08, 0x0005080a, 0x0c0b0a08, 0x0005080a,
 157	},
 158	{	/* Bank 7 */
 159		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 160		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 161		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 162		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 163		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 164		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 165		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 166		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 167		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 168		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 169		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 170		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 171		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 172		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 173		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 174		0x0909090a, 0x00090909, 0x0909090a, 0x00090909,
 175	}
 176};
 177
 178static const unsigned int
 179mali_c55_rsz_filter_coeffs_v[MALI_C55_RSZ_COEFS_BANKS]
 180			    [MALI_C55_RSZ_COEFS_ENTRIES] = {
 181	{	/* Bank 0 */
 182		0x2424fc00, 0x000000fc, 0x2721fc00, 0x000000fc,
 183		0x281ffd00, 0x000000fc, 0x2c1cfd00, 0x000000fb,
 184		0x2e1afd00, 0x000000fb, 0x3017fe00, 0x000000fb,
 185		0x3215fe00, 0x000000fb, 0x3512fe00, 0x000000fb,
 186		0x3510ff00, 0x000000fc, 0x370eff00, 0x000000fc,
 187		0x390cff00, 0x000000fc, 0x3a0aff00, 0x000000fd,
 188		0x3a080000, 0x000000fe, 0x3c060000, 0x000000fe,
 189		0x3d040000, 0x000000ff, 0x3d030000, 0x00000000,
 190		0x3c020000, 0x00000002, 0x3d000000, 0x00000003,
 191		0x3dff0000, 0x00000004, 0x3cfe0000, 0x00000006,
 192		0x3afe0000, 0x00000008, 0x3afd0000, 0x0000ff0a,
 193		0x39fc0000, 0x0000ff0c, 0x37fc0000, 0x0000ff0e,
 194		0x35fc0000, 0x0000ff10, 0x35fb0000, 0x0000fe12,
 195		0x32fb0000, 0x0000fe15, 0x30fb0000, 0x0000fe17,
 196		0x2efb0000, 0x0000fd1a, 0x2cfb0000, 0x0000fd1c,
 197		0x28fc0000, 0x0000fd1f, 0x27fc0000, 0x0000fc21,
 198	},
 199	{	/* Bank 1 */
 200		0x2525fb00, 0x000000fb, 0x2723fb00, 0x000000fb,
 201		0x2921fb00, 0x000000fb, 0x2a1ffb00, 0x000000fc,
 202		0x2c1dfb00, 0x000000fc, 0x2e1bfb00, 0x000000fc,
 203		0x2f19fb00, 0x000000fd, 0x2f17fc00, 0x000000fe,
 204		0x3115fc00, 0x000000fe, 0x3213fc00, 0x000000ff,
 205		0x3411fc00, 0x0000ff00, 0x3310fd00, 0x0000ff01,
 206		0x340efd00, 0x0000ff02, 0x350cfd00, 0x0000ff03,
 207		0x350afd00, 0x0000ff05, 0x3509fe00, 0x0000fe06,
 208		0x3607fe00, 0x0000fe07, 0x3506fe00, 0x0000fe09,
 209		0x3505ff00, 0x0000fd0a, 0x3503ff00, 0x0000fd0c,
 210		0x3402ff00, 0x0000fd0e, 0x3301ff00, 0x0000fd10,
 211		0x3400ff00, 0x0000fc11, 0x32ff0000, 0x0000fc13,
 212		0x31fe0000, 0x0000fc15, 0x2ffe0000, 0x0000fc17,
 213		0x2ffd0000, 0x0000fb19, 0x2efc0000, 0x0000fb1b,
 214		0x2cfc0000, 0x0000fb1d, 0x2afc0000, 0x0000fb1f,
 215		0x29fb0000, 0x0000fb21, 0x27fb0000, 0x0000fb23,
 216	},
 217	{	/* Bank 2 */
 218		0x1f1f0100, 0x00000001, 0x211e0000, 0x00000001,
 219		0x211d0000, 0x00000002, 0x221c0000, 0x00000002,
 220		0x231bff00, 0x00000003, 0x241aff00, 0x0000ff04,
 221		0x2519ff00, 0x0000ff04, 0x2518ff00, 0x0000ff05,
 222		0x2617fe00, 0x0000ff06, 0x2616fe00, 0x0000ff07,
 223		0x2714fe00, 0x0000ff08, 0x2713fe00, 0x0000ff09,
 224		0x2712fe00, 0x0000ff0a, 0x2811fe00, 0x0000fe0b,
 225		0x2810fe00, 0x0000fe0c, 0x280ffe00, 0x0000fe0d,
 226		0x280efe00, 0x0000fe0e, 0x280dfe00, 0x0000fe0f,
 227		0x280cfe00, 0x0000fe10, 0x280bfe00, 0x0000fe11,
 228		0x270aff00, 0x0000fe12, 0x2709ff00, 0x0000fe13,
 229		0x2708ff00, 0x0000fe14, 0x2607ff00, 0x0000fe16,
 230		0x2606ff00, 0x0000fe17, 0x2505ff00, 0x0000ff18,
 231		0x2504ff00, 0x0000ff19, 0x2404ff00, 0x0000ff1a,
 232		0x23030000, 0x0000ff1b, 0x22020000, 0x0000001c,
 233		0x21020000, 0x0000001d, 0x21010000, 0x0000001e,
 234	},
 235	{	/* Bank 3 */
 236		0x1b1b06ff, 0x0000ff06, 0x1b1a06ff, 0x0000ff07,
 237		0x1c1a05ff, 0x0000ff07, 0x1c1905ff, 0x0000ff08,
 238		0x1c1904ff, 0x0000ff09, 0x1d1804ff, 0x0000ff09,
 239		0x1e1703ff, 0x0000ff0a, 0x1e1703ff, 0x0000ff0a,
 240		0x1e1603ff, 0x0000ff0b, 0x1f1502ff, 0x0000ff0c,
 241		0x1e150200, 0x0000ff0c, 0x1e140200, 0x0000ff0d,
 242		0x1e130100, 0x0000000e, 0x1e130100, 0x0000000e,
 243		0x1e120100, 0x0000000f, 0x1f110000, 0x00000010,
 244		0x20100000, 0x00000010, 0x1f100000, 0x00000011,
 245		0x1e0f0000, 0x00000112, 0x1e0e0000, 0x00000113,
 246		0x1e0e0000, 0x00000113, 0x1e0dff00, 0x00000214,
 247		0x1e0cff00, 0x00000215, 0x1f0cff00, 0x00ff0215,
 248		0x1e0bff00, 0x00ff0316, 0x1e0aff00, 0x00ff0317,
 249		0x1e0aff00, 0x00ff0317, 0x1d09ff00, 0x00ff0418,
 250		0x1c09ff00, 0x00ff0419, 0x1c08ff00, 0x00ff0519,
 251		0x1c07ff00, 0x00ff051a, 0x1b07ff00, 0x00ff061a,
 252	},
 253	{	/* Bank 4 */
 254		0x17170900, 0x00000009, 0x18160900, 0x00000009,
 255		0x17160800, 0x0000010a, 0x17160800, 0x0000010a,
 256		0x18150700, 0x0000010b, 0x18150700, 0x0000010b,
 257		0x17150700, 0x0000010c, 0x19140600, 0x0000010c,
 258		0x18140600, 0x0000010d, 0x19130500, 0x0000020d,
 259		0x18130500, 0x0000020e, 0x18130500, 0x0000020e,
 260		0x1a120400, 0x0000020e, 0x19120400, 0x0000020f,
 261		0x19110400, 0x0000030f, 0x18110400, 0x00000310,
 262		0x1a100300, 0x00000310, 0x18100300, 0x00000411,
 263		0x190f0300, 0x00000411, 0x190f0200, 0x00000412,
 264		0x1a0e0200, 0x00000412, 0x180e0200, 0x00000513,
 265		0x180e0200, 0x00000513, 0x190d0200, 0x00000513,
 266		0x180d0100, 0x00000614, 0x190c0100, 0x00000614,
 267		0x170c0100, 0x00000715, 0x180b0100, 0x00000715,
 268		0x180b0100, 0x00000715, 0x170a0100, 0x00000816,
 269		0x170a0100, 0x00000816, 0x18090000, 0x00000916,
 270	},
 271	{	/* Bank 5 */
 272		0x12120b03, 0x0000030b, 0x12110b03, 0x0000030c,
 273		0x11110b03, 0x0000040c, 0x11110b03, 0x0000040c,
 274		0x13110a02, 0x0000040c, 0x12110a02, 0x0000040d,
 275		0x11110a02, 0x0000050d, 0x11110a02, 0x0000050d,
 276		0x13110901, 0x0000050d, 0x13100901, 0x0000050e,
 277		0x12100901, 0x0000060e, 0x12100901, 0x0000060e,
 278		0x13100801, 0x0000060e, 0x12100801, 0x0000060f,
 279		0x12100800, 0x0000070f, 0x130f0800, 0x0000070f,
 280		0x140f0700, 0x0000070f, 0x130f0700, 0x0000080f,
 281		0x120f0700, 0x00000810, 0x120f0600, 0x00010810,
 282		0x130e0600, 0x00010810, 0x120e0600, 0x00010910,
 283		0x120e0600, 0x00010910, 0x130e0500, 0x00010910,
 284		0x130d0500, 0x00010911, 0x110d0500, 0x00020a11,
 285		0x110d0500, 0x00020a11, 0x120d0400, 0x00020a11,
 286		0x130c0400, 0x00020a11, 0x110c0400, 0x00030b11,
 287		0x110c0400, 0x00030b11, 0x120c0300, 0x00030b11,
 288	},
 289	{	/* Bank 6 */
 290		0x0b0c0a08, 0x0005080a, 0x0b0c0a08, 0x0005080a,
 291		0x0c0b0a08, 0x0005080a, 0x0c0b0a08, 0x0005080a,
 292		0x0d0b0a07, 0x0005080a, 0x0d0b0a07, 0x0005080a,
 293		0x0d0b0a07, 0x0005080a, 0x0c0b0a07, 0x0006080a,
 294		0x0b0b0a07, 0x0006080b, 0x0c0b0907, 0x0006080b,
 295		0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b,
 296		0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b,
 297		0x0b0b0907, 0x0006090b, 0x0c0b0906, 0x0006090b,
 298		0x0c0b0906, 0x0006090b, 0x0c0b0906, 0x0006090b,
 299		0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b,
 300		0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b,
 301		0x0b0b0906, 0x0007090b, 0x0c0b0806, 0x0007090b,
 302		0x0b0b0806, 0x00070a0b, 0x0c0a0806, 0x00070a0b,
 303		0x0d0a0805, 0x00070a0b, 0x0d0a0805, 0x00070a0b,
 304		0x0d0a0805, 0x00070a0b, 0x0c0a0805, 0x00080a0b,
 305		0x0c0a0805, 0x00080a0b, 0x0c0a0805, 0x00080a0b,
 306	},
 307	{	/* Bank 7 */
 308		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 309		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 310		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 311		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 312		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 313		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 314		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 315		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 316		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 317		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 318		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 319		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 320		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 321		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 322		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 323		0x09090909, 0x000a0909, 0x09090909, 0x000a0909,
 324	}
 325};
 326
 327static const unsigned int mali_c55_rsz_coef_banks_range_start[] = {
 328	770, 600, 460, 354, 273, 210, 162, 125
 329};
 330
 331/*
 332 * Select the right filter coefficients bank based on the scaler input and the
 333 * scaler output sizes ratio, set by the v4l2 crop and scale selection
 334 * rectangles respectively.
 335 */
 336static unsigned int mali_c55_rsz_calculate_bank(struct mali_c55 *mali_c55,
 337						unsigned int rsz_in,
 338						unsigned int rsz_out)
 339{
 340	unsigned int rsz_ratio = (rsz_out * 1000U) / rsz_in;
 341	unsigned int i;
 342
 343	for (i = 0; i < ARRAY_SIZE(mali_c55_rsz_coef_banks_range_start); i++)
 344		if (rsz_ratio >= mali_c55_rsz_coef_banks_range_start[i])
 345			break;
 346
 347	return i;
 348}
 349
 350static const u32 rsz_non_bypass_src_fmts[] = {
 351	MEDIA_BUS_FMT_RGB121212_1X36,
 352	MEDIA_BUS_FMT_YUV10_1X30
 353};
 354
 355static void mali_c55_resizer_program_coefficients(struct mali_c55_resizer *rsz)
 356{
 357	struct mali_c55 *mali_c55 = rsz->mali_c55;
 358	unsigned int haddr = rsz->id == MALI_C55_RSZ_FR ?
 359			     MALI_C55_REG_FR_SCALER_HFILT :
 360			     MALI_C55_REG_DS_SCALER_HFILT;
 361	unsigned int vaddr = rsz->id == MALI_C55_RSZ_FR ?
 362			     MALI_C55_REG_FR_SCALER_VFILT :
 363			     MALI_C55_REG_DS_SCALER_VFILT;
 364
 365	for (unsigned int i = 0; i < MALI_C55_RSZ_COEFS_BANKS; i++) {
 366		for (unsigned int j = 0; j < MALI_C55_RSZ_COEFS_ENTRIES; j++) {
 367			mali_c55_write(mali_c55, haddr,
 368				       mali_c55_rsz_filter_coeffs_h[i][j]);
 369			mali_c55_write(mali_c55, vaddr,
 370				       mali_c55_rsz_filter_coeffs_v[i][j]);
 371
 372			haddr += sizeof(u32);
 373			vaddr += sizeof(u32);
 374		}
 375	}
 376}
 377
 378static int mali_c55_rsz_program_crop(struct mali_c55_resizer *rsz,
 379				     const struct v4l2_subdev_state *state)
 380{
 381	const struct v4l2_mbus_framefmt *fmt;
 382	const struct v4l2_rect *crop;
 383
 384	/* Verify if crop should be enabled. */
 385	fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SINK_PAD, 0);
 386	crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD, 0);
 387
 388	if (fmt->width == crop->width && fmt->height == crop->height)
 389		return MALI_C55_BYPASS_CROP;
 390
 391	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_X_START,
 392			       crop->left);
 393	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_Y_START,
 394			       crop->top);
 395	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_X_SIZE,
 396			       crop->width);
 397	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_Y_SIZE,
 398			       crop->height);
 399
 400	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_EN,
 401			       MALI_C55_CROP_ENABLE);
 402
 403	return 0;
 404}
 405
 406static int mali_c55_rsz_program_resizer(struct mali_c55_resizer *rsz,
 407					struct v4l2_subdev_state *state)
 408{
 409	struct mali_c55 *mali_c55 = rsz->mali_c55;
 410	const struct v4l2_rect *crop, *scale;
 411	unsigned int h_bank, v_bank;
 412	u64 h_scale, v_scale;
 413
 414	/* Verify if scaling should be enabled. */
 415	crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD, 0);
 416	scale = v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD, 0);
 417
 418	if (crop->width == scale->width && crop->height == scale->height)
 419		return MALI_C55_BYPASS_SCALER;
 420
 421	/* Program the scaler coefficients if the scaler is in use. */
 422	mali_c55_resizer_program_coefficients(rsz);
 423
 424	/* Program the V/H scaling factor in Q4.20 format. */
 425	h_scale = crop->width * MALI_C55_RSZ_SCALER_FACTOR;
 426	v_scale = crop->height * MALI_C55_RSZ_SCALER_FACTOR;
 427
 428	do_div(h_scale, scale->width);
 429	do_div(v_scale, scale->height);
 430
 431	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_IN_WIDTH,
 432			       crop->width);
 433	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_IN_HEIGHT,
 434			       crop->height);
 435
 436	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_OUT_WIDTH,
 437			       scale->width);
 438	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_OUT_HEIGHT,
 439			       scale->height);
 440
 441	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_HFILT_TINC,
 442			       h_scale);
 443	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_VFILT_TINC,
 444			       v_scale);
 445
 446	/* Select the scaler coefficients bank to use. */
 447	h_bank = mali_c55_rsz_calculate_bank(mali_c55, crop->width,
 448					     scale->width);
 449	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_HFILT_COEF,
 450			       h_bank);
 451
 452	v_bank = mali_c55_rsz_calculate_bank(mali_c55, crop->height,
 453					     scale->height);
 454	mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_VFILT_COEF,
 455			       v_bank);
 456
 457	return 0;
 458}
 459
 460static void mali_c55_rsz_program(struct mali_c55_resizer *rsz,
 461				 struct v4l2_subdev_state *state)
 462{
 463	struct mali_c55 *mali_c55 = rsz->mali_c55;
 464	u32 bypass = 0;
 465
 466	/* Verify if cropping and scaling should be enabled. */
 467	bypass |= mali_c55_rsz_program_crop(rsz, state);
 468	bypass |= mali_c55_rsz_program_resizer(rsz, state);
 469
 470	mali_c55_ctx_update_bits(mali_c55, rsz->id == MALI_C55_RSZ_FR ?
 471				 MALI_C55_REG_FR_BYPASS : MALI_C55_REG_DS_BYPASS,
 472				 MALI_C55_BYPASS_CROP | MALI_C55_BYPASS_SCALER,
 473				 bypass);
 474}
 475
 476/*
 477 * Inspect the routing table to know which of the two (mutually exclusive)
 478 * routes is enabled and return the sink pad id of the active route.
 479 */
 480static unsigned int mali_c55_rsz_get_active_sink(struct v4l2_subdev_state *state)
 481{
 482	struct v4l2_subdev_krouting *routing = &state->routing;
 483	struct v4l2_subdev_route *route;
 484
 485	/* A single route is enabled at a time. */
 486	for_each_active_route(routing, route)
 487		return route->sink_pad;
 488
 489	return MALI_C55_RSZ_SINK_PAD;
 490}
 491
 492/*
 493 * When operating in bypass mode, the ISP takes input in a 20-bit format, but
 494 * can only output 16-bit RAW bayer data (with the 4 least significant bits from
 495 * the input being lost). Return the 16-bit version of the 20-bit input formats.
 496 */
 497static u32 mali_c55_rsz_shift_mbus_code(u32 mbus_code)
 498{
 499	const struct mali_c55_isp_format_info *fmt =
 500		mali_c55_isp_get_mbus_config_by_code(mbus_code);
 501
 502	if (!fmt)
 503		return -EINVAL;
 504
 505	return fmt->shifted_code;
 506}
 507
 508static int __mali_c55_rsz_set_routing(struct v4l2_subdev *sd,
 509				      struct v4l2_subdev_state *state,
 510				      const struct v4l2_subdev_krouting *routing)
 511{
 512	struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd);
 513	unsigned int active_sink = UINT_MAX;
 514	struct v4l2_mbus_framefmt *src_fmt;
 515	struct v4l2_subdev_route *route;
 516	unsigned int active_routes = 0;
 517	struct v4l2_mbus_framefmt *fmt;
 518	int ret;
 519
 520	ret = v4l2_subdev_routing_validate(sd, routing, 0);
 521	if (ret)
 522		return ret;
 523
 524	/* Only a single route can be enabled at a time. */
 525	for_each_active_route(routing, route) {
 526		if (++active_routes > 1) {
 527			dev_dbg(rsz->mali_c55->dev,
 528				"Only one route can be active");
 529			return -EINVAL;
 530		}
 531
 532		active_sink = route->sink_pad;
 533	}
 534	if (active_sink == UINT_MAX) {
 535		dev_dbg(rsz->mali_c55->dev, "One route has to be active");
 536		return -EINVAL;
 537	}
 538
 539	ret = v4l2_subdev_set_routing(sd, state, routing);
 540	if (ret) {
 541		dev_dbg(rsz->mali_c55->dev, "Failed to set routing\n");
 542		return ret;
 543	}
 544
 545	fmt = v4l2_subdev_state_get_format(state, active_sink, 0);
 546	fmt->width = MALI_C55_DEFAULT_WIDTH;
 547	fmt->height = MALI_C55_DEFAULT_HEIGHT;
 548	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 549	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
 550	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
 551	fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false,
 552							  fmt->colorspace,
 553							  fmt->ycbcr_enc);
 554	fmt->field = V4L2_FIELD_NONE;
 555
 556	if (active_sink == MALI_C55_RSZ_SINK_PAD) {
 557		struct v4l2_rect *crop, *compose;
 558
 559		fmt->code = MEDIA_BUS_FMT_RGB121212_1X36;
 560
 561		crop = v4l2_subdev_state_get_crop(state, active_sink, 0);
 562		compose = v4l2_subdev_state_get_compose(state, active_sink, 0);
 563
 564		crop->left = 0;
 565		crop->top = 0;
 566		crop->width = MALI_C55_DEFAULT_WIDTH;
 567		crop->height = MALI_C55_DEFAULT_HEIGHT;
 568
 569		*compose = *crop;
 570	} else {
 571		fmt->code = MEDIA_BUS_FMT_SRGGB20_1X20;
 572	}
 573
 574	/* Propagate the format to the source pad */
 575	src_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SOURCE_PAD,
 576					       0);
 577	*src_fmt = *fmt;
 578
 579	/* In the event this is the bypass pad the mbus code needs correcting */
 580	if (active_sink == MALI_C55_RSZ_SINK_BYPASS_PAD)
 581		src_fmt->code = mali_c55_rsz_shift_mbus_code(src_fmt->code);
 582
 583	return 0;
 584}
 585
 586static int mali_c55_rsz_enum_mbus_code(struct v4l2_subdev *sd,
 587				       struct v4l2_subdev_state *state,
 588				       struct v4l2_subdev_mbus_code_enum *code)
 589{
 590	const struct mali_c55_isp_format_info *fmt;
 591	struct v4l2_mbus_framefmt *sink_fmt;
 592	u32 sink_pad;
 593
 594	switch (code->pad) {
 595	case MALI_C55_RSZ_SINK_PAD:
 596		if (code->index)
 597			return -EINVAL;
 598
 599		code->code = MEDIA_BUS_FMT_RGB121212_1X36;
 600
 601		return 0;
 602	case MALI_C55_RSZ_SOURCE_PAD:
 603		sink_pad = mali_c55_rsz_get_active_sink(state);
 604		sink_fmt = v4l2_subdev_state_get_format(state, sink_pad, 0);
 605
 606		/*
 607		 * If the active route is from the Bypass sink pad, then the
 608		 * source pad is a simple passthrough of the sink format,
 609		 * downshifted to 16-bits.
 610		 */
 611
 612		if (sink_pad == MALI_C55_RSZ_SINK_BYPASS_PAD) {
 613			if (code->index)
 614				return -EINVAL;
 615
 616			code->code = mali_c55_rsz_shift_mbus_code(sink_fmt->code);
 617			if (!code->code)
 618				return -EINVAL;
 619
 620			return 0;
 621		}
 622
 623		/*
 624		 * If the active route is from the non-bypass sink then we can
 625		 * select either RGB or conversion to YUV.
 626		 */
 627
 628		if (code->index >= ARRAY_SIZE(rsz_non_bypass_src_fmts))
 629			return -EINVAL;
 630
 631		code->code = rsz_non_bypass_src_fmts[code->index];
 632
 633		return 0;
 634	case MALI_C55_RSZ_SINK_BYPASS_PAD:
 635		fmt = mali_c55_isp_get_mbus_config_by_index(code->index);
 636		if (fmt) {
 637			code->code = fmt->code;
 638			return 0;
 639		}
 640
 641		break;
 642	}
 643
 644	return -EINVAL;
 645}
 646
 647static int mali_c55_rsz_enum_frame_size(struct v4l2_subdev *sd,
 648					struct v4l2_subdev_state *state,
 649					struct v4l2_subdev_frame_size_enum *fse)
 650{
 651	const struct mali_c55_isp_format_info *fmt;
 652	struct v4l2_mbus_framefmt *sink_fmt;
 653	struct v4l2_rect *compose;
 654	u32 sink_pad;
 655
 656	switch (fse->pad) {
 657	case MALI_C55_RSZ_SINK_PAD:
 658		if (fse->index || fse->code != MEDIA_BUS_FMT_RGB121212_1X36)
 659			return -EINVAL;
 660
 661		fse->max_width = MALI_C55_MAX_WIDTH;
 662		fse->max_height = MALI_C55_MAX_HEIGHT;
 663		fse->min_width = MALI_C55_MIN_WIDTH;
 664		fse->min_height = MALI_C55_MIN_HEIGHT;
 665
 666		return 0;
 667	case MALI_C55_RSZ_SOURCE_PAD:
 668		sink_pad = mali_c55_rsz_get_active_sink(state);
 669		sink_fmt = v4l2_subdev_state_get_format(state, sink_pad, 0);
 670
 671		if (sink_pad == MALI_C55_RSZ_SINK_BYPASS_PAD) {
 672			if (fse->index)
 673				return -EINVAL;
 674
 675			fmt = mali_c55_isp_get_mbus_config_by_shifted_code(fse->code);
 676			if (!fmt)
 677				return -EINVAL;
 678
 679			fse->min_width = sink_fmt->width;
 680			fse->max_width = sink_fmt->width;
 681			fse->min_height = sink_fmt->height;
 682			fse->max_height = sink_fmt->height;
 683
 684			return 0;
 685		}
 686
 687		if ((fse->code != MEDIA_BUS_FMT_RGB121212_1X36 &&
 688		     fse->code != MEDIA_BUS_FMT_YUV10_1X30) || fse->index > 1)
 689			return -EINVAL;
 690
 691		compose = v4l2_subdev_state_get_compose(state,
 692							MALI_C55_RSZ_SINK_PAD,
 693							0);
 694
 695		fse->min_width = compose->width;
 696		fse->max_width = compose->width;
 697		fse->min_height = compose->height;
 698		fse->max_height = compose->height;
 699
 700		return 0;
 701	case MALI_C55_RSZ_SINK_BYPASS_PAD:
 702		fmt = mali_c55_isp_get_mbus_config_by_code(fse->code);
 703		if (fse->index || !fmt)
 704			return -EINVAL;
 705
 706		fse->max_width = MALI_C55_MAX_WIDTH;
 707		fse->max_height = MALI_C55_MAX_HEIGHT;
 708		fse->min_width = MALI_C55_MIN_WIDTH;
 709		fse->min_height = MALI_C55_MIN_HEIGHT;
 710
 711		return 0;
 712	}
 713
 714	return -EINVAL;
 715}
 716
 717static int mali_c55_rsz_set_sink_fmt(struct v4l2_subdev *sd,
 718				     struct v4l2_subdev_state *state,
 719				     struct v4l2_subdev_format *format)
 720{
 721	struct v4l2_mbus_framefmt *fmt = &format->format;
 722	struct v4l2_mbus_framefmt *sink_fmt;
 723	unsigned int active_sink;
 724	struct v4l2_rect *rect;
 725
 726	sink_fmt = v4l2_subdev_state_get_format(state, format->pad, 0);
 727
 728	/*
 729	 * Clamp to min/max and then reset crop and compose rectangles to the
 730	 * newly applied size.
 731	 */
 732	sink_fmt->width = clamp_t(unsigned int, fmt->width,
 733				  MALI_C55_MIN_WIDTH, MALI_C55_MAX_WIDTH);
 734	sink_fmt->height = clamp_t(unsigned int, fmt->height,
 735				   MALI_C55_MIN_HEIGHT, MALI_C55_MAX_HEIGHT);
 736
 737	/*
 738	 * Make sure the media bus code for the bypass pad is one of the
 739	 * supported ISP input media bus codes. Default it to SRGGB otherwise.
 740	 */
 741	if (format->pad == MALI_C55_RSZ_SINK_BYPASS_PAD)
 742		sink_fmt->code = mali_c55_isp_get_mbus_config_by_code(fmt->code) ?
 743				 fmt->code : MEDIA_BUS_FMT_SRGGB20_1X20;
 744
 745	*fmt = *sink_fmt;
 746
 747	if (format->pad == MALI_C55_RSZ_SINK_PAD) {
 748		rect = v4l2_subdev_state_get_crop(state, format->pad);
 749		rect->left = 0;
 750		rect->top = 0;
 751		rect->width = fmt->width;
 752		rect->height = fmt->height;
 753
 754		rect = v4l2_subdev_state_get_compose(state, format->pad);
 755		rect->left = 0;
 756		rect->top = 0;
 757		rect->width = fmt->width;
 758		rect->height = fmt->height;
 759	}
 760
 761	/* If format->pad is routed to the source pad, propagate the format. */
 762	active_sink = mali_c55_rsz_get_active_sink(state);
 763	if (active_sink == format->pad) {
 764		/* If the bypass route is used, downshift the code to 16bpp. */
 765		if (active_sink == MALI_C55_RSZ_SINK_BYPASS_PAD)
 766			fmt->code = mali_c55_rsz_shift_mbus_code(fmt->code);
 767
 768		*v4l2_subdev_state_get_format(state,
 769					      MALI_C55_RSZ_SOURCE_PAD, 0) = *fmt;
 770	}
 771
 772	return 0;
 773}
 774
 775static int mali_c55_rsz_set_source_fmt(struct v4l2_subdev *sd,
 776				       struct v4l2_subdev_state *state,
 777				       struct v4l2_subdev_format *format)
 778{
 779	struct v4l2_mbus_framefmt *fmt = &format->format;
 780	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
 781	unsigned int active_sink;
 782
 783	active_sink = mali_c55_rsz_get_active_sink(state);
 784	sink_fmt = v4l2_subdev_state_get_format(state, active_sink, 0);
 785	src_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SOURCE_PAD);
 786
 787	if (active_sink == MALI_C55_RSZ_SINK_PAD) {
 788		/*
 789		 * Regular processing pipe: RGB121212 can be color-space
 790		 * converted to YUV101010.
 791		 */
 792		unsigned int i;
 793
 794		for (i = 0; i < ARRAY_SIZE(rsz_non_bypass_src_fmts); i++) {
 795			if (fmt->code == rsz_non_bypass_src_fmts[i])
 796				break;
 797		}
 798
 799		src_fmt->code = i == ARRAY_SIZE(rsz_non_bypass_src_fmts) ?
 800				MEDIA_BUS_FMT_RGB121212_1X36 : fmt->code;
 801	} else {
 802		/*
 803		 * Bypass pipe: the source format is the same as the bypass
 804		 * sink pad downshifted to 16bpp.
 805		 */
 806		fmt->code = mali_c55_rsz_shift_mbus_code(sink_fmt->code);
 807	}
 808
 809	*fmt = *src_fmt;
 810
 811	return 0;
 812}
 813
 814static int mali_c55_rsz_set_fmt(struct v4l2_subdev *sd,
 815				struct v4l2_subdev_state *state,
 816				struct v4l2_subdev_format *format)
 817{
 818	/*
 819	 * On sink pads fmt is either fixed for the 'regular' processing
 820	 * pad or a RAW format or 20-bit wide RGB/YUV format for the FR bypass
 821	 * pad.
 822	 *
 823	 * On source pad sizes are the result of crop+compose on the sink
 824	 * pad sizes, while the format depends on the active route.
 825	 */
 826
 827	if (format->pad == MALI_C55_RSZ_SINK_PAD ||
 828	    format->pad == MALI_C55_RSZ_SINK_BYPASS_PAD)
 829		return mali_c55_rsz_set_sink_fmt(sd, state, format);
 830
 831	return mali_c55_rsz_set_source_fmt(sd, state, format);
 832}
 833
 834static int mali_c55_rsz_get_selection(struct v4l2_subdev *sd,
 835				      struct v4l2_subdev_state *state,
 836				      struct v4l2_subdev_selection *sel)
 837{
 838	if (sel->pad != MALI_C55_RSZ_SINK_PAD)
 839		return -EINVAL;
 840
 841	if (sel->target != V4L2_SEL_TGT_CROP &&
 842	    sel->target != V4L2_SEL_TGT_COMPOSE)
 843		return -EINVAL;
 844
 845	sel->r = sel->target == V4L2_SEL_TGT_CROP
 846	       ? *v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD)
 847	       : *v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD);
 848
 849	return 0;
 850}
 851
 852static int mali_c55_rsz_set_crop(struct v4l2_subdev *sd,
 853				 struct v4l2_subdev_state *state,
 854				 struct v4l2_subdev_selection *sel)
 855{
 856	struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd);
 857	struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
 858	struct v4l2_rect *crop, *compose;
 859
 860	sink_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SINK_PAD);
 861	crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD);
 862	compose = v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD);
 863
 864	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
 865	    v4l2_subdev_is_streaming(sd)) {
 866		/*
 867		 * At runtime the compose rectangle and output size cannot be
 868		 * changed so we need to clamp the crop rectangle such that the
 869		 * compose rectangle can fit within it.
 870		 */
 871		crop->left = clamp_t(unsigned int, sel->r.left, 0,
 872				     sink_fmt->width - compose->width);
 873		crop->top = clamp_t(unsigned int, sel->r.top, 0,
 874				    sink_fmt->height - compose->height);
 875		crop->width = clamp_t(unsigned int, sel->r.width, compose->width,
 876				      sink_fmt->width - crop->left);
 877		crop->height = clamp_t(unsigned int, sel->r.height, compose->height,
 878				       sink_fmt->height - crop->top);
 879
 880		mali_c55_rsz_program(rsz, state);
 881	} else {
 882		/*
 883		 * If we're not streaming we can utilise the ISP's full range
 884		 * and simply need to propagate the selected rectangle to the
 885		 * compose target and source pad format.
 886		 */
 887		crop->left = clamp_t(unsigned int, sel->r.left, 0,
 888				     sink_fmt->width);
 889		crop->top = clamp_t(unsigned int, sel->r.top, 0,
 890				    sink_fmt->height);
 891		crop->width = clamp_t(unsigned int, sel->r.width,
 892				      MALI_C55_MIN_WIDTH,
 893				      sink_fmt->width - crop->left);
 894		crop->height = clamp_t(unsigned int, sel->r.height,
 895				       MALI_C55_MIN_HEIGHT,
 896				       sink_fmt->height - crop->top);
 897
 898		*compose = *crop;
 899
 900		src_fmt = v4l2_subdev_state_get_format(state,
 901						       MALI_C55_RSZ_SOURCE_PAD);
 902		src_fmt->width = compose->width;
 903		src_fmt->height = compose->height;
 904	}
 905
 906	sel->r = *crop;
 907	return 0;
 908}
 909
 910static int mali_c55_rsz_set_compose(struct v4l2_subdev *sd,
 911				    struct v4l2_subdev_state *state,
 912				    struct v4l2_subdev_selection *sel)
 913{
 914	struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd);
 915	struct mali_c55 *mali_c55 = rsz->mali_c55;
 916	struct v4l2_mbus_framefmt *src_fmt;
 917	struct v4l2_rect *compose, *crop;
 918
 919	/*
 920	 * We cannot change the compose rectangle during streaming, as that
 921	 * would require a change in the output buffer size.
 922	 */
 923	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
 924	    v4l2_subdev_is_streaming(sd))
 925		return -EBUSY;
 926
 927	/*
 928	 * In the FR pipe, the scaler is an optional component that may not be
 929	 * fitted.
 930	 */
 931	if (rsz->id == MALI_C55_RSZ_FR &&
 932	    !(mali_c55->capabilities & MALI_C55_GPS_FRSCALER_FITTED))
 933		return -EINVAL;
 934
 935	compose = v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD);
 936	crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD);
 937
 938	compose->left = 0;
 939	compose->top = 0;
 940	compose->width = clamp_t(unsigned int, sel->r.width, crop->width / 8,
 941				 crop->width);
 942	compose->height = clamp_t(unsigned int, sel->r.height, crop->height / 8,
 943				  crop->height);
 944
 945	sel->r = *compose;
 946
 947	/*
 948	 * We need to be sure to propagate the compose rectangle size to the
 949	 * source pad format.
 950	 */
 951	src_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SOURCE_PAD);
 952	src_fmt->width = compose->width;
 953	src_fmt->height = compose->height;
 954
 955	return 0;
 956}
 957
 958static int mali_c55_rsz_set_selection(struct v4l2_subdev *sd,
 959				      struct v4l2_subdev_state *state,
 960				      struct v4l2_subdev_selection *sel)
 961{
 962	if (sel->pad != MALI_C55_RSZ_SINK_PAD)
 963		return -EINVAL;
 964
 965	if (sel->target == V4L2_SEL_TGT_CROP)
 966		return mali_c55_rsz_set_crop(sd, state, sel);
 967
 968	if (sel->target == V4L2_SEL_TGT_COMPOSE)
 969		return mali_c55_rsz_set_compose(sd, state, sel);
 970
 971	return -EINVAL;
 972}
 973
 974static int mali_c55_rsz_set_routing(struct v4l2_subdev *sd,
 975				    struct v4l2_subdev_state *state,
 976				    enum v4l2_subdev_format_whence which,
 977				    struct v4l2_subdev_krouting *routing)
 978{
 979	if (which == V4L2_SUBDEV_FORMAT_ACTIVE &&
 980	    media_entity_is_streaming(&sd->entity))
 981		return -EBUSY;
 982
 983	return __mali_c55_rsz_set_routing(sd, state, routing);
 984}
 985
 986static int mali_c55_rsz_enable_streams(struct v4l2_subdev *sd,
 987				       struct v4l2_subdev_state *state, u32 pad,
 988				       u64 streams_mask)
 989{
 990	struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd);
 991	struct mali_c55 *mali_c55 = rsz->mali_c55;
 992	unsigned int sink_pad;
 993
 994	sink_pad = mali_c55_rsz_get_active_sink(state);
 995	if (sink_pad == MALI_C55_RSZ_SINK_BYPASS_PAD) {
 996		/* Bypass FR pipe processing if the bypass route is active. */
 997		mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_ISP_RAW_BYPASS,
 998					 MALI_C55_ISP_RAW_BYPASS_FR_BYPASS_MASK,
 999					 MALI_C55_ISP_RAW_BYPASS_RAW_FR_BYPASS);
1000		return 0;
1001	}
1002
1003	/* Disable bypass and use regular processing. */
1004	mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_ISP_RAW_BYPASS,
1005				 MALI_C55_ISP_RAW_BYPASS_FR_BYPASS_MASK, 0);
1006	mali_c55_rsz_program(rsz, state);
1007
1008	return 0;
1009}
1010
1011static int mali_c55_rsz_disable_streams(struct v4l2_subdev *sd,
1012					struct v4l2_subdev_state *state, u32 pad,
1013					u64 streams_mask)
1014{
1015	return 0;
1016}
1017
1018static const struct v4l2_subdev_pad_ops mali_c55_resizer_pad_ops = {
1019	.enum_mbus_code		= mali_c55_rsz_enum_mbus_code,
1020	.enum_frame_size	= mali_c55_rsz_enum_frame_size,
1021	.get_fmt		= v4l2_subdev_get_fmt,
1022	.set_fmt		= mali_c55_rsz_set_fmt,
1023	.get_selection		= mali_c55_rsz_get_selection,
1024	.set_selection		= mali_c55_rsz_set_selection,
1025	.set_routing		= mali_c55_rsz_set_routing,
1026	.enable_streams		= mali_c55_rsz_enable_streams,
1027	.disable_streams	= mali_c55_rsz_disable_streams,
1028};
1029
1030static const struct v4l2_subdev_ops mali_c55_resizer_ops = {
1031	.pad	= &mali_c55_resizer_pad_ops,
1032};
1033
1034static int mali_c55_rsz_init_state(struct v4l2_subdev *sd,
1035				   struct v4l2_subdev_state *state)
1036{
1037	struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd);
1038	struct v4l2_subdev_route routes[2] = {
1039		{
1040			.sink_pad = MALI_C55_RSZ_SINK_PAD,
1041			.source_pad = MALI_C55_RSZ_SOURCE_PAD,
1042			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
1043		}, {
1044			.sink_pad = MALI_C55_RSZ_SINK_BYPASS_PAD,
1045			.source_pad = MALI_C55_RSZ_SOURCE_PAD,
1046		},
1047	};
1048	struct v4l2_subdev_krouting routing = {
1049		.num_routes = rsz->num_routes,
1050		.routes = routes,
1051	};
1052
1053	return __mali_c55_rsz_set_routing(sd, state, &routing);
1054}
1055
1056static const struct v4l2_subdev_internal_ops mali_c55_resizer_internal_ops = {
1057	.init_state = mali_c55_rsz_init_state,
1058};
1059
1060static int mali_c55_register_resizer(struct mali_c55 *mali_c55,
1061				     unsigned int index)
1062{
1063	struct mali_c55_resizer *rsz = &mali_c55->resizers[index];
1064	struct v4l2_subdev *sd = &rsz->sd;
1065	unsigned int num_pads;
1066	int ret;
1067
1068	rsz->id = index;
1069	v4l2_subdev_init(sd, &mali_c55_resizer_ops);
1070	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
1071	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
1072	sd->internal_ops = &mali_c55_resizer_internal_ops;
1073
1074	rsz->pads[MALI_C55_RSZ_SINK_PAD].flags = MEDIA_PAD_FL_SINK;
1075	rsz->pads[MALI_C55_RSZ_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE;
1076
1077	if (rsz->id == MALI_C55_RSZ_FR) {
1078		num_pads = MALI_C55_RSZ_NUM_PADS;
1079		rsz->num_routes = 2;
1080
1081		rsz->pads[MALI_C55_RSZ_SINK_BYPASS_PAD].flags =
1082			MEDIA_PAD_FL_SINK;
1083
1084		snprintf(sd->name, sizeof(sd->name), "%s resizer fr",
1085			 MALI_C55_DRIVER_NAME);
1086
1087	} else {
1088		num_pads = MALI_C55_RSZ_NUM_PADS - 1;
1089		rsz->num_routes = 1;
1090
1091		snprintf(sd->name, sizeof(sd->name), "%s resizer ds",
1092			 MALI_C55_DRIVER_NAME);
1093	}
1094
1095	ret = media_entity_pads_init(&sd->entity, num_pads, rsz->pads);
1096	if (ret)
1097		return ret;
1098
1099	ret = v4l2_subdev_init_finalize(sd);
1100	if (ret)
1101		goto err_media_cleanup;
1102
1103	ret = v4l2_device_register_subdev(&mali_c55->v4l2_dev, sd);
1104	if (ret)
1105		goto err_subdev_cleanup;
1106
1107	rsz->cap_dev = &mali_c55->cap_devs[index];
1108	rsz->mali_c55 = mali_c55;
1109
1110	return 0;
1111
1112err_subdev_cleanup:
1113	v4l2_subdev_cleanup(sd);
1114err_media_cleanup:
1115	media_entity_cleanup(&sd->entity);
1116
1117	return ret;
1118}
1119
1120static void mali_c55_unregister_resizer(struct mali_c55_resizer *rsz)
1121{
1122	if (!rsz->mali_c55)
1123		return;
1124
1125	v4l2_device_unregister_subdev(&rsz->sd);
1126	v4l2_subdev_cleanup(&rsz->sd);
1127	media_entity_cleanup(&rsz->sd.entity);
1128}
1129
1130int mali_c55_register_resizers(struct mali_c55 *mali_c55)
1131{
1132	int ret;
1133
1134	ret = mali_c55_register_resizer(mali_c55, MALI_C55_RSZ_FR);
1135	if (ret)
1136		return ret;
1137
1138	if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) {
1139		ret = mali_c55_register_resizer(mali_c55, MALI_C55_RSZ_DS);
1140		if (ret)
1141			goto err_unregister_fr;
1142	}
1143
1144	return 0;
1145
1146err_unregister_fr:
1147	mali_c55_unregister_resizer(&mali_c55->resizers[MALI_C55_RSZ_FR]);
1148
1149	return ret;
1150}
1151
1152void mali_c55_unregister_resizers(struct mali_c55 *mali_c55)
1153{
1154	for (unsigned int i = 0; i < MALI_C55_NUM_RSZS; i++)
1155		mali_c55_unregister_resizer(&mali_c55->resizers[i]);
1156}
~/ Read-only file preview.