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 23 static inline struct mali_c55_resizer * 24 sd_to_mali_c55_rsz(struct v4l2_subdev *sd) 25 { 26 return container_of(sd, struct mali_c55_resizer, sd); 27 } 28 29 static const unsigned int 30 mali_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 178 static const unsigned int 179 mali_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 327 static 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 */ 336 static 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 350 static const u32 rsz_non_bypass_src_fmts[] = { 351 MEDIA_BUS_FMT_RGB121212_1X36, 352 MEDIA_BUS_FMT_YUV10_1X30 353 }; 354 355 static 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 378 static 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 406 static 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 460 static 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 */ 480 static 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 */ 497 static 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 508 static 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 586 static 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 647 static 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 717 static 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 775 static 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 814 static 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 834 static 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 852 static 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 910 static 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 958 static 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 974 static 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 986 static 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 1011 static 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 1018 static 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 1030 static const struct v4l2_subdev_ops mali_c55_resizer_ops = { 1031 .pad = &mali_c55_resizer_pad_ops, 1032 }; 1033 1034 static 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 1056 static const struct v4l2_subdev_internal_ops mali_c55_resizer_internal_ops = { 1057 .init_state = mali_c55_rsz_init_state, 1058 }; 1059 1060 static 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 1112 err_subdev_cleanup: 1113 v4l2_subdev_cleanup(sd); 1114 err_media_cleanup: 1115 media_entity_cleanup(&sd->entity); 1116 1117 return ret; 1118 } 1119 1120 static 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 1130 int 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 1146 err_unregister_fr: 1147 mali_c55_unregister_resizer(&mali_c55->resizers[MALI_C55_RSZ_FR]); 1148 1149 return ret; 1150 } 1151 1152 void 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 } 1157