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