[PATCH 04/18] media: microchip-isc: Improve histogram calculation with outlier rejection

Balamanikandan Gunasundar
2025-10-09T15:54:10Z

From: Balakrishnan Sambath <balakrishnan.s@microchip.com>

Replace simple min/max detection with smart outlier rejection that skips
bottom/top 2% of histogram to avoid noise and saturation. Add channel
average calculation using weighted pixel intensity instead of simple
pixel counting for more accurate color analysis.

Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 83 ++++++++++++++++---
.../media/platform/microchip/microchip-isc.h | 2 +
2 files changed, 75 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index c138e92a1aca..956bdea830e3 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -262,6 +262,10 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
struct isc_ctrls *ctrls = &isc->ctrls;

if (enable) {
+ /* Initialize histogram data storage for clean start */
+ memset(ctrls->total_pixels, 0, sizeof(ctrls->total_pixels));
+ memset(ctrls->hist_minmax, 0, sizeof(ctrls->hist_minmax));
+
regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
ISC_HIS_CFG_MODE_GR |
(isc->config.sd_format->cfa_baycfg
@@ -1231,24 +1235,83 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
hist_entry, HIST_ENTRIES);

- *hist_count = 0;
- /*
- * we deliberately ignore the end of the histogram,
- * the most white pixels
- */
+ /* Calculate total pixels */
+ u32 total_pixels = 0;
+
+ for (i = 0; i < HIST_ENTRIES; i++)
+ total_pixels += hist_entry[i];
+
+ /* Handle empty histogram case */
+ if (total_pixels == 0) {
+ *hist_count = 0;
+ ctrls->channel_avg[ctrls->hist_id] = 256; /* Default middle value */
+ ctrls->total_pixels[ctrls->hist_id] = 0;
+ *min = 1;
+ *max = HIST_ENTRIES - 1;
+ dev_dbg(isc->dev, "isc wb: no pixels in histogram for channel %u", ctrls->hist_id);
+ return;
+ }
+
+ /* Smart outlier rejection - skip bottom/top 2% */
+ u32 dark_threshold = total_pixels / 50; /* Bottom 2% */
+ u32 bright_threshold = total_pixels / 50; /* Top 2% */
+ u32 cumulative = 0;
+
+ /* Find effective minimum (skip dark noise) */
+ *min = 1;
for (i = 1; i < HIST_ENTRIES; i++) {
- if (*hist_entry && !*min)
+ cumulative += hist_entry[i];
+ if (cumulative > dark_threshold) {
*min = i;
- if (*hist_entry)
+ break;
+ }
+ }
+
+ /* Find effective maximum (skip bright saturation) */
+ cumulative = 0;
+ *max = HIST_ENTRIES - 1;
+ for (i = HIST_ENTRIES - 1; i > *min; i--) {
+ cumulative += hist_entry[i];
+ if (cumulative > bright_threshold) {
*max = i;
- *hist_count += i * (*hist_entry++);
+ break;
+ }
}

+ /* Ensure reasonable range */
+ if (*max <= *min) {
+ *min = HIST_ENTRIES / 4;
+ *max = (HIST_ENTRIES * 3) / 4;
+ }
+
+ /* Calculate both pixel count and weighted average for useful range */
+ *hist_count = 0;
+ u64 weighted_sum = 0;
+
+ for (i = *min; i <= *max; i++) {
+ u32 pixel_count = hist_entry[i];
+ *hist_count += pixel_count;
+ weighted_sum += (u64)i * pixel_count;
+ }
+
+ /* Store total useful pixels for this channel */
+ ctrls->total_pixels[ctrls->hist_id] = *hist_count;
+
+ /* Calculate channel average */
+ if (*hist_count > 0)
+ ctrls->channel_avg[ctrls->hist_id] =
+ div64_u64(weighted_sum, *hist_count);
+ else
+ /* Default middle value */
+ ctrls->channel_avg[ctrls->hist_id] = 256;
+
if (!*min)
*min = 1;

- dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u",
- ctrls->hist_id, *hist_count);
+ dev_dbg(isc->dev,
+ "isc wb: hist_id %u, avg %u, count %u, range [%u,%u], total %u",
+ ctrls->hist_id, ctrls->channel_avg[ctrls->hist_id],
+ *hist_count, *min, *max, total_pixels);
}

static void isc_wb_update(struct isc_ctrls *ctrls)
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index ad4e98a1dd8f..bd75ff4f109b 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -156,6 +156,8 @@ struct isc_ctrls {
#define HIST_MIN_INDEX 0
#define HIST_MAX_INDEX 1
u32 hist_minmax[HIST_BAYER][2];
+ u32 channel_avg[HIST_BAYER]; /* Average pixel intensity per channel */
+ u32 total_pixels[HIST_BAYER]; /* Total pixels per channel */
};

#define ISC_PIPE_LINE_NODE_NUM 15
--
2.34.1