xref: /linux/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.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 #define AWB_MEAS_VERSION_REG			0x0000
11 
12 #define AWB_MEAS_PROP_REG			0x0004
13 #define AWB_MEAS_PROP_MEAS_MODE_RGB		BIT(16) /* 0: YCbCr 1: RGB */
14 #define AWB_MEAS_PROP_YMAX			BIT(2)
15 #define AWB_MEAS_PROP_AWB_MODE_ON		BIT(1)
16 
17 #define AWB_MEAS_H_OFFS_REG			0x0008
18 #define AWB_MEAS_V_OFFS_REG			0x000c
19 #define AWB_MEAS_H_SIZE_REG			0x0010
20 #define AWB_MEAS_V_SIZE_REG			0x0014
21 #define AWB_MEAS_FRAMES_REG			0x0018
22 #define AWB_MEAS_REF_CB_MAX_B_REG		0x001c
23 #define AWB_MEAS_REF_CR_MAX_R_REG		0x0020
24 #define AWB_MEAS_MAX_Y_REG			0x0024
25 #define AWB_MEAS_MIN_Y_MAX_G_REG		0x0028
26 #define AWB_MEAS_MAX_CSUM_REG			0x002c
27 #define AWB_MEAS_MIN_C_REG			0x0030
28 #define AWB_MEAS_WHITE_CNT_REG			0x0034
29 #define AWB_MEAS_MEAN_Y_G_REG			0x0038
30 #define AWB_MEAS_MEAN_CB_B_REG			0x003c
31 #define AWB_MEAS_MEAN_CR_R_REG			0x0040
32 
33 #define AWB_MEAS_CCOR_COEFF_NUM			9
34 #define AWB_MEAS_CCOR_COEFF_REG(n)		(0x0044 + (4 * (n)))
35 
36 #define AWB_MEAS_CCOR_OFFSET_R_REG		0x0068
37 #define AWB_MEAS_CCOR_OFFSET_G_REG		0x006c
38 #define AWB_MEAS_CCOR_OFFSET_B_REG		0x0070
39 
40 static int rppx1_wbmeas_probe(struct rpp_module *mod)
41 {
42 	/* Version check. */
43 	switch (rpp_module_read(mod, AWB_MEAS_VERSION_REG)) {
44 	case 1:
45 		/* 8-bit. */
46 		break;
47 	case 2:
48 		/* 20-bit. */
49 		break;
50 	case 3:
51 		/* 24-bit. */
52 		break;
53 	default:
54 		return -EINVAL;
55 	}
56 
57 	return 0;
58 }
59 
60 static int
61 rppx1_wbmeas_fill_params(struct rpp_module *mod,
62 			 const union rppx1_params_block *block,
63 			 rppx1_reg_write write, void *priv)
64 {
65 	const struct rppx1_wbmeas_params *cfg = &block->wbmeas;
66 	u32 awb_meas_props;
67 
68 	/* If the modules is disabled, simply bypass it. */
69 	if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) {
70 		write(priv, mod->base + AWB_MEAS_PROP_REG, 0);
71 		return 0;
72 	}
73 
74 	/* Program measurement window. */
75 	write(priv, mod->base + AWB_MEAS_H_OFFS_REG, cfg->wnd.h_offs);
76 	write(priv, mod->base + AWB_MEAS_V_OFFS_REG, cfg->wnd.v_offs);
77 	write(priv, mod->base + AWB_MEAS_H_SIZE_REG, cfg->wnd.h_size);
78 	write(priv, mod->base + AWB_MEAS_V_SIZE_REG, cfg->wnd.v_size);
79 
80 	/* Set number of frames to sample. */
81 	write(priv, mod->base + AWB_MEAS_FRAMES_REG, cfg->frames);
82 
83 	if (cfg->mode == RPPX1_WBMEAS_MODE_YCBCR) {
84 		write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG,
85 		      cfg->ref_cb_max_b);
86 		write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG,
87 		      cfg->ref_cr_max_r);
88 		write(priv, mod->base + AWB_MEAS_MAX_Y_REG, cfg->max_y);
89 		write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG,
90 		      cfg->min_y_max_g);
91 		write(priv, mod->base + AWB_MEAS_MAX_CSUM_REG, cfg->max_csum);
92 		write(priv, mod->base + AWB_MEAS_MIN_C_REG, cfg->min_c);
93 
94 		/*
95 		 * Program the color conversion matrix coefficients and the
96 		 * per-color channel offsets.
97 		 */
98 		for (unsigned int i = 0; i < 3; i++) {
99 			for (unsigned int j = 0; j < 3; j++) {
100 				unsigned int index = i * 3 + j;
101 
102 				write(priv,
103 				      mod->base + AWB_MEAS_CCOR_COEFF_REG(index),
104 				      cfg->ccor_coeff[i][j]);
105 			}
106 		}
107 
108 		write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG,
109 		      cfg->ccor_offs[0]);
110 		write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG,
111 		      cfg->ccor_offs[1]);
112 		write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG,
113 		      cfg->ccor_offs[2]);
114 
115 		awb_meas_props = cfg->ymax_cmp ? AWB_MEAS_PROP_YMAX : 0;
116 	} else {
117 		write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG,
118 		      cfg->ref_cb_max_b);
119 		write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG,
120 		      cfg->ref_cr_max_r);
121 		write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG,
122 		      cfg->min_y_max_g);
123 
124 		/* Bypass color conversion matrix and color offsets. */
125 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(0), 0x1000);
126 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(1), 0x0000);
127 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(2), 0x0000);
128 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(3), 0x0000);
129 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(4), 0x1000);
130 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(5), 0x0000);
131 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(6), 0x0000);
132 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(7), 0x0000);
133 		write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(8), 0x1000);
134 		write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, 0x00000000);
135 		write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, 0x00000000);
136 		write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, 0x00000000);
137 
138 		awb_meas_props = AWB_MEAS_PROP_MEAS_MODE_RGB;
139 	}
140 
141 	write(priv, mod->base + AWB_MEAS_PROP_REG,
142 	      awb_meas_props | AWB_MEAS_PROP_AWB_MODE_ON);
143 
144 	return 0;
145 }
146 
147 static int rppx1_wbmeas_fill_stats(struct rpp_module *mod,
148 				   union rppx1_stats_block *block)
149 {
150 	struct rppx1_wbmeas_stats *stats = &block->wbmeas;
151 
152 	/* Return measurements at native hardware precision. */
153 	stats->cnt = rpp_module_read(mod, AWB_MEAS_WHITE_CNT_REG);
154 	stats->mean_y_or_g = rpp_module_read(mod, AWB_MEAS_MEAN_Y_G_REG);
155 	stats->mean_cb_or_b = rpp_module_read(mod, AWB_MEAS_MEAN_CB_B_REG);
156 	stats->mean_cr_or_r = rpp_module_read(mod, AWB_MEAS_MEAN_CR_R_REG);
157 
158 	return 0;
159 }
160 
161 const struct rpp_module_ops rppx1_wbmeas_ops = {
162 	.probe = rppx1_wbmeas_probe,
163 	.fill_params = rppx1_wbmeas_fill_params,
164 	.fill_stats = rppx1_wbmeas_fill_stats
165 };
166