1*51fe835cSWenmeng Liu // SPDX-License-Identifier: GPL-2.0 2*51fe835cSWenmeng Liu /* 3*51fe835cSWenmeng Liu * 4*51fe835cSWenmeng Liu * Qualcomm MSM Camera Subsystem - TPG (Test Pattern Generator) Module 5*51fe835cSWenmeng Liu * 6*51fe835cSWenmeng Liu * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 7*51fe835cSWenmeng Liu */ 8*51fe835cSWenmeng Liu #include <linux/io.h> 9*51fe835cSWenmeng Liu #include <linux/kernel.h> 10*51fe835cSWenmeng Liu 11*51fe835cSWenmeng Liu #include "camss-tpg.h" 12*51fe835cSWenmeng Liu #include "camss.h" 13*51fe835cSWenmeng Liu 14*51fe835cSWenmeng Liu /* TPG global registers */ 15*51fe835cSWenmeng Liu #define TPG_HW_VERSION 0x0 16*51fe835cSWenmeng Liu # define HW_VERSION_STEPPING GENMASK(15, 0) 17*51fe835cSWenmeng Liu # define HW_VERSION_REVISION GENMASK(27, 16) 18*51fe835cSWenmeng Liu # define HW_VERSION_GENERATION GENMASK(31, 28) 19*51fe835cSWenmeng Liu 20*51fe835cSWenmeng Liu #define TPG_HW_VER(gen, rev, step) \ 21*51fe835cSWenmeng Liu (((u32)(gen) << 28) | ((u32)(rev) << 16) | (u32)(step)) 22*51fe835cSWenmeng Liu 23*51fe835cSWenmeng Liu #define TPG_HW_VER_2_0_0 TPG_HW_VER(2, 0, 0) 24*51fe835cSWenmeng Liu #define TPG_HW_VER_2_1_0 TPG_HW_VER(2, 1, 0) 25*51fe835cSWenmeng Liu 26*51fe835cSWenmeng Liu #define TPG_HW_STATUS 0x4 27*51fe835cSWenmeng Liu 28*51fe835cSWenmeng Liu #define TPG_CTRL 0x64 29*51fe835cSWenmeng Liu # define TPG_CTRL_TEST_EN BIT(0) 30*51fe835cSWenmeng Liu # define TPG_CTRL_PHY_SEL BIT(3) 31*51fe835cSWenmeng Liu # define TPG_CTRL_NUM_ACTIVE_LANES GENMASK(5, 4) 32*51fe835cSWenmeng Liu # define TPG_CTRL_VC_DT_PATTERN_ID GENMASK(8, 6) 33*51fe835cSWenmeng Liu # define TPG_CTRL_OVERLAP_SHDR_EN BIT(10) 34*51fe835cSWenmeng Liu # define TPG_CTRL_NUM_ACTIVE_VC GENMASK(31, 30) 35*51fe835cSWenmeng Liu 36*51fe835cSWenmeng Liu #define TPG_CLEAR 0x1F4 37*51fe835cSWenmeng Liu 38*51fe835cSWenmeng Liu /* TPG VC-based registers */ 39*51fe835cSWenmeng Liu #define TPG_VC_n_GAIN_CFG(n) (0x60 + (n) * 0x60) 40*51fe835cSWenmeng Liu 41*51fe835cSWenmeng Liu #define TPG_VC_n_CFG0(n) (0x68 + (n) * 0x60) 42*51fe835cSWenmeng Liu # define TPG_VC_n_CFG0_VC_NUM GENMASK(4, 0) 43*51fe835cSWenmeng Liu # define TPG_VC_n_CFG0_NUM_ACTIVE_DT GENMASK(9, 8) 44*51fe835cSWenmeng Liu # define TPG_VC_n_CFG0_NUM_BATCH GENMASK(15, 12) 45*51fe835cSWenmeng Liu # define TPG_VC_n_CFG0_NUM_FRAMES GENMASK(31, 16) 46*51fe835cSWenmeng Liu 47*51fe835cSWenmeng Liu #define TPG_VC_n_LSFR_SEED(n) (0x6C + (n) * 0x60) 48*51fe835cSWenmeng Liu #define TPG_VC_n_HBI_CFG(n) (0x70 + (n) * 0x60) 49*51fe835cSWenmeng Liu #define TPG_VC_n_VBI_CFG(n) (0x74 + (n) * 0x60) 50*51fe835cSWenmeng Liu 51*51fe835cSWenmeng Liu #define TPG_VC_n_COLOR_BARS_CFG(n) (0x78 + (n) * 0x60) 52*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_PIX_PATTERN GENMASK(2, 0) 53*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_QCFA_EN BIT(3) 54*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_SPLIT_EN BIT(4) 55*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_NOISE_EN BIT(5) 56*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_ROTATE_PERIOD GENMASK(13, 8) 57*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_XCFA_EN BIT(16) 58*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_SIZE_X GENMASK(26, 24) 59*51fe835cSWenmeng Liu # define TPG_VC_n_COLOR_BARS_CFG_SIZE_Y GENMASK(30, 28) 60*51fe835cSWenmeng Liu 61*51fe835cSWenmeng Liu /* TPG DT-based registers */ 62*51fe835cSWenmeng Liu #define TPG_VC_m_DT_n_CFG_0(m, n) (0x7C + (m) * 0x60 + (n) * 0xC) 63*51fe835cSWenmeng Liu # define TPG_VC_m_DT_n_CFG_0_FRAME_HEIGHT GENMASK(15, 0) 64*51fe835cSWenmeng Liu # define TPG_VC_m_DT_n_CFG_0_FRAME_WIDTH GENMASK(31, 16) 65*51fe835cSWenmeng Liu 66*51fe835cSWenmeng Liu #define TPG_VC_m_DT_n_CFG_1(m, n) (0x80 + (m) * 0x60 + (n) * 0xC) 67*51fe835cSWenmeng Liu # define TPG_VC_m_DT_n_CFG_1_DATA_TYPE GENMASK(5, 0) 68*51fe835cSWenmeng Liu # define TPG_VC_m_DT_n_CFG_1_ECC_XOR_MASK GENMASK(13, 8) 69*51fe835cSWenmeng Liu # define TPG_VC_m_DT_n_CFG_1_CRC_XOR_MASK GENMASK(31, 16) 70*51fe835cSWenmeng Liu 71*51fe835cSWenmeng Liu #define TPG_VC_m_DT_n_CFG_2(m, n) (0x84 + (m) * 0x60 + (n) * 0xC) 72*51fe835cSWenmeng Liu # define TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE GENMASK(3, 0) 73*51fe835cSWenmeng Liu /* v2.0.0: USER[19:4], ENC[23:20] */ 74*51fe835cSWenmeng Liu # define TPG_V2_0_0_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD GENMASK(19, 4) 75*51fe835cSWenmeng Liu # define TPG_V2_0_0_VC_m_DT_n_CFG_2_ENCODE_FORMAT GENMASK(23, 20) 76*51fe835cSWenmeng Liu /* v2.1.0: USER[27:4], ENC[31:28] */ 77*51fe835cSWenmeng Liu # define TPG_V2_1_0_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD GENMASK(27, 4) 78*51fe835cSWenmeng Liu # define TPG_V2_1_0_VC_m_DT_n_CFG_2_ENCODE_FORMAT GENMASK(31, 28) 79*51fe835cSWenmeng Liu 80*51fe835cSWenmeng Liu #define TPG_HBI_PCT_DEFAULT 545 /* 545% */ 81*51fe835cSWenmeng Liu #define TPG_VBI_PCT_DEFAULT 10 /* 10% */ 82*51fe835cSWenmeng Liu #define PERCENT_BASE 100 83*51fe835cSWenmeng Liu 84*51fe835cSWenmeng Liu /* Default user-specified payload for TPG test generator. 85*51fe835cSWenmeng Liu * Keep consistent with CSID TPG default: 0xBE. 86*51fe835cSWenmeng Liu */ 87*51fe835cSWenmeng Liu #define TPG_USER_SPECIFIED_PAYLOAD_DEFAULT 0xBE 88*51fe835cSWenmeng Liu #define TPG_LFSR_SEED_DEFAULT 0x12345678 89*51fe835cSWenmeng Liu #define TPG_COLOR_BARS_CFG_STANDARD \ 90*51fe835cSWenmeng Liu FIELD_PREP(TPG_VC_n_COLOR_BARS_CFG_ROTATE_PERIOD, 0xA) 91*51fe835cSWenmeng Liu 92*51fe835cSWenmeng Liu static const char * const testgen_payload_modes[] = { 93*51fe835cSWenmeng Liu [TPG_PAYLOAD_MODE_DISABLED] = "Disabled", 94*51fe835cSWenmeng Liu [TPG_PAYLOAD_MODE_INCREMENTING] = "Incrementing", 95*51fe835cSWenmeng Liu [TPG_PAYLOAD_MODE_ALTERNATING_55_AA] = "Alternating 0x55/0xAA", 96*51fe835cSWenmeng Liu [TPG_PAYLOAD_MODE_RANDOM] = "Pseudo-random Data", 97*51fe835cSWenmeng Liu [TPG_PAYLOAD_MODE_USER_SPECIFIED] = "User Specified", 98*51fe835cSWenmeng Liu [TPG_PAYLOAD_MODE_COLOR_BARS] = "Color bars", 99*51fe835cSWenmeng Liu }; 100*51fe835cSWenmeng Liu 101*51fe835cSWenmeng Liu static int tpg_stream_on(struct tpg_device *tpg) 102*51fe835cSWenmeng Liu { 103*51fe835cSWenmeng Liu struct tpg_testgen_config *tg = &tpg->testgen; 104*51fe835cSWenmeng Liu struct v4l2_mbus_framefmt *input_format; 105*51fe835cSWenmeng Liu const struct tpg_format_info *format; 106*51fe835cSWenmeng Liu u8 payload_mode = (tg->mode > TPG_PAYLOAD_MODE_DISABLED) ? 107*51fe835cSWenmeng Liu tg->mode - 1 : 0; 108*51fe835cSWenmeng Liu u8 lane_cnt = tpg->res->lane_cnt; 109*51fe835cSWenmeng Liu u8 vc, dt, last_vc = 0; 110*51fe835cSWenmeng Liu u32 val; 111*51fe835cSWenmeng Liu 112*51fe835cSWenmeng Liu for (vc = 0; vc <= MSM_TPG_ACTIVE_VC; vc++) { 113*51fe835cSWenmeng Liu last_vc = vc; 114*51fe835cSWenmeng Liu 115*51fe835cSWenmeng Liu input_format = &tpg->fmt; 116*51fe835cSWenmeng Liu format = tpg_get_fmt_entry(tpg->res->formats->formats, 117*51fe835cSWenmeng Liu tpg->res->formats->nformats, 118*51fe835cSWenmeng Liu input_format->code); 119*51fe835cSWenmeng Liu if (IS_ERR(format)) 120*51fe835cSWenmeng Liu return -EINVAL; 121*51fe835cSWenmeng Liu 122*51fe835cSWenmeng Liu /* VC configuration */ 123*51fe835cSWenmeng Liu val = FIELD_PREP(TPG_VC_n_CFG0_NUM_ACTIVE_DT, MSM_TPG_ACTIVE_DT) | 124*51fe835cSWenmeng Liu FIELD_PREP(TPG_VC_n_CFG0_NUM_FRAMES, 0); 125*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_VC_n_CFG0(vc)); 126*51fe835cSWenmeng Liu 127*51fe835cSWenmeng Liu writel(TPG_LFSR_SEED_DEFAULT, tpg->base + TPG_VC_n_LSFR_SEED(vc)); 128*51fe835cSWenmeng Liu 129*51fe835cSWenmeng Liu val = DIV_ROUND_UP(input_format->width * format->bpp * TPG_HBI_PCT_DEFAULT, 130*51fe835cSWenmeng Liu BITS_PER_BYTE * lane_cnt * PERCENT_BASE); 131*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_VC_n_HBI_CFG(vc)); 132*51fe835cSWenmeng Liu 133*51fe835cSWenmeng Liu val = input_format->height * TPG_VBI_PCT_DEFAULT / PERCENT_BASE; 134*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_VC_n_VBI_CFG(vc)); 135*51fe835cSWenmeng Liu 136*51fe835cSWenmeng Liu writel(TPG_COLOR_BARS_CFG_STANDARD, tpg->base + TPG_VC_n_COLOR_BARS_CFG(vc)); 137*51fe835cSWenmeng Liu 138*51fe835cSWenmeng Liu /* DT configuration */ 139*51fe835cSWenmeng Liu for (dt = 0; dt <= MSM_TPG_ACTIVE_DT; dt++) { 140*51fe835cSWenmeng Liu val = FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_HEIGHT, 141*51fe835cSWenmeng Liu input_format->height & 0xffff) | 142*51fe835cSWenmeng Liu FIELD_PREP(TPG_VC_m_DT_n_CFG_0_FRAME_WIDTH, 143*51fe835cSWenmeng Liu input_format->width & 0xffff); 144*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_VC_m_DT_n_CFG_0(vc, dt)); 145*51fe835cSWenmeng Liu 146*51fe835cSWenmeng Liu val = FIELD_PREP(TPG_VC_m_DT_n_CFG_1_DATA_TYPE, format->data_type); 147*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_VC_m_DT_n_CFG_1(vc, dt)); 148*51fe835cSWenmeng Liu 149*51fe835cSWenmeng Liu if (tpg->hw_version == TPG_HW_VER_2_0_0) { 150*51fe835cSWenmeng Liu val = FIELD_PREP(TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE, payload_mode) | 151*51fe835cSWenmeng Liu FIELD_PREP(TPG_V2_0_0_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD, 152*51fe835cSWenmeng Liu TPG_USER_SPECIFIED_PAYLOAD_DEFAULT) | 153*51fe835cSWenmeng Liu FIELD_PREP(TPG_V2_0_0_VC_m_DT_n_CFG_2_ENCODE_FORMAT, 154*51fe835cSWenmeng Liu format->encode_format); 155*51fe835cSWenmeng Liu } else if (tpg->hw_version >= TPG_HW_VER_2_1_0) { 156*51fe835cSWenmeng Liu val = FIELD_PREP(TPG_VC_m_DT_n_CFG_2_PAYLOAD_MODE, payload_mode) | 157*51fe835cSWenmeng Liu FIELD_PREP(TPG_V2_1_0_VC_m_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD, 158*51fe835cSWenmeng Liu TPG_USER_SPECIFIED_PAYLOAD_DEFAULT) | 159*51fe835cSWenmeng Liu FIELD_PREP(TPG_V2_1_0_VC_m_DT_n_CFG_2_ENCODE_FORMAT, 160*51fe835cSWenmeng Liu format->encode_format); 161*51fe835cSWenmeng Liu } 162*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_VC_m_DT_n_CFG_2(vc, dt)); 163*51fe835cSWenmeng Liu } 164*51fe835cSWenmeng Liu } 165*51fe835cSWenmeng Liu 166*51fe835cSWenmeng Liu /* Global TPG control */ 167*51fe835cSWenmeng Liu val = FIELD_PREP(TPG_CTRL_TEST_EN, 1) | 168*51fe835cSWenmeng Liu FIELD_PREP(TPG_CTRL_NUM_ACTIVE_LANES, lane_cnt - 1) | 169*51fe835cSWenmeng Liu FIELD_PREP(TPG_CTRL_NUM_ACTIVE_VC, last_vc); 170*51fe835cSWenmeng Liu writel(val, tpg->base + TPG_CTRL); 171*51fe835cSWenmeng Liu 172*51fe835cSWenmeng Liu return 0; 173*51fe835cSWenmeng Liu } 174*51fe835cSWenmeng Liu 175*51fe835cSWenmeng Liu static int tpg_reset(struct tpg_device *tpg) 176*51fe835cSWenmeng Liu { 177*51fe835cSWenmeng Liu writel(0, tpg->base + TPG_CTRL); 178*51fe835cSWenmeng Liu writel(1, tpg->base + TPG_CLEAR); 179*51fe835cSWenmeng Liu 180*51fe835cSWenmeng Liu return 0; 181*51fe835cSWenmeng Liu } 182*51fe835cSWenmeng Liu 183*51fe835cSWenmeng Liu static void tpg_stream_off(struct tpg_device *tpg) 184*51fe835cSWenmeng Liu { 185*51fe835cSWenmeng Liu tpg_reset(tpg); 186*51fe835cSWenmeng Liu } 187*51fe835cSWenmeng Liu 188*51fe835cSWenmeng Liu static int tpg_configure_stream(struct tpg_device *tpg, u8 enable) 189*51fe835cSWenmeng Liu { 190*51fe835cSWenmeng Liu if (enable) 191*51fe835cSWenmeng Liu return tpg_stream_on(tpg); 192*51fe835cSWenmeng Liu 193*51fe835cSWenmeng Liu tpg_stream_off(tpg); 194*51fe835cSWenmeng Liu 195*51fe835cSWenmeng Liu return 0; 196*51fe835cSWenmeng Liu } 197*51fe835cSWenmeng Liu 198*51fe835cSWenmeng Liu static int tpg_configure_testgen_pattern(struct tpg_device *tpg, s32 val) 199*51fe835cSWenmeng Liu { 200*51fe835cSWenmeng Liu if (val >= 0 && val <= TPG_PAYLOAD_MODE_COLOR_BARS) 201*51fe835cSWenmeng Liu tpg->testgen.mode = val; 202*51fe835cSWenmeng Liu 203*51fe835cSWenmeng Liu return 0; 204*51fe835cSWenmeng Liu } 205*51fe835cSWenmeng Liu 206*51fe835cSWenmeng Liu static u32 tpg_hw_version(struct tpg_device *tpg) 207*51fe835cSWenmeng Liu { 208*51fe835cSWenmeng Liu u32 hw_version = readl(tpg->base + TPG_HW_VERSION); 209*51fe835cSWenmeng Liu 210*51fe835cSWenmeng Liu tpg->hw_version = hw_version; 211*51fe835cSWenmeng Liu dev_dbg(tpg->camss->dev, "tpg HW Version = %u.%u.%u\n", 212*51fe835cSWenmeng Liu (u32)FIELD_GET(HW_VERSION_GENERATION, hw_version), 213*51fe835cSWenmeng Liu (u32)FIELD_GET(HW_VERSION_REVISION, hw_version), 214*51fe835cSWenmeng Liu (u32)FIELD_GET(HW_VERSION_STEPPING, hw_version)); 215*51fe835cSWenmeng Liu 216*51fe835cSWenmeng Liu return hw_version; 217*51fe835cSWenmeng Liu } 218*51fe835cSWenmeng Liu 219*51fe835cSWenmeng Liu static void tpg_subdev_init(struct tpg_device *tpg) 220*51fe835cSWenmeng Liu { 221*51fe835cSWenmeng Liu tpg->testgen.modes = testgen_payload_modes; 222*51fe835cSWenmeng Liu tpg->testgen.nmodes = TPG_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; 223*51fe835cSWenmeng Liu } 224*51fe835cSWenmeng Liu 225*51fe835cSWenmeng Liu const struct tpg_hw_ops tpg_ops_gen1 = { 226*51fe835cSWenmeng Liu .configure_stream = tpg_configure_stream, 227*51fe835cSWenmeng Liu .configure_testgen_pattern = tpg_configure_testgen_pattern, 228*51fe835cSWenmeng Liu .hw_version = tpg_hw_version, 229*51fe835cSWenmeng Liu .reset = tpg_reset, 230*51fe835cSWenmeng Liu .subdev_init = tpg_subdev_init, 231*51fe835cSWenmeng Liu }; 232