diff options
Diffstat (limited to 'drivers/gpu/drm/xlnx/xlnx_scaler.c')
-rw-r--r-- | drivers/gpu/drm/xlnx/xlnx_scaler.c | 1748 |
1 files changed, 1748 insertions, 0 deletions
diff --git a/drivers/gpu/drm/xlnx/xlnx_scaler.c b/drivers/gpu/drm/xlnx/xlnx_scaler.c new file mode 100644 index 000000000000..9d20671c8c83 --- /dev/null +++ b/drivers/gpu/drm/xlnx/xlnx_scaler.c @@ -0,0 +1,1748 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VPSS SCALER DRM bridge driver + * + * Copyright (C) 2017-2018 Xilinx, Inc. + * + * Author: Venkateshwar rao G <vgannava@xilinx.com> + * Rohit Athavale <rathavale@xilinx.com> + */ + +/* + * Overview: + * This experimentatl driver works as a bridge driver and + * reused the code from V4L2. + * TODO: + * Need to implement in a modular approach to share driver code between + * V4L2 and DRM frameworks. + * Should be integrated with plane. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <uapi/linux/media-bus-format.h> + +#include "xlnx_bridge.h" + +#define XSCALER_MAX_WIDTH (3840) +#define XSCALER_MAX_HEIGHT (2160) +#define XSCALER_MAX_PHASES (64) +#define XSCALER_MIN_WIDTH (64) +#define XSCALER_MIN_HEIGHT (64) + +/* Video subsytems block offset */ +#define S_AXIS_RESET_OFF (0x00010000) +#define V_HSCALER_OFF (0x00000000) +#define V_VSCALER_OFF (0x00020000) + +/* HW Reset Network GPIO Channel */ +#define XGPIO_CH_RESET_SEL (1) +#define XGPIO_RESET_MASK_VIDEO_IN BIT(0) +#define XGPIO_RESET_MASK_IP_AXIS BIT(1) +#define XGPIO_RESET_MASK_ALL_BLOCKS (XGPIO_RESET_MASK_VIDEO_IN | \ + XGPIO_RESET_MASK_IP_AXIS) +#define XGPIO_DATA_OFFSET (0x0) +#define XGPIO_DATA2_OFFSET (0x8) +#define XGPIO_TRI2_OFFSET (0xc) + +#define XGPIO_ISR_OFFSET (0x120) +#define XGPIO_IER_OFFSET (0x128) +#define XGPIO_CHAN_OFFSET (8) +#define STEP_PRECISION (65536) + +/* SCALER POWER MACROS */ +#define XSCALER_RESET_ASSERT (0x1) +#define XSCALER_RESET_DEASSERT (0x0) + +/* Video IP PPC */ +#define XSCALER_PPC_1 (1) +#define XSCALER_PPC_2 (2) + +#define XV_HSCALER_MAX_H_TAPS (12) +#define XV_HSCALER_MAX_H_PHASES (64) +#define XV_HSCALER_MAX_LINE_WIDTH (3840) +#define XV_VSCALER_MAX_V_TAPS (12) +#define XV_VSCALER_MAX_V_PHASES (64) + +#define XV_HSCALER_TAPS_2 (2) +#define XV_HSCALER_TAPS_4 (4) +#define XV_HSCALER_TAPS_6 (6) +#define XV_HSCALER_TAPS_8 (8) +#define XV_HSCALER_TAPS_10 (10) +#define XV_HSCALER_TAPS_12 (12) +#define XV_VSCALER_TAPS_2 (2) +#define XV_VSCALER_TAPS_4 (4) +#define XV_VSCALER_TAPS_6 (6) +#define XV_VSCALER_TAPS_8 (8) +#define XV_VSCALER_TAPS_10 (10) +#define XV_VSCALER_TAPS_12 (12) + +/* Mask definitions for Low and high 16 bits in a 32 bit number */ +#define XHSC_MASK_LOW_16BITS GENMASK(15, 0) +#define XHSC_MASK_HIGH_16BITS GENMASK(31, 16) +#define XHSC_MASK_LOW_32BITS GENMASK(31, 0) +#define XHSC_STEP_PRECISION_SHIFT (16) +#define XHSC_HPHASE_SHIFT_BY_6 (6) +#define XHSC_HPHASE_MULTIPLIER (9) +#define XSCALER_BITSHIFT_16 (16) + +/* Mask definitions for Low and high 16 bits in a 32 bit number */ +#define XVSC_MASK_LOW_16BITS GENMASK(15, 0) +#define XVSC_MASK_HIGH_16BITS GENMASK(31, 16) + +/* Scaler AP Control Registers */ +#define XSCALER_START BIT(0) +#define XSCALER_AUTO_RESTART BIT(7) +#define XSCALER_STREAM_ON (XSCALER_START | XSCALER_AUTO_RESTART) + +/* H-scaler registers */ +#define XV_HSCALER_CTRL_ADDR_AP_CTRL (0x0000) +#define XV_HSCALER_CTRL_ADDR_GIE (0x0004) +#define XV_HSCALER_CTRL_ADDR_IER (0x0008) +#define XV_HSCALER_CTRL_ADDR_ISR (0x000c) +#define XV_HSCALER_CTRL_ADDR_HWREG_HEIGHT_DATA (0x0010) +#define XV_HSCALER_CTRL_ADDR_HWREG_WIDTHIN_DATA (0x0018) +#define XV_HSCALER_CTRL_ADDR_HWREG_WIDTHOUT_DATA (0x0020) +#define XV_HSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA (0x0028) +#define XV_HSCALER_CTRL_ADDR_HWREG_PIXELRATE_DATA (0x0030) +#define XV_HSCALER_CTRL_ADDR_HWREG_COLORMODEOUT_DATA (0X0038) +#define XV_HSCALER_CTRL_ADDR_HWREG_HFLTCOEFF_BASE (0x0800) +#define XV_HSCALER_CTRL_ADDR_HWREG_HFLTCOEFF_HIGH (0x0bff) + +#define XV_HSCALER_CTRL_WIDTH_HWREG_HFLTCOEFF (16) +#define XV_HSCALER_CTRL_DEPTH_HWREG_HFLTCOEFF (384) +#define XV_HSCALER_CTRL_ADDR_HWREG_PHASESH_V_BASE (0x2000) +#define XV_HSCALER_CTRL_ADDR_HWREG_PHASESH_V_HIGH (0x3fff) +#define XV_HSCALER_CTRL_WIDTH_HWREG_PHASESH_V (18) +#define XV_HSCALER_CTRL_DEPTH_HWREG_PHASESH_V (1920) + +/* H-scaler masks */ +#define XV_HSCALER_PHASESH_V_OUTPUT_WR_EN BIT(8) + +/* V-scaler registers */ +#define XV_VSCALER_CTRL_ADDR_AP_CTRL (0x000) +#define XV_VSCALER_CTRL_ADDR_GIE (0x004) +#define XV_VSCALER_CTRL_ADDR_IER (0x008) +#define XV_VSCALER_CTRL_ADDR_ISR (0x00c) +#define XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTIN_DATA (0x010) +#define XV_VSCALER_CTRL_ADDR_HWREG_WIDTH_DATA (0x018) +#define XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTOUT_DATA (0x020) +#define XV_VSCALER_CTRL_ADDR_HWREG_LINERATE_DATA (0x028) +#define XV_VSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA (0x030) +#define XV_VSCALER_CTRL_ADDR_HWREG_VFLTCOEFF_BASE (0x800) +#define XV_VSCALER_CTRL_ADDR_HWREG_VFLTCOEFF_HIGH (0xbff) + +/* H-scaler coefficients for 6, 8, 10 and 12 tap filters */ +static const u16 +xhsc_coeff_taps6[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_TAPS_6] = { + { -132, 236, 3824, 236, -132, 64, }, + { -116, 184, 3816, 292, -144, 64, }, + { -100, 132, 3812, 348, -160, 64, }, + { -88, 84, 3808, 404, -176, 64, }, + { -72, 36, 3796, 464, -192, 64, }, + { -60, -8, 3780, 524, -208, 68, }, + { -48, -52, 3768, 588, -228, 68, }, + { -32, -96, 3748, 652, -244, 68, }, + { -20, -136, 3724, 716, -260, 72, }, + { -8, -172, 3696, 784, -276, 72, }, + { 0, -208, 3676, 848, -292, 72, }, + { 12, -244, 3640, 920, -308, 76, }, + { 20, -276, 3612, 988, -324, 76, }, + { 32, -304, 3568, 1060, -340, 80, }, + { 40, -332, 3532, 1132, -356, 80, }, + { 48, -360, 3492, 1204, -372, 84, }, + { 56, -384, 3448, 1276, -388, 88, }, + { 64, -408, 3404, 1352, -404, 88, }, + { 72, -428, 3348, 1428, -416, 92, }, + { 76, -448, 3308, 1500, -432, 92, }, + { 84, -464, 3248, 1576, -444, 96, }, + { 88, -480, 3200, 1652, -460, 96, }, + { 92, -492, 3140, 1728, -472, 100, }, + { 96, -504, 3080, 1804, -484, 104, }, + { 100, -516, 3020, 1880, -492, 104, }, + { 104, -524, 2956, 1960, -504, 104, }, + { 104, -532, 2892, 2036, -512, 108, }, + { 108, -540, 2832, 2108, -520, 108, }, + { 108, -544, 2764, 2184, -528, 112, }, + { 112, -544, 2688, 2260, -532, 112, }, + { 112, -548, 2624, 2336, -540, 112, }, + { 112, -548, 2556, 2408, -544, 112, }, + { 112, -544, 2480, 2480, -544, 112, }, + { 112, -544, 2408, 2556, -548, 112, }, + { 112, -540, 2336, 2624, -548, 112, }, + { 112, -532, 2260, 2688, -544, 112, }, + { 112, -528, 2184, 2764, -544, 108, }, + { 108, -520, 2108, 2832, -540, 108, }, + { 108, -512, 2036, 2892, -532, 104, }, + { 104, -504, 1960, 2956, -524, 104, }, + { 104, -492, 1880, 3020, -516, 100, }, + { 104, -484, 1804, 3080, -504, 96, }, + { 100, -472, 1728, 3140, -492, 92, }, + { 96, -460, 1652, 3200, -480, 88, }, + { 96, -444, 1576, 3248, -464, 84, }, + { 92, -432, 1500, 3308, -448, 76, }, + { 92, -416, 1428, 3348, -428, 72, }, + { 88, -404, 1352, 3404, -408, 64, }, + { 88, -388, 1276, 3448, -384, 56, }, + { 84, -372, 1204, 3492, -360, 48, }, + { 80, -356, 1132, 3532, -332, 40, }, + { 80, -340, 1060, 3568, -304, 32, }, + { 76, -324, 988, 3612, -276, 20, }, + { 76, -308, 920, 3640, -244, 12, }, + { 72, -292, 848, 3676, -208, 0, }, + { 72, -276, 784, 3696, -172, -8, }, + { 72, -260, 716, 3724, -136, -20, }, + { 68, -244, 652, 3748, -96, -32, }, + { 68, -228, 588, 3768, -52, -48, }, + { 68, -208, 524, 3780, -8, -60, }, + { 64, -192, 464, 3796, 36, -72, }, + { 64, -176, 404, 3808, 84, -88, }, + { 64, -160, 348, 3812, 132, -100, }, + { 64, -144, 292, 3816, 184, -116, } +}; + +static const u16 +xhsc_coeff_taps8[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_TAPS_8] = { + {-5, 309, 1023, 1445, 1034, 317, -3, -24, }, + {-6, 300, 1011, 1445, 1045, 326, -1, -24, }, + {-7, 291, 1000, 1444, 1056, 336, 0, -24, }, + {-9, 282, 988, 1444, 1067, 345, 2, -24, }, + {-10, 274, 977, 1443, 1078, 354, 4, -24, }, + {-11, 266, 965, 1441, 1089, 364, 6, -24, }, + {-12, 258, 953, 1440, 1100, 373, 8, -24, }, + {-13, 250, 942, 1438, 1110, 383, 10, -24, }, + {-14, 242, 930, 1437, 1121, 393, 12, -24, }, + {-15, 234, 918, 1434, 1131, 403, 14, -24, }, + {-16, 226, 906, 1432, 1142, 413, 17, -24, }, + {-17, 219, 894, 1430, 1152, 423, 19, -24, }, + {-17, 211, 882, 1427, 1162, 433, 22, -24, }, + {-18, 204, 870, 1424, 1172, 443, 24, -24, }, + {-19, 197, 858, 1420, 1182, 454, 27, -24, }, + {-19, 190, 846, 1417, 1191, 464, 30, -24, }, + {-20, 183, 834, 1413, 1201, 475, 33, -24, }, + {-20, 176, 822, 1409, 1210, 486, 36, -24, }, + {-21, 170, 810, 1405, 1220, 497, 39, -24, }, + {-21, 163, 798, 1401, 1229, 507, 42, -24, }, + {-22, 157, 786, 1396, 1238, 518, 46, -24, }, + {-22, 151, 774, 1392, 1247, 529, 49, -24, }, + {-22, 144, 762, 1387, 1255, 540, 53, -24, }, + {-23, 139, 750, 1382, 1264, 552, 57, -24, }, + {-23, 133, 738, 1376, 1272, 563, 60, -24, }, + {-23, 127, 726, 1371, 1280, 574, 64, -24, }, + {-23, 121, 714, 1365, 1288, 586, 69, -24, }, + {-23, 116, 703, 1359, 1296, 597, 73, -24, }, + {-24, 111, 691, 1353, 1304, 609, 77, -24, }, + {-24, 105, 679, 1346, 1312, 620, 81, -24, }, + {-24, 100, 667, 1340, 1319, 632, 86, -24, }, + {-24, 96, 655, 1333, 1326, 644, 91, -24, }, + {-24, 91, 644, 1326, 1333, 655, 96, -24, }, + {-24, 86, 632, 1319, 1340, 667, 100, -24, }, + {-24, 81, 620, 1312, 1346, 679, 105, -24, }, + {-24, 77, 609, 1304, 1353, 691, 111, -24, }, + {-24, 73, 597, 1296, 1359, 703, 116, -23, }, + {-24, 69, 586, 1288, 1365, 714, 121, -23, }, + {-24, 64, 574, 1280, 1371, 726, 127, -23, }, + {-24, 60, 563, 1272, 1376, 738, 133, -23, }, + {-24, 57, 552, 1264, 1382, 750, 139, -23, }, + {-24, 53, 540, 1255, 1387, 762, 144, -22, }, + {-24, 49, 529, 1247, 1392, 774, 151, -22, }, + {-24, 46, 518, 1238, 1396, 786, 157, -22, }, + {-24, 42, 507, 1229, 1401, 798, 163, -21, }, + {-24, 39, 497, 1220, 1405, 810, 170, -21, }, + {-24, 36, 486, 1210, 1409, 822, 176, -20, }, + {-24, 33, 475, 1201, 1413, 834, 183, -20, }, + {-24, 30, 464, 1191, 1417, 846, 190, -19, }, + {-24, 27, 454, 1182, 1420, 858, 197, -19, }, + {-24, 24, 443, 1172, 1424, 870, 204, -18, }, + {-24, 22, 433, 1162, 1427, 882, 211, -17, }, + {-24, 19, 423, 1152, 1430, 894, 219, -17, }, + {-24, 17, 413, 1142, 1432, 906, 226, -16, }, + {-24, 14, 403, 1131, 1434, 918, 234, -15, }, + {-24, 12, 393, 1121, 1437, 930, 242, -14, }, + {-24, 10, 383, 1110, 1438, 942, 250, -13, }, + {-24, 8, 373, 1100, 1440, 953, 258, -12, }, + {-24, 6, 364, 1089, 1441, 965, 266, -11, }, + {-24, 4, 354, 1078, 1443, 977, 274, -10, }, + {-24, 2, 345, 1067, 1444, 988, 282, -9, }, + {-24, 0, 336, 1056, 1444, 1000, 291, -7, }, + {-24, -1, 326, 1045, 1445, 1011, 300, -6, }, + {-24, -3, 317, 1034, 1445, 1023, 309, -5, }, +}; + +static const u16 +xhsc_coeff_taps10[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_TAPS_10] = { + {59, 224, 507, 790, 911, 793, 512, 227, 61, 13, }, + {58, 220, 502, 786, 911, 797, 516, 231, 62, 13, }, + {56, 216, 497, 783, 911, 800, 521, 235, 64, 13, }, + {55, 213, 492, 779, 910, 804, 526, 238, 65, 13, }, + {54, 209, 487, 775, 910, 807, 531, 242, 67, 14, }, + {52, 206, 482, 772, 910, 810, 536, 246, 69, 14, }, + {51, 202, 477, 768, 909, 813, 541, 250, 70, 14, }, + {50, 199, 473, 764, 909, 817, 545, 254, 72, 14, }, + {48, 195, 468, 760, 908, 820, 550, 258, 74, 15, }, + {47, 192, 463, 756, 908, 823, 555, 262, 76, 15, }, + {46, 188, 458, 752, 907, 826, 560, 266, 78, 15, }, + {45, 185, 453, 748, 906, 829, 565, 270, 79, 16, }, + {44, 182, 448, 744, 906, 832, 569, 274, 81, 16, }, + {42, 179, 444, 740, 905, 835, 574, 278, 83, 16, }, + {41, 175, 439, 736, 904, 837, 579, 282, 85, 17, }, + {40, 172, 434, 732, 903, 840, 584, 286, 87, 17, }, + {39, 169, 429, 728, 902, 843, 589, 290, 89, 18, }, + {38, 166, 425, 724, 901, 846, 593, 294, 91, 18, }, + {37, 163, 420, 720, 900, 848, 598, 298, 93, 18, }, + {36, 160, 415, 716, 899, 851, 603, 302, 95, 19, }, + {35, 157, 410, 711, 897, 854, 608, 307, 98, 19, }, + {34, 154, 406, 707, 896, 856, 612, 311, 100, 20, }, + {33, 151, 401, 703, 895, 859, 617, 315, 102, 20, }, + {33, 148, 396, 698, 893, 861, 622, 320, 104, 21, }, + {32, 145, 392, 694, 892, 863, 626, 324, 107, 21, }, + {31, 142, 387, 690, 890, 866, 631, 328, 109, 22, }, + {30, 140, 382, 685, 889, 868, 636, 333, 111, 23, }, + {29, 137, 378, 681, 887, 870, 640, 337, 114, 23, }, + {28, 134, 373, 677, 886, 872, 645, 342, 116, 24, }, + {28, 131, 369, 672, 884, 874, 649, 346, 119, 24, }, + {27, 129, 364, 668, 882, 876, 654, 350, 121, 25, }, + {26, 126, 359, 663, 880, 878, 659, 355, 124, 26, }, + {26, 124, 355, 659, 878, 880, 663, 359, 126, 26, }, + {25, 121, 350, 654, 876, 882, 668, 364, 129, 27, }, + {24, 119, 346, 649, 874, 884, 672, 369, 131, 28, }, + {24, 116, 342, 645, 872, 886, 677, 373, 134, 28, }, + {23, 114, 337, 640, 870, 887, 681, 378, 137, 29, }, + {23, 111, 333, 636, 868, 889, 685, 382, 140, 30, }, + {22, 109, 328, 631, 866, 890, 690, 387, 142, 31, }, + {21, 107, 324, 626, 863, 892, 694, 392, 145, 32, }, + {21, 104, 320, 622, 861, 893, 698, 396, 148, 33, }, + {20, 102, 315, 617, 859, 895, 703, 401, 151, 33, }, + {20, 100, 311, 612, 856, 896, 707, 406, 154, 34, }, + {19, 98, 307, 608, 854, 897, 711, 410, 157, 35, }, + {19, 95, 302, 603, 851, 899, 716, 415, 160, 36, }, + {18, 93, 298, 598, 848, 900, 720, 420, 163, 37, }, + {18, 91, 294, 593, 846, 901, 724, 425, 166, 38, }, + {18, 89, 290, 589, 843, 902, 728, 429, 169, 39, }, + {17, 87, 286, 584, 840, 903, 732, 434, 172, 40, }, + {17, 85, 282, 579, 837, 904, 736, 439, 175, 41, }, + {16, 83, 278, 574, 835, 905, 740, 444, 179, 42, }, + {16, 81, 274, 569, 832, 906, 744, 448, 182, 44, }, + {16, 79, 270, 565, 829, 906, 748, 453, 185, 45, }, + {15, 78, 266, 560, 826, 907, 752, 458, 188, 46, }, + {15, 76, 262, 555, 823, 908, 756, 463, 192, 47, }, + {15, 74, 258, 550, 820, 908, 760, 468, 195, 48, }, + {14, 72, 254, 545, 817, 909, 764, 473, 199, 50, }, + {14, 70, 250, 541, 813, 909, 768, 477, 202, 51, }, + {14, 69, 246, 536, 810, 910, 772, 482, 206, 52, }, + {14, 67, 242, 531, 807, 910, 775, 487, 209, 54, }, + {13, 65, 238, 526, 804, 910, 779, 492, 213, 55, }, + {13, 64, 235, 521, 800, 911, 783, 497, 216, 56, }, + {13, 62, 231, 516, 797, 911, 786, 502, 220, 58, }, + {13, 61, 227, 512, 793, 911, 790, 507, 224, 59, }, +}; + +static const u16 +xhsc_coeff_taps12[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_TAPS_12] = { + {48, 143, 307, 504, 667, 730, 669, 507, 310, 145, 49, 18, }, + {47, 141, 304, 501, 665, 730, 670, 510, 313, 147, 50, 18, }, + {46, 138, 301, 498, 663, 730, 672, 513, 316, 149, 51, 18, }, + {45, 136, 298, 495, 661, 730, 674, 516, 319, 151, 52, 18, }, + {44, 134, 295, 492, 659, 730, 676, 519, 322, 153, 53, 18, }, + {44, 132, 292, 489, 657, 730, 677, 522, 325, 155, 54, 18, }, + {43, 130, 289, 486, 655, 729, 679, 525, 328, 157, 55, 19, }, + {42, 129, 287, 483, 653, 729, 681, 528, 331, 160, 56, 19, }, + {41, 127, 284, 480, 651, 729, 683, 531, 334, 162, 57, 19, }, + {40, 125, 281, 477, 648, 729, 684, 534, 337, 164, 58, 19, }, + {40, 123, 278, 474, 646, 728, 686, 537, 340, 166, 59, 20, }, + {39, 121, 275, 471, 644, 728, 687, 539, 343, 169, 60, 20, }, + {38, 119, 272, 468, 642, 727, 689, 542, 346, 171, 61, 20, }, + {37, 117, 269, 465, 640, 727, 690, 545, 349, 173, 62, 20, }, + {37, 115, 266, 461, 638, 727, 692, 548, 353, 175, 63, 21, }, + {36, 114, 264, 458, 635, 726, 693, 551, 356, 178, 65, 21, }, + {35, 112, 261, 455, 633, 726, 695, 554, 359, 180, 66, 21, }, + {35, 110, 258, 452, 631, 725, 696, 556, 362, 183, 67, 21, }, + {34, 108, 255, 449, 628, 724, 698, 559, 365, 185, 68, 22, }, + {33, 107, 252, 446, 626, 724, 699, 562, 368, 187, 69, 22, }, + {33, 105, 250, 443, 624, 723, 700, 565, 371, 190, 71, 22, }, + {32, 103, 247, 440, 621, 723, 702, 567, 374, 192, 72, 23, }, + {32, 101, 244, 437, 619, 722, 703, 570, 377, 195, 73, 23, }, + {31, 100, 241, 433, 617, 721, 704, 573, 380, 197, 75, 23, }, + {31, 98, 239, 430, 614, 720, 705, 576, 383, 200, 76, 24, }, + {30, 97, 236, 427, 612, 720, 707, 578, 387, 202, 77, 24, }, + {29, 95, 233, 424, 609, 719, 708, 581, 390, 205, 79, 24, }, + {29, 93, 231, 421, 607, 718, 709, 584, 393, 207, 80, 25, }, + {28, 92, 228, 418, 604, 717, 710, 586, 396, 210, 81, 25, }, + {28, 90, 225, 415, 602, 716, 711, 589, 399, 212, 83, 26, }, + {27, 89, 223, 412, 599, 715, 712, 591, 402, 215, 84, 26, }, + {27, 87, 220, 408, 597, 714, 713, 594, 405, 217, 86, 27, }, + {27, 86, 217, 405, 594, 713, 714, 597, 408, 220, 87, 27, }, + {26, 84, 215, 402, 591, 712, 715, 599, 412, 223, 89, 27, }, + {26, 83, 212, 399, 589, 711, 716, 602, 415, 225, 90, 28, }, + {25, 81, 210, 396, 586, 710, 717, 604, 418, 228, 92, 28, }, + {25, 80, 207, 393, 584, 709, 718, 607, 421, 231, 93, 29, }, + {24, 79, 205, 390, 581, 708, 719, 609, 424, 233, 95, 29, }, + {24, 77, 202, 387, 578, 707, 720, 612, 427, 236, 97, 30, }, + {24, 76, 200, 383, 576, 705, 720, 614, 430, 239, 98, 31, }, + {23, 75, 197, 380, 573, 704, 721, 617, 433, 241, 100, 31, }, + {23, 73, 195, 377, 570, 703, 722, 619, 437, 244, 101, 32, }, + {23, 72, 192, 374, 567, 702, 723, 621, 440, 247, 103, 32, }, + {22, 71, 190, 371, 565, 700, 723, 624, 443, 250, 105, 33, }, + {22, 69, 187, 368, 562, 699, 724, 626, 446, 252, 107, 33, }, + {22, 68, 185, 365, 559, 698, 724, 628, 449, 255, 108, 34, }, + {21, 67, 183, 362, 556, 696, 725, 631, 452, 258, 110, 35, }, + {21, 66, 180, 359, 554, 695, 726, 633, 455, 261, 112, 35, }, + {21, 65, 178, 356, 551, 693, 726, 635, 458, 264, 114, 36, }, + {21, 63, 175, 353, 548, 692, 727, 638, 461, 266, 115, 37, }, + {20, 62, 173, 349, 545, 690, 727, 640, 465, 269, 117, 37, }, + {20, 61, 171, 346, 542, 689, 727, 642, 468, 272, 119, 38, }, + {20, 60, 169, 343, 539, 687, 728, 644, 471, 275, 121, 39, }, + {20, 59, 166, 340, 537, 686, 728, 646, 474, 278, 123, 40, }, + {19, 58, 164, 337, 534, 684, 729, 648, 477, 281, 125, 40, }, + {19, 57, 162, 334, 531, 683, 729, 651, 480, 284, 127, 41, }, + {19, 56, 160, 331, 528, 681, 729, 653, 483, 287, 129, 42, }, + {19, 55, 157, 328, 525, 679, 729, 655, 486, 289, 130, 43, }, + {18, 54, 155, 325, 522, 677, 730, 657, 489, 292, 132, 44, }, + {18, 53, 153, 322, 519, 676, 730, 659, 492, 295, 134, 44, }, + {18, 52, 151, 319, 516, 674, 730, 661, 495, 298, 136, 45, }, + {18, 51, 149, 316, 513, 672, 730, 663, 498, 301, 138, 46, }, + {18, 50, 147, 313, 510, 670, 730, 665, 501, 304, 141, 47, }, + {18, 49, 145, 310, 507, 669, 730, 667, 504, 307, 143, 48, }, +}; + +/* V-scaler coefficients for 6, 8, 10 and 12 tap filters */ +static const u16 +xvsc_coeff_taps6[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_TAPS_6] = { + {-132, 236, 3824, 236, -132, 64, }, + {-116, 184, 3816, 292, -144, 64, }, + {-100, 132, 3812, 348, -160, 64, }, + {-88, 84, 3808, 404, -176, 64, }, + {-72, 36, 3796, 464, -192, 64, }, + {-60, -8, 3780, 524, -208, 68, }, + {-48, -52, 3768, 588, -228, 68, }, + {-32, -96, 3748, 652, -244, 68, }, + {-20, -136, 3724, 716, -260, 72, }, + {-8, -172, 3696, 784, -276, 72, }, + {0, -208, 3676, 848, -292, 72, }, + {12, -244, 3640, 920, -308, 76, }, + {20, -276, 3612, 988, -324, 76, }, + {32, -304, 3568, 1060, -340, 80, }, + {40, -332, 3532, 1132, -356, 80, }, + {48, -360, 3492, 1204, -372, 84, }, + {56, -384, 3448, 1276, -388, 88, }, + {64, -408, 3404, 1352, -404, 88, }, + {72, -428, 3348, 1428, -416, 92, }, + {76, -448, 3308, 1500, -432, 92, }, + {84, -464, 3248, 1576, -444, 96, }, + {88, -480, 3200, 1652, -460, 96, }, + {92, -492, 3140, 1728, -472, 100, }, + {96, -504, 3080, 1804, -484, 104, }, + {100, -516, 3020, 1880, -492, 104, }, + {104, -524, 2956, 1960, -504, 104, }, + {104, -532, 2892, 2036, -512, 108, }, + {108, -540, 2832, 2108, -520, 108, }, + {108, -544, 2764, 2184, -528, 112, }, + {112, -544, 2688, 2260, -532, 112, }, + {112, -548, 2624, 2336, -540, 112, }, + {112, -548, 2556, 2408, -544, 112, }, + {112, -544, 2480, 2480, -544, 112, }, + {112, -544, 2408, 2556, -548, 112, }, + {112, -540, 2336, 2624, -548, 112, }, + {112, -532, 2260, 2688, -544, 112, }, + {112, -528, 2184, 2764, -544, 108, }, + {108, -520, 2108, 2832, -540, 108, }, + {108, -512, 2036, 2892, -532, 104, }, + {104, -504, 1960, 2956, -524, 104, }, + {104, -492, 1880, 3020, -516, 100, }, + {104, -484, 1804, 3080, -504, 96, }, + {100, -472, 1728, 3140, -492, 92, }, + { 96, -460, 1652, 3200, -480, 88, }, + { 96, -444, 1576, 3248, -464, 84, }, + { 92, -432, 1500, 3308, -448, 76, }, + { 92, -416, 1428, 3348, -428, 72, }, + { 88, -404, 1352, 3404, -408, 64, }, + { 88, -388, 1276, 3448, -384, 56, }, + { 84, -372, 1204, 3492, -360, 48, }, + { 80, -356, 1132, 3532, -332, 40, }, + { 80, -340, 1060, 3568, -304, 32, }, + { 76, -324, 988, 3612, -276, 20, }, + { 76, -308, 920, 3640, -244, 12, }, + { 72, -292, 848, 3676, -208, 0, }, + { 72, -276, 784, 3696, -172, -8, }, + { 72, -260, 716, 3724, -136, -20, }, + { 68, -244, 652, 3748, -96, -32, }, + { 68, -228, 588, 3768, -52, -48, }, + { 68, -208, 524, 3780, -8, -60, }, + { 64, -192, 464, 3796, 36, -72, }, + { 64, -176, 404, 3808, 84, -88, }, + { 64, -160, 348, 3812, 132, -100, }, + { 64, -144, 292, 3816, 184, -116, } +}; + +static const u16 +xvsc_coeff_taps8[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_TAPS_8] = { + {-5, 309, 1023, 1445, 1034, 317, -3, -24, }, + {-6, 300, 1011, 1445, 1045, 326, -1, -24, }, + {-7, 291, 1000, 1444, 1056, 336, 0, -24, }, + {-9, 282, 988, 1444, 1067, 345, 2, -24, }, + {-10, 274, 977, 1443, 1078, 354, 4, -24, }, + {-11, 266, 965, 1441, 1089, 364, 6, -24, }, + {-12, 258, 953, 1440, 1100, 373, 8, -24, }, + {-13, 250, 942, 1438, 1110, 383, 10, -24, }, + {-14, 242, 930, 1437, 1121, 393, 12, -24, }, + {-15, 234, 918, 1434, 1131, 403, 14, -24, }, + {-16, 226, 906, 1432, 1142, 413, 17, -24, }, + {-17, 219, 894, 1430, 1152, 423, 19, -24, }, + {-17, 211, 882, 1427, 1162, 433, 22, -24, }, + {-18, 204, 870, 1424, 1172, 443, 24, -24, }, + {-19, 197, 858, 1420, 1182, 454, 27, -24, }, + {-19, 190, 846, 1417, 1191, 464, 30, -24, }, + {-20, 183, 834, 1413, 1201, 475, 33, -24, }, + {-20, 176, 822, 1409, 1210, 486, 36, -24, }, + {-21, 170, 810, 1405, 1220, 497, 39, -24, }, + {-21, 163, 798, 1401, 1229, 507, 42, -24, }, + {-22, 157, 786, 1396, 1238, 518, 46, -24, }, + {-22, 151, 774, 1392, 1247, 529, 49, -24, }, + {-22, 144, 762, 1387, 1255, 540, 53, -24, }, + {-23, 139, 750, 1382, 1264, 552, 57, -24, }, + {-23, 133, 738, 1376, 1272, 563, 60, -24, }, + {-23, 127, 726, 1371, 1280, 574, 64, -24, }, + {-23, 121, 714, 1365, 1288, 586, 69, -24, }, + {-23, 116, 703, 1359, 1296, 597, 73, -24, }, + {-24, 111, 691, 1353, 1304, 609, 77, -24, }, + {-24, 105, 679, 1346, 1312, 620, 81, -24, }, + {-24, 100, 667, 1340, 1319, 632, 86, -24, }, + {-24, 96, 655, 1333, 1326, 644, 91, -24, }, + {-24, 91, 644, 1326, 1333, 655, 96, -24, }, + {-24, 86, 632, 1319, 1340, 667, 100, -24, }, + {-24, 81, 620, 1312, 1346, 679, 105, -24, }, + {-24, 77, 609, 1304, 1353, 691, 111, -24, }, + {-24, 73, 597, 1296, 1359, 703, 116, -23, }, + {-24, 69, 586, 1288, 1365, 714, 121, -23, }, + {-24, 64, 574, 1280, 1371, 726, 127, -23, }, + {-24, 60, 563, 1272, 1376, 738, 133, -23, }, + {-24, 57, 552, 1264, 1382, 750, 139, -23, }, + {-24, 53, 540, 1255, 1387, 762, 144, -22, }, + {-24, 49, 529, 1247, 1392, 774, 151, -22, }, + {-24, 46, 518, 1238, 1396, 786, 157, -22, }, + {-24, 42, 507, 1229, 1401, 798, 163, -21, }, + {-24, 39, 497, 1220, 1405, 810, 170, -21, }, + {-24, 36, 486, 1210, 1409, 822, 176, -20, }, + {-24, 33, 475, 1201, 1413, 834, 183, -20, }, + {-24, 30, 464, 1191, 1417, 846, 190, -19, }, + {-24, 27, 454, 1182, 1420, 858, 197, -19, }, + {-24, 24, 443, 1172, 1424, 870, 204, -18, }, + {-24, 22, 433, 1162, 1427, 882, 211, -17, }, + {-24, 19, 423, 1152, 1430, 894, 219, -17, }, + {-24, 17, 413, 1142, 1432, 906, 226, -16, }, + {-24, 14, 403, 1131, 1434, 918, 234, -15, }, + {-24, 12, 393, 1121, 1437, 930, 242, -14, }, + {-24, 10, 383, 1110, 1438, 942, 250, -13, }, + {-24, 8, 373, 1100, 1440, 953, 258, -12, }, + {-24, 6, 364, 1089, 1441, 965, 266, -11, }, + {-24, 4, 354, 1078, 1443, 977, 274, -10, }, + {-24, 2, 345, 1067, 1444, 988, 282, -9, }, + {-24, 0, 336, 1056, 1444, 1000, 291, -7, }, + {-24, -1, 326, 1045, 1445, 1011, 300, -6, }, + {-24, -3, 317, 1034, 1445, 1023, 309, -5, }, +}; + +static const u16 +xvsc_coeff_taps10[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_TAPS_10] = { + {59, 224, 507, 790, 911, 793, 512, 227, 61, 13, }, + {58, 220, 502, 786, 911, 797, 516, 231, 62, 13, }, + {56, 216, 497, 783, 911, 800, 521, 235, 64, 13, }, + {55, 213, 492, 779, 910, 804, 526, 238, 65, 13, }, + {54, 209, 487, 775, 910, 807, 531, 242, 67, 14, }, + {52, 206, 482, 772, 910, 810, 536, 246, 69, 14, }, + {51, 202, 477, 768, 909, 813, 541, 250, 70, 14, }, + {50, 199, 473, 764, 909, 817, 545, 254, 72, 14, }, + {48, 195, 468, 760, 908, 820, 550, 258, 74, 15, }, + {47, 192, 463, 756, 908, 823, 555, 262, 76, 15, }, + {46, 188, 458, 752, 907, 826, 560, 266, 78, 15, }, + {45, 185, 453, 748, 906, 829, 565, 270, 79, 16, }, + {44, 182, 448, 744, 906, 832, 569, 274, 81, 16, }, + {42, 179, 444, 740, 905, 835, 574, 278, 83, 16, }, + {41, 175, 439, 736, 904, 837, 579, 282, 85, 17, }, + {40, 172, 434, 732, 903, 840, 584, 286, 87, 17, }, + {39, 169, 429, 728, 902, 843, 589, 290, 89, 18, }, + {38, 166, 425, 724, 901, 846, 593, 294, 91, 18, }, + {37, 163, 420, 720, 900, 848, 598, 298, 93, 18, }, + {36, 160, 415, 716, 899, 851, 603, 302, 95, 19, }, + {35, 157, 410, 711, 897, 854, 608, 307, 98, 19, }, + {34, 154, 406, 707, 896, 856, 612, 311, 100, 20, }, + {33, 151, 401, 703, 895, 859, 617, 315, 102, 20, }, + {33, 148, 396, 698, 893, 861, 622, 320, 104, 21, }, + {32, 145, 392, 694, 892, 863, 626, 324, 107, 21, }, + {31, 142, 387, 690, 890, 866, 631, 328, 109, 22, }, + {30, 140, 382, 685, 889, 868, 636, 333, 111, 23, }, + {29, 137, 378, 681, 887, 870, 640, 337, 114, 23, }, + {28, 134, 373, 677, 886, 872, 645, 342, 116, 24, }, + {28, 131, 369, 672, 884, 874, 649, 346, 119, 24, }, + {27, 129, 364, 668, 882, 876, 654, 350, 121, 25, }, + {26, 126, 359, 663, 880, 878, 659, 355, 124, 26, }, + {26, 124, 355, 659, 878, 880, 663, 359, 126, 26, }, + {25, 121, 350, 654, 876, 882, 668, 364, 129, 27, }, + {24, 119, 346, 649, 874, 884, 672, 369, 131, 28, }, + {24, 116, 342, 645, 872, 886, 677, 373, 134, 28, }, + {23, 114, 337, 640, 870, 887, 681, 378, 137, 29, }, + {23, 111, 333, 636, 868, 889, 685, 382, 140, 30, }, + {22, 109, 328, 631, 866, 890, 690, 387, 142, 31, }, + {21, 107, 324, 626, 863, 892, 694, 392, 145, 32, }, + {21, 104, 320, 622, 861, 893, 698, 396, 148, 33, }, + {20, 102, 315, 617, 859, 895, 703, 401, 151, 33, }, + {20, 100, 311, 612, 856, 896, 707, 406, 154, 34, }, + {19, 98, 307, 608, 854, 897, 711, 410, 157, 35, }, + {19, 95, 302, 603, 851, 899, 716, 415, 160, 36, }, + {18, 93, 298, 598, 848, 900, 720, 420, 163, 37, }, + {18, 91, 294, 593, 846, 901, 724, 425, 166, 38, }, + {18, 89, 290, 589, 843, 902, 728, 429, 169, 39, }, + {17, 87, 286, 584, 840, 903, 732, 434, 172, 40, }, + {17, 85, 282, 579, 837, 904, 736, 439, 175, 41, }, + {16, 83, 278, 574, 835, 905, 740, 444, 179, 42, }, + {16, 81, 274, 569, 832, 906, 744, 448, 182, 44, }, + {16, 79, 270, 565, 829, 906, 748, 453, 185, 45, }, + {15, 78, 266, 560, 826, 907, 752, 458, 188, 46, }, + {15, 76, 262, 555, 823, 908, 756, 463, 192, 47, }, + {15, 74, 258, 550, 820, 908, 760, 468, 195, 48, }, + {14, 72, 254, 545, 817, 909, 764, 473, 199, 50, }, + {14, 70, 250, 541, 813, 909, 768, 477, 202, 51, }, + {14, 69, 246, 536, 810, 910, 772, 482, 206, 52, }, + {14, 67, 242, 531, 807, 910, 775, 487, 209, 54, }, + {13, 65, 238, 526, 804, 910, 779, 492, 213, 55, }, + {13, 64, 235, 521, 800, 911, 783, 497, 216, 56, }, + {13, 62, 231, 516, 797, 911, 786, 502, 220, 58, }, + {13, 61, 227, 512, 793, 911, 790, 507, 224, 59, }, +}; + +static const u16 +xvsc_coeff_taps12[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_TAPS_12] = { + {48, 143, 307, 504, 667, 730, 669, 507, 310, 145, 49, 18, }, + {47, 141, 304, 501, 665, 730, 670, 510, 313, 147, 50, 18, }, + {46, 138, 301, 498, 663, 730, 672, 513, 316, 149, 51, 18, }, + {45, 136, 298, 495, 661, 730, 674, 516, 319, 151, 52, 18, }, + {44, 134, 295, 492, 659, 730, 676, 519, 322, 153, 53, 18, }, + {44, 132, 292, 489, 657, 730, 677, 522, 325, 155, 54, 18, }, + {43, 130, 289, 486, 655, 729, 679, 525, 328, 157, 55, 19, }, + {42, 129, 287, 483, 653, 729, 681, 528, 331, 160, 56, 19, }, + {41, 127, 284, 480, 651, 729, 683, 531, 334, 162, 57, 19, }, + {40, 125, 281, 477, 648, 729, 684, 534, 337, 164, 58, 19, }, + {40, 123, 278, 474, 646, 728, 686, 537, 340, 166, 59, 20, }, + {39, 121, 275, 471, 644, 728, 687, 539, 343, 169, 60, 20, }, + {38, 119, 272, 468, 642, 727, 689, 542, 346, 171, 61, 20, }, + {37, 117, 269, 465, 640, 727, 690, 545, 349, 173, 62, 20, }, + {37, 115, 266, 461, 638, 727, 692, 548, 353, 175, 63, 21, }, + {36, 114, 264, 458, 635, 726, 693, 551, 356, 178, 65, 21, }, + {35, 112, 261, 455, 633, 726, 695, 554, 359, 180, 66, 21, }, + {35, 110, 258, 452, 631, 725, 696, 556, 362, 183, 67, 21, }, + {34, 108, 255, 449, 628, 724, 698, 559, 365, 185, 68, 22, }, + {33, 107, 252, 446, 626, 724, 699, 562, 368, 187, 69, 22, }, + {33, 105, 250, 443, 624, 723, 700, 565, 371, 190, 71, 22, }, + {32, 103, 247, 440, 621, 723, 702, 567, 374, 192, 72, 23, }, + {32, 101, 244, 437, 619, 722, 703, 570, 377, 195, 73, 23, }, + {31, 100, 241, 433, 617, 721, 704, 573, 380, 197, 75, 23, }, + {31, 98, 239, 430, 614, 720, 705, 576, 383, 200, 76, 24, }, + {30, 97, 236, 427, 612, 720, 707, 578, 387, 202, 77, 24, }, + {29, 95, 233, 424, 609, 719, 708, 581, 390, 205, 79, 24, }, + {29, 93, 231, 421, 607, 718, 709, 584, 393, 207, 80, 25, }, + {28, 92, 228, 418, 604, 717, 710, 586, 396, 210, 81, 25, }, + {28, 90, 225, 415, 602, 716, 711, 589, 399, 212, 83, 26, }, + {27, 89, 223, 412, 599, 715, 712, 591, 402, 215, 84, 26, }, + {27, 87, 220, 408, 597, 714, 713, 594, 405, 217, 86, 27, }, + {27, 86, 217, 405, 594, 713, 714, 597, 408, 220, 87, 27, }, + {26, 84, 215, 402, 591, 712, 715, 599, 412, 223, 89, 27, }, + {26, 83, 212, 399, 589, 711, 716, 602, 415, 225, 90, 28, }, + {25, 81, 210, 396, 586, 710, 717, 604, 418, 228, 92, 28, }, + {25, 80, 207, 393, 584, 709, 718, 607, 421, 231, 93, 29, }, + {24, 79, 205, 390, 581, 708, 719, 609, 424, 233, 95, 29, }, + {24, 77, 202, 387, 578, 707, 720, 612, 427, 236, 97, 30, }, + {24, 76, 200, 383, 576, 705, 720, 614, 430, 239, 98, 31, }, + {23, 75, 197, 380, 573, 704, 721, 617, 433, 241, 100, 31, }, + {23, 73, 195, 377, 570, 703, 722, 619, 437, 244, 101, 32, }, + {23, 72, 192, 374, 567, 702, 723, 621, 440, 247, 103, 32, }, + {22, 71, 190, 371, 565, 700, 723, 624, 443, 250, 105, 33, }, + {22, 69, 187, 368, 562, 699, 724, 626, 446, 252, 107, 33, }, + {22, 68, 185, 365, 559, 698, 724, 628, 449, 255, 108, 34, }, + {21, 67, 183, 362, 556, 696, 725, 631, 452, 258, 110, 35, }, + {21, 66, 180, 359, 554, 695, 726, 633, 455, 261, 112, 35, }, + {21, 65, 178, 356, 551, 693, 726, 635, 458, 264, 114, 36, }, + {21, 63, 175, 353, 548, 692, 727, 638, 461, 266, 115, 37, }, + {20, 62, 173, 349, 545, 690, 727, 640, 465, 269, 117, 37, }, + {20, 61, 171, 346, 542, 689, 727, 642, 468, 272, 119, 38, }, + {20, 60, 169, 343, 539, 687, 728, 644, 471, 275, 121, 39, }, + {20, 59, 166, 340, 537, 686, 728, 646, 474, 278, 123, 40, }, + {19, 58, 164, 337, 534, 684, 729, 648, 477, 281, 125, 40, }, + {19, 57, 162, 334, 531, 683, 729, 651, 480, 284, 127, 41, }, + {19, 56, 160, 331, 528, 681, 729, 653, 483, 287, 129, 42, }, + {19, 55, 157, 328, 525, 679, 729, 655, 486, 289, 130, 43, }, + {18, 54, 155, 325, 522, 677, 730, 657, 489, 292, 132, 44, }, + {18, 53, 153, 322, 519, 676, 730, 659, 492, 295, 134, 44, }, + {18, 52, 151, 319, 516, 674, 730, 661, 495, 298, 136, 45, }, + {18, 51, 149, 316, 513, 672, 730, 663, 498, 301, 138, 46, }, + {18, 50, 147, 313, 510, 670, 730, 665, 501, 304, 141, 47, }, + {18, 49, 145, 310, 507, 669, 730, 667, 504, 307, 143, 48, }, +}; + +enum xilinx_scaler_vid_reg_fmts { + XVIDC_CSF_RGB = 0, + XVIDC_CSF_YCRCB_444, + XVIDC_CSF_YCRCB_422, + XVIDC_CSF_YCRCB_420, +}; + +static const u32 xilinx_scaler_video_fmts[] = { + MEDIA_BUS_FMT_RGB888_1X24, + MEDIA_BUS_FMT_VUY8_1X24, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYYUYY8_1X24, +}; + +/** + * struct xilinx_scaler - Core configuration of scaler device structure + * @base: pointer to register base address + * @dev: device structure + * @bridge: xilinx bridge + * @width_in: input width + * @height_in: input height + * @width_out: output width + * @height_out: output height + * @fmt_in: input format + * @fmt_out: output format + * @num_hori_taps: number of horizontal taps + * @num_vert_taps: number of vertical taps + * @max_num_phases: maximum number of phases + * @pix_per_clk: Pixels per Clock cycle the IP operates upon + * @max_pixels: The maximum number of pixels that the H-scaler examines + * @max_lines: The maximum number of lines that the V-scaler examines + * @H_phases: The phases needed to program the H-scaler for different taps + * @hscaler_coeff: The complete array of H-scaler coefficients + * @vscaler_coeff: The complete array of V-scaler coefficients + * @is_polyphase: Track if scaling algorithm is polyphase or not + * @rst_gpio: GPIO reset line to bring VPSS Scaler out of reset + * @ctrl_clk: AXI Lite clock + * @axis_clk: Video Clock + */ +struct xilinx_scaler { + void __iomem *base; + struct device *dev; + struct xlnx_bridge bridge; + u32 width_in; + u32 height_in; + u32 width_out; + u32 height_out; + u32 fmt_in; + u32 fmt_out; + u32 num_hori_taps; + u32 num_vert_taps; + u32 max_num_phases; + u32 pix_per_clk; + u32 max_pixels; + u32 max_lines; + u32 H_phases[XV_HSCALER_MAX_LINE_WIDTH]; + short hscaler_coeff[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]; + short vscaler_coeff[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_MAX_V_TAPS]; + bool is_polyphase; + struct gpio_desc *rst_gpio; + struct clk *ctrl_clk; + struct clk *axis_clk; +}; + +static inline void xilinx_scaler_write(void __iomem *base, u32 offset, u32 val) +{ + writel(val, base + offset); +} + +static inline u32 xilinx_scaler_read(void __iomem *base, u32 offset) +{ + return readl(base + offset); +} + +static inline void xilinx_scaler_clr(void __iomem *base, u32 offset, u32 clr) +{ + xilinx_scaler_write(base, offset, + xilinx_scaler_read(base, offset) & ~clr); +} + +static inline void xilinx_scaler_set(void __iomem *base, u32 offset, u32 set) +{ + xilinx_scaler_write(base, offset, + xilinx_scaler_read(base, offset) | set); +} + +static inline void +xilinx_scaler_disable_block(struct xilinx_scaler *scaler, u32 channel, + u32 ip_block) +{ + xilinx_scaler_clr(scaler->base, ((channel - 1) * XGPIO_CHAN_OFFSET) + + XGPIO_DATA_OFFSET + S_AXIS_RESET_OFF, ip_block); +} + +static inline void +xilinx_scaler_enable_block(struct xilinx_scaler *scaler, u32 channel, + u32 ip_block) +{ + xilinx_scaler_set(scaler->base, ((channel - 1) * XGPIO_CHAN_OFFSET) + + XGPIO_DATA_OFFSET + S_AXIS_RESET_OFF, ip_block); +} + +/** + * bridge_to_layer - Gets the parent structure + * @bridge: pointer to the member. + * + * Return: parent structure pointer + */ +static inline struct xilinx_scaler *bridge_to_layer(struct xlnx_bridge *bridge) +{ + return container_of(bridge, struct xilinx_scaler, bridge); +} + +/** + * xilinx_scaler_reset - Resets scaler block + * @scaler: Pointer to scaler device structure + * + * This function resets scaler block + */ +static void xilinx_scaler_reset(struct xilinx_scaler *scaler) +{ + xilinx_scaler_disable_block(scaler, XGPIO_CH_RESET_SEL, + XGPIO_RESET_MASK_ALL_BLOCKS); + xilinx_scaler_enable_block(scaler, XGPIO_CH_RESET_SEL, + XGPIO_RESET_MASK_IP_AXIS); +} + +/** + * xv_hscaler_calculate_phases - Calculates h-scaler phases + * @scaler: Pointer to scaler registers base + * @width_in: input width + * @width_out: output width + * @pixel_rate: pixel rate + */ +static void +xv_hscaler_calculate_phases(struct xilinx_scaler *scaler, + u32 width_in, u32 width_out, u32 pixel_rate) +{ + unsigned int loop_width; + unsigned int x, s; + int offset = 0; + int xwrite_pos = 0; + bool output_write_en; + bool get_new_pix; + u64 phaseH; + u32 array_idx = 0; + int nr_rds; + int nr_rds_clck; + unsigned int nphases = scaler->max_num_phases; + unsigned int nppc = scaler->pix_per_clk; + unsigned int shift = XHSC_STEP_PRECISION_SHIFT - ilog2(nphases); + + loop_width = max_t(u32, width_in, width_out); + loop_width = ALIGN(loop_width + nppc - 1, nppc); + + for (x = 0; x < loop_width; x++) { + nr_rds_clck = 0; + for (s = 0; s < nppc; s++) { + phaseH = (offset >> shift) & (nphases - 1); + get_new_pix = false; + output_write_en = false; + if ((offset >> XHSC_STEP_PRECISION_SHIFT) != 0) { + get_new_pix = true; + offset -= (1 << XHSC_STEP_PRECISION_SHIFT); + array_idx++; + } + + if (((offset >> XHSC_STEP_PRECISION_SHIFT) == 0) && + xwrite_pos < width_out) { + offset += pixel_rate; + output_write_en = true; + xwrite_pos++; + } + + scaler->H_phases[x] |= (phaseH << + (s * XHSC_HPHASE_MULTIPLIER)); + scaler->H_phases[x] |= (array_idx << + (XHSC_HPHASE_SHIFT_BY_6 + + (s * XHSC_HPHASE_MULTIPLIER))); + if (output_write_en) { + scaler->H_phases[x] |= + (XV_HSCALER_PHASESH_V_OUTPUT_WR_EN << + (s * XHSC_HPHASE_MULTIPLIER)); + } + + if (get_new_pix) + nr_rds_clck++; + } + if (array_idx >= nppc) + array_idx &= (nppc - 1); + + nr_rds += nr_rds_clck; + if (nr_rds >= nppc) + nr_rds -= nppc; + } +} + +/** + * xv_hscaler_load_ext_coeff - Loads external coefficients of h-scaler + * @scaler: Pointer to scaler registers base + * @coeff: Pointer to coeff array + * @ntaps: number of taps + * + * This function loads h-scaler coefficients. + */ +static void +xv_hscaler_load_ext_coeff(struct xilinx_scaler *scaler, + const short *coeff, u32 ntaps) +{ + unsigned int i, j, pad, offset; + u32 nphases = scaler->max_num_phases; + + /* Determine if coefficient needs padding (effective vs. max taps) */ + pad = XV_HSCALER_MAX_H_TAPS - ntaps; + offset = pad >> 1; + /* Load coefficients into scaler coefficient table */ + for (i = 0; i < nphases; i++) { + for (j = 0; j < ntaps; ++j) + scaler->hscaler_coeff[i][j + offset] = + coeff[i * ntaps + j]; + } + + if (pad) { + for (i = 0; i < nphases; i++) { + for (j = 0; j < offset; j++) + scaler->hscaler_coeff[i][j] = 0; + j = ntaps + offset; + for (; j < XV_HSCALER_MAX_H_TAPS; j++) + scaler->hscaler_coeff[i][j] = 0; + } + } +} + +/** + * xv_hscaler_coeff_select - Selection of H-Scaler coefficients of operation + * @scaler: Pointer to Scaler device structure + * @width_in: Width of input video + * @width_out: Width of desired output video + * + * There are instances when a N-tap filter might operate in an M-tap + * configuration where N > M. + * + * For example : + * Depending on the ratio of scaling (while downscaling), a 12-tap + * filter may operate with 10 tap coefficients and zero-pads the remaining + * coefficients. + * + * While upscaling the driver will program 6-tap filter coefficients + * in any N-tap configurations (for N >= 6). + * + * This selection is adopted by the as it gives optimal + * video output determined by repeated testing of the IP + * + * Return: Will return 0 if successful. Returns -EINVAL on an unsupported + * H-scaler number of taps. + */ +static int +xv_hscaler_select_coeff(struct xilinx_scaler *scaler, + u32 width_in, u32 width_out) +{ + const short *coeff; + u16 hscale_ratio; + u32 ntaps = scaler->num_hori_taps; + + /* + * Scale Down Mode will use dynamic filter selection logic + * Scale Up Mode (including 1:1) will always use 6 tap filter + */ + if (width_out < width_in) { + hscale_ratio = ((width_in * 10) / width_out); + + switch (scaler->num_hori_taps) { + case XV_HSCALER_TAPS_6: + coeff = &xhsc_coeff_taps6[0][0]; + ntaps = XV_HSCALER_TAPS_6; + break; + case XV_HSCALER_TAPS_8: + if (hscale_ratio > 15) { + coeff = &xhsc_coeff_taps8[0][0]; + ntaps = XV_HSCALER_TAPS_8; + } else { + coeff = &xhsc_coeff_taps6[0][0]; + ntaps = XV_HSCALER_TAPS_6; + } + break; + case XV_HSCALER_TAPS_10: + if (hscale_ratio > 25) { + coeff = &xhsc_coeff_taps10[0][0]; + ntaps = XV_HSCALER_TAPS_10; + } else if (hscale_ratio > 15) { + coeff = &xhsc_coeff_taps8[0][0]; + ntaps = XV_HSCALER_TAPS_8; + } else { + coeff = &xhsc_coeff_taps6[0][0]; + ntaps = XV_HSCALER_TAPS_6; + } + break; + case XV_HSCALER_TAPS_12: + if (hscale_ratio > 35) { + coeff = &xhsc_coeff_taps12[0][0]; + ntaps = XV_HSCALER_TAPS_12; + } else if (hscale_ratio > 25) { + coeff = &xhsc_coeff_taps10[0][0]; + ntaps = XV_HSCALER_TAPS_10; + } else if (hscale_ratio > 15) { + coeff = &xhsc_coeff_taps8[0][0]; + ntaps = XV_HSCALER_TAPS_8; + } else { + coeff = &xhsc_coeff_taps6[0][0]; + ntaps = XV_HSCALER_TAPS_6; + } + break; + default: + dev_info(scaler->dev, "Unsupported H-scaler number of taps\n"); + return -EINVAL; + } + } else { + coeff = &xhsc_coeff_taps6[0][0]; + ntaps = XV_HSCALER_TAPS_6; + } + xv_hscaler_load_ext_coeff(scaler, coeff, ntaps); + return 0; +} + +/** + * xv_hscaler_set_coeff - Sets h-scaler coefficients + * @scaler: Pointer to scaler device structure + * + * This function sets coefficients of h-scaler. + */ +static void xv_hscaler_set_coeff(struct xilinx_scaler *scaler) +{ + int val, i, j, offset, rd_indx; + u32 ntaps = scaler->num_hori_taps; + u32 nphases = scaler->max_num_phases; + u32 base_addr; + + offset = (XV_HSCALER_MAX_H_TAPS - ntaps) / 2; + base_addr = V_HSCALER_OFF + XV_HSCALER_CTRL_ADDR_HWREG_HFLTCOEFF_BASE; + for (i = 0; i < nphases; i++) { + for (j = 0; j < ntaps / 2; j++) { + rd_indx = j * 2 + offset; + val = (scaler->hscaler_coeff[i][rd_indx + 1] << + XSCALER_BITSHIFT_16) | + (scaler->hscaler_coeff[i][rd_indx] & + XHSC_MASK_LOW_16BITS); + xilinx_scaler_write(scaler->base, base_addr + + ((i * ntaps / 2 + j) * 4), val); + } + } +} + +/** + * xv_vscaler_load_ext_coeff - Loads external coefficients of v-scaler + * @scaler: Pointer to scaler device structure + * @coeff: Pointer to coeff array + * @ntaps: number of taps + * + * This function loads v-scaler coefficients. + */ +static void +xv_vscaler_load_ext_coeff(struct xilinx_scaler *scaler, + const short *coeff, u32 ntaps) +{ + int i, j, pad, offset; + u32 nphases = scaler->max_num_phases; + + /* Determine if coefficient needs padding (effective vs. max taps) */ + pad = XV_VSCALER_MAX_V_TAPS - ntaps; + offset = pad ? (pad >> 1) : 0; + /* Load User defined coefficients into scaler coefficient table */ + for (i = 0; i < nphases; i++) { + for (j = 0; j < ntaps; ++j) + scaler->vscaler_coeff[i][j + offset] = + coeff[i * ntaps + j]; + } + if (pad) { + /* effective taps < max_taps */ + for (i = 0; i < nphases; i++) { + /* pad left */ + for (j = 0; j < offset; j++) + scaler->vscaler_coeff[i][j] = 0; + /* pad right */ + j = ntaps + offset; + for (; j < XV_VSCALER_MAX_V_TAPS; j++) + scaler->vscaler_coeff[i][j] = 0; + } + } +} + +/** + * xv_vscaler_set_coeff - Sets v-scaler coefficients + * @scaler: Pointer to scaler device structure + * + * This function sets coefficients of v-scaler. + */ +static void xv_vscaler_set_coeff(struct xilinx_scaler *scaler) +{ + u32 nphases = scaler->max_num_phases; + u32 ntaps = scaler->num_vert_taps; + int val, i, j, offset, rd_indx; + u32 base_addr; + + offset = (XV_VSCALER_MAX_V_TAPS - ntaps) / 2; + base_addr = V_VSCALER_OFF + XV_VSCALER_CTRL_ADDR_HWREG_VFLTCOEFF_BASE; + + for (i = 0; i < nphases; i++) { + for (j = 0; j < ntaps / 2; j++) { + rd_indx = j * 2 + offset; + val = (scaler->vscaler_coeff[i][rd_indx + 1] << + XSCALER_BITSHIFT_16) | + (scaler->vscaler_coeff[i][rd_indx] & + XVSC_MASK_LOW_16BITS); + xilinx_scaler_write(scaler->base, base_addr + + ((i * ntaps / 2 + j) * 4), val); + } + } +} + +/** + * xv_vscaler_coeff_select - Selection of V-Scaler coefficients of operation + * @scaler: Pointer to Scaler device structure + * @height_in: Height of input video + * @height_out: Height of desired output video + * + * There are instances when a N-tap filter might operate in an M-tap + * configuration where N > M. + * + * For example : + * Depending on the ratio of scaling (while downscaling), a 10-tap + * filter may operate with 6 tap coefficients and zero-pads the remaining + * coefficients. + * + * While upscaling the driver will program 6-tap filter coefficients + * in any N-tap configurations (for N >= 6). + * + * This selection is adopted by the as it gives optimal + * video output determined by repeated testing of the IP + * + * Return: Will return 0 if successful. Returns -EINVAL on an unsupported + * V-scaler number of taps. + */ +static int +xv_vscaler_select_coeff(struct xilinx_scaler *scaler, + u32 height_in, u32 height_out) +{ + const short *coeff; + u16 vscale_ratio; + u32 ntaps = scaler->num_vert_taps; + + /* + * Scale Down Mode will use dynamic filter selection logic + * Scale Up Mode (including 1:1) will always use 6 tap filter + */ + + if (height_out < height_in) { + vscale_ratio = ((height_in * 10) / height_out); + + switch (scaler->num_vert_taps) { + case XV_VSCALER_TAPS_6: + coeff = &xvsc_coeff_taps6[0][0]; + ntaps = XV_VSCALER_TAPS_6; + break; + case XV_VSCALER_TAPS_8: + if (vscale_ratio > 15) { + coeff = &xvsc_coeff_taps8[0][0]; + ntaps = XV_VSCALER_TAPS_8; + } else { + coeff = &xvsc_coeff_taps6[0][0]; + ntaps = XV_VSCALER_TAPS_6; + } + break; + case XV_VSCALER_TAPS_10: + if (vscale_ratio > 25) { + coeff = &xvsc_coeff_taps10[0][0]; + ntaps = XV_VSCALER_TAPS_10; + } else if (vscale_ratio > 15) { + coeff = &xvsc_coeff_taps8[0][0]; + ntaps = XV_VSCALER_TAPS_8; + } else { + coeff = &xvsc_coeff_taps6[0][0]; + ntaps = XV_VSCALER_TAPS_6; + } + break; + case XV_VSCALER_TAPS_12: + if (vscale_ratio > 35) { + coeff = &xvsc_coeff_taps12[0][0]; + ntaps = XV_VSCALER_TAPS_12; + } else if (vscale_ratio > 25) { + coeff = &xvsc_coeff_taps10[0][0]; + ntaps = XV_VSCALER_TAPS_10; + } else if (vscale_ratio > 15) { + coeff = &xvsc_coeff_taps8[0][0]; + ntaps = XV_VSCALER_TAPS_8; + } else { + coeff = &xvsc_coeff_taps6[0][0]; + ntaps = XV_VSCALER_TAPS_6; + } + break; + default: + return -EINVAL; + } + } else { + coeff = &xvsc_coeff_taps6[0][0]; + ntaps = XV_VSCALER_TAPS_6; + } + + xv_vscaler_load_ext_coeff(scaler, coeff, ntaps); + return 0; +} + +/** + * xv_hscaler_set_phases - Sets phases of h-scaler + * @scaler: Pointer to scaler device structure + * + * This function sets phases of h-scaler. + */ +static void +xv_hscaler_set_phases(struct xilinx_scaler *scaler) +{ + u32 loop_width; + u32 index, val; + u32 offset, i, lsb, msb; + + loop_width = scaler->max_pixels / scaler->pix_per_clk; + offset = V_HSCALER_OFF + XV_HSCALER_CTRL_ADDR_HWREG_PHASESH_V_BASE; + + switch (scaler->pix_per_clk) { + case XSCALER_PPC_1: + index = 0; + for (i = 0; i < loop_width; i += 2) { + lsb = scaler->H_phases[i] & XHSC_MASK_LOW_16BITS; + msb = scaler->H_phases[i + 1] & XHSC_MASK_LOW_16BITS; + val = (msb << 16 | lsb); + xilinx_scaler_write(scaler->base, offset + + (index * 4), val); + ++index; + } + return; + case XSCALER_PPC_2: + for (i = 0; i < loop_width; i++) { + val = (scaler->H_phases[i] & XHSC_MASK_LOW_32BITS); + xilinx_scaler_write(scaler->base, offset + + (i * 4), val); + } + return; + } +} + +/** + * xv_vscaler_setup_video_fmt - Sets video format of v-scaler + * @scaler: Pointer to scaler device structure + * @code_in: format to be set + * + * This function set the given format of v-scaler + * + * Return: format value on success. -EINVAL for invalid format. + * + */ +static int +xv_vscaler_setup_video_fmt(struct xilinx_scaler *scaler, u32 code_in) +{ + u32 video_in; + + switch (code_in) { + case MEDIA_BUS_FMT_UYVY8_1X16: + video_in = XVIDC_CSF_YCRCB_422; + break; + case MEDIA_BUS_FMT_VUY8_1X24: + video_in = XVIDC_CSF_YCRCB_444; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + video_in = XVIDC_CSF_RGB; + break; + case MEDIA_BUS_FMT_VYYUYY8_1X24: + video_in = XVIDC_CSF_YCRCB_420; + break; + default: + dev_info(scaler->dev, "Vscaler Unsupported media fmt\n"); + return -EINVAL; + } + xilinx_scaler_write(scaler->base, V_VSCALER_OFF + + XV_VSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA, + video_in); + return video_in; +} + +/** + * xv_hscaler_setup_video_fmt - Sets video format of h-scaler + * @scaler: Pointer to scaler device structure + * @code_out: bus format to be set + * @vsc_out: return value of vscaler + * + * This function set the given video format of h-scaler + * + * Return: format value on success. -EINVAL for invalid format. + * + */ +static int xv_hscaler_setup_video_fmt(struct xilinx_scaler *scaler, + u32 code_out, u32 vsc_out) +{ + u32 video_out; + + switch (vsc_out) { + case XVIDC_CSF_YCRCB_422: + break; + case XVIDC_CSF_YCRCB_444: + break; + case XVIDC_CSF_RGB: + break; + case XVIDC_CSF_YCRCB_420: + break; + default: + dev_info(scaler->dev, "unsupported format from Vscaler"); + return -EINVAL; + } + + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA, + vsc_out); + + switch (code_out) { + case MEDIA_BUS_FMT_UYVY8_1X16: + video_out = XVIDC_CSF_YCRCB_422; + break; + case MEDIA_BUS_FMT_VUY8_1X24: + video_out = XVIDC_CSF_YCRCB_444; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + video_out = XVIDC_CSF_RGB; + break; + case MEDIA_BUS_FMT_VYYUYY8_1X24: + video_out = XVIDC_CSF_YCRCB_420; + break; + default: + dev_info(scaler->dev, "Hscaler Unsupported Out media fmt\n"); + return -EINVAL; + } + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_HWREG_COLORMODEOUT_DATA, + video_out); + return 0; +} + +/** + * xilinx_scaler_parse_of - Parse device tree information + * @scaler: Pointer to scaler device structure + * + * This function reads the device tree contents + * + * Return: 0 on success. -EINVAL for invalid value. + * + */ +static int xilinx_scaler_parse_of(struct xilinx_scaler *scaler) +{ + int ret; + u32 dt_ppc; + struct device_node *node = scaler->dev->of_node; + + scaler->ctrl_clk = devm_clk_get(scaler->dev, "aclk_ctrl"); + if (IS_ERR(scaler->ctrl_clk)) { + ret = PTR_ERR(scaler->ctrl_clk); + dev_err(scaler->dev, "failed to get axi lite clk %d\n", ret); + return ret; + } + + scaler->axis_clk = devm_clk_get(scaler->dev, "aclk_axis"); + if (IS_ERR(scaler->axis_clk)) { + ret = PTR_ERR(scaler->axis_clk); + dev_err(scaler->dev, "failed to get video clk %d\n", ret); + return ret; + } + + ret = of_property_read_u32(node, "xlnx,h-scaler-taps", + &scaler->num_hori_taps); + if (ret < 0) { + dev_info(scaler->dev, "h-scaler-taps not present in DT\n"); + return ret; + } + switch (scaler->num_hori_taps) { + case XV_HSCALER_TAPS_2: + case XV_HSCALER_TAPS_4: + scaler->is_polyphase = false; + break; + case XV_HSCALER_TAPS_6: + case XV_HSCALER_TAPS_8: + case XV_HSCALER_TAPS_10: + case XV_HSCALER_TAPS_12: + scaler->is_polyphase = true; + break; + default: + return -EINVAL; + } + + ret = of_property_read_u32(node, "xlnx,v-scaler-taps", + &scaler->num_vert_taps); + if (ret < 0) { + dev_info(scaler->dev, "v-scaler-taps not present in DT\n"); + return ret; + } + + switch (scaler->num_vert_taps) { + case XV_HSCALER_TAPS_2: + case XV_VSCALER_TAPS_4: + if (scaler->num_vert_taps != scaler->num_hori_taps) + return -EINVAL; + break; + case XV_VSCALER_TAPS_6: + case XV_VSCALER_TAPS_8: + case XV_VSCALER_TAPS_10: + case XV_VSCALER_TAPS_12: + scaler->is_polyphase = true; + break; + default: + return -EINVAL; + } + + ret = of_property_read_u32(node, "xlnx,samples-per-clk", &dt_ppc); + if (ret < 0) { + dev_info(scaler->dev, "PPC is missing in DT\n"); + return ret; + } + if (dt_ppc != XSCALER_PPC_1 && dt_ppc != XSCALER_PPC_2) { + dev_info(scaler->dev, "Unsupported ppc: %d", dt_ppc); + return -EINVAL; + } + scaler->pix_per_clk = dt_ppc; + + /* Reset GPIO */ + scaler->rst_gpio = devm_gpiod_get(scaler->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(scaler->rst_gpio)) { + if (PTR_ERR(scaler->rst_gpio) != -EPROBE_DEFER) + dev_err(scaler->dev, "Reset GPIO not setup in DT"); + return PTR_ERR(scaler->rst_gpio); + } + + ret = of_property_read_u32(node, "xlnx,max-height", + &scaler->max_lines); + if (ret < 0) { + dev_err(scaler->dev, "xlnx,max-height is missing!"); + return -EINVAL; + } else if (scaler->max_lines > XSCALER_MAX_HEIGHT || + scaler->max_lines < XSCALER_MIN_HEIGHT) { + dev_err(scaler->dev, "Invalid height in dt"); + return -EINVAL; + } + + ret = of_property_read_u32(node, "xlnx,max-width", + &scaler->max_pixels); + if (ret < 0) { + dev_err(scaler->dev, "xlnx,max-width is missing!"); + return -EINVAL; + } else if (scaler->max_pixels > XSCALER_MAX_WIDTH || + scaler->max_pixels < XSCALER_MIN_WIDTH) { + dev_err(scaler->dev, "Invalid width in dt"); + return -EINVAL; + } + + return 0; +} + +/** + * xilinx_scaler_stream - Set up v-scaler and h-scaler for streaming + * @scaler: Pointer to scaler device structure + * + * This function sets up the required configuration of v-scaler and h-scaler + * + * Return: 0 on success. Returns -EINVAL on failure conditions. + */ +static int xilinx_scaler_stream(struct xilinx_scaler *scaler) +{ + u32 fmt_in, fmt_out; + u32 pixel_rate; + u32 line_rate; + int ret; + + fmt_in = scaler->fmt_in; + fmt_out = scaler->fmt_out; + line_rate = (scaler->height_in * STEP_PRECISION) / scaler->height_out; + + if (scaler->is_polyphase) { + ret = xv_vscaler_select_coeff(scaler, scaler->height_in, + scaler->height_out); + if (ret < 0) { + dev_info(scaler->dev, "Failed: vscaler select coeff\n"); + return ret; + } + xv_vscaler_set_coeff(scaler); + } + xilinx_scaler_write(scaler->base, V_VSCALER_OFF + + XV_VSCALER_CTRL_ADDR_HWREG_LINERATE_DATA, + line_rate); + ret = xv_vscaler_setup_video_fmt(scaler, scaler->fmt_in); + if (ret < 0) { + dev_info(scaler->dev, "Failed: vscaler setup video format\n"); + return ret; + } + pixel_rate = (scaler->width_in * STEP_PRECISION) / scaler->width_out; + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_HWREG_PIXELRATE_DATA, + pixel_rate); + ret = xv_hscaler_setup_video_fmt(scaler, scaler->fmt_out, ret); + if (ret < 0) { + dev_info(scaler->dev, "Failed: vscaler setup video format\n"); + return ret; + } + if (scaler->is_polyphase) { + ret = xv_hscaler_select_coeff(scaler, scaler->width_in, + scaler->width_out); + if (ret < 0) { + dev_info(scaler->dev, "Failed: hscaler select coeff\n"); + return ret; + } + xv_hscaler_set_coeff(scaler); + } + xv_hscaler_calculate_phases(scaler, scaler->width_in, + scaler->width_out, pixel_rate); + xv_hscaler_set_phases(scaler); + return 0; +} + +/** + * xilinx_scaler_bridge_enable - enabes scaler sub-cores + * @bridge: bridge instance + * + * This function enables the scaler sub-cores + * + * Return: 0 on success. Return -EINVAL on failure conditions. + * + */ +static int xilinx_scaler_bridge_enable(struct xlnx_bridge *bridge) +{ + int ret; + struct xilinx_scaler *scaler = bridge_to_layer(bridge); + + ret = xilinx_scaler_stream(scaler); + if (ret) + return ret; + + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_AP_CTRL, XSCALER_STREAM_ON); + xilinx_scaler_write(scaler->base, V_VSCALER_OFF + + XV_VSCALER_CTRL_ADDR_AP_CTRL, XSCALER_STREAM_ON); + xilinx_scaler_enable_block(scaler, XGPIO_CH_RESET_SEL, + XGPIO_RESET_MASK_IP_AXIS); + return ret; +} + +/** + * xilinx_scaler_bridge_disable - disables scaler sub-cores + * @bridge: bridge instance + * + * This function disables the scaler sub-cores + */ +static void xilinx_scaler_bridge_disable(struct xlnx_bridge *bridge) +{ + struct xilinx_scaler *scaler = bridge_to_layer(bridge); + + xilinx_scaler_disable_block(scaler, XGPIO_CH_RESET_SEL, + XGPIO_RESET_MASK_ALL_BLOCKS); +} + +/** + * xilinx_scaler_bridge_set_input - Sets the input parameters of scaler + * @bridge: bridge instance + * @width: width of video + * @height: height of video + * @bus_fmt: video bus format + * + * This function sets the input parameters of scaler + * Return: 0 on success. -EINVAL for invalid parameters. + */ +static int xilinx_scaler_bridge_set_input(struct xlnx_bridge *bridge, + u32 width, u32 height, u32 bus_fmt) +{ + struct xilinx_scaler *scaler = bridge_to_layer(bridge); + + if (width > scaler->max_pixels || height > scaler->max_lines) + return -EINVAL; + + scaler->height_in = height; + scaler->width_in = width; + scaler->fmt_in = bus_fmt; + + /* IP Reset through GPIO */ + gpiod_set_value_cansleep(scaler->rst_gpio, XSCALER_RESET_ASSERT); + gpiod_set_value_cansleep(scaler->rst_gpio, XSCALER_RESET_DEASSERT); + xilinx_scaler_reset(scaler); + memset(scaler->H_phases, 0, sizeof(scaler->H_phases)); + + xilinx_scaler_write(scaler->base, V_VSCALER_OFF + + XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTIN_DATA, height); + xilinx_scaler_write(scaler->base, V_VSCALER_OFF + + XV_VSCALER_CTRL_ADDR_HWREG_WIDTH_DATA, width); + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_HWREG_WIDTHIN_DATA, width); + + return 0; +} + +/** + * xilinx_scaler_bridge_get_input_fmts - input formats supported by scaler + * @bridge: bridge instance + * @fmts: Pointer to be updated with formats information + * @count: count of video bus formats + * + * This function provides the input video formats information scaler + * Return: 0 on success. + */ +static int xilinx_scaler_bridge_get_input_fmts(struct xlnx_bridge *bridge, + const u32 **fmts, u32 *count) +{ + *fmts = xilinx_scaler_video_fmts; + *count = ARRAY_SIZE(xilinx_scaler_video_fmts); + return 0; +} + +/** + * xilinx_scaler_bridge_set_output - Sets the output parameters of scaler + * @bridge: bridge instance + * @width: width of video + * @height: height of video + * @bus_fmt: video bus format + * + * This function sets the output parameters of scaler + * Return: 0 on success. -EINVAL for invalid parameters. + */ +static int xilinx_scaler_bridge_set_output(struct xlnx_bridge *bridge, + u32 width, u32 height, u32 bus_fmt) +{ + struct xilinx_scaler *scaler = bridge_to_layer(bridge); + + if (width > scaler->max_pixels || height > scaler->max_lines) + return -EINVAL; + + scaler->height_out = height; + scaler->width_out = width; + scaler->fmt_out = bus_fmt; + + xilinx_scaler_write(scaler->base, V_VSCALER_OFF + + XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTOUT_DATA, height); + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_HWREG_HEIGHT_DATA, height); + xilinx_scaler_write(scaler->base, V_HSCALER_OFF + + XV_HSCALER_CTRL_ADDR_HWREG_WIDTHOUT_DATA, width); + return 0; +} + +/** + * xilinx_scaler_bridge_get_output_fmts - output formats supported by scaler + * @bridge: bridge instance + * @fmts: Pointer to be updated with formats information + * @count: count of video bus formats + * + * This function provides the output video formats information scaler + * Return: 0 on success. + */ +static int xilinx_scaler_bridge_get_output_fmts(struct xlnx_bridge *bridge, + const u32 **fmts, u32 *count) +{ + *fmts = xilinx_scaler_video_fmts; + *count = ARRAY_SIZE(xilinx_scaler_video_fmts); + return 0; +} + +static int xilinx_scaler_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct xilinx_scaler *scaler; + int ret; + + scaler = devm_kzalloc(dev, sizeof(*scaler), GFP_KERNEL); + if (!scaler) + return -ENOMEM; + scaler->dev = dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + scaler->base = devm_ioremap_resource(dev, res); + if (IS_ERR(scaler->base)) { + dev_err(dev, "failed to remap io region\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, scaler); + + ret = xilinx_scaler_parse_of(scaler); + if (ret < 0) { + dev_info(scaler->dev, "parse_of failed\n"); + return ret; + } + + ret = clk_prepare_enable(scaler->ctrl_clk); + if (ret) { + dev_err(scaler->dev, "unable to enable axi lite clk %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(scaler->axis_clk); + if (ret) { + dev_err(scaler->dev, "unable to enable video clk %d\n", ret); + goto err_ctrl_clk; + } + + scaler->max_num_phases = XSCALER_MAX_PHASES; + + /* Reset the Global IP Reset through a GPIO */ + gpiod_set_value_cansleep(scaler->rst_gpio, XSCALER_RESET_DEASSERT); + xilinx_scaler_reset(scaler); + + scaler->bridge.enable = &xilinx_scaler_bridge_enable; + scaler->bridge.disable = &xilinx_scaler_bridge_disable; + scaler->bridge.set_input = &xilinx_scaler_bridge_set_input; + scaler->bridge.get_input_fmts = &xilinx_scaler_bridge_get_input_fmts; + scaler->bridge.set_output = &xilinx_scaler_bridge_set_output; + scaler->bridge.get_output_fmts = &xilinx_scaler_bridge_get_output_fmts; + scaler->bridge.of_node = dev->of_node; + + ret = xlnx_bridge_register(&scaler->bridge); + if (ret) { + dev_info(scaler->dev, "Bridge registration failed\n"); + goto err_axis_clk; + } + dev_info(scaler->dev, "xlnx drm scaler experimental driver probed\n"); + + return 0; + +err_axis_clk: + clk_disable_unprepare(scaler->axis_clk); +err_ctrl_clk: + clk_disable_unprepare(scaler->ctrl_clk); + return ret; +} + +static int xilinx_scaler_remove(struct platform_device *pdev) +{ + struct xilinx_scaler *scaler = platform_get_drvdata(pdev); + + xlnx_bridge_unregister(&scaler->bridge); + clk_disable_unprepare(scaler->axis_clk); + clk_disable_unprepare(scaler->ctrl_clk); + return 0; +} + +static const struct of_device_id xilinx_scaler_of_match[] = { + { .compatible = "xlnx,vpss-scaler"}, + { } +}; +MODULE_DEVICE_TABLE(of, xilinx_scaler_of_match); + +static struct platform_driver scaler_bridge_driver = { + .probe = xilinx_scaler_probe, + .remove = xilinx_scaler_remove, + .driver = { + .name = "xlnx,scaler-bridge", + .of_match_table = xilinx_scaler_of_match, + }, +}; + +module_platform_driver(scaler_bridge_driver); + +MODULE_AUTHOR("Venkateshwar Rao <vgannava@xilinx.com>"); +MODULE_DESCRIPTION("Xilinx FPGA SCALER Bridge Driver"); +MODULE_LICENSE("GPL v2"); |