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