xref: /linux/drivers/media/platform/dreamchip/rppx1/rppx1_bls.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 #include "rppx1.h"
10 
11 #define BLS_VERSION_REG				0x0000
12 
13 #define BLS_CTRL_REG				0x0004
14 #define BLS_CTRL_BLS_WIN2			BIT(3)
15 #define BLS_CTRL_BLS_WIN1			BIT(2)
16 #define BLS_CTRL_BLS_MODE_MEASURED		BIT(1)
17 #define BLS_CTRL_BLS_EN				BIT(0)
18 
19 #define BLS_SAMPLES_REG				0x0008
20 #define BLS_H1_START_REG			0x000c
21 #define BLS_H1_STOP_REG				0x0010
22 #define BLS_V1_START_REG			0x0014
23 #define BLS_V1_STOP_REG				0x0018
24 #define BLS_H2_START_REG			0x001c
25 #define BLS_H2_STOP_REG				0x0020
26 #define BLS_V2_START_REG			0x0024
27 #define BLS_V2_STOP_REG				0x0028
28 #define BLS_A_FIXED_REG				0x002c
29 #define BLS_B_FIXED_REG				0x0030
30 #define BLS_C_FIXED_REG				0x0034
31 #define BLS_D_FIXED_REG				0x0038
32 #define BLS_A_MEASURED_REG			0x003c
33 #define BLS_B_MEASURED_REG			0x0040
34 #define BLS_C_MEASURED_REG			0x0044
35 #define BLS_D_MEASURED_REG			0x0048
36 #define BLS_PRE1_FIXED_MASK			GENMASK(24, 0)
37 #define BLS_PRE2_FIXED_MASK			GENMASK(12, 0)
38 
39 static int rppx1_bls_probe(struct rpp_module *mod)
40 {
41 	/* Version check. */
42 	switch (rpp_module_read(mod, BLS_VERSION_REG)) {
43 	case 3:
44 	case 5:
45 		/* 12-bit. */
46 		break;
47 	case 2:
48 	case 4:
49 		/* 20-bit. */
50 		break;
51 	case 6:
52 		/* 24-bit. */
53 		break;
54 	default:
55 		return -EINVAL;
56 	}
57 
58 	return 0;
59 }
60 
61 static void
62 rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output[4])
63 {
64 	static const unsigned int swap[4][4] = {
65 		[RPP_RGGB] = { 0, 1, 2, 3 },
66 		[RPP_GRBG] = { 1, 0, 3, 2 },
67 		[RPP_GBRG] = { 2, 3, 0, 1 },
68 		[RPP_BGGR] = { 3, 2, 1, 0 },
69 	};
70 
71 	/* Swap to pattern used in our path, PRE1 or PRE2. */
72 	struct rpp_module *acq = mod == &mod->rpp->pre1.bls ?
73 		&mod->rpp->pre1.acq : &mod->rpp->pre2.bls;
74 	enum rpp_raw_pattern pattern = acq->info.acq.raw_pattern;
75 
76 	for (unsigned int i = 0; i < 4; ++i)
77 		output[i] = input[swap[pattern][i]];
78 }
79 
80 static int
81 rppx1_bls_fill_params(struct rpp_module *mod,
82 		      const union rppx1_params_block *block,
83 		      rppx1_reg_write write, void *priv)
84 {
85 	const struct rppx1_bls_params *cfg = &block->bls;
86 
87 	/* If the modules is disabled, simply bypass it. */
88 	if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) {
89 		write(priv, mod->base + BLS_CTRL_REG, 0);
90 		return 0;
91 	}
92 
93 	u32 ctrl = BLS_CTRL_BLS_EN;
94 
95 	if (cfg->mode == RPPX1_BLS_MODE_FIXED) {
96 		static const u32 regs[] = {
97 			BLS_A_FIXED_REG,
98 			BLS_B_FIXED_REG,
99 			BLS_C_FIXED_REG,
100 			BLS_D_FIXED_REG,
101 		};
102 		u32 swapped[4];
103 
104 		rppx1_bls_swap_regs(mod, regs, swapped);
105 
106 		/*
107 		 * The PRE1 pipe fixed values are 24-bits + 1 sign bit, while
108 		 * the PRE2 pipe values are 12-bits + 1 sign bit.
109 		 */
110 		u32 mask;
111 
112 		switch (cfg->header.type) {
113 		case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1:
114 			mask = BLS_PRE1_FIXED_MASK;
115 			break;
116 		case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2:
117 			mask = BLS_PRE2_FIXED_MASK;
118 			break;
119 		default:
120 			return -EINVAL;
121 		}
122 
123 		write(priv, mod->base + swapped[0], cfg->fixed.a & mask);
124 		write(priv, mod->base + swapped[1], cfg->fixed.b & mask);
125 		write(priv, mod->base + swapped[2], cfg->fixed.c & mask);
126 		write(priv, mod->base + swapped[3], cfg->fixed.d & mask);
127 	} else {
128 		write(priv, mod->base + BLS_SAMPLES_REG, cfg->samples);
129 
130 		if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN1) {
131 			write(priv, mod->base + BLS_H1_START_REG, cfg->window1.h_offs);
132 			write(priv, mod->base + BLS_H1_STOP_REG, cfg->window1.h_size);
133 			write(priv, mod->base + BLS_V1_START_REG, cfg->window1.v_offs);
134 			write(priv, mod->base + BLS_V1_STOP_REG, cfg->window1.v_size);
135 			ctrl |= BLS_CTRL_BLS_WIN1;
136 		}
137 
138 		if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN2) {
139 			write(priv, mod->base + BLS_H2_START_REG, cfg->window2.h_offs);
140 			write(priv, mod->base + BLS_H2_STOP_REG, cfg->window2.h_size);
141 			write(priv, mod->base + BLS_V2_START_REG, cfg->window2.v_offs);
142 			write(priv, mod->base + BLS_V2_STOP_REG, cfg->window2.v_size);
143 			ctrl |= BLS_CTRL_BLS_WIN2;
144 		}
145 
146 		ctrl |= BLS_CTRL_BLS_MODE_MEASURED;
147 	}
148 
149 	write(priv, mod->base + BLS_CTRL_REG, ctrl);
150 
151 	return 0;
152 }
153 
154 const struct rpp_module_ops rppx1_bls_ops = {
155 	.probe = rppx1_bls_probe,
156 	.fill_params = rppx1_bls_fill_params,
157 };
158