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 CCOR_VERSION_REG 0x0000 11 12 #define CCOR_COEFF_REG_NUM 9 13 #define CCOR_COEFF_REG(n) (0x0004 + (4 * (n))) 14 15 #define CCOR_OFFSET_R_REG 0x0028 16 #define CCOR_OFFSET_G_REG 0x002c 17 #define CCOR_OFFSET_B_REG 0x0030 18 19 #define CCOR_CONFIG_TYPE_REG 0x0034 20 #define CCOR_CONFIG_TYPE_USE_OFFSETS_AS_PRE_OFFSETS BIT(1) 21 #define CCOR_CONFIG_TYPE_CCOR_RANGE_AVAILABLE BIT(0) 22 23 #define CCOR_RANGE_REG 0x0038 24 #define CCOR_RANGE_CCOR_C_RANGE BIT(1) 25 #define CCOR_RANGE_CCOR_Y_RANGE BIT(0) 26 27 static int rppx1_ccor_probe(struct rpp_module *mod) 28 { 29 /* Version check. */ 30 switch (rpp_module_read(mod, CCOR_VERSION_REG)) { 31 case 3: 32 /* 12-bit. */ 33 break; 34 case 4: 35 /* 20-bit. */ 36 break; 37 case 5: 38 /* 24-bit. */ 39 break; 40 default: 41 return -EINVAL; 42 } 43 44 return 0; 45 } 46 47 static int rppx1_ccor_start(struct rpp_module *mod, 48 const struct v4l2_mbus_framefmt *fmt) 49 { 50 /* Configure matrix in bypass mode. */ 51 rpp_module_write(mod, CCOR_COEFF_REG(0), 0x1000); 52 rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0000); 53 rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0000); 54 55 rpp_module_write(mod, CCOR_COEFF_REG(3), 0x0000); 56 rpp_module_write(mod, CCOR_COEFF_REG(4), 0x1000); 57 rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0000); 58 59 rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0000); 60 rpp_module_write(mod, CCOR_COEFF_REG(7), 0x0000); 61 rpp_module_write(mod, CCOR_COEFF_REG(8), 0x1000); 62 63 rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); 64 rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000000); 65 rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000000); 66 67 return 0; 68 } 69 70 static int 71 rppx1_ccor_fill_params(struct rpp_module *mod, 72 const union rppx1_params_block *block, 73 rppx1_reg_write write, void *priv) 74 { 75 const struct rppx1_ccor_params *cfg = &block->ccor; 76 77 /* If the modules is disabled, configure in bypass mode. */ 78 if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { 79 write(priv, mod->base + CCOR_COEFF_REG(0), 0x1000); 80 write(priv, mod->base + CCOR_COEFF_REG(1), 0x0000); 81 write(priv, mod->base + CCOR_COEFF_REG(2), 0x0000); 82 83 write(priv, mod->base + CCOR_COEFF_REG(3), 0x0000); 84 write(priv, mod->base + CCOR_COEFF_REG(4), 0x1000); 85 write(priv, mod->base + CCOR_COEFF_REG(5), 0x0000); 86 87 write(priv, mod->base + CCOR_COEFF_REG(6), 0x0000); 88 write(priv, mod->base + CCOR_COEFF_REG(7), 0x0000); 89 write(priv, mod->base + CCOR_COEFF_REG(8), 0x1000); 90 91 write(priv, mod->base + CCOR_OFFSET_R_REG, 0x00000000); 92 write(priv, mod->base + CCOR_OFFSET_G_REG, 0x00000000); 93 write(priv, mod->base + CCOR_OFFSET_B_REG, 0x00000000); 94 95 return 0; 96 } 97 98 /* 99 * Coefficient n for color correction matrix. 100 * 101 * RPP coefficients are 16-bit signed fixed-point numbers with 4 bit 102 * integer and 12 bit fractional part ranging from -8 (0x8000) to 103 * +7.9996 (0x7FFF). 0 is represented by 0x0000 and a coefficient 104 * value of 1 as 0x1000. 105 */ 106 write(priv, mod->base + CCOR_COEFF_REG(0), cfg->coeff[0][0]); 107 write(priv, mod->base + CCOR_COEFF_REG(1), cfg->coeff[0][1]); 108 write(priv, mod->base + CCOR_COEFF_REG(2), cfg->coeff[0][2]); 109 110 write(priv, mod->base + CCOR_COEFF_REG(3), cfg->coeff[1][0]); 111 write(priv, mod->base + CCOR_COEFF_REG(4), cfg->coeff[1][1]); 112 write(priv, mod->base + CCOR_COEFF_REG(5), cfg->coeff[1][2]); 113 114 write(priv, mod->base + CCOR_COEFF_REG(6), cfg->coeff[2][0]); 115 write(priv, mod->base + CCOR_COEFF_REG(7), cfg->coeff[2][1]); 116 write(priv, mod->base + CCOR_COEFF_REG(8), cfg->coeff[2][2]); 117 118 /* 119 * Offset for color components correction matrix. 120 * 121 * Values are a two's complement integer with one sign bit. 122 */ 123 write(priv, mod->base + CCOR_OFFSET_R_REG, cfg->offset[0]); 124 write(priv, mod->base + CCOR_OFFSET_G_REG, cfg->offset[1]); 125 write(priv, mod->base + CCOR_OFFSET_B_REG, cfg->offset[2]); 126 127 return 0; 128 } 129 130 const struct rpp_module_ops rppx1_ccor_ops = { 131 .probe = rppx1_ccor_probe, 132 .start = rppx1_ccor_start, 133 .fill_params = rppx1_ccor_fill_params, 134 }; 135 136 static int rppx1_ccor_csm_start(struct rpp_module *mod, 137 const struct v4l2_mbus_framefmt *fmt) 138 { 139 /* Reuse bypass matrix setup. */ 140 if (fmt->code == MEDIA_BUS_FMT_RGB888_1X24) 141 return rppx1_ccor_start(mod, fmt); 142 143 /* Color Transformation RGB to YUV according to ITU-R BT.709. */ 144 rpp_module_write(mod, CCOR_COEFF_REG(0), 0x0367); 145 rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0b71); 146 rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0128); 147 148 rpp_module_write(mod, CCOR_COEFF_REG(3), 0xfe2b); 149 rpp_module_write(mod, CCOR_COEFF_REG(4), 0xf9d5); 150 rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0800); 151 152 rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0800); 153 rpp_module_write(mod, CCOR_COEFF_REG(7), 0xf8bc); 154 rpp_module_write(mod, CCOR_COEFF_REG(8), 0xff44); 155 156 rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); 157 rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000800); 158 rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000800); 159 160 return 0; 161 } 162 163 const struct rpp_module_ops rppx1_ccor_csm_ops = { 164 .probe = rppx1_ccor_probe, 165 .start = rppx1_ccor_csm_start, 166 }; 167