xref: /linux/drivers/media/platform/qcom/camss/camss-tpg-gen1.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
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