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