xref: /linux/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c (revision f4cdf7ca9a1fdcca413157df19753f388a5a224e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2026 Renesas Electronics Corp.
4  * Copyright (C) 2026 Ideas on Board Oy
5  * Copyright (C) 2026 Ragnatech AB
6  */
7 
8 #include "rpp_module.h"
9 
10 #include <linux/bitfield.h>
11 
12 #define HIST_VERSION_REG			0x0000
13 
14 #define HIST_CTRL_REG				0x0004
15 #define HIST_CTRL_HIST_UPDATE_ENABLE		BIT(0)
16 
17 #define HIST_MODE_REG				0x0008
18 #define HIST_MODE_HIST_MODE_MASK		GENMASK(2, 0)
19 #define HIST_MODE_HIST_MODE_DISABLE		0
20 #define HIST_MODE_HIST_MODE_YRGB		1
21 #define HIST_MODE_HIST_MODE_R			2
22 #define HIST_MODE_HIST_MODE_GR			3
23 #define HIST_MODE_HIST_MODE_B			4
24 #define HIST_MODE_HIST_MODE_GB			5
25 
26 #define HIST_CHANNEL_SEL_REG			0x000c
27 #define HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK	GENMASK(2, 0)
28 
29 #define HIST_LAST_MEAS_LINE_REG			0x0010
30 #define HIST_SUBSAMPLING_REG			0x0014
31 #define HIST_SUBSAMPLING_V_STEPSIZE(x)		(((x) & 0x7f) << 24)
32 #define HIST_SUBSAMPLING_H_STEP_INC(x)		(((x) & 0x1ffff))
33 
34 #define HIST_COEFF_R_REG			0x0018
35 #define HIST_COEFF_G_REG			0x001c
36 #define HIST_COEFF_B_REG			0x0020
37 #define HIST_H_OFFS_REG				0x0024
38 #define HIST_V_OFFS_REG				0x0028
39 #define HIST_H_SIZE_REG				0x002c
40 #define HIST_V_SIZE_REG				0x0030
41 
42 #define HIST_SAMPLE_RANGE_REG			0x0034
43 #define HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK	GENMASK(28, 24)
44 #define HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK	GENMASK(23, 0)
45 
46 #define HIST_WEIGHT_00TO30_REG			0x0038
47 #define HIST_WEIGHT_40TO21_REG			0x003c
48 #define HIST_WEIGHT_31TO12_REG			0x0040
49 #define HIST_WEIGHT_22TO03_REG			0x0044
50 #define HIST_WEIGHT_13TO43_REG			0x0048
51 #define HIST_WEIGHT_04TO34_REG			0x004c
52 #define HIST_WEIGHT_44_REG			0x0050
53 #define HIST_FORCED_UPD_START_LINE_REG		0x0054
54 #define HIST_FORCED_UPDATE_REG			0x0058
55 #define HIST_VSTART_STATUS_REG			0x005c
56 
57 #define HIST_BIN_REG(n)				(0x0060 + (4 * (n)))
58 
59 static int rppx1_hist_probe(struct rpp_module *mod)
60 {
61 	/* Version check. */
62 	switch (rpp_module_read(mod, HIST_VERSION_REG)) {
63 	case 3:
64 		/* 12-bit. */
65 		break;
66 	case 4:
67 		/* 20-bit. */
68 		break;
69 	case 5:
70 		/* 24-bit. */
71 		break;
72 	default:
73 		return -EINVAL;
74 	}
75 
76 	return 0;
77 }
78 
79 #define RPPX1_HIST_WEIGHT(v0, v1, v2, v3) \
80 	(((v0) & 0x1f) | (((v1) & 0x1f) << 8)  | \
81 	(((v2) & 0x1f) << 16) | \
82 	(((v3) & 0x1f) << 24))
83 
84 static int rppx1_hist_fill_params(struct rpp_module *mod,
85 				  const union rppx1_params_block *block,
86 				  rppx1_reg_write write, void *priv)
87 {
88 	const struct rppx1_hist_params *cfg = &block->hist;
89 	u32 h_offs, v_offs, h_size, v_size;
90 
91 	/* If the modules is disabled, simply bypass it. */
92 	if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) {
93 		write(priv, mod->base + HIST_MODE_REG,
94 		      HIST_MODE_HIST_MODE_DISABLE);
95 		return 0;
96 	}
97 
98 	/* Select sample point */
99 	write(priv, mod->base + HIST_CHANNEL_SEL_REG,
100 	      cfg->channel_sel & HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK);
101 
102 	/*
103 	 * Configure the input subsampling.
104 	 *
105 	 * In Bayer mode the vertical and horizontal subsampling counters are
106 	 * only incremented for color channels selected by hist_mode.
107 	 */
108 	write(priv, mod->base + HIST_SUBSAMPLING_REG,
109 	      HIST_SUBSAMPLING_V_STEPSIZE(cfg->v_stepsize) |
110 	      HIST_SUBSAMPLING_H_STEP_INC(cfg->h_step_inc));
111 
112 	/*
113 	 * Adjust and set measurement window to hardware limitations,
114 	 * - Offsets must be even.
115 	 * - Width and height must be even and divisible in 5 windows.
116 	 */
117 	h_offs = cfg->wnd.h_offs & 0x1ffe;
118 	v_offs = cfg->wnd.v_offs & 0x1ffe;
119 	h_size = cfg->wnd.h_size - cfg->wnd.h_size % 10;
120 	v_size = cfg->wnd.v_size - cfg->wnd.v_size % 10;
121 
122 	write(priv, mod->base + HIST_H_OFFS_REG, h_offs);
123 	write(priv, mod->base + HIST_V_OFFS_REG, v_offs);
124 	write(priv, mod->base + HIST_H_SIZE_REG, h_size / 5);
125 	write(priv, mod->base + HIST_V_SIZE_REG, v_size / 5);
126 
127 	/*
128 	 * Set last measurement line for ready interrupt. Ignore the value
129 	 * from the parameters as it is only useful for fast-channel switching.
130 	 */
131 	write(priv, mod->base + HIST_LAST_MEAS_LINE_REG, v_offs + v_size + 1);
132 
133 	/* Set measurement window weights. */
134 	write(priv, mod->base + HIST_WEIGHT_00TO30_REG,
135 	      RPPX1_HIST_WEIGHT(cfg->weights[0], cfg->weights[1],
136 				cfg->weights[2], cfg->weights[3]));
137 	write(priv, mod->base + HIST_WEIGHT_40TO21_REG,
138 	      RPPX1_HIST_WEIGHT(cfg->weights[4], cfg->weights[5],
139 				cfg->weights[6], cfg->weights[7]));
140 	write(priv, mod->base + HIST_WEIGHT_31TO12_REG,
141 	      RPPX1_HIST_WEIGHT(cfg->weights[8], cfg->weights[9],
142 				cfg->weights[10], cfg->weights[11]));
143 	write(priv, mod->base + HIST_WEIGHT_22TO03_REG,
144 	      RPPX1_HIST_WEIGHT(cfg->weights[12], cfg->weights[13],
145 				cfg->weights[14], cfg->weights[15]));
146 	write(priv, mod->base + HIST_WEIGHT_13TO43_REG,
147 	      RPPX1_HIST_WEIGHT(cfg->weights[16], cfg->weights[17],
148 				cfg->weights[18], cfg->weights[19]));
149 	write(priv, mod->base + HIST_WEIGHT_04TO34_REG,
150 	      RPPX1_HIST_WEIGHT(cfg->weights[20], cfg->weights[21],
151 				cfg->weights[22], cfg->weights[23]));
152 	write(priv, mod->base + HIST_WEIGHT_44_REG,
153 	      RPPX1_HIST_WEIGHT(cfg->weights[24], 0, 0, 0));
154 
155 	write(priv, mod->base + HIST_MODE_REG, cfg->mode);
156 	write(priv, mod->base + HIST_COEFF_R_REG, cfg->coeff[0]);
157 	write(priv, mod->base + HIST_COEFF_G_REG, cfg->coeff[1]);
158 	write(priv, mod->base + HIST_COEFF_B_REG, cfg->coeff[2]);
159 
160 	u32 sample_reg = FIELD_PREP(HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK,
161 				    cfg->sample_shift) |
162 			 FIELD_PREP(HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK,
163 				    cfg->sample_offs);
164 	write(priv, mod->base + HIST_SAMPLE_RANGE_REG, sample_reg);
165 
166 	write(priv, mod->base + HIST_FORCED_UPDATE_REG, 1);
167 
168 	return 0;
169 }
170 
171 static int rppx1_hist_fill_stats(struct rpp_module *mod,
172 				 union rppx1_stats_block *block)
173 {
174 	struct rppx1_hist_stats *stats = &block->hist;
175 
176 	for (unsigned int i = 0; i < RPPX1_HIST_NUM_BINS; i++)
177 		stats->hist_bins[i] = rpp_module_read(mod, HIST_BIN_REG(i));
178 
179 	return 0;
180 }
181 
182 const struct rpp_module_ops rppx1_hist_ops = {
183 	.probe = rppx1_hist_probe,
184 	.fill_params = rppx1_hist_fill_params,
185 	.fill_stats = rppx1_hist_fill_stats,
186 };
187