* [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
@ 2025-10-09 15:52 Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 01/18] media: platform: microchip: set maximum resolution for sam9x7 Balamanikandan Gunasundar
` (21 more replies)
0 siblings, 22 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
Hi,
This patch series has a set of enhancements to the Microchip Image Sensor
Controller driver. The objective is to expand its image processing
capabilities and to improve the colors.
This series also introduces a new stats driver that exposes the histogram
data to userspace via v4l2 controls. This allows applications such as
libcamera to access real time image statistics for advanced image
processing like automatic exposure, white balance adjustments etc.
Balakrishnan Sambath (11):
media: microchip-isc: Enable GDC and CBC module flags for RGB formats
media: microchip-isc: Improve histogram calculation with outlier
rejection
media: microchip-isc: Use channel averages for Grey World AWB
media: microchip-isc: Add range based black level correction
media: platform: microchip: Extend gamma table and control range
media: platform: microchip: Add new histogram submodule
media: microchip-isc: Register and unregister statistics device
media: microchip-isc: Always enable histogram for all RAW formats
media: microchip-isc: fix histogram state initialization order
media: microchip-isc: decouple histogram cycling from AWB mode
media: microchip-isc: enable userspace histogram statistics export
Balamanikandan Gunasundar (7):
media: platform: microchip: set maximum resolution for sam9x7
media: platform: microchip: Include DPC modules flags in pipeline
media: microchip-isc: expose hue and saturation as v4l2 controls
media: microchip-isc: Rename CBC to CBHS
media: microchip-isc: Store histogram data of all channels
media: videodev2.h, v4l2-ioctl: Add microchip statistics format
media: microchip-isc: expose color correction registers as v4l2
controls
drivers/media/platform/microchip/Kconfig | 2 +
drivers/media/platform/microchip/Makefile | 2 +-
.../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
.../platform/microchip/microchip-isc-regs.h | 3 +
.../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
.../media/platform/microchip/microchip-isc.h | 44 +-
.../microchip/microchip-sama5d2-isc.c | 2 +-
.../microchip/microchip-sama7g5-isc.c | 73 ++-
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
include/linux/atmel-isc-media.h | 13 +
include/uapi/linux/videodev2.h | 3 +
11 files changed, 1001 insertions(+), 64 deletions(-)
create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
--
2.34.1
^ permalink raw reply [flat|nested] 65+ messages in thread
* [PATCH 01/18] media: platform: microchip: set maximum resolution for sam9x7
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 02/18] media: platform: microchip: Include DPC modules flags in pipeline Balamanikandan Gunasundar
` (20 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
The maximum resolution for sam9x7 is 2560x1920. And its is 3264x2464 for
sama7g5.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
.../media/platform/microchip/microchip-sama7g5-isc.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index b0302dfc3278..36c3f4ba1962 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -55,6 +55,9 @@
#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH 3264
#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
+#define ISC_SAM9X7_MAX_SUPPORT_WIDTH 2560
+#define ISC_SAM9X7_MAX_SUPPORT_HEIGHT 1920
+
#define ISC_SAMA7G5_PIPELINE \
(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
@@ -432,8 +435,13 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 0;
- isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
- isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+ if ((of_machine_is_compatible("microchip,sam9x7"))) {
+ isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAM9X7_MAX_SUPPORT_HEIGHT;
+ } else {
+ isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+ }
isc->config_dpc = isc_sama7g5_config_dpc;
isc->config_csc = isc_sama7g5_config_csc;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 02/18] media: platform: microchip: Include DPC modules flags in pipeline
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 01/18] media: platform: microchip: set maximum resolution for sam9x7 Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 03/18] media: microchip-isc: Enable GDC and CBC module flags for RGB formats Balamanikandan Gunasundar
` (19 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
Add DPC_DPCENABLE, DPC_GDCENABLE, and DPC_BLCENABLE enable bits to
ISC_SAMA7G5_PIPELINE macro to prevent isc_sama7g5_adapt_pipeline() from
masking out DPC modules during pipeline configuration
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
drivers/media/platform/microchip/microchip-sama7g5-isc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 36c3f4ba1962..03f7a46acd47 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -59,7 +59,8 @@
#define ISC_SAM9X7_MAX_SUPPORT_HEIGHT 1920
#define ISC_SAMA7G5_PIPELINE \
- (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ (DPC_DPCENABLE | DPC_GDCENABLE | DPC_BLCENABLE | \
+ WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 03/18] media: microchip-isc: Enable GDC and CBC module flags for RGB formats
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 01/18] media: platform: microchip: set maximum resolution for sam9x7 Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 02/18] media: platform: microchip: Include DPC modules flags in pipeline Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 04/18] media: microchip-isc: Improve histogram calculation with outlier rejection Balamanikandan Gunasundar
` (18 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Include DPC_GDCENABLE and CBC_ENABLE flags in pipeline configuration for
RGB raw formats to enable green disparity correction and
contrast/brightness control.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index a7cdc743fda7..c138e92a1aca 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -787,7 +787,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
- CC_ENABLE;
+ DPC_GDCENABLE | CBC_ENABLE | CC_ENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 04/18] media: microchip-isc: Improve histogram calculation with outlier rejection
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (2 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 03/18] media: microchip-isc: Enable GDC and CBC module flags for RGB formats Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 05/18] media: microchip-isc: Use channel averages for Grey World AWB Balamanikandan Gunasundar
` (17 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
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
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 05/18] media: microchip-isc: Use channel averages for Grey World AWB
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (3 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 04/18] media: microchip-isc: Improve histogram calculation with outlier rejection Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 06/18] media: microchip-isc: Add range based black level correction Balamanikandan Gunasundar
` (16 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Replace pixel counting with actual pixel intensity averages in Grey
World algorithm for more accurate white balance calculation.This
provides better color correction especially in mixed lighting
conditions.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 35 ++++++++++---------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 956bdea830e3..bb2dd69a83f0 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1317,7 +1317,6 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
static void isc_wb_update(struct isc_ctrls *ctrls)
{
struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
- u32 *hist_count = &ctrls->hist_count[0];
u32 c, offset[4];
u64 avg = 0;
/* We compute two gains, stretch gain and grey world gain */
@@ -1328,10 +1327,10 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
* them towards the green channel.
* Thus we want to keep Green as fixed and adjust only Red/Blue
* Compute the average of the both green channels first
+ * Use channel averages for Grey World algorithm
*/
- avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
- (u64)hist_count[ISC_HIS_CFG_MODE_GB];
- avg >>= 1;
+ avg = (ctrls->channel_avg[ISC_HIS_CFG_MODE_GR] +
+ ctrls->channel_avg[ISC_HIS_CFG_MODE_GB]) >> 1;
dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
@@ -1340,6 +1339,11 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
return;
for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ u32 hist_min = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ u32 hist_max = ctrls->hist_minmax[c][HIST_MAX_INDEX];
+ u32 channel_avg = ctrls->channel_avg[c];
+ u32 total_pixels = ctrls->total_pixels[c];
+
/*
* the color offset is the minimum value of the histogram.
* we stretch this color to the full range by substracting
@@ -1373,23 +1377,21 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
* decimals
*/
s_gain[c] = (HIST_ENTRIES << 9) /
- (ctrls->hist_minmax[c][HIST_MAX_INDEX] -
- ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
+ (hist_max - hist_min + 1);
/*
- * Now we have to compute the gain w.r.t. the average.
- * Add/lose gain to the component towards the average.
- * If it happens that the component is zero, use the
- * fixed point value : 1.0 gain.
+ * Grey World gain using channel averages
+ * This is much more accurate than using hist_count
*/
- if (hist_count[c])
- gw_gain[c] = div_u64(avg << 9, hist_count[c]);
+ if (channel_avg > 0 && total_pixels > 1000)
+ gw_gain[c] = div64_u64((avg << 9), channel_avg);
else
gw_gain[c] = 1 << 9;
dev_dbg(isc->dev,
- "isc wb: component %d, s_gain %u, gw_gain %u\n",
- c, s_gain[c], gw_gain[c]);
+ "isc wb: component %d, black_level=%u, avg=%u, s_gain=%u, gw_gain=%u",
+ c, hist_min, channel_avg, s_gain[c], gw_gain[c]);
+
/* multiply both gains and adjust for decimals */
ctrls->gain[c] = s_gain[c] * gw_gain[c];
ctrls->gain[c] >>= 9;
@@ -1397,8 +1399,9 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
/* make sure we are not out of range */
ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
- dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
- c, ctrls->gain[c]);
+ dev_dbg(isc->dev,
+ "isc wb: component %d, final gain %u, offset %d\n",
+ c, ctrls->gain[c], ctrls->offset[c]);
}
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 06/18] media: microchip-isc: Add range based black level correction
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (4 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 05/18] media: microchip-isc: Use channel averages for Grey World AWB Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 07/18] media: platform: microchip: Extend gamma table and control range Balamanikandan Gunasundar
` (15 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Add adaptive black level offset based on histogram minimum and pixel
statistics. Apply conservative correction for high black levels and
gentle correction for low levels to prevent overcorrection and improve
dynamic range.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 22 ++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index bb2dd69a83f0..2706a27a2506 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1349,7 +1349,27 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
* we stretch this color to the full range by substracting
* this value from the color component.
*/
- offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ if (hist_min > 5 && hist_min < 60 && total_pixels > 1000) {
+ /*
+ * Basic adaptive black level offset correction
+ * (Simplified version for kernel fallback)
+ */
+ if (hist_min > 20)
+ /* Conservative for high levels */
+ offset[c] = hist_min - 4;
+ else if (hist_min > 10)
+ /* Moderate correction */
+ offset[c] = hist_min - 2;
+ else
+ /* Gentle correction */
+ offset[c] = hist_min - 1;
+
+ offset[c] = max(1U, offset[c]); /* Ensure minimum of 1 */
+ } else {
+ /* Use default behavior for edge cases */
+ offset[c] = hist_min;
+ }
+
/*
* The offset is always at least 1. If the offset is 1, we do
* not need to adjust it, so our result must be zero.
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 07/18] media: platform: microchip: Extend gamma table and control range
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (5 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 06/18] media: microchip-isc: Add range based black level correction Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 08/18] media: platform: microchip: Add new histogram submodule Balamanikandan Gunasundar
` (14 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Add support for multiple levels of gamma correction options (1/2.4,
1/2.2, 1/1.8) which can be modified through V4L2 controls(with range
0-2), with a default of 1/2.2(index 1).
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 3 +-
.../microchip/microchip-sama7g5-isc.c | 54 ++++++++++++++-----
2 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 2706a27a2506..cd379f95fc1c 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1715,8 +1715,7 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->brightness = 0;
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
- isc->gamma_max);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1, 1);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
0, 1, 1, 1);
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 03f7a46acd47..d3ed9cfe6686 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -320,21 +320,47 @@ static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
}
-/* Gamma table with gamma 1/2.2 */
+/* Gamma tables with gamma values 0.42, 0.45(Default), 0.56 */
static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
- /* index 0 --> gamma bipartite */
+ /* index 0 --> gamma bipartite 1/2.4(=0.42) */
{
- 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
- 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
- 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
- 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
- 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
- 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
- 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
- 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
- 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
- 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
- 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+ 0x940, 0x4b0310, 0x630250, 0x7601d0, 0x840190, 0x910170,
+ 0x9d0150, 0xa80110, 0xb10110, 0xba0110, 0xc300f0, 0xcb00f0,
+ 0xd300e0, 0xda00e0, 0xe100c0, 0xe800c0, 0xee00c0, 0xf400c0,
+ 0xfa00a0, 0x10000a0, 0x10500a0, 0x10b00a0, 0x11000a0, 0x11500a0,
+ 0x11a0080, 0x11f0080, 0x1240080, 0x1290080, 0x12e0080, 0x1330070,
+ 0x1380070, 0x13c0070, 0x1410070, 0x17a0060, 0x1aa0052, 0x1d40046,
+ 0x1f90042, 0x21b003c, 0x23a0038, 0x2570034, 0x2720030, 0x28b002e,
+ 0x2a3002c, 0x2ba002a, 0x2d0002a, 0x2e60028, 0x2fa0026, 0x30e0026,
+ 0x3210024, 0x3330022, 0x3450022, 0x3560020, 0x3670020, 0x3770020,
+ 0x387001e, 0x396001e, 0x3a5001c, 0x3b3001c, 0x3c1001c, 0x3cf001a,
+ 0x3dd001a, 0x3eb0018, 0x3f90018 },
+ /* index 1 --> gamma bipartite 1/2.2(=0.45) */
+ {
+ 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
+ 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
+ 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
+ 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
+ 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
+ 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
+ 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
+ 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
+ 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
+ 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
+ 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+ /* index 2 --> gamma bipartite 1/1.8(=0.56) */
+ {
+ 0xa62, 0x4f0350, 0x680280, 0x7e0200, 0x8d01c0, 0x9a01a0,
+ 0xa50180, 0xb00140, 0xb90140, 0xc20120, 0xcb0120, 0xd30100,
+ 0xdb0100, 0xe300e0, 0xea00e0, 0xf100e0, 0xf700c0, 0xfd00c0,
+ 0x10300c0, 0x10900a0, 0x10e00a0, 0x11400a0, 0x11900a0, 0x11e00a0,
+ 0x12300a0, 0x12800a0, 0x12d0080, 0x1320080, 0x1370080, 0x13c0080,
+ 0x1410080, 0x1460080, 0x14a0070, 0x1830060, 0x1b40052, 0x1df0048,
+ 0x2040042, 0x2250040, 0x2440038, 0x2600036, 0x27b0032, 0x2940030,
+ 0x2ac002e, 0x2c4002c, 0x2da002a, 0x2f0002a, 0x3050028, 0x3190026,
+ 0x32c0026, 0x33e0024, 0x3500024, 0x3610022, 0x3720020, 0x3820020,
+ 0x3920020, 0x3a2001e, 0x3b1001e, 0x3c0001c, 0x3ce001c, 0x3dc001c,
+ 0x3ea001a, 0x3f8001a, 0x4060018, 0x4130018 },
};
static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
@@ -434,7 +460,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
}
isc->gamma_table = isc_sama7g5_gamma_table;
- isc->gamma_max = 0;
+ isc->gamma_max = 2;
if ((of_machine_is_compatible("microchip,sam9x7"))) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 08/18] media: platform: microchip: Add new histogram submodule
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (6 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 07/18] media: platform: microchip: Extend gamma table and control range Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-11-10 8:41 ` Hans Verkuil
2025-11-10 8:55 ` Hans Verkuil
2025-10-09 15:52 ` [PATCH 09/18] media: microchip-isc: Register and unregister statistics device Balamanikandan Gunasundar
` (13 subsequent siblings)
21 siblings, 2 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Add new histogram submodule driver to export raw histogram statistics
and data to userspace.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/Kconfig | 2 +
drivers/media/platform/microchip/Makefile | 2 +-
.../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
.../media/platform/microchip/microchip-isc.h | 24 +
4 files changed, 576 insertions(+), 1 deletion(-)
create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
diff --git a/drivers/media/platform/microchip/Kconfig b/drivers/media/platform/microchip/Kconfig
index 4734ecced029..2864a57e2ff4 100644
--- a/drivers/media/platform/microchip/Kconfig
+++ b/drivers/media/platform/microchip/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_MICROCHIP_ISC
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
select REGMAP_MMIO
select V4L2_FWNODE
select VIDEO_MICROCHIP_ISC_BASE
@@ -26,6 +27,7 @@ config VIDEO_MICROCHIP_XISC
depends on VIDEO_DEV && COMMON_CLK
depends on ARCH_AT91 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
select REGMAP_MMIO
select V4L2_FWNODE
select VIDEO_MICROCHIP_ISC_BASE
diff --git a/drivers/media/platform/microchip/Makefile b/drivers/media/platform/microchip/Makefile
index bd8d6e779c51..94c64d3d242c 100644
--- a/drivers/media/platform/microchip/Makefile
+++ b/drivers/media/platform/microchip/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
microchip-isc-objs = microchip-sama5d2-isc.o
microchip-xisc-objs = microchip-sama7g5-isc.o
-microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o
+microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o microchip-isc-stats.o
obj-$(CONFIG_VIDEO_MICROCHIP_ISC_BASE) += microchip-isc-common.o
obj-$(CONFIG_VIDEO_MICROCHIP_ISC) += microchip-isc.o
diff --git a/drivers/media/platform/microchip/microchip-isc-stats.c b/drivers/media/platform/microchip/microchip-isc-stats.c
new file mode 100644
index 000000000000..d7813c9d95ac
--- /dev/null
+++ b/drivers/media/platform/microchip/microchip-isc-stats.c
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Microchip ISC Driver - Statistics Subdevice
+ * Raw Histogram Export for Userspace Applications
+ *
+ * Copyright (C) 2025 Microchip Technology Inc.
+ *
+ * Author: Balakrishnan Sambath <balakrishnan.s@microchip.com>
+ */
+
+#include <linux/clk.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
+#include "microchip-isc-regs.h"
+#include "microchip-isc.h"
+
+#define ISC_STATS_DEV_NAME "microchip-isc_stats"
+#define ISC_STATS_MIN_BUFS 2
+#define ISC_STATS_MAX_BUFS 8
+
+/**
+ * struct isc_stat_buffer - Raw histogram statistics buffer structure
+ * @frame_number: Sequential frame number from capture
+ * @timestamp: Frame capture timestamp in nanoseconds
+ * @meas_type: Bitmask of measurement types available (ISC_CIF_ISP_STAT_*)
+ * @hist: Array of histogram data for each Bayer channel
+ * @hist.hist_bins: Raw 512-bin histogram data from hardware
+ * @hist.hist_min: Minimum pixel value observed in channel
+ * @hist.hist_max: Maximum pixel value observed in channel
+ * @hist.total_pixels: Total number of pixels processed in channel
+ * @valid_channels: Bitmask indicating which Bayer channels contain valid data
+ * @bayer_pattern: Current Bayer pattern configuration (CFA_BAYCFG_*)
+ * @reserved: Padding for future expansion and alignment
+ *
+ * This structure contains raw, unprocessed histogram data from the ISC
+ * hardware for all four Bayer channels (GR, R, GB, B). No algorithmic
+ * processing is performed - data is exported directly from hardware
+ * registers for userspace processing applications.
+ */
+struct isc_stat_buffer {
+ u32 frame_number;
+ u64 timestamp;
+ u32 meas_type;
+
+ struct {
+ u32 hist_bins[HIST_ENTRIES];
+ u32 hist_min;
+ u32 hist_max;
+ u32 total_pixels;
+ } hist[HIST_BAYER];
+
+ u8 valid_channels;
+ u8 bayer_pattern;
+ u16 reserved[2];
+} __packed;
+
+/* Statistics measurement type flags */
+#define ISC_CIF_ISP_STAT_HIST BIT(0)
+
+static bool isc_stats_in_use(struct isc_stats *stats)
+{
+ struct video_device *vdev;
+
+ if (!stats || !stats->isc)
+ return false;
+
+ vdev = &stats->vnode.vdev;
+ return vdev && video_is_registered(vdev) && !list_empty(&vdev->fh_list);
+}
+
+static bool isc_stats_has_bufs(struct isc_stats *stats)
+{
+ bool has_buffers;
+
+ if (!stats)
+ return false;
+
+ spin_lock(&stats->lock);
+ has_buffers = !list_empty(&stats->stat);
+ spin_unlock(&stats->lock);
+
+ return has_buffers;
+}
+
+/*
+ * V4L2 device operations
+ */
+
+static int isc_stats_enum_fmt_meta_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct video_device *video = video_devdata(file);
+ struct isc_stats *stats = video_get_drvdata(video);
+
+ if (f->index > 0 || f->type != video->queue->type)
+ return -EINVAL;
+
+ f->pixelformat = stats->vdev_fmt.fmt.meta.dataformat;
+ return 0;
+}
+
+static int isc_stats_g_fmt_meta_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *video = video_devdata(file);
+ struct isc_stats *stats = video_get_drvdata(video);
+ struct v4l2_meta_format *meta = &f->fmt.meta;
+
+ if (f->type != video->queue->type)
+ return -EINVAL;
+
+ memset(meta, 0, sizeof(*meta));
+ meta->dataformat = stats->vdev_fmt.fmt.meta.dataformat;
+ meta->buffersize = stats->vdev_fmt.fmt.meta.buffersize;
+
+ return 0;
+}
+
+static int isc_stats_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
+ strscpy(cap->card, vdev->name, sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:microchip-isc", sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static int isc_stats_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct isc_stats *stats = video_get_drvdata(vdev);
+
+ dev_dbg(stats->isc->dev, "Stats device opened by %s (pid %d)\n",
+ current->comm, current->pid);
+
+ return v4l2_fh_open(file);
+}
+
+static int isc_stats_release(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct isc_stats *stats = video_get_drvdata(vdev);
+
+ dev_dbg(stats->isc->dev, "Stats device closed by %s (pid %d)\n",
+ current->comm, current->pid);
+
+ return _vb2_fop_release(file, NULL);
+}
+
+static const struct v4l2_ioctl_ops isc_stats_ioctl_ops = {
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_enum_fmt_meta_cap = isc_stats_enum_fmt_meta_cap,
+ .vidioc_g_fmt_meta_cap = isc_stats_g_fmt_meta_cap,
+ .vidioc_s_fmt_meta_cap = isc_stats_g_fmt_meta_cap,
+ .vidioc_try_fmt_meta_cap = isc_stats_g_fmt_meta_cap,
+ .vidioc_querycap = isc_stats_querycap,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations isc_stats_fops = {
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = vb2_fop_poll,
+ .open = isc_stats_open,
+ .release = isc_stats_release
+};
+
+/*
+ * VB2 queue operations
+ */
+
+static int isc_stats_vb2_queue_setup(struct vb2_queue *vq,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct isc_stats *stats = vq->drv_priv;
+
+ *num_planes = 1;
+ *num_buffers = clamp_t(u32, *num_buffers, ISC_STATS_MIN_BUFS,
+ ISC_STATS_MAX_BUFS);
+ sizes[0] = sizeof(struct isc_stat_buffer);
+
+ dev_dbg(stats->isc->dev, "Stats queue: %u buffers, %u bytes each\n",
+ *num_buffers, sizes[0]);
+
+ return 0;
+}
+
+static void isc_stats_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct isc_buffer *stats_buf = container_of(vbuf, struct isc_buffer, vb);
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct isc_stats *stats_dev = vq->drv_priv;
+
+ spin_lock_irq(&stats_dev->lock);
+ list_add_tail(&stats_buf->list, &stats_dev->stat);
+ spin_unlock_irq(&stats_dev->lock);
+
+ dev_dbg(stats_dev->isc->dev, "Stats buffer %d queued\n", vb->index);
+}
+
+static int isc_stats_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ if (vb2_plane_size(vb, 0) < sizeof(struct isc_stat_buffer))
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb, 0, sizeof(struct isc_stat_buffer));
+ return 0;
+}
+
+static int isc_stats_vb2_start_streaming(struct vb2_queue *vq,
+ unsigned int count)
+{
+ struct isc_stats *stats = vq->drv_priv;
+
+ dev_dbg(stats->isc->dev, "Stats streaming started\n");
+ return 0;
+}
+
+static void isc_stats_vb2_stop_streaming(struct vb2_queue *vq)
+{
+ struct isc_stats *stats = vq->drv_priv;
+ struct isc_buffer *buf;
+ unsigned int i;
+
+ dev_dbg(stats->isc->dev, "Stats streaming stopped\n");
+
+ spin_lock_irq(&stats->lock);
+ for (i = 0; i < ISC_STATS_MAX_BUFS; i++) {
+ if (list_empty(&stats->stat))
+ break;
+ buf = list_first_entry(&stats->stat, struct isc_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irq(&stats->lock);
+}
+
+static const struct vb2_ops isc_stats_vb2_ops = {
+ .queue_setup = isc_stats_vb2_queue_setup,
+ .buf_queue = isc_stats_vb2_buf_queue,
+ .buf_prepare = isc_stats_vb2_buf_prepare,
+ .start_streaming = isc_stats_vb2_start_streaming,
+ .stop_streaming = isc_stats_vb2_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int isc_stats_init_vb2_queue(struct vb2_queue *q,
+ struct isc_stats *stats)
+{
+ struct isc_vdev_node *node;
+
+ node = container_of(q, struct isc_vdev_node, buf_queue);
+
+ q->type = V4L2_BUF_TYPE_META_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = stats;
+ q->ops = &isc_stats_vb2_ops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->buf_struct_size = sizeof(struct isc_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &node->vlock;
+
+ return vb2_queue_init(q);
+}
+
+/*
+ * Histogram data processing
+ */
+
+static void isc_stats_fill_data(struct isc_stats *stats,
+ struct isc_stat_buffer *pbuf)
+{
+ struct isc_device *isc = stats->isc;
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ int c;
+
+ pbuf->meas_type |= ISC_CIF_ISP_STAT_HIST;
+
+ /* Copy existing histogram data from AWB work function */
+ for (c = 0; c < HIST_BAYER; c++) {
+ memcpy(pbuf->hist[c].hist_bins, isc->full_hist_data[c],
+ sizeof(pbuf->hist[c].hist_bins));
+
+ pbuf->hist[c].hist_min = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ pbuf->hist[c].hist_max = ctrls->hist_minmax[c][HIST_MAX_INDEX];
+ pbuf->hist[c].total_pixels = ctrls->total_pixels[c];
+ }
+
+ /* Set valid channels - all 4 Bayer channels */
+ pbuf->valid_channels = 0x0F;
+
+ /* Set Bayer pattern */
+ if (isc->config.sd_format)
+ pbuf->bayer_pattern = isc->config.sd_format->cfa_baycfg;
+ else
+ pbuf->bayer_pattern = 0;
+
+ dev_dbg(isc->dev,
+ "Stats data ready: pixels=[%u,%u,%u,%u], valid_channels=0x%x\n",
+ pbuf->hist[0].total_pixels, pbuf->hist[1].total_pixels,
+ pbuf->hist[2].total_pixels, pbuf->hist[3].total_pixels,
+ pbuf->valid_channels);
+}
+
+static void isc_stats_send_buf(struct isc_stats *stats)
+{
+ struct isc_stat_buffer *cur_stat_buf;
+ struct isc_buffer *cur_buf = NULL;
+ struct isc_device *isc = stats->isc;
+ unsigned int frame_sequence = isc->sequence;
+ u64 timestamp = ktime_get_ns();
+
+ /* Get one empty buffer from userspace */
+ spin_lock(&stats->lock);
+ if (!list_empty(&stats->stat)) {
+ cur_buf = list_first_entry(&stats->stat,
+ struct isc_buffer, list);
+ list_del(&cur_buf->list);
+ }
+ spin_unlock(&stats->lock);
+
+ if (!cur_buf) {
+ dev_dbg(isc->dev, "No stats buffer available\n");
+ return;
+ }
+
+ cur_stat_buf = vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
+ if (!cur_stat_buf) {
+ dev_err(isc->dev, "Failed to get stats buffer vaddr\n");
+ goto error_return_buffer;
+ }
+
+ /* Clear buffer and fill metadata */
+ memset(cur_stat_buf, 0, sizeof(*cur_stat_buf));
+ cur_stat_buf->frame_number = frame_sequence;
+ cur_stat_buf->timestamp = timestamp;
+
+ /* Fill raw histogram data */
+ isc_stats_fill_data(stats, cur_stat_buf);
+
+ /* Send buffer to userspace */
+ vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0,
+ sizeof(struct isc_stat_buffer));
+ cur_buf->vb.sequence = frame_sequence;
+ cur_buf->vb.vb2_buf.timestamp = timestamp;
+ vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ dev_dbg(isc->dev,
+ "Stats sent: frame=%u, channels=[%u,%u,%u,%u] pixels\n",
+ frame_sequence,
+ cur_stat_buf->hist[0].total_pixels,
+ cur_stat_buf->hist[1].total_pixels,
+ cur_stat_buf->hist[2].total_pixels,
+ cur_stat_buf->hist[3].total_pixels);
+ return;
+
+error_return_buffer:
+ /* Return buffer to queue on error */
+ spin_lock(&stats->lock);
+ list_add(&cur_buf->list, &stats->stat);
+ spin_unlock(&stats->lock);
+}
+
+/*
+ * Public API functions
+ */
+
+/**
+ * isc_stats_isr() - Process statistics in interrupt context
+ * @stats: ISC histogram statistics device
+ *
+ * Called from the ISC interrupt handler when histogram data is ready.
+ * Exports raw histogram data to userspace applications that have
+ * buffers queued on the statistics device.
+ */
+void isc_stats_isr(struct isc_stats *stats)
+{
+ if (!stats) {
+ pr_err("ISC stats: stats is NULL\n");
+ return;
+ }
+
+ if (!stats->isc) {
+ pr_err("ISC stats: stats->isc is NULL\n");
+ return;
+ }
+
+ /* Only send data if userspace is using the device */
+ if (!isc_stats_in_use(stats)) {
+ dev_dbg(stats->isc->dev, "Stats device not in use\n");
+ return;
+ }
+
+ /* Only send data if userspace has queued buffers */
+ if (!isc_stats_has_bufs(stats)) {
+ dev_dbg(stats->isc->dev, "No queued buffers\n");
+ return;
+ }
+
+ /* Send histogram data to userspace */
+ isc_stats_send_buf(stats);
+}
+EXPORT_SYMBOL_GPL(isc_stats_isr);
+
+/**
+ * isc_stats_active() - Check if userspace is actively using stats
+ * @stats: ISC histogram statistics device
+ *
+ * Determines if any userspace application has the statistics device open
+ * and has queued buffers waiting for histogram data.
+ *
+ * Return: true if userspace is ready to receive data, false otherwise
+ */
+bool isc_stats_active(struct isc_stats *stats)
+{
+ return isc_stats_in_use(stats) && isc_stats_has_bufs(stats);
+}
+EXPORT_SYMBOL_GPL(isc_stats_active);
+
+static void isc_stats_init(struct isc_stats *stats)
+{
+ stats->vdev_fmt.fmt.meta.dataformat = V4L2_META_FMT_ISC_STAT_3A;
+ stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct isc_stat_buffer);
+}
+
+/**
+ * isc_stats_register() - Register statistics device
+ * @isc: ISC device
+ *
+ * Creates and registers a V4L2 video device for exporting raw histogram
+ * statistics to userspace.
+ *
+ */
+int isc_stats_register(struct isc_device *isc)
+{
+ struct isc_stats *stats = &isc->stats;
+ struct isc_vdev_node *node = &stats->vnode;
+ struct video_device *vdev = &node->vdev;
+ int ret;
+
+ /* Initialize stats structure */
+ stats->isc = isc;
+ mutex_init(&node->vlock);
+ INIT_LIST_HEAD(&stats->stat);
+ spin_lock_init(&stats->lock);
+
+ /* Configure video device */
+ strscpy(vdev->name, ISC_STATS_DEV_NAME, sizeof(vdev->name));
+ vdev->ioctl_ops = &isc_stats_ioctl_ops;
+ vdev->fops = &isc_stats_fops;
+ vdev->release = video_device_release_empty;
+ vdev->lock = &node->vlock;
+ vdev->v4l2_dev = &isc->v4l2_dev;
+ vdev->queue = &node->buf_queue;
+ vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
+ vdev->vfl_dir = VFL_DIR_RX;
+
+ /* Initialize VB2 queue */
+ ret = isc_stats_init_vb2_queue(vdev->queue, stats);
+ if (ret) {
+ dev_err(isc->dev, "Failed to init stats VB2 queue: %d\n", ret);
+ goto error_cleanup;
+ }
+
+ /* Initialize stats format */
+ isc_stats_init(stats);
+
+ video_set_drvdata(vdev, stats);
+
+ node->pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
+ if (ret) {
+ dev_err(isc->dev, "Failed to init stats media entity: %d\n", ret);
+ goto error_cleanup;
+ }
+
+ /* Register video device */
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(isc->dev, "Failed to register stats device: %d\n", ret);
+ goto error_media_cleanup;
+ }
+
+ dev_info(isc->dev, "Stats device registered as %s\n",
+ video_device_node_name(vdev));
+
+ return 0;
+
+error_media_cleanup:
+ media_entity_cleanup(&vdev->entity);
+error_cleanup:
+ mutex_destroy(&node->vlock);
+ stats->isc = NULL;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(isc_stats_register);
+
+/**
+ * isc_stats_unregister() - Unregister statistics device
+ * @isc: ISC device
+ *
+ * Unregisters and cleans up the statistics video device.
+ */
+void isc_stats_unregister(struct isc_device *isc)
+{
+ struct isc_stats *stats = &isc->stats;
+ struct isc_vdev_node *node = &stats->vnode;
+ struct video_device *vdev = &node->vdev;
+
+ if (!stats->isc)
+ return;
+
+ dev_dbg(isc->dev, "Unregistering stats device\n");
+
+ /* Unregister video device */
+ vb2_video_unregister_device(vdev);
+
+ media_entity_cleanup(&vdev->entity);
+
+ /* Destroy synchronization primitives */
+ mutex_destroy(&node->vlock);
+
+ stats->isc = NULL;
+}
+EXPORT_SYMBOL_GPL(isc_stats_unregister);
+
+MODULE_AUTHOR("Balakrishnan Sambath <balakrishnan.s@microchip.com>");
+MODULE_DESCRIPTION("Microchip ISC Statistics Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index bd75ff4f109b..5245e2790268 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -197,6 +197,23 @@ enum isc_scaler_pads {
ISC_SCALER_PADS_NUM = 2,
};
+/* Video device node structure */
+struct isc_vdev_node {
+ struct video_device vdev;
+ struct vb2_queue buf_queue;
+ struct mutex vlock; /* lock for video node */
+ struct media_pad pad;
+};
+
+/* Statistics device structure */
+struct isc_stats {
+ struct isc_device *isc;
+ struct isc_vdev_node vnode;
+ struct list_head stat;
+ spinlock_t lock; /* lock for buffers */
+ struct v4l2_format vdev_fmt;
+};
+
/*
* struct isc_device - ISC device driver data/config struct
* @regmap: Register map
@@ -340,6 +357,9 @@ struct isc_device {
struct v4l2_ctrl *gb_off_ctrl;
};
+ /* Statistics device */
+ struct isc_stats stats;
+
#define GAMMA_ENTRIES 64
/* pointer to the defined gamma table */
const u32 (*gamma_table)[GAMMA_ENTRIES];
@@ -396,6 +416,10 @@ int isc_scaler_link(struct isc_device *isc);
int isc_scaler_init(struct isc_device *isc);
int isc_mc_init(struct isc_device *isc, u32 ver);
void isc_mc_cleanup(struct isc_device *isc);
+int isc_stats_register(struct isc_device *isc);
+void isc_stats_unregister(struct isc_device *isc);
+void isc_stats_isr(struct isc_stats *stats);
+bool isc_stats_active(struct isc_stats *stats);
struct isc_format *isc_find_format_by_code(struct isc_device *isc,
unsigned int code, int *index);
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 09/18] media: microchip-isc: Register and unregister statistics device
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (7 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 08/18] media: platform: microchip: Add new histogram submodule Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 10/18] media: microchip-isc: Always enable histogram for all RAW formats Balamanikandan Gunasundar
` (12 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Register the statistics sub-device during async complete and ensure
proper cleanup for the same in isc_mc_cleanup().
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index cd379f95fc1c..5b49b6ff5ae9 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1912,6 +1912,13 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
goto isc_async_complete_err;
}
+ /* Register statistics device */
+ ret = isc_stats_register(isc);
+ if (ret) {
+ dev_err(isc->dev, "Failed to register stats device: %d\n", ret);
+ goto isc_async_complete_unregister_device;
+ }
+
ret = isc_scaler_link(isc);
if (ret < 0)
goto isc_async_complete_unregister_device;
@@ -2036,6 +2043,7 @@ void isc_mc_cleanup(struct isc_device *isc)
{
media_entity_cleanup(&isc->video_dev.entity);
media_device_cleanup(&isc->mdev);
+ isc_stats_unregister(isc);
}
EXPORT_SYMBOL_GPL(isc_mc_cleanup);
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 10/18] media: microchip-isc: Always enable histogram for all RAW formats
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (8 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 09/18] media: microchip-isc: Register and unregister statistics device Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 11/18] media: microchip-isc: expose hue and saturation as v4l2 controls Balamanikandan Gunasundar
` (11 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Remove AWB dependency to allow histogram collection even when AWB is
handled in userspace.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 5b49b6ff5ae9..e6d7f59893ac 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -318,8 +318,7 @@ static int isc_configure(struct isc_device *isc)
* The current implemented histogram is available for RAW R, B, GB, GR
* channels. We need to check if sensor is outputting RAW BAYER
*/
- if (isc->ctrls.awb &&
- ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
isc_set_histogram(isc, true);
else
isc_set_histogram(isc, false);
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 11/18] media: microchip-isc: expose hue and saturation as v4l2 controls
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (9 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 10/18] media: microchip-isc: Always enable histogram for all RAW formats Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 12/18] media: microchip-isc: Rename CBC to CBHS Balamanikandan Gunasundar
` (10 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
Expose hue and saturation as adjustable controls allowing users to modify
it. Write the user specified values to the hardware registers. Additionally
write the brightness and contrast values to the registers that were
missing.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 17 +++++++++++++++++
.../platform/microchip/microchip-isc-regs.h | 3 +++
.../media/platform/microchip/microchip-isc.h | 2 ++
3 files changed, 22 insertions(+)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index e6d7f59893ac..ce22b4789ebd 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1520,6 +1520,7 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
struct isc_device *isc = container_of(ctrl->handler,
struct isc_device, ctrls.handler);
struct isc_ctrls *ctrls = &isc->ctrls;
+ struct regmap *regmap = isc->regmap;
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
return 0;
@@ -1527,9 +1528,19 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, ctrls->brightness);
break;
case V4L2_CID_CONTRAST:
ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, ctrls->contrast);
+ break;
+ case V4L2_CID_HUE:
+ ctrls->hue = ctrl->val & ISC_CBCHS_HUE_MASK;
+ regmap_write(regmap, ISC_CBCHS_HUE, ctrls->hue);
+ break;
+ case V4L2_CID_SATURATION:
+ ctrls->saturation = ctrl->val & ISC_CBCHS_SAT_MASK;
+ regmap_write(regmap, ISC_CBCHS_SAT, ctrls->saturation);
break;
case V4L2_CID_GAMMA:
ctrls->gamma_index = ctrl->val;
@@ -1538,6 +1549,10 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
+ mutex_lock(&isc->awb_mutex);
+ isc_update_profile(isc);
+ mutex_unlock(&isc->awb_mutex);
+
return 0;
}
@@ -1714,6 +1729,8 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->brightness = 0;
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, -180, 180, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 0, 100, 1, 16);
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1, 1);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
diff --git a/drivers/media/platform/microchip/microchip-isc-regs.h b/drivers/media/platform/microchip/microchip-isc-regs.h
index e77e1d9a1db8..2593bd533cac 100644
--- a/drivers/media/platform/microchip/microchip-isc-regs.h
+++ b/drivers/media/platform/microchip/microchip-isc-regs.h
@@ -270,8 +270,11 @@
/* Hue Register */
#define ISC_CBCHS_HUE 0x4e0
+#define ISC_CBCHS_HUE_MASK GENMASK(8, 0)
+
/* Saturation Register */
#define ISC_CBCHS_SAT 0x4e4
+#define ISC_CBCHS_SAT_MASK GENMASK(11, 0)
/* Offset for SUB422 register specific to sama5d2 product */
#define ISC_SAMA5D2_SUB422_OFFSET 0
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 5245e2790268..7afba3c04dfb 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -139,6 +139,8 @@ struct isc_ctrls {
u32 brightness;
u32 contrast;
+ u32 hue;
+ u32 saturation;
u8 gamma_index;
#define ISC_WB_NONE 0
#define ISC_WB_AUTO 1
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 12/18] media: microchip-isc: Rename CBC to CBHS
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (10 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 11/18] media: microchip-isc: expose hue and saturation as v4l2 controls Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 13/18] media: microchip-isc: Store histogram data of all channels Balamanikandan Gunasundar
` (9 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
As per the datasheet the more relevant name for this enable bit is
"Contrast, Brightness, Hue and Saturation Control Enable"
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 10 +++++-----
drivers/media/platform/microchip/microchip-isc.h | 2 +-
.../media/platform/microchip/microchip-sama5d2-isc.c | 2 +-
.../media/platform/microchip/microchip-sama7g5-isc.c | 2 +-
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index ce22b4789ebd..e9bd191f042b 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -790,7 +790,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
- DPC_GDCENABLE | CBC_ENABLE | CC_ENABLE;
+ DPC_GDCENABLE | CBHS_ENABLE | CC_ENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -800,7 +800,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
- SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
+ SUB420_ENABLE | SUB422_ENABLE | CBHS_ENABLE |
DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
@@ -811,7 +811,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ SUB422_ENABLE | CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -823,7 +823,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ SUB422_ENABLE | CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -834,7 +834,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- CBC_ENABLE | DPC_BLCENABLE;
+ CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 7afba3c04dfb..35dfd2501ea2 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -88,7 +88,7 @@ struct isc_format {
#define GAM_RENABLE BIT(9)
#define VHXS_ENABLE BIT(10)
#define CSC_ENABLE BIT(11)
-#define CBC_ENABLE BIT(12)
+#define CBHS_ENABLE BIT(12)
#define SUB422_ENABLE BIT(13)
#define SUB420_ENABLE BIT(14)
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index 66d3d7891991..239aac170472 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -54,7 +54,7 @@
#define ISC_SAMA5D2_PIPELINE \
(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
- CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+ CBHS_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
static const struct isc_format sama5d2_controller_formats[] = {
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index d3ed9cfe6686..985281c4dc76 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -61,7 +61,7 @@
#define ISC_SAMA7G5_PIPELINE \
(DPC_DPCENABLE | DPC_GDCENABLE | DPC_BLCENABLE | \
WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
- CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+ CBHS_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
static const struct isc_format sama7g5_controller_formats[] = {
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 13/18] media: microchip-isc: Store histogram data of all channels
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (11 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 12/18] media: microchip-isc: Rename CBC to CBHS Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 14/18] media: microchip-isc: fix histogram state initialization order Balamanikandan Gunasundar
` (8 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
Store the histogram data for all 4 channels(R, B, GR, GB). The data of each
channel is available on one interrupt. We need 4 interrupt cycles to get
all four channels. Store all the channels in a 2D array. This data is later
passed to the application buffer when it requests for a dequeue.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 2 +-
drivers/media/platform/microchip/microchip-isc-stats.c | 2 +-
drivers/media/platform/microchip/microchip-isc.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index e9bd191f042b..6651be6fcb57 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1225,7 +1225,7 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
struct regmap *regmap = isc->regmap;
struct isc_ctrls *ctrls = &isc->ctrls;
u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
- u32 *hist_entry = &ctrls->hist_entry[0];
+ u32 *hist_entry = &ctrls->hist_entry[ctrls->hist_id][0];
u32 i;
*min = 0;
diff --git a/drivers/media/platform/microchip/microchip-isc-stats.c b/drivers/media/platform/microchip/microchip-isc-stats.c
index d7813c9d95ac..1f3d1ea75005 100644
--- a/drivers/media/platform/microchip/microchip-isc-stats.c
+++ b/drivers/media/platform/microchip/microchip-isc-stats.c
@@ -298,7 +298,7 @@ static void isc_stats_fill_data(struct isc_stats *stats,
/* Copy existing histogram data from AWB work function */
for (c = 0; c < HIST_BAYER; c++) {
- memcpy(pbuf->hist[c].hist_bins, isc->full_hist_data[c],
+ memcpy(pbuf->hist[c].hist_bins, &isc->ctrls.hist_entry[0][c],
sizeof(pbuf->hist[c].hist_bins));
pbuf->hist[c].hist_min = ctrls->hist_minmax[c][HIST_MIN_INDEX];
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 35dfd2501ea2..fcb20669ef69 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -151,7 +151,7 @@ struct isc_ctrls {
u32 gain[HIST_BAYER];
s32 offset[HIST_BAYER];
- u32 hist_entry[HIST_ENTRIES];
+ u32 hist_entry[HIST_BAYER][HIST_ENTRIES];
u32 hist_count[HIST_BAYER];
u8 hist_id;
u8 hist_stat;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 14/18] media: microchip-isc: fix histogram state initialization order
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (12 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 13/18] media: microchip-isc: Store histogram data of all channels Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 15/18] media: microchip-isc: decouple histogram cycling from AWB mode Balamanikandan Gunasundar
` (7 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Move hist_stat assignment before profile update to ensure histogram state
is properly set when update_profile triggers register writes. This prevents
race conditions during histogram initialization.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 6651be6fcb57..e9f14de7ae32 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -275,10 +275,10 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
ISC_HIS_CTRL_EN);
regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
+ ctrls->hist_stat = HIST_ENABLED;
isc_update_profile(isc);
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
- ctrls->hist_stat = HIST_ENABLED;
} else {
regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 15/18] media: microchip-isc: decouple histogram cycling from AWB mode
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (13 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 14/18] media: microchip-isc: fix histogram state initialization order Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 16/18] media: microchip-isc: enable userspace histogram statistics export Balamanikandan Gunasundar
` (6 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Fix histogram cycling stopping after first channel when AWB is disabled.
Now the histogram cycling will continue even when AWB is disabled,
enabling hardware histogram data export to userspace.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index e9f14de7ae32..cafd05244db2 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1509,7 +1509,7 @@ static void isc_awb_work(struct work_struct *w)
mutex_unlock(&isc->awb_mutex);
/* if awb has been disabled, we don't need to start another histogram */
- if (ctrls->awb)
+ if (ctrls->hist_stat == HIST_ENABLED)
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
pm_runtime_put_sync(isc->dev);
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 16/18] media: microchip-isc: enable userspace histogram statistics export
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (14 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 15/18] media: microchip-isc: decouple histogram cycling from AWB mode Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 17/18] media: videodev2.h, v4l2-ioctl: Add microchip statistics format Balamanikandan Gunasundar
` (5 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Export raw histogram data to userspace only when all 4 Bayer channels
are ready and userspace has active listeners. Also continue AWB work as
long as userspace listeners are active.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index cafd05244db2..6c937a20fce0 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1450,6 +1450,15 @@ static void isc_awb_work(struct work_struct *w)
if (hist_id != ISC_HIS_CFG_MODE_B) {
hist_id++;
} else {
+ /* All 4 channels processed - notify userspace */
+ if (isc_stats_active(&isc->stats))
+ isc_stats_isr(&isc->stats);
+ else
+ dev_info(isc->dev, "No active userspace listeners\n");
+ }
+
+ /* Continue with AWB processing only if AWB is enabled */
+ if (ctrls->awb != ISC_WB_NONE) {
isc_wb_update(ctrls);
hist_id = ISC_HIS_CFG_MODE_GR;
}
@@ -1499,7 +1508,7 @@ static void isc_awb_work(struct work_struct *w)
mutex_lock(&isc->awb_mutex);
/* streaming is not active anymore */
- if (isc->stop) {
+ if (isc->stop && !isc_stats_active(&isc->stats)) {
mutex_unlock(&isc->awb_mutex);
return;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 17/18] media: videodev2.h, v4l2-ioctl: Add microchip statistics format
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (15 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 16/18] media: microchip-isc: enable userspace histogram statistics export Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-11-10 8:49 ` Hans Verkuil
2025-10-09 15:52 ` [PATCH 18/18] media: microchip-isc: expose color correction registers as v4l2 controls Balamanikandan Gunasundar
` (4 subsequent siblings)
21 siblings, 1 reply; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
Add microchip ISC specific statistics meta data format. This data consists
of raw histogram statistics that is exported to userspace for further
processing. This fixes the kernel warning "Unknown pixelformat"
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
include/uapi/linux/videodev2.h | 3 +++
2 files changed, 4 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 01cf52c3ea33..a03e8f3ab610 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1467,6 +1467,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break;
case V4L2_META_FMT_RK_ISP1_STAT_3A: descr = "Rockchip ISP1 3A Statistics"; break;
case V4L2_META_FMT_RK_ISP1_EXT_PARAMS: descr = "Rockchip ISP1 Ext 3A Params"; break;
+ case V4L2_META_FMT_ISC_STAT_3A: descr = "Microchip ISP statistics"; break;
case V4L2_META_FMT_C3ISP_PARAMS: descr = "Amlogic C3 ISP Parameters"; break;
case V4L2_META_FMT_C3ISP_STATS: descr = "Amlogic C3 ISP Statistics"; break;
case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index becd08fdbddb..ba628f9bb89f 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -875,6 +875,9 @@ struct v4l2_pix_format {
#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */
#define V4L2_META_FMT_RK_ISP1_EXT_PARAMS v4l2_fourcc('R', 'K', '1', 'E') /* Rockchip ISP1 3a Extensible Parameters */
+/* Vendor specific - used for Microchip camera sub-system */
+#define V4L2_META_FMT_ISC_STAT_3A v4l2_fourcc('I', 'S', 'C', 'S')
+
/* Vendor specific - used for C3_ISP */
#define V4L2_META_FMT_C3ISP_PARAMS v4l2_fourcc('C', '3', 'P', 'M') /* Amlogic C3 ISP Parameters */
#define V4L2_META_FMT_C3ISP_STATS v4l2_fourcc('C', '3', 'S', 'T') /* Amlogic C3 ISP Statistics */
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH 18/18] media: microchip-isc: expose color correction registers as v4l2 controls
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (16 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 17/18] media: videodev2.h, v4l2-ioctl: Add microchip statistics format Balamanikandan Gunasundar
@ 2025-10-09 15:52 ` Balamanikandan Gunasundar
2025-10-09 20:11 ` [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Eugen Hristev
` (3 subsequent siblings)
21 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan Gunasundar @ 2025-10-09 15:52 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel, Balamanikandan Gunasundar
Enable the Color correction registers as v4l2 controls. Applications such
as libcamera can read and write the elements of color correction matrix
through the standard v4l2 control API.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 175 +++++++++++++++++-
.../media/platform/microchip/microchip-isc.h | 12 ++
include/linux/atmel-isc-media.h | 13 ++
3 files changed, 199 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 6c937a20fce0..e679dc02dc9f 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -32,7 +32,7 @@
#include "microchip-isc-regs.h"
#include "microchip-isc.h"
-#define ISC_IS_FORMAT_RAW(mbus_code) \
+#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
#define ISC_IS_FORMAT_GREY(mbus_code) \
@@ -1677,6 +1677,165 @@ static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int isc_cc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct regmap *regmap = isc->regmap;
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ regmap_update_bits(regmap, ISC_CC_RR_RG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_RG:
+ regmap_update_bits(regmap, ISC_CC_RR_RG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_RB:
+ regmap_update_bits(regmap, ISC_CC_RB_OR, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_OR:
+ regmap_update_bits(regmap, ISC_CC_RB_OR, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_GR:
+ regmap_update_bits(regmap, ISC_CC_GR_GG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_GG:
+ regmap_update_bits(regmap, ISC_CC_GR_GG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_GB:
+ regmap_update_bits(regmap, ISC_CC_GB_OG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_OG:
+ regmap_update_bits(regmap, ISC_CC_GB_OG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_BR:
+ regmap_update_bits(regmap, ISC_CC_BR_BG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_BG:
+ regmap_update_bits(regmap, ISC_CC_BR_BG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_BB:
+ regmap_update_bits(regmap, ISC_CC_BB_OB, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_OB:
+ regmap_update_bits(regmap, ISC_CC_BB_OB, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int isc_cc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct regmap *regmap = isc->regmap;
+ unsigned int reg;
+
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_RG:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_RB:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OR:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GR:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_GG:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GB:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OG:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BR:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_BG:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_cc_ops = {
+ .s_ctrl = isc_cc_s_ctrl,
+ .g_volatile_ctrl = isc_cc_g_volatile_ctrl,
+};
+
+#define ISC_CTRL_CC(_name, _id, _name_str) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_cc_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .flags = V4L2_CTRL_FLAG_SLIDER, \
+ .min = -2048, \
+ .max = 2047, \
+ .step = 1, \
+ .def = 0, \
+ }
+
+ISC_CTRL_CC(isc_cc_rr_ctrl, ISC_CID_CC_RR, "CC RR");
+ISC_CTRL_CC(isc_cc_rg_ctrl, ISC_CID_CC_RG, "CC RG");
+
+ISC_CTRL_CC(isc_cc_rb_ctrl, ISC_CID_CC_RB, "CC RB");
+ISC_CTRL_CC(isc_cc_or_ctrl, ISC_CID_CC_OR, "CC OR");
+
+ISC_CTRL_CC(isc_cc_gr_ctrl, ISC_CID_CC_GR, "CC GR");
+ISC_CTRL_CC(isc_cc_gg_ctrl, ISC_CID_CC_GG, "CC GG");
+
+ISC_CTRL_CC(isc_cc_gb_ctrl, ISC_CID_CC_GB, "CC GB");
+ISC_CTRL_CC(isc_cc_og_ctrl, ISC_CID_CC_OG, "CC OG");
+
+ISC_CTRL_CC(isc_cc_br_ctrl, ISC_CID_CC_BR, "CC BR");
+ISC_CTRL_CC(isc_cc_bg_ctrl, ISC_CID_CC_BG, "CC BG");
+
+ISC_CTRL_CC(isc_cc_bb_ctrl, ISC_CID_CC_BB, "CC BB");
+ISC_CTRL_CC(isc_cc_ob_ctrl, ISC_CID_CC_OB, "CC OB");
+
static const struct v4l2_ctrl_ops isc_awb_ops = {
.s_ctrl = isc_s_awb_ctrl,
.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
@@ -1767,6 +1926,20 @@ static int isc_ctrl_init(struct isc_device *isc)
isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
+ /* Color correction control */
+ isc->cc_rr = v4l2_ctrl_new_custom(hdl, &isc_cc_rr_ctrl, NULL);
+ isc->cc_rg = v4l2_ctrl_new_custom(hdl, &isc_cc_rg_ctrl, NULL);
+ isc->cc_rb = v4l2_ctrl_new_custom(hdl, &isc_cc_rb_ctrl, NULL);
+ isc->cc_or = v4l2_ctrl_new_custom(hdl, &isc_cc_or_ctrl, NULL);
+ isc->cc_gr = v4l2_ctrl_new_custom(hdl, &isc_cc_gr_ctrl, NULL);
+ isc->cc_gg = v4l2_ctrl_new_custom(hdl, &isc_cc_gg_ctrl, NULL);
+ isc->cc_gb = v4l2_ctrl_new_custom(hdl, &isc_cc_gb_ctrl, NULL);
+ isc->cc_og = v4l2_ctrl_new_custom(hdl, &isc_cc_og_ctrl, NULL);
+ isc->cc_br = v4l2_ctrl_new_custom(hdl, &isc_cc_br_ctrl, NULL);
+ isc->cc_bg = v4l2_ctrl_new_custom(hdl, &isc_cc_bg_ctrl, NULL);
+ isc->cc_bb = v4l2_ctrl_new_custom(hdl, &isc_cc_bb_ctrl, NULL);
+ isc->cc_ob = v4l2_ctrl_new_custom(hdl, &isc_cc_ob_ctrl, NULL);
+
/*
* The cluster is in auto mode with autowhitebalance enabled
* and manual mode otherwise.
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index fcb20669ef69..aaa6c4b653d4 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -357,6 +357,18 @@ struct isc_device {
struct v4l2_ctrl *b_off_ctrl;
struct v4l2_ctrl *gr_off_ctrl;
struct v4l2_ctrl *gb_off_ctrl;
+ struct v4l2_ctrl *cc_rr;
+ struct v4l2_ctrl *cc_rg;
+ struct v4l2_ctrl *cc_rb;
+ struct v4l2_ctrl *cc_or;
+ struct v4l2_ctrl *cc_gr;
+ struct v4l2_ctrl *cc_gg;
+ struct v4l2_ctrl *cc_gb;
+ struct v4l2_ctrl *cc_og;
+ struct v4l2_ctrl *cc_br;
+ struct v4l2_ctrl *cc_bg;
+ struct v4l2_ctrl *cc_bb;
+ struct v4l2_ctrl *cc_ob;
};
/* Statistics device */
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
index 79a320fb724e..028d34c8de81 100644
--- a/include/linux/atmel-isc-media.h
+++ b/include/linux/atmel-isc-media.h
@@ -53,6 +53,19 @@ enum atmel_isc_ctrl_id {
ISC_CID_GR_OFFSET,
/* Green Blue component offset control */
ISC_CID_GB_OFFSET,
+ /* Color correction registers */
+ ISC_CID_CC_RR,
+ ISC_CID_CC_RG,
+ ISC_CID_CC_RB,
+ ISC_CID_CC_OR,
+ ISC_CID_CC_GR,
+ ISC_CID_CC_GG,
+ ISC_CID_CC_GB,
+ ISC_CID_CC_OG,
+ ISC_CID_CC_BR,
+ ISC_CID_CC_BG,
+ ISC_CID_CC_BB,
+ ISC_CID_CC_OB,
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (17 preceding siblings ...)
2025-10-09 15:52 ` [PATCH 18/18] media: microchip-isc: expose color correction registers as v4l2 controls Balamanikandan Gunasundar
@ 2025-10-09 20:11 ` Eugen Hristev
2025-10-10 8:21 ` Kieran Bingham
2025-10-15 5:26 ` Balamanikandan.Gunasundar
2025-11-10 9:01 ` Hans Verkuil
` (2 subsequent siblings)
21 siblings, 2 replies; 65+ messages in thread
From: Eugen Hristev @ 2025-10-09 20:11 UTC (permalink / raw)
To: Balamanikandan Gunasundar
Cc: Chas Williams, Nicolas Ferre, Alexandre Belloni, Claudiu Beznea,
Balakrishnan Sambath, Hans Verkuil, Ricardo Ribalda,
Laurent Pinchart, Jacopo Mondi, Daniel Scally, Tomi Valkeinen,
linux-kernel, linux-media, linux-atm-general, netdev,
linux-arm-kernel, Mauro Carvalho Chehab
Hi Bala,
On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
> Hi,
>
> This patch series has a set of enhancements to the Microchip Image Sensor
> Controller driver. The objective is to expand its image processing
> capabilities and to improve the colors.
>
> This series also introduces a new stats driver that exposes the histogram
> data to userspace via v4l2 controls. This allows applications such as
> libcamera to access real time image statistics for advanced image
> processing like automatic exposure, white balance adjustments etc.
>
> Balakrishnan Sambath (11):
> media: microchip-isc: Enable GDC and CBC module flags for RGB formats
> media: microchip-isc: Improve histogram calculation with outlier
> rejection
> media: microchip-isc: Use channel averages for Grey World AWB
> media: microchip-isc: Add range based black level correction
> media: platform: microchip: Extend gamma table and control range
> media: platform: microchip: Add new histogram submodule
> media: microchip-isc: Register and unregister statistics device
> media: microchip-isc: Always enable histogram for all RAW formats
> media: microchip-isc: fix histogram state initialization order
> media: microchip-isc: decouple histogram cycling from AWB mode
> media: microchip-isc: enable userspace histogram statistics export
>
> Balamanikandan Gunasundar (7):
> media: platform: microchip: set maximum resolution for sam9x7
> media: platform: microchip: Include DPC modules flags in pipeline
> media: microchip-isc: expose hue and saturation as v4l2 controls
> media: microchip-isc: Rename CBC to CBHS
> media: microchip-isc: Store histogram data of all channels
> media: videodev2.h, v4l2-ioctl: Add microchip statistics format
> media: microchip-isc: expose color correction registers as v4l2
> controls
>
> drivers/media/platform/microchip/Kconfig | 2 +
> drivers/media/platform/microchip/Makefile | 2 +-
> .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
> .../platform/microchip/microchip-isc-regs.h | 3 +
> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> .../media/platform/microchip/microchip-isc.h | 44 +-
> .../microchip/microchip-sama5d2-isc.c | 2 +-
> .../microchip/microchip-sama7g5-isc.c | 73 ++-
> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> include/linux/atmel-isc-media.h | 13 +
> include/uapi/linux/videodev2.h | 3 +
> 11 files changed, 1001 insertions(+), 64 deletions(-)
> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>
This looks interesting.
I would like to see the compliance tool output for more platforms
(sama7g5, sama5d2, and the new sam9x7), also the media-ctl -p , to see
the topology with your new driver.
Thanks,
Eugen
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-09 20:11 ` [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Eugen Hristev
@ 2025-10-10 8:21 ` Kieran Bingham
2025-10-10 8:27 ` Laurent Pinchart
` (2 more replies)
2025-10-15 5:26 ` Balamanikandan.Gunasundar
1 sibling, 3 replies; 65+ messages in thread
From: Kieran Bingham @ 2025-10-10 8:21 UTC (permalink / raw)
To: Balamanikandan Gunasundar, Eugen Hristev
Cc: Chas Williams, Nicolas Ferre, Alexandre Belloni, Claudiu Beznea,
Balakrishnan Sambath, Hans Verkuil, Ricardo Ribalda,
Laurent Pinchart, Jacopo Mondi, Daniel Scally, Tomi Valkeinen,
linux-kernel, linux-media, linux-atm-general, netdev,
linux-arm-kernel, Mauro Carvalho Chehab
Quoting Eugen Hristev (2025-10-09 21:11:17)
> Hi Bala,
>
> On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
> > Hi,
> >
> > This patch series has a set of enhancements to the Microchip Image Sensor
> > Controller driver. The objective is to expand its image processing
> > capabilities and to improve the colors.
> >
> > This series also introduces a new stats driver that exposes the histogram
> > data to userspace via v4l2 controls. This allows applications such as
> > libcamera to access real time image statistics for advanced image
> > processing like automatic exposure, white balance adjustments etc.
How much data do you anticipate to be passing through controls? (What
can the hardware provide in total if we look at the bigger picture to
support the full device?)
For all other ISPs we've been working towards using structured parameter
buffers to pass data - and we've been making that format extensible,
which I think could also be a design that can apply to statistics.
This would greatly reduce the overhead of managing 'one control per
value' ... or things like passing large tables (like a lens shading
table perhaps) through controls.
--
Kieran
> >
> > Balakrishnan Sambath (11):
> > media: microchip-isc: Enable GDC and CBC module flags for RGB formats
> > media: microchip-isc: Improve histogram calculation with outlier
> > rejection
> > media: microchip-isc: Use channel averages for Grey World AWB
> > media: microchip-isc: Add range based black level correction
> > media: platform: microchip: Extend gamma table and control range
> > media: platform: microchip: Add new histogram submodule
> > media: microchip-isc: Register and unregister statistics device
> > media: microchip-isc: Always enable histogram for all RAW formats
> > media: microchip-isc: fix histogram state initialization order
> > media: microchip-isc: decouple histogram cycling from AWB mode
> > media: microchip-isc: enable userspace histogram statistics export
> >
> > Balamanikandan Gunasundar (7):
> > media: platform: microchip: set maximum resolution for sam9x7
> > media: platform: microchip: Include DPC modules flags in pipeline
> > media: microchip-isc: expose hue and saturation as v4l2 controls
> > media: microchip-isc: Rename CBC to CBHS
> > media: microchip-isc: Store histogram data of all channels
> > media: videodev2.h, v4l2-ioctl: Add microchip statistics format
> > media: microchip-isc: expose color correction registers as v4l2
> > controls
> >
> > drivers/media/platform/microchip/Kconfig | 2 +
> > drivers/media/platform/microchip/Makefile | 2 +-
> > .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
> > .../platform/microchip/microchip-isc-regs.h | 3 +
> > .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> > .../media/platform/microchip/microchip-isc.h | 44 +-
> > .../microchip/microchip-sama5d2-isc.c | 2 +-
> > .../microchip/microchip-sama7g5-isc.c | 73 ++-
> > drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> > include/linux/atmel-isc-media.h | 13 +
> > include/uapi/linux/videodev2.h | 3 +
> > 11 files changed, 1001 insertions(+), 64 deletions(-)
> > create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
> >
>
> This looks interesting.
> I would like to see the compliance tool output for more platforms
> (sama7g5, sama5d2, and the new sam9x7), also the media-ctl -p , to see
> the topology with your new driver.
>
> Thanks,
> Eugen
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-10 8:21 ` Kieran Bingham
@ 2025-10-10 8:27 ` Laurent Pinchart
2025-10-15 6:05 ` Balamanikandan.Gunasundar
2025-10-15 6:33 ` Balamanikandan.Gunasundar
2 siblings, 0 replies; 65+ messages in thread
From: Laurent Pinchart @ 2025-10-10 8:27 UTC (permalink / raw)
To: Kieran Bingham
Cc: Balamanikandan Gunasundar, Eugen Hristev, Chas Williams,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea,
Balakrishnan Sambath, Hans Verkuil, Ricardo Ribalda, Jacopo Mondi,
Daniel Scally, Tomi Valkeinen, linux-kernel, linux-media,
linux-atm-general, netdev, linux-arm-kernel,
Mauro Carvalho Chehab
On Fri, Oct 10, 2025 at 09:21:51AM +0100, Kieran Bingham wrote:
> Quoting Eugen Hristev (2025-10-09 21:11:17)
> > On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
> > > Hi,
> > >
> > > This patch series has a set of enhancements to the Microchip Image Sensor
> > > Controller driver. The objective is to expand its image processing
> > > capabilities and to improve the colors.
> > >
> > > This series also introduces a new stats driver that exposes the histogram
> > > data to userspace via v4l2 controls. This allows applications such as
> > > libcamera to access real time image statistics for advanced image
> > > processing like automatic exposure, white balance adjustments etc.
>
> How much data do you anticipate to be passing through controls? (What
> can the hardware provide in total if we look at the bigger picture to
> support the full device?)
>
> For all other ISPs we've been working towards using structured parameter
> buffers to pass data - and we've been making that format extensible,
> which I think could also be a design that can apply to statistics.
>
> This would greatly reduce the overhead of managing 'one control per
> value' ... or things like passing large tables (like a lens shading
> table perhaps) through controls.
V4L2 is standardizing on parameter buffers and statistics buffers for
ISPs. Using the same mechanism here will keep the driver in line with
other ISPs, which will help in userspace too.
> > >
> > > Balakrishnan Sambath (11):
> > > media: microchip-isc: Enable GDC and CBC module flags for RGB formats
> > > media: microchip-isc: Improve histogram calculation with outlier
> > > rejection
> > > media: microchip-isc: Use channel averages for Grey World AWB
> > > media: microchip-isc: Add range based black level correction
> > > media: platform: microchip: Extend gamma table and control range
> > > media: platform: microchip: Add new histogram submodule
> > > media: microchip-isc: Register and unregister statistics device
> > > media: microchip-isc: Always enable histogram for all RAW formats
> > > media: microchip-isc: fix histogram state initialization order
> > > media: microchip-isc: decouple histogram cycling from AWB mode
> > > media: microchip-isc: enable userspace histogram statistics export
> > >
> > > Balamanikandan Gunasundar (7):
> > > media: platform: microchip: set maximum resolution for sam9x7
> > > media: platform: microchip: Include DPC modules flags in pipeline
> > > media: microchip-isc: expose hue and saturation as v4l2 controls
> > > media: microchip-isc: Rename CBC to CBHS
> > > media: microchip-isc: Store histogram data of all channels
> > > media: videodev2.h, v4l2-ioctl: Add microchip statistics format
> > > media: microchip-isc: expose color correction registers as v4l2
> > > controls
> > >
> > > drivers/media/platform/microchip/Kconfig | 2 +
> > > drivers/media/platform/microchip/Makefile | 2 +-
> > > .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
> > > .../platform/microchip/microchip-isc-regs.h | 3 +
> > > .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> > > .../media/platform/microchip/microchip-isc.h | 44 +-
> > > .../microchip/microchip-sama5d2-isc.c | 2 +-
> > > .../microchip/microchip-sama7g5-isc.c | 73 ++-
> > > drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> > > include/linux/atmel-isc-media.h | 13 +
> > > include/uapi/linux/videodev2.h | 3 +
> > > 11 files changed, 1001 insertions(+), 64 deletions(-)
> > > create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
> >
> > This looks interesting.
> > I would like to see the compliance tool output for more platforms
> > (sama7g5, sama5d2, and the new sam9x7), also the media-ctl -p , to see
> > the topology with your new driver.
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-09 20:11 ` [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Eugen Hristev
2025-10-10 8:21 ` Kieran Bingham
@ 2025-10-15 5:26 ` Balamanikandan.Gunasundar
1 sibling, 0 replies; 65+ messages in thread
From: Balamanikandan.Gunasundar @ 2025-10-15 5:26 UTC (permalink / raw)
To: eugen.hristev
Cc: 3chas3, Nicolas.Ferre, alexandre.belloni, claudiu.beznea,
Balakrishnan.S, hverkuil, ribalda, laurent.pinchart+renesas,
jacopo.mondi, dan.scally+renesas, tomi.valkeinen, linux-kernel,
linux-media, linux-atm-general, netdev, linux-arm-kernel, mchehab
On 10/10/25 1:41 am, Eugen Hristev wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> Hi Bala,
>
> On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
>> Hi,
>>
>> This patch series has a set of enhancements to the Microchip Image Sensor
>> Controller driver. The objective is to expand its image processing
>> capabilities and to improve the colors.
>>
>> This series also introduces a new stats driver that exposes the histogram
>> data to userspace via v4l2 controls. This allows applications such as
>> libcamera to access real time image statistics for advanced image
>> processing like automatic exposure, white balance adjustments etc.
>>
>> Balakrishnan Sambath (11):
>> media: microchip-isc: Enable GDC and CBC module flags for RGB formats
>> media: microchip-isc: Improve histogram calculation with outlier
>> rejection
>> media: microchip-isc: Use channel averages for Grey World AWB
>> media: microchip-isc: Add range based black level correction
>> media: platform: microchip: Extend gamma table and control range
>> media: platform: microchip: Add new histogram submodule
>> media: microchip-isc: Register and unregister statistics device
>> media: microchip-isc: Always enable histogram for all RAW formats
>> media: microchip-isc: fix histogram state initialization order
>> media: microchip-isc: decouple histogram cycling from AWB mode
>> media: microchip-isc: enable userspace histogram statistics export
>>
>> Balamanikandan Gunasundar (7):
>> media: platform: microchip: set maximum resolution for sam9x7
>> media: platform: microchip: Include DPC modules flags in pipeline
>> media: microchip-isc: expose hue and saturation as v4l2 controls
>> media: microchip-isc: Rename CBC to CBHS
>> media: microchip-isc: Store histogram data of all channels
>> media: videodev2.h, v4l2-ioctl: Add microchip statistics format
>> media: microchip-isc: expose color correction registers as v4l2
>> controls
>>
>> drivers/media/platform/microchip/Kconfig | 2 +
>> drivers/media/platform/microchip/Makefile | 2 +-
>> .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
>> .../platform/microchip/microchip-isc-regs.h | 3 +
>> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
>> .../media/platform/microchip/microchip-isc.h | 44 +-
>> .../microchip/microchip-sama5d2-isc.c | 2 +-
>> .../microchip/microchip-sama7g5-isc.c | 73 ++-
>> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
>> include/linux/atmel-isc-media.h | 13 +
>> include/uapi/linux/videodev2.h | 3 +
>> 11 files changed, 1001 insertions(+), 64 deletions(-)
>> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>>
> This looks interesting.
> I would like to see the compliance tool output for more platforms
> (sama7g5, sama5d2, and the new sam9x7), also the media-ctl -p , to see
> the topology with your new driver.
>
> Thanks,
> Eugen
Please find the output below,
-------- sama7g5ek --------
root@sama7g5ek-sd:~# v4l2-compliance -d /dev/video0
v4l2-compliance 1.26.1-5142, 32 bits, 64-bit time_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38
Compliance test for microchip-isc device /dev/video0:
Driver Info:
Driver name : microchip-isc
Card type : Microchip Image Sensor Controll
Bus info : platform:e1408000.xisc
Driver version : 6.12.48
Capabilities : 0xa4200001
Video Capture
I/O MC
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x24200001
Video Capture
I/O MC
Streaming
Extended Pix Format
Media Driver Info:
Driver name : microchip_isc_c
Model : microchip,sama7g5-isc
Serial :
Bus info : platform:e1408000.xisc
Media version : 6.12.48
Hardware revision: 0x00000220 (544)
Driver version : 6.12.48
Interface Info:
ID : 0x0300001a
Type : V4L Video
Entity Info:
ID : 0x00000018 (24)
Name : microchip_isc_common
Function : V4L2 I/O
Flags : default
Pad 0x01000019 : 0: Sink
Link 0x02000022: from remote pad 0x1000003 of entity
'microchip_isc_scaler' (Video Scaler): Data, Enabled, Immutable
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
test VIDIOC_QUERYCAP: OK
test invalid ioctls: OK
Allow for multiple opens:
test second /dev/video0 open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 1 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls (Input 0):
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 8 Private Controls: 20
Format ioctls (Input 0):
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK
Codec ioctls (Input 0):
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls (Input 0):
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test CREATE_BUFS maximum buffers: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)
test TIME32/64: OK
Total for microchip-isc device /dev/video0: 48, Succeeded: 48, Failed:
0, Warnings: 0
root@sama7g5ek-sd:~# v4l2-compliance -d /dev/video1
v4l2-compliance 1.26.1-5142, 32 bits, 64-bit time_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38
Compliance test for microchip-isc device /dev/video1:
Driver Info:
Driver name : microchip-isc
Card type : microchip-isc_stats
Bus info : platform:microchip-isc
Driver version : 6.12.48
Capabilities : 0x84a00000
Metadata Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04a00000
Metadata Capture
Streaming
Extended Pix Format
Media Driver Info:
Driver name : microchip_isc_c
Model : microchip,sama7g5-isc
Serial :
Bus info : platform:e1408000.xisc
Media version : 6.12.48
Hardware revision: 0x00000220 (544)
Driver version : 6.12.48
Interface Info:
ID : 0x0300001e
Type : V4L Video
Entity Info:
ID : 0x0000001c (28)
Name : microchip-isc_stats
Function : V4L2 I/O
Pad 0x0100001d : 0: Sink
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
warn: v4l2-compliance.cpp(670): media bus_info
'platform:e1408000.xisc' differs from V4L2 bus_info 'platform:microchip-isc'
test VIDIOC_QUERYCAP: OK
test invalid ioctls: OK
Allow for multiple opens:
test second /dev/video1 open: OK
warn: v4l2-compliance.cpp(670): media bus_info
'platform:e1408000.xisc' differs from V4L2 bus_info 'platform:microchip-isc'
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
test VIDIOC_QUERYCTRL: OK (Not Supported)
test VIDIOC_G/S_CTRL: OK (Not Supported)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 0 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test CREATE_BUFS maximum buffers: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)
test TIME32/64: OK
Total for microchip-isc device /dev/video1: 48, Succeeded: 48, Failed:
0, Warnings: 2
root@sama7g5ek-sd:~# media-ctl -p
Media controller API version 6.12.48
Media device information
------------------------
driver microchip_isc_c
model microchip,sama7g5-isc
serial
bus info platform:e1408000.xisc
hw revision 0x220
driver version 6.12.48
Device topology
- entity 1: microchip_isc_scaler (2 pads, 2 links, 0 routes)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
[stream:0 fmt:SBGGR8_1X8/3264x2464 field:none
colorspace:srgb
crop.bounds:(0,0)/3264x2464
crop:(0,0)/3264x2464]
<- "csi2dc":1 [ENABLED,IMMUTABLE]
pad1: Source
[stream:0 fmt:SBGGR8_1X8/3264x2464 field:none
colorspace:srgb]
-> "microchip_isc_common":0 [ENABLED,IMMUTABLE]
- entity 4: csi2dc (2 pads, 2 links, 0 routes)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[stream:0 fmt:SRGGB8_1X8/640x480 field:none
colorspace:srgb]
<- "dw-csi.0":1 [ENABLED]
pad1: Source
[stream:0 fmt:SRGGB8_1X8/640x480 field:none
colorspace:srgb]
-> "microchip_isc_scaler":0 [ENABLED,IMMUTABLE]
- entity 7: dw-csi.0 (2 pads, 2 links, 0 routes)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev2
pad0: Sink
[stream:0 fmt:SBGGR8_1X8/0x0]
<- "imx219 1-0010":0 [ENABLED]
pad1: Source
[stream:0 fmt:SBGGR8_1X8/0x0]
-> "csi2dc":0 [ENABLED]
- entity 12: imx219 1-0010 (1 pad, 1 link, 0 routes)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev3
pad0: Source
[stream:0 fmt:SRGGB10_1X10/3280x2464 field:none
colorspace:raw xfer:none ycbcr:601 quantization:full-range
crop.bounds:(8,8)/3280x2464
crop:(8,8)/3280x2464]
-> "dw-csi.0":0 [ENABLED]
- entity 24: microchip_isc_common (1 pad, 1 link)
type Node subtype V4L flags 1
device node name /dev/video0
pad0: Sink
<- "microchip_isc_scaler":1 [ENABLED,IMMUTABLE]
- entity 28: microchip-isc_stats (1 pad, 0 link)
type Node subtype V4L flags 0
device node name /dev/video1
pad0: Sink
-------------sam9x75_curiosity------------------
root@sam9x75-curiosity-sd:~# v4l2-compliance -d /dev/video0
v4l2-compliance 1.26.1-5142, 32 bits, 64-bit time_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38
Compliance test for microchip-isc device /dev/video0:
Driver Info:
Driver name : microchip-isc
Card type : Microchip Image Sensor Controll
Bus info : platform:f8048000.xisc
Driver version : 6.12.48
Capabilities : 0xa4200001
Video Capture
I/O MC
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x24200001
Video Capture
I/O MC
Streaming
Extended Pix Format
Media Driver Info:
Driver name : microchip_isc_c
Model : microchip,sama7g5-isc
Serial :
Bus info : platform:f8048000.xisc
Media version : 6.12.48
Hardware revision: 0x00010260 (66144)
Driver version : 6.12.48
Interface Info:
ID : 0x0300001a
Type : V4L Video
Entity Info:
ID : 0x00000018 (24)
Name : microchip_isc_common
Function : V4L2 I/O
Flags : default
Pad 0x01000019 : 0: Sink
Link 0x02000022: from remote pad 0x1000003 of entity
'microchip_isc_scaler' (Video Scaler): Data, Enabled, Immutable
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
test VIDIOC_QUERYCAP: OK
test invalid ioctls: OK
Allow for multiple opens:
test second /dev/video0 open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 1 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls (Input 0):
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 8 Private Controls: 20
Format ioctls (Input 0):
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK
Codec ioctls (Input 0):
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls (Input 0):
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test CREATE_BUFS maximum buffers: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)
test TIME32/64: OK
Total for microchip-isc device /dev/video0: 48, Succeeded: 48, Failed:
0, Warnings: 0
root@sam9x75-curiosity-sd:~# v4l2-compliance -d /dev/video1
v4l2-compliance 1.26.1-5142, 32 bits, 64-bit time_t
v4l2-compliance SHA: 4aee01a02792 2023-12-12 21:40:38
Compliance test for microchip-isc device /dev/video1:
Driver Info:
Driver name : microchip-isc
Card type : microchip-isc_stats
Bus info : platform:microchip-isc
Driver version : 6.12.48
Capabilities : 0x84a00000
Metadata Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04a00000
Metadata Capture
Streaming
Extended Pix Format
Media Driver Info:
Driver name : microchip_isc_c
Model : microchip,sama7g5-isc
Serial :
Bus info : platform:f8048000.xisc
Media version : 6.12.48
Hardware revision: 0x00010260 (66144)
Driver version : 6.12.48
Interface Info:
ID : 0x0300001e
Type : V4L Video
Entity Info:
ID : 0x0000001c (28)
Name : microchip-isc_stats
Function : V4L2 I/O
Pad 0x0100001d : 0: Sink
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
warn: v4l2-compliance.cpp(670): media bus_info
'platform:f8048000.xisc' differs from V4L2 bus_info 'platform:microchip-isc'
test VIDIOC_QUERYCAP: OK
test invalid ioctls: OK
Allow for multiple opens:
test second /dev/video1 open: OK
warn: v4l2-compliance.cpp(670): media bus_info
'platform:f8048000.xisc' differs from V4L2 bus_info 'platform:microchip-isc'
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
test VIDIOC_QUERYCTRL: OK (Not Supported)
test VIDIOC_G/S_CTRL: OK (Not Supported)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 0 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test CREATE_BUFS maximum buffers: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)
test TIME32/64: OK
Total for microchip-isc device /dev/video1: 48, Succeeded: 48, Failed:
0, Warnings: 2
root@sam9x75-curiosity-sd:~# media-ctl -p
Media controller API version 6.12.48
Media device information
------------------------
driver microchip_isc_c
model microchip,sama7g5-isc
serial
bus info platform:f8048000.xisc
hw revision 0x10260
driver version 6.12.48
Device topology
- entity 1: microchip_isc_scaler (2 pads, 2 links, 0 routes)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
[stream:0 fmt:SBGGR8_1X8/2560x1920 field:none
colorspace:srgb
crop.bounds:(0,0)/2560x1920
crop:(0,0)/2560x1920]
<- "csi2dc":1 [ENABLED,IMMUTABLE]
pad1: Source
[stream:0 fmt:SBGGR8_1X8/2560x1920 field:none
colorspace:srgb]
-> "microchip_isc_common":0 [ENABLED,IMMUTABLE]
- entity 4: csi2dc (2 pads, 2 links, 0 routes)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[stream:0 fmt:SRGGB8_1X8/640x480 field:none
colorspace:srgb]
<- "dw-csi.0":1 [ENABLED]
pad1: Source
[stream:0 fmt:SRGGB8_1X8/640x480 field:none
colorspace:srgb]
-> "microchip_isc_scaler":0 [ENABLED,IMMUTABLE]
- entity 7: dw-csi.0 (2 pads, 2 links, 0 routes)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev2
pad0: Sink
[stream:0 fmt:SBGGR8_1X8/0x0]
<- "imx219 0-0010":0 [ENABLED]
pad1: Source
[stream:0 fmt:SBGGR8_1X8/0x0]
-> "csi2dc":0 [ENABLED]
- entity 12: imx219 0-0010 (1 pad, 1 link, 0 routes)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev3
pad0: Source
[stream:0 fmt:SRGGB10_1X10/3280x2464 field:none
colorspace:raw xfer:none ycbcr:601 quantization:full-range
crop.bounds:(8,8)/3280x2464
crop:(8,8)/3280x2464]
-> "dw-csi.0":0 [ENABLED]
- entity 24: microchip_isc_common (1 pad, 1 link)
type Node subtype V4L flags 1
device node name /dev/video0
pad0: Sink
<- "microchip_isc_scaler":1 [ENABLED,IMMUTABLE]
- entity 28: microchip-isc_stats (1 pad, 0 link)
type Node subtype V4L flags 0
device node name /dev/video1
pad0: Sink
I will get you the output for sama5d2 shortly.
Thanks,
Bala
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-10 8:21 ` Kieran Bingham
2025-10-10 8:27 ` Laurent Pinchart
@ 2025-10-15 6:05 ` Balamanikandan.Gunasundar
2025-10-15 6:45 ` Balamanikandan.Gunasundar
2025-10-15 6:33 ` Balamanikandan.Gunasundar
2 siblings, 1 reply; 65+ messages in thread
From: Balamanikandan.Gunasundar @ 2025-10-15 6:05 UTC (permalink / raw)
To: kieran.bingham, eugen.hristev
Cc: 3chas3, Nicolas.Ferre, alexandre.belloni, claudiu.beznea,
Balakrishnan.S, hverkuil, ribalda, laurent.pinchart+renesas,
jacopo.mondi, dan.scally+renesas, tomi.valkeinen, linux-kernel,
linux-media, linux-atm-general, netdev, linux-arm-kernel, mchehab
Hi Kieran,
On 10/10/25 1:51 pm, Kieran Bingham wrote:
>> Hi Bala,
>>
>> On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
>>> Hi,
>>>
>>> This patch series has a set of enhancements to the Microchip Image Sensor
>>> Controller driver. The objective is to expand its image processing
>>> capabilities and to improve the colors.
>>>
>>> This series also introduces a new stats driver that exposes the histogram
>>> data to userspace via v4l2 controls. This allows applications such as
>>> libcamera to access real time image statistics for advanced image
>>> processing like automatic exposure, white balance adjustments etc.
> How much data do you anticipate to be passing through controls? (What
> can the hardware provide in total if we look at the bigger picture to
> support the full device?)
Thanks for the feedback. Currently the hardware provides histogram data
with 256 bins per color (R, G, B and Y) each 32 bit wide. So roughly
around 4 x 256 x 4 = 4K of data per frame. The intent to use it as v4l2
controls was to make this data easily accessible to user space without a
need for a new data interface initially. However I agree that we may
expand the statistics for future ISP blocks to include region based
stats (We are already in discussion with the design)
>
> For all other ISPs we've been working towards using structured parameter
> buffers to pass data - and we've been making that format extensible,
> which I think could also be a design that can apply to statistics.
That sounds great and we can certainly explore aligning with the
structured buffers for histogram data and any other future statistics.
Thanks,
Bala
>
> This would greatly reduce the overhead of managing 'one control per
> value' ... or things like passing large tables (like a lens shading
> table perhaps) through controls.
>
> --
> Kieran
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-10 8:21 ` Kieran Bingham
2025-10-10 8:27 ` Laurent Pinchart
2025-10-15 6:05 ` Balamanikandan.Gunasundar
@ 2025-10-15 6:33 ` Balamanikandan.Gunasundar
2 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan.Gunasundar @ 2025-10-15 6:33 UTC (permalink / raw)
To: kieran.bingham, eugen.hristev
Cc: 3chas3, Nicolas.Ferre, alexandre.belloni, claudiu.beznea,
Balakrishnan.S, hverkuil, ribalda, laurent.pinchart+renesas,
jacopo.mondi, dan.scally+renesas, tomi.valkeinen, linux-kernel,
linux-media, linux-atm-general, netdev, linux-arm-kernel, mchehab
Hi Kieran,
On 10/10/25 1:51 pm, Kieran Bingham wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> Quoting Eugen Hristev (2025-10-09 21:11:17)
>> Hi Bala,
>>
>> On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
>>> Hi,
>>>
>>> This patch series has a set of enhancements to the Microchip Image Sensor
>>> Controller driver. The objective is to expand its image processing
>>> capabilities and to improve the colors.
>>>
>>> This series also introduces a new stats driver that exposes the histogram
>>> data to userspace via v4l2 controls. This allows applications such as
My apologies. I made a mistake clarifying this earlier. The new stats
driver does not use V4L2 controls, it exports the buffer through the
v4l2 meta data| (|V4L2_BUF_TYPE_META_CAPTURE)||instead. So I guess this
is the approach you are suggesting.
The controls like brightness, contrast, hue and saturation are exported
as V4L2 controls.
root@sam9x75-curiosity-sd:~# v4l2-ctl -l
User Controls
brightness 0x00980900 (int) : min=-1024
max=1023 step=1 default=0 value=0 flags=slider
contrast 0x00980901 (int) : min=-2048
max=2047 step=1 default=16 value=16 flags=slider
saturation 0x00980902 (int) : min=0 max=100
step=1 default=16 value=16 flags=slider
hue 0x00980903 (int) : min=-180 max=180
step=1 default=0 value=0 flags=slider
<snip>
Thanks,
Bala.
>>> libcamera to access real time image statistics for advanced image
>>> processing like automatic exposure, white balance adjustments etc.
> How much data do you anticipate to be passing through controls? (What
> can the hardware provide in total if we look at the bigger picture to
> support the full device?)
>
> For all other ISPs we've been working towards using structured parameter
> buffers to pass data - and we've been making that format extensible,
> which I think could also be a design that can apply to statistics.
>
> This would greatly reduce the overhead of managing 'one control per
> value' ... or things like passing large tables (like a lens shading
> table perhaps) through controls.
>
> --
> Kieran
>
>>> Balakrishnan Sambath (11):
>>> media: microchip-isc: Enable GDC and CBC module flags for RGB formats
>>> media: microchip-isc: Improve histogram calculation with outlier
>>> rejection
>>> media: microchip-isc: Use channel averages for Grey World AWB
>>> media: microchip-isc: Add range based black level correction
>>> media: platform: microchip: Extend gamma table and control range
>>> media: platform: microchip: Add new histogram submodule
>>> media: microchip-isc: Register and unregister statistics device
>>> media: microchip-isc: Always enable histogram for all RAW formats
>>> media: microchip-isc: fix histogram state initialization order
>>> media: microchip-isc: decouple histogram cycling from AWB mode
>>> media: microchip-isc: enable userspace histogram statistics export
>>>
>>> Balamanikandan Gunasundar (7):
>>> media: platform: microchip: set maximum resolution for sam9x7
>>> media: platform: microchip: Include DPC modules flags in pipeline
>>> media: microchip-isc: expose hue and saturation as v4l2 controls
>>> media: microchip-isc: Rename CBC to CBHS
>>> media: microchip-isc: Store histogram data of all channels
>>> media: videodev2.h, v4l2-ioctl: Add microchip statistics format
>>> media: microchip-isc: expose color correction registers as v4l2
>>> controls
>>>
>>> drivers/media/platform/microchip/Kconfig | 2 +
>>> drivers/media/platform/microchip/Makefile | 2 +-
>>> .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
>>> .../platform/microchip/microchip-isc-regs.h | 3 +
>>> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
>>> .../media/platform/microchip/microchip-isc.h | 44 +-
>>> .../microchip/microchip-sama5d2-isc.c | 2 +-
>>> .../microchip/microchip-sama7g5-isc.c | 73 ++-
>>> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
>>> include/linux/atmel-isc-media.h | 13 +
>>> include/uapi/linux/videodev2.h | 3 +
>>> 11 files changed, 1001 insertions(+), 64 deletions(-)
>>> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>>>
>> This looks interesting.
>> I would like to see the compliance tool output for more platforms
>> (sama7g5, sama5d2, and the new sam9x7), also the media-ctl -p , to see
>> the topology with your new driver.
>>
>> Thanks,
>> Eugen
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-15 6:05 ` Balamanikandan.Gunasundar
@ 2025-10-15 6:45 ` Balamanikandan.Gunasundar
0 siblings, 0 replies; 65+ messages in thread
From: Balamanikandan.Gunasundar @ 2025-10-15 6:45 UTC (permalink / raw)
To: kieran.bingham, eugen.hristev
Cc: 3chas3, Nicolas.Ferre, alexandre.belloni, claudiu.beznea,
Balakrishnan.S, hverkuil, ribalda, laurent.pinchart+renesas,
jacopo.mondi, dan.scally+renesas, tomi.valkeinen, linux-kernel,
linux-media, linux-atm-general, netdev, linux-arm-kernel, mchehab
Hi Kieran,
On 15/10/25 11:35 am, Balamanikandan Gunasundar - I64410 wrote:
> Hi Kieran,
>
> On 10/10/25 1:51 pm, Kieran Bingham wrote:
>>> Hi Bala,
>>>
>>> On 10/9/25 18:52, Balamanikandan Gunasundar wrote:
>>>> Hi,
>>>>
>>>> This patch series has a set of enhancements to the Microchip Image Sensor
>>>> Controller driver. The objective is to expand its image processing
>>>> capabilities and to improve the colors.
>>>>
>>>> This series also introduces a new stats driver that exposes the histogram
>>>> data to userspace via v4l2 controls. This allows applications such as
>>>> libcamera to access real time image statistics for advanced image
>>>> processing like automatic exposure, white balance adjustments etc.
>> How much data do you anticipate to be passing through controls? (What
>> can the hardware provide in total if we look at the bigger picture to
>> support the full device?)
> Thanks for the feedback. Currently the hardware provides histogram data
> with 256 bins per color (R, G, B and Y) each 32 bit wide. So roughly
> around 4 x 256 x 4 = 4K of data per frame. The intent to use it as v4l2
> controls was to make this data easily accessible to user space without a
Correcting my mistake here. The histogram statistics are exported to
userspace as v4l2 meta data through the new driver. Not the v4l2 controls.
The controls like brightness, contrast etc are exported as v4l2 controls.
Thanks,
Bala.
> need for a new data interface initially. However I agree that we may
> expand the statistics for future ISP blocks to include region based
> stats (We are already in discussion with the design)
>> For all other ISPs we've been working towards using structured parameter
>> buffers to pass data - and we've been making that format extensible,
>> which I think could also be a design that can apply to statistics.
> That sounds great and we can certainly explore aligning with the
> structured buffers for histogram data and any other future statistics.
>
> Thanks,
>
> Bala
>
>> This would greatly reduce the overhead of managing 'one control per
>> value' ... or things like passing large tables (like a lens shading
>> table perhaps) through controls.
>>
>> --
>> Kieran
>
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 08/18] media: platform: microchip: Add new histogram submodule
2025-10-09 15:52 ` [PATCH 08/18] media: platform: microchip: Add new histogram submodule Balamanikandan Gunasundar
@ 2025-11-10 8:41 ` Hans Verkuil
2025-11-10 8:55 ` Hans Verkuil
1 sibling, 0 replies; 65+ messages in thread
From: Hans Verkuil @ 2025-11-10 8:41 UTC (permalink / raw)
To: Balamanikandan Gunasundar, Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
Apologies for the late review, but this needs a bit more work:
On 09/10/2025 17:52, Balamanikandan Gunasundar wrote:
> From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
>
> Add new histogram submodule driver to export raw histogram statistics
> and data to userspace.
>
> Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
> ---
> drivers/media/platform/microchip/Kconfig | 2 +
> drivers/media/platform/microchip/Makefile | 2 +-
> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> .../media/platform/microchip/microchip-isc.h | 24 +
> 4 files changed, 576 insertions(+), 1 deletion(-)
> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>
> diff --git a/drivers/media/platform/microchip/Kconfig b/drivers/media/platform/microchip/Kconfig
> index 4734ecced029..2864a57e2ff4 100644
> --- a/drivers/media/platform/microchip/Kconfig
> +++ b/drivers/media/platform/microchip/Kconfig
> @@ -10,6 +10,7 @@ config VIDEO_MICROCHIP_ISC
> select MEDIA_CONTROLLER
> select VIDEO_V4L2_SUBDEV_API
> select VIDEOBUF2_DMA_CONTIG
> + select VIDEOBUF2_VMALLOC
> select REGMAP_MMIO
> select V4L2_FWNODE
> select VIDEO_MICROCHIP_ISC_BASE
> @@ -26,6 +27,7 @@ config VIDEO_MICROCHIP_XISC
> depends on VIDEO_DEV && COMMON_CLK
> depends on ARCH_AT91 || COMPILE_TEST
> select VIDEOBUF2_DMA_CONTIG
> + select VIDEOBUF2_VMALLOC
> select REGMAP_MMIO
> select V4L2_FWNODE
> select VIDEO_MICROCHIP_ISC_BASE
> diff --git a/drivers/media/platform/microchip/Makefile b/drivers/media/platform/microchip/Makefile
> index bd8d6e779c51..94c64d3d242c 100644
> --- a/drivers/media/platform/microchip/Makefile
> +++ b/drivers/media/platform/microchip/Makefile
> @@ -1,7 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0-only
> microchip-isc-objs = microchip-sama5d2-isc.o
> microchip-xisc-objs = microchip-sama7g5-isc.o
> -microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o
> +microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o microchip-isc-stats.o
>
> obj-$(CONFIG_VIDEO_MICROCHIP_ISC_BASE) += microchip-isc-common.o
> obj-$(CONFIG_VIDEO_MICROCHIP_ISC) += microchip-isc.o
> diff --git a/drivers/media/platform/microchip/microchip-isc-stats.c b/drivers/media/platform/microchip/microchip-isc-stats.c
> new file mode 100644
> index 000000000000..d7813c9d95ac
> --- /dev/null
> +++ b/drivers/media/platform/microchip/microchip-isc-stats.c
> @@ -0,0 +1,549 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Microchip ISC Driver - Statistics Subdevice
> + * Raw Histogram Export for Userspace Applications
> + *
> + * Copyright (C) 2025 Microchip Technology Inc.
> + *
> + * Author: Balakrishnan Sambath <balakrishnan.s@microchip.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-vmalloc.h>
> +#include "microchip-isc-regs.h"
> +#include "microchip-isc.h"
> +
> +#define ISC_STATS_DEV_NAME "microchip-isc_stats"
> +#define ISC_STATS_MIN_BUFS 2
> +#define ISC_STATS_MAX_BUFS 8
> +
> +/**
> + * struct isc_stat_buffer - Raw histogram statistics buffer structure
> + * @frame_number: Sequential frame number from capture
> + * @timestamp: Frame capture timestamp in nanoseconds
> + * @meas_type: Bitmask of measurement types available (ISC_CIF_ISP_STAT_*)
> + * @hist: Array of histogram data for each Bayer channel
> + * @hist.hist_bins: Raw 512-bin histogram data from hardware
> + * @hist.hist_min: Minimum pixel value observed in channel
> + * @hist.hist_max: Maximum pixel value observed in channel
> + * @hist.total_pixels: Total number of pixels processed in channel
> + * @valid_channels: Bitmask indicating which Bayer channels contain valid data
> + * @bayer_pattern: Current Bayer pattern configuration (CFA_BAYCFG_*)
> + * @reserved: Padding for future expansion and alignment
> + *
> + * This structure contains raw, unprocessed histogram data from the ISC
> + * hardware for all four Bayer channels (GR, R, GB, B). No algorithmic
> + * processing is performed - data is exported directly from hardware
> + * registers for userspace processing applications.
> + */
> +struct isc_stat_buffer {
> + u32 frame_number;
> + u64 timestamp;
> + u32 meas_type;
> +
> + struct {
> + u32 hist_bins[HIST_ENTRIES];
> + u32 hist_min;
> + u32 hist_max;
> + u32 total_pixels;
> + } hist[HIST_BAYER];
> +
> + u8 valid_channels;
> + u8 bayer_pattern;
> + u16 reserved[2];
> +} __packed;
> +
> +/* Statistics measurement type flags */
> +#define ISC_CIF_ISP_STAT_HIST BIT(0)
> +
> +static bool isc_stats_in_use(struct isc_stats *stats)
> +{
> + struct video_device *vdev;
> +
> + if (!stats || !stats->isc)
> + return false;
> +
> + vdev = &stats->vnode.vdev;
> + return vdev && video_is_registered(vdev) && !list_empty(&vdev->fh_list);
> +}
> +
> +static bool isc_stats_has_bufs(struct isc_stats *stats)
> +{
> + bool has_buffers;
> +
> + if (!stats)
> + return false;
> +
> + spin_lock(&stats->lock);
> + has_buffers = !list_empty(&stats->stat);
> + spin_unlock(&stats->lock);
> +
> + return has_buffers;
> +}
> +
> +/*
> + * V4L2 device operations
> + */
> +
> +static int isc_stats_enum_fmt_meta_cap(struct file *file, void *priv,
> + struct v4l2_fmtdesc *f)
> +{
> + struct video_device *video = video_devdata(file);
> + struct isc_stats *stats = video_get_drvdata(video);
> +
> + if (f->index > 0 || f->type != video->queue->type)
> + return -EINVAL;
No need for the f->type check.
> +
> + f->pixelformat = stats->vdev_fmt.fmt.meta.dataformat;
> + return 0;
> +}
> +
> +static int isc_stats_g_fmt_meta_cap(struct file *file, void *priv,
> + struct v4l2_format *f)
> +{
> + struct video_device *video = video_devdata(file);
> + struct isc_stats *stats = video_get_drvdata(video);
> + struct v4l2_meta_format *meta = &f->fmt.meta;
> +
> + if (f->type != video->queue->type)
> + return -EINVAL;
No need for this, just drop this check.
> +
> + memset(meta, 0, sizeof(*meta));
No need, it's already zeroed by the V4L2 core.
> + meta->dataformat = stats->vdev_fmt.fmt.meta.dataformat;
> + meta->buffersize = stats->vdev_fmt.fmt.meta.buffersize;
> +
> + return 0;
> +}
> +
> +static int isc_stats_querycap(struct file *file, void *priv,
> + struct v4l2_capability *cap)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
> + strscpy(cap->card, vdev->name, sizeof(cap->card));
> + strscpy(cap->bus_info, "platform:microchip-isc", sizeof(cap->bus_info));
You can drop the last line, it's filled in by the V4L2 core.
> +
> + return 0;
> +}
> +
> +static int isc_stats_open(struct file *file)
> +{
> + struct video_device *vdev = video_devdata(file);
> + struct isc_stats *stats = video_get_drvdata(vdev);
> +
> + dev_dbg(stats->isc->dev, "Stats device opened by %s (pid %d)\n",
> + current->comm, current->pid);
> +
> + return v4l2_fh_open(file);
> +}
> +
> +static int isc_stats_release(struct file *file)
> +{
> + struct video_device *vdev = video_devdata(file);
> + struct isc_stats *stats = video_get_drvdata(vdev);
> +
> + dev_dbg(stats->isc->dev, "Stats device closed by %s (pid %d)\n",
> + current->comm, current->pid);
> +
> + return _vb2_fop_release(file, NULL);
> +}
These two functions make no sense. Drop them, see below for what to use instead.
> +
> +static const struct v4l2_ioctl_ops isc_stats_ioctl_ops = {
> + .vidioc_reqbufs = vb2_ioctl_reqbufs,
> + .vidioc_querybuf = vb2_ioctl_querybuf,
> + .vidioc_create_bufs = vb2_ioctl_create_bufs,
> + .vidioc_qbuf = vb2_ioctl_qbuf,
> + .vidioc_dqbuf = vb2_ioctl_dqbuf,
> + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> + .vidioc_expbuf = vb2_ioctl_expbuf,
> + .vidioc_streamon = vb2_ioctl_streamon,
> + .vidioc_streamoff = vb2_ioctl_streamoff,
> + .vidioc_enum_fmt_meta_cap = isc_stats_enum_fmt_meta_cap,
> + .vidioc_g_fmt_meta_cap = isc_stats_g_fmt_meta_cap,
> + .vidioc_s_fmt_meta_cap = isc_stats_g_fmt_meta_cap,
> + .vidioc_try_fmt_meta_cap = isc_stats_g_fmt_meta_cap,
> + .vidioc_querycap = isc_stats_querycap,
> + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> +};
> +
> +static const struct v4l2_file_operations isc_stats_fops = {
> + .mmap = vb2_fop_mmap,
> + .unlocked_ioctl = video_ioctl2,
> + .poll = vb2_fop_poll,
> + .open = isc_stats_open,
Just use v4l2_fh_open.
> + .release = isc_stats_release
And for this use vb2_fop_release.
> +};
> +
> +/*
> + * VB2 queue operations
> + */
> +
> +static int isc_stats_vb2_queue_setup(struct vb2_queue *vq,
> + unsigned int *num_buffers,
> + unsigned int *num_planes,
> + unsigned int sizes[],
> + struct device *alloc_devs[])
> +{
> + struct isc_stats *stats = vq->drv_priv;
> +
This doesn't handle VIDIOC_CREATEBUFS correctly. See isc_queue_setup
on how to do that correctly.
> + *num_planes = 1;
> + *num_buffers = clamp_t(u32, *num_buffers, ISC_STATS_MIN_BUFS,
> + ISC_STATS_MAX_BUFS);
Why limit the number of buffers? The default max is 32 (VIDEO_MAX_FRAME),
and unless there are hardware limitations that require adjustments, I'd
just leave *num_buffers alone.
> + sizes[0] = sizeof(struct isc_stat_buffer);
> +
> + dev_dbg(stats->isc->dev, "Stats queue: %u buffers, %u bytes each\n",
> + *num_buffers, sizes[0]);
> +
> + return 0;
> +}
> +
> +static void isc_stats_vb2_buf_queue(struct vb2_buffer *vb)
> +{
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct isc_buffer *stats_buf = container_of(vbuf, struct isc_buffer, vb);
> + struct vb2_queue *vq = vb->vb2_queue;
> + struct isc_stats *stats_dev = vq->drv_priv;
> +
> + spin_lock_irq(&stats_dev->lock);
> + list_add_tail(&stats_buf->list, &stats_dev->stat);
> + spin_unlock_irq(&stats_dev->lock);
> +
> + dev_dbg(stats_dev->isc->dev, "Stats buffer %d queued\n", vb->index);
> +}
> +
> +static int isc_stats_vb2_buf_prepare(struct vb2_buffer *vb)
> +{
> + if (vb2_plane_size(vb, 0) < sizeof(struct isc_stat_buffer))
> + return -EINVAL;
> +
> + vb2_set_plane_payload(vb, 0, sizeof(struct isc_stat_buffer));
> + return 0;
> +}
> +
> +static int isc_stats_vb2_start_streaming(struct vb2_queue *vq,
> + unsigned int count)
> +{
> + struct isc_stats *stats = vq->drv_priv;
> +
> + dev_dbg(stats->isc->dev, "Stats streaming started\n");
> + return 0;
> +}
> +
> +static void isc_stats_vb2_stop_streaming(struct vb2_queue *vq)
> +{
> + struct isc_stats *stats = vq->drv_priv;
> + struct isc_buffer *buf;
> + unsigned int i;
> +
> + dev_dbg(stats->isc->dev, "Stats streaming stopped\n");
> +
> + spin_lock_irq(&stats->lock);
> + for (i = 0; i < ISC_STATS_MAX_BUFS; i++) {
> + if (list_empty(&stats->stat))
> + break;
> + buf = list_first_entry(&stats->stat, struct isc_buffer, list);
> + list_del(&buf->list);
> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
> + }
> + spin_unlock_irq(&stats->lock);
> +}
> +
> +static const struct vb2_ops isc_stats_vb2_ops = {
> + .queue_setup = isc_stats_vb2_queue_setup,
> + .buf_queue = isc_stats_vb2_buf_queue,
> + .buf_prepare = isc_stats_vb2_buf_prepare,
> + .start_streaming = isc_stats_vb2_start_streaming,
> + .stop_streaming = isc_stats_vb2_stop_streaming,
> + .wait_prepare = vb2_ops_wait_prepare,
> + .wait_finish = vb2_ops_wait_finish,
Drop these last two lines: wait_prepare/finish is deprecated and will hopefully be
removed in 6.20.
> +};
> +
> +static int isc_stats_init_vb2_queue(struct vb2_queue *q,
> + struct isc_stats *stats)
> +{
> + struct isc_vdev_node *node;
> +
> + node = container_of(q, struct isc_vdev_node, buf_queue);
> +
> + q->type = V4L2_BUF_TYPE_META_CAPTURE;
> + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
I'm not keen on VB2_USERPTR for new drivers. But I won't block it if you
believe there is a good use case for this.
> + q->drv_priv = stats;
> + q->ops = &isc_stats_vb2_ops;
> + q->mem_ops = &vb2_vmalloc_memops;
> + q->buf_struct_size = sizeof(struct isc_buffer);
> + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> + q->lock = &node->vlock;
> +
> + return vb2_queue_init(q);
> +}
> +
> +/*
> + * Histogram data processing
> + */
> +
> +static void isc_stats_fill_data(struct isc_stats *stats,
> + struct isc_stat_buffer *pbuf)
> +{
> + struct isc_device *isc = stats->isc;
> + struct isc_ctrls *ctrls = &isc->ctrls;
> + int c;
> +
> + pbuf->meas_type |= ISC_CIF_ISP_STAT_HIST;
> +
> + /* Copy existing histogram data from AWB work function */
> + for (c = 0; c < HIST_BAYER; c++) {
> + memcpy(pbuf->hist[c].hist_bins, isc->full_hist_data[c],
> + sizeof(pbuf->hist[c].hist_bins));
> +
> + pbuf->hist[c].hist_min = ctrls->hist_minmax[c][HIST_MIN_INDEX];
> + pbuf->hist[c].hist_max = ctrls->hist_minmax[c][HIST_MAX_INDEX];
> + pbuf->hist[c].total_pixels = ctrls->total_pixels[c];
> + }
> +
> + /* Set valid channels - all 4 Bayer channels */
> + pbuf->valid_channels = 0x0F;
> +
> + /* Set Bayer pattern */
> + if (isc->config.sd_format)
> + pbuf->bayer_pattern = isc->config.sd_format->cfa_baycfg;
> + else
> + pbuf->bayer_pattern = 0;
> +
> + dev_dbg(isc->dev,
> + "Stats data ready: pixels=[%u,%u,%u,%u], valid_channels=0x%x\n",
> + pbuf->hist[0].total_pixels, pbuf->hist[1].total_pixels,
> + pbuf->hist[2].total_pixels, pbuf->hist[3].total_pixels,
> + pbuf->valid_channels);
> +}
> +
> +static void isc_stats_send_buf(struct isc_stats *stats)
> +{
> + struct isc_stat_buffer *cur_stat_buf;
> + struct isc_buffer *cur_buf = NULL;
> + struct isc_device *isc = stats->isc;
> + unsigned int frame_sequence = isc->sequence;
> + u64 timestamp = ktime_get_ns();
> +
> + /* Get one empty buffer from userspace */
> + spin_lock(&stats->lock);
> + if (!list_empty(&stats->stat)) {
> + cur_buf = list_first_entry(&stats->stat,
> + struct isc_buffer, list);
> + list_del(&cur_buf->list);
> + }
> + spin_unlock(&stats->lock);
> +
> + if (!cur_buf) {
> + dev_dbg(isc->dev, "No stats buffer available\n");
> + return;
> + }
> +
> + cur_stat_buf = vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
> + if (!cur_stat_buf) {
> + dev_err(isc->dev, "Failed to get stats buffer vaddr\n");
> + goto error_return_buffer;
> + }
> +
> + /* Clear buffer and fill metadata */
> + memset(cur_stat_buf, 0, sizeof(*cur_stat_buf));
> + cur_stat_buf->frame_number = frame_sequence;
> + cur_stat_buf->timestamp = timestamp;
> +
> + /* Fill raw histogram data */
> + isc_stats_fill_data(stats, cur_stat_buf);
> +
> + /* Send buffer to userspace */
> + vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0,
> + sizeof(struct isc_stat_buffer));
> + cur_buf->vb.sequence = frame_sequence;
> + cur_buf->vb.vb2_buf.timestamp = timestamp;
> + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> + dev_dbg(isc->dev,
> + "Stats sent: frame=%u, channels=[%u,%u,%u,%u] pixels\n",
> + frame_sequence,
> + cur_stat_buf->hist[0].total_pixels,
> + cur_stat_buf->hist[1].total_pixels,
> + cur_stat_buf->hist[2].total_pixels,
> + cur_stat_buf->hist[3].total_pixels);
> + return;
> +
> +error_return_buffer:
> + /* Return buffer to queue on error */
> + spin_lock(&stats->lock);
> + list_add(&cur_buf->list, &stats->stat);
> + spin_unlock(&stats->lock);
> +}
> +
> +/*
> + * Public API functions
> + */
> +
> +/**
> + * isc_stats_isr() - Process statistics in interrupt context
> + * @stats: ISC histogram statistics device
> + *
> + * Called from the ISC interrupt handler when histogram data is ready.
> + * Exports raw histogram data to userspace applications that have
> + * buffers queued on the statistics device.
> + */
> +void isc_stats_isr(struct isc_stats *stats)
> +{
> + if (!stats) {
> + pr_err("ISC stats: stats is NULL\n");
> + return;
> + }
> +
> + if (!stats->isc) {
> + pr_err("ISC stats: stats->isc is NULL\n");
> + return;
> + }
> +
> + /* Only send data if userspace is using the device */
> + if (!isc_stats_in_use(stats)) {
> + dev_dbg(stats->isc->dev, "Stats device not in use\n");
> + return;
> + }
> +
> + /* Only send data if userspace has queued buffers */
> + if (!isc_stats_has_bufs(stats)) {
> + dev_dbg(stats->isc->dev, "No queued buffers\n");
> + return;
> + }
> +
> + /* Send histogram data to userspace */
> + isc_stats_send_buf(stats);
> +}
> +EXPORT_SYMBOL_GPL(isc_stats_isr);
> +
> +/**
> + * isc_stats_active() - Check if userspace is actively using stats
> + * @stats: ISC histogram statistics device
> + *
> + * Determines if any userspace application has the statistics device open
> + * and has queued buffers waiting for histogram data.
> + *
> + * Return: true if userspace is ready to receive data, false otherwise
> + */
> +bool isc_stats_active(struct isc_stats *stats)
> +{
> + return isc_stats_in_use(stats) && isc_stats_has_bufs(stats);
> +}
> +EXPORT_SYMBOL_GPL(isc_stats_active);
> +
> +static void isc_stats_init(struct isc_stats *stats)
> +{
> + stats->vdev_fmt.fmt.meta.dataformat = V4L2_META_FMT_ISC_STAT_3A;
> + stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct isc_stat_buffer);
It's a bit overkill to have the vdev_fmt field in stats. Just drop the field and
this function and just set these values directly in g/enum_fmt.
> +}
> +
> +/**
> + * isc_stats_register() - Register statistics device
> + * @isc: ISC device
> + *
> + * Creates and registers a V4L2 video device for exporting raw histogram
> + * statistics to userspace.
> + *
> + */
> +int isc_stats_register(struct isc_device *isc)
> +{
> + struct isc_stats *stats = &isc->stats;
> + struct isc_vdev_node *node = &stats->vnode;
> + struct video_device *vdev = &node->vdev;
> + int ret;
> +
> + /* Initialize stats structure */
> + stats->isc = isc;
> + mutex_init(&node->vlock);
> + INIT_LIST_HEAD(&stats->stat);
> + spin_lock_init(&stats->lock);
> +
> + /* Configure video device */
> + strscpy(vdev->name, ISC_STATS_DEV_NAME, sizeof(vdev->name));
> + vdev->ioctl_ops = &isc_stats_ioctl_ops;
> + vdev->fops = &isc_stats_fops;
> + vdev->release = video_device_release_empty;
> + vdev->lock = &node->vlock;
> + vdev->v4l2_dev = &isc->v4l2_dev;
> + vdev->queue = &node->buf_queue;
> + vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
> + vdev->vfl_dir = VFL_DIR_RX;
> +
> + /* Initialize VB2 queue */
> + ret = isc_stats_init_vb2_queue(vdev->queue, stats);
> + if (ret) {
> + dev_err(isc->dev, "Failed to init stats VB2 queue: %d\n", ret);
> + goto error_cleanup;
> + }
> +
> + /* Initialize stats format */
> + isc_stats_init(stats);
> +
> + video_set_drvdata(vdev, stats);
> +
> + node->pad.flags = MEDIA_PAD_FL_SINK;
> + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
> + if (ret) {
> + dev_err(isc->dev, "Failed to init stats media entity: %d\n", ret);
> + goto error_cleanup;
> + }
> +
> + /* Register video device */
> + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
> + if (ret) {
> + dev_err(isc->dev, "Failed to register stats device: %d\n", ret);
> + goto error_media_cleanup;
> + }
> +
> + dev_info(isc->dev, "Stats device registered as %s\n",
> + video_device_node_name(vdev));
> +
> + return 0;
> +
> +error_media_cleanup:
> + media_entity_cleanup(&vdev->entity);
> +error_cleanup:
> + mutex_destroy(&node->vlock);
> + stats->isc = NULL;
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(isc_stats_register);
> +
> +/**
> + * isc_stats_unregister() - Unregister statistics device
> + * @isc: ISC device
> + *
> + * Unregisters and cleans up the statistics video device.
> + */
> +void isc_stats_unregister(struct isc_device *isc)
> +{
> + struct isc_stats *stats = &isc->stats;
> + struct isc_vdev_node *node = &stats->vnode;
> + struct video_device *vdev = &node->vdev;
> +
> + if (!stats->isc)
> + return;
> +
> + dev_dbg(isc->dev, "Unregistering stats device\n");
> +
> + /* Unregister video device */
> + vb2_video_unregister_device(vdev);
> +
> + media_entity_cleanup(&vdev->entity);
> +
> + /* Destroy synchronization primitives */
> + mutex_destroy(&node->vlock);
> +
> + stats->isc = NULL;
> +}
> +EXPORT_SYMBOL_GPL(isc_stats_unregister);
> +
> +MODULE_AUTHOR("Balakrishnan Sambath <balakrishnan.s@microchip.com>");
> +MODULE_DESCRIPTION("Microchip ISC Statistics Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
> index bd75ff4f109b..5245e2790268 100644
> --- a/drivers/media/platform/microchip/microchip-isc.h
> +++ b/drivers/media/platform/microchip/microchip-isc.h
> @@ -197,6 +197,23 @@ enum isc_scaler_pads {
> ISC_SCALER_PADS_NUM = 2,
> };
>
> +/* Video device node structure */
> +struct isc_vdev_node {
> + struct video_device vdev;
> + struct vb2_queue buf_queue;
> + struct mutex vlock; /* lock for video node */
> + struct media_pad pad;
> +};
> +
> +/* Statistics device structure */
> +struct isc_stats {
> + struct isc_device *isc;
> + struct isc_vdev_node vnode;
> + struct list_head stat;
> + spinlock_t lock; /* lock for buffers */
> + struct v4l2_format vdev_fmt;
> +};
> +
> /*
> * struct isc_device - ISC device driver data/config struct
> * @regmap: Register map
> @@ -340,6 +357,9 @@ struct isc_device {
> struct v4l2_ctrl *gb_off_ctrl;
> };
>
> + /* Statistics device */
> + struct isc_stats stats;
> +
> #define GAMMA_ENTRIES 64
> /* pointer to the defined gamma table */
> const u32 (*gamma_table)[GAMMA_ENTRIES];
> @@ -396,6 +416,10 @@ int isc_scaler_link(struct isc_device *isc);
> int isc_scaler_init(struct isc_device *isc);
> int isc_mc_init(struct isc_device *isc, u32 ver);
> void isc_mc_cleanup(struct isc_device *isc);
> +int isc_stats_register(struct isc_device *isc);
> +void isc_stats_unregister(struct isc_device *isc);
> +void isc_stats_isr(struct isc_stats *stats);
> +bool isc_stats_active(struct isc_stats *stats);
>
> struct isc_format *isc_find_format_by_code(struct isc_device *isc,
> unsigned int code, int *index);
Regards,
Hans
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 17/18] media: videodev2.h, v4l2-ioctl: Add microchip statistics format
2025-10-09 15:52 ` [PATCH 17/18] media: videodev2.h, v4l2-ioctl: Add microchip statistics format Balamanikandan Gunasundar
@ 2025-11-10 8:49 ` Hans Verkuil
0 siblings, 0 replies; 65+ messages in thread
From: Hans Verkuil @ 2025-11-10 8:49 UTC (permalink / raw)
To: Balamanikandan Gunasundar, Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
On 09/10/2025 17:52, Balamanikandan Gunasundar wrote:
> Add microchip ISC specific statistics meta data format. This data consists
> of raw histogram statistics that is exported to userspace for further
> processing. This fixes the kernel warning "Unknown pixelformat"
>
> Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
> ---
> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> include/uapi/linux/videodev2.h | 3 +++
> 2 files changed, 4 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 01cf52c3ea33..a03e8f3ab610 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -1467,6 +1467,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
> case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break;
> case V4L2_META_FMT_RK_ISP1_STAT_3A: descr = "Rockchip ISP1 3A Statistics"; break;
> case V4L2_META_FMT_RK_ISP1_EXT_PARAMS: descr = "Rockchip ISP1 Ext 3A Params"; break;
> + case V4L2_META_FMT_ISC_STAT_3A: descr = "Microchip ISP statistics"; break;
statistics -> Statistics
> case V4L2_META_FMT_C3ISP_PARAMS: descr = "Amlogic C3 ISP Parameters"; break;
> case V4L2_META_FMT_C3ISP_STATS: descr = "Amlogic C3 ISP Statistics"; break;
> case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break;
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index becd08fdbddb..ba628f9bb89f 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -875,6 +875,9 @@ struct v4l2_pix_format {
> #define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */
> #define V4L2_META_FMT_RK_ISP1_EXT_PARAMS v4l2_fourcc('R', 'K', '1', 'E') /* Rockchip ISP1 3a Extensible Parameters */
>
> +/* Vendor specific - used for Microchip camera sub-system */
> +#define V4L2_META_FMT_ISC_STAT_3A v4l2_fourcc('I', 'S', 'C', 'S')
> +
> /* Vendor specific - used for C3_ISP */
> #define V4L2_META_FMT_C3ISP_PARAMS v4l2_fourcc('C', '3', 'P', 'M') /* Amlogic C3 ISP Parameters */
> #define V4L2_META_FMT_C3ISP_STATS v4l2_fourcc('C', '3', 'S', 'T') /* Amlogic C3 ISP Statistics */
This meta format must be documented just like e.g. V4L2_META_FMT_C3ISP_STATS.
Regards,
Hans
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 08/18] media: platform: microchip: Add new histogram submodule
2025-10-09 15:52 ` [PATCH 08/18] media: platform: microchip: Add new histogram submodule Balamanikandan Gunasundar
2025-11-10 8:41 ` Hans Verkuil
@ 2025-11-10 8:55 ` Hans Verkuil
1 sibling, 0 replies; 65+ messages in thread
From: Hans Verkuil @ 2025-11-10 8:55 UTC (permalink / raw)
To: Balamanikandan Gunasundar, Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
On 09/10/2025 17:52, Balamanikandan Gunasundar wrote:
> From: Balakrishnan Sambath <balakrishnan.s@microchip.com>
>
> Add new histogram submodule driver to export raw histogram statistics
> and data to userspace.
>
> Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
> ---
> drivers/media/platform/microchip/Kconfig | 2 +
> drivers/media/platform/microchip/Makefile | 2 +-
> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> .../media/platform/microchip/microchip-isc.h | 24 +
> 4 files changed, 576 insertions(+), 1 deletion(-)
> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>
> diff --git a/drivers/media/platform/microchip/Kconfig b/drivers/media/platform/microchip/Kconfig
> index 4734ecced029..2864a57e2ff4 100644
> --- a/drivers/media/platform/microchip/Kconfig
> +++ b/drivers/media/platform/microchip/Kconfig
> @@ -10,6 +10,7 @@ config VIDEO_MICROCHIP_ISC
> select MEDIA_CONTROLLER
> select VIDEO_V4L2_SUBDEV_API
> select VIDEOBUF2_DMA_CONTIG
> + select VIDEOBUF2_VMALLOC
> select REGMAP_MMIO
> select V4L2_FWNODE
> select VIDEO_MICROCHIP_ISC_BASE
> @@ -26,6 +27,7 @@ config VIDEO_MICROCHIP_XISC
> depends on VIDEO_DEV && COMMON_CLK
> depends on ARCH_AT91 || COMPILE_TEST
> select VIDEOBUF2_DMA_CONTIG
> + select VIDEOBUF2_VMALLOC
> select REGMAP_MMIO
> select V4L2_FWNODE
> select VIDEO_MICROCHIP_ISC_BASE
> diff --git a/drivers/media/platform/microchip/Makefile b/drivers/media/platform/microchip/Makefile
> index bd8d6e779c51..94c64d3d242c 100644
> --- a/drivers/media/platform/microchip/Makefile
> +++ b/drivers/media/platform/microchip/Makefile
> @@ -1,7 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0-only
> microchip-isc-objs = microchip-sama5d2-isc.o
> microchip-xisc-objs = microchip-sama7g5-isc.o
> -microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o
> +microchip-isc-common-objs = microchip-isc-base.o microchip-isc-clk.o microchip-isc-scaler.o microchip-isc-stats.o
>
> obj-$(CONFIG_VIDEO_MICROCHIP_ISC_BASE) += microchip-isc-common.o
> obj-$(CONFIG_VIDEO_MICROCHIP_ISC) += microchip-isc.o
> diff --git a/drivers/media/platform/microchip/microchip-isc-stats.c b/drivers/media/platform/microchip/microchip-isc-stats.c
> new file mode 100644
> index 000000000000..d7813c9d95ac
> --- /dev/null
> +++ b/drivers/media/platform/microchip/microchip-isc-stats.c
> @@ -0,0 +1,549 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Microchip ISC Driver - Statistics Subdevice
> + * Raw Histogram Export for Userspace Applications
> + *
> + * Copyright (C) 2025 Microchip Technology Inc.
> + *
> + * Author: Balakrishnan Sambath <balakrishnan.s@microchip.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-vmalloc.h>
> +#include "microchip-isc-regs.h"
> +#include "microchip-isc.h"
> +
> +#define ISC_STATS_DEV_NAME "microchip-isc_stats"
> +#define ISC_STATS_MIN_BUFS 2
> +#define ISC_STATS_MAX_BUFS 8
> +
> +/**
> + * struct isc_stat_buffer - Raw histogram statistics buffer structure
> + * @frame_number: Sequential frame number from capture
> + * @timestamp: Frame capture timestamp in nanoseconds
> + * @meas_type: Bitmask of measurement types available (ISC_CIF_ISP_STAT_*)
> + * @hist: Array of histogram data for each Bayer channel
> + * @hist.hist_bins: Raw 512-bin histogram data from hardware
> + * @hist.hist_min: Minimum pixel value observed in channel
> + * @hist.hist_max: Maximum pixel value observed in channel
> + * @hist.total_pixels: Total number of pixels processed in channel
> + * @valid_channels: Bitmask indicating which Bayer channels contain valid data
> + * @bayer_pattern: Current Bayer pattern configuration (CFA_BAYCFG_*)
> + * @reserved: Padding for future expansion and alignment
> + *
> + * This structure contains raw, unprocessed histogram data from the ISC
> + * hardware for all four Bayer channels (GR, R, GB, B). No algorithmic
> + * processing is performed - data is exported directly from hardware
> + * registers for userspace processing applications.
> + */
> +struct isc_stat_buffer {
> + u32 frame_number;
> + u64 timestamp;
Swap the two fields above to avoid introducing holes due to alignment problems.
> + u32 meas_type;
> +
> + struct {
> + u32 hist_bins[HIST_ENTRIES];
> + u32 hist_min;
> + u32 hist_max;
> + u32 total_pixels;
> + } hist[HIST_BAYER];
> +
> + u8 valid_channels;
> + u8 bayer_pattern;
> + u16 reserved[2];
> +} __packed;
After swapping those two fields you probably can drop __packed, but I'm not certain.
It's probably a good idea to check with the pahole utility if there are no holes in
this structure.
This structure must be part of include/uapi/linux/, probably
include/uapi/linux/media/microchip/something.h
Userspace must have access to this, otherwise it can't parse the metadata. Note
that that also means that the HIST_ENTRIES and HIST_BAYER/ISC_HIS_CFG_MODE_B
defines are in that uapi include as well.
> +
> +/* Statistics measurement type flags */
> +#define ISC_CIF_ISP_STAT_HIST BIT(0)
> +
Regards,
Hans
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (18 preceding siblings ...)
2025-10-09 20:11 ` [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Eugen Hristev
@ 2025-11-10 9:01 ` Hans Verkuil
2025-11-10 9:26 ` Hans Verkuil
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
21 siblings, 0 replies; 65+ messages in thread
From: Hans Verkuil @ 2025-11-10 9:01 UTC (permalink / raw)
To: Balamanikandan Gunasundar, Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
Hi Balamanikandan,
On 09/10/2025 17:52, Balamanikandan Gunasundar wrote:
> Hi,
>
> This patch series has a set of enhancements to the Microchip Image Sensor
> Controller driver. The objective is to expand its image processing
> capabilities and to improve the colors.
>
> This series also introduces a new stats driver that exposes the histogram
> data to userspace via v4l2 controls. This allows applications such as
> libcamera to access real time image statistics for advanced image
> processing like automatic exposure, white balance adjustments etc.
Most of this series is fine, but the histogram part needs more work.
I would recommend splitting up this series in two parts: one for the
various fixes and improvements, and one for the histogram feature.
The first series with the fixes I can take easily. In fact, if you
post that this week (no later than Thursday), then I can pick it
up in time for v6.19.
As mentioned the histogram part needs more work. Mostly small stuff,
but the documentation is the major missing part.
I also want to see the output of 'v4l2-compliance -m0 -s' (i.e.
with streaming) in the cover letter of the histogram series to be
certain nothing was forgotten.
Make sure you compile v4l2-compliance straight from the git repo,
don't use a distro version since that's usually out of date.
Regards,
Hans
>
> Balakrishnan Sambath (11):
> media: microchip-isc: Enable GDC and CBC module flags for RGB formats
> media: microchip-isc: Improve histogram calculation with outlier
> rejection
> media: microchip-isc: Use channel averages for Grey World AWB
> media: microchip-isc: Add range based black level correction
> media: platform: microchip: Extend gamma table and control range
> media: platform: microchip: Add new histogram submodule
> media: microchip-isc: Register and unregister statistics device
> media: microchip-isc: Always enable histogram for all RAW formats
> media: microchip-isc: fix histogram state initialization order
> media: microchip-isc: decouple histogram cycling from AWB mode
> media: microchip-isc: enable userspace histogram statistics export
>
> Balamanikandan Gunasundar (7):
> media: platform: microchip: set maximum resolution for sam9x7
> media: platform: microchip: Include DPC modules flags in pipeline
> media: microchip-isc: expose hue and saturation as v4l2 controls
> media: microchip-isc: Rename CBC to CBHS
> media: microchip-isc: Store histogram data of all channels
> media: videodev2.h, v4l2-ioctl: Add microchip statistics format
> media: microchip-isc: expose color correction registers as v4l2
> controls
>
> drivers/media/platform/microchip/Kconfig | 2 +
> drivers/media/platform/microchip/Makefile | 2 +-
> .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
> .../platform/microchip/microchip-isc-regs.h | 3 +
> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> .../media/platform/microchip/microchip-isc.h | 44 +-
> .../microchip/microchip-sama5d2-isc.c | 2 +-
> .../microchip/microchip-sama7g5-isc.c | 73 ++-
> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> include/linux/atmel-isc-media.h | 13 +
> include/uapi/linux/videodev2.h | 3 +
> 11 files changed, 1001 insertions(+), 64 deletions(-)
> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH 00/18] media: microchip-isc: Color correction and histogram stats
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (19 preceding siblings ...)
2025-11-10 9:01 ` Hans Verkuil
@ 2025-11-10 9:26 ` Hans Verkuil
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
21 siblings, 0 replies; 65+ messages in thread
From: Hans Verkuil @ 2025-11-10 9:26 UTC (permalink / raw)
To: Balamanikandan Gunasundar, Mauro Carvalho Chehab
Cc: Eugen Hristev, Chas Williams, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Balakrishnan Sambath, Hans Verkuil,
Ricardo Ribalda, Laurent Pinchart, Jacopo Mondi, Daniel Scally,
Tomi Valkeinen, linux-kernel, linux-media, linux-atm-general,
netdev, linux-arm-kernel
On 09/10/2025 17:52, Balamanikandan Gunasundar wrote:
> Hi,
>
> This patch series has a set of enhancements to the Microchip Image Sensor
> Controller driver. The objective is to expand its image processing
> capabilities and to improve the colors.
>
> This series also introduces a new stats driver that exposes the histogram
> data to userspace via v4l2 controls. This allows applications such as
> libcamera to access real time image statistics for advanced image
> processing like automatic exposure, white balance adjustments etc.
Note that bisect of this series failed: some patches seem to have dependencies
on later patches, which is obviously wrong. Make sure you double check that
for v2.
The documentation also fails to build since there is no documentation for the
new meta format, but I already commented on that.
Regards,
Hans
>
> Balakrishnan Sambath (11):
> media: microchip-isc: Enable GDC and CBC module flags for RGB formats
> media: microchip-isc: Improve histogram calculation with outlier
> rejection
> media: microchip-isc: Use channel averages for Grey World AWB
> media: microchip-isc: Add range based black level correction
> media: platform: microchip: Extend gamma table and control range
> media: platform: microchip: Add new histogram submodule
> media: microchip-isc: Register and unregister statistics device
> media: microchip-isc: Always enable histogram for all RAW formats
> media: microchip-isc: fix histogram state initialization order
> media: microchip-isc: decouple histogram cycling from AWB mode
> media: microchip-isc: enable userspace histogram statistics export
>
> Balamanikandan Gunasundar (7):
> media: platform: microchip: set maximum resolution for sam9x7
> media: platform: microchip: Include DPC modules flags in pipeline
> media: microchip-isc: expose hue and saturation as v4l2 controls
> media: microchip-isc: Rename CBC to CBHS
> media: microchip-isc: Store histogram data of all channels
> media: videodev2.h, v4l2-ioctl: Add microchip statistics format
> media: microchip-isc: expose color correction registers as v4l2
> controls
>
> drivers/media/platform/microchip/Kconfig | 2 +
> drivers/media/platform/microchip/Makefile | 2 +-
> .../platform/microchip/microchip-isc-base.c | 373 ++++++++++--
> .../platform/microchip/microchip-isc-regs.h | 3 +
> .../platform/microchip/microchip-isc-stats.c | 549 ++++++++++++++++++
> .../media/platform/microchip/microchip-isc.h | 44 +-
> .../microchip/microchip-sama5d2-isc.c | 2 +-
> .../microchip/microchip-sama7g5-isc.c | 73 ++-
> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> include/linux/atmel-isc-media.h | 13 +
> include/uapi/linux/videodev2.h | 3 +
> 11 files changed, 1001 insertions(+), 64 deletions(-)
> create mode 100644 drivers/media/platform/microchip/microchip-isc-stats.c
>
^ permalink raw reply [flat|nested] 65+ messages in thread
* [PATCH v2 00/15] media: microchip-isc: fixes and enhancements
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
` (20 preceding siblings ...)
2025-11-10 9:26 ` Hans Verkuil
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
` (15 more replies)
21 siblings, 16 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
Bug fixes and feature additions for the Microchip ISC/XISC driver.
Fixes:
- SBGGR10 Bayer pattern was mapped incorrectly (red/blue swap)
- WB register fields corrupted by sign extension
- Race between histogram IRQ and stream stop
- PM runtime reference leak in AWB work handler
Features:
- Driver documentation
- Gamma 1.8/2.4 curves, per-channel gamma LUT
- Hue/saturation controls for SAMA7G5
- Color correction matrix controls
- Grey World AWB with EMA smoothing
Split from v1 per review. Histogram stats follow as Series 2.
Tested on SAMA7G5-EK with IMX219 (RAW10 Bayer capture, AWB, color
controls verified). Build tested with COMPILE_TEST and W=1. All
patches pass checkpatch --strict.
Based on v6.19-rc8 (18f7fcd5e69a).
v1: https://lore.kernel.org/linux-media/20251009155251.102472-1-balamanikandan.gunasundar@microchip.com/
v2:
- Split series (histogram stats moved to Series 2)
- Bug fixes first, then features
- New fixes and features as listed above
- Commit message cleanups
- Rebased on v6.19-rc8
Balakrishnan Sambath (15):
media: microchip-isc: fix SBGGR10 Bayer pattern
media: microchip-isc: mask WB offset and gain register fields
media: microchip-isc: fix race condition on stream stop
media: microchip-isc: fix PM runtime leak in AWB work handler
media: microchip-isc: add driver documentation
media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920
media: microchip-isc: configure DPC and pipeline for SAMA7G5
media: microchip-isc: add gamma 1.8 and 2.4 correction curves
media: microchip-isc: add SAMA7G5 hue and saturation controls
media: microchip-isc: expose color correction matrix as V4L2 controls
media: microchip-isc: add per-channel gamma LUT controls
media: microchip-isc: reset pipeline state on kernel AWB enable
media: microchip-isc: use weighted averages for Grey World AWB
media: microchip-isc: smooth AWB gains with EMA filter
media: microchip-isc: scale DPC black level to sensor bit depth
.../userspace-api/media/drivers/index.rst | 1 +
.../media/drivers/microchip-isc.rst | 71 ++
MAINTAINERS | 1 +
.../platform/microchip/microchip-isc-base.c | 730 ++++++++++++++++--
.../platform/microchip/microchip-isc-regs.h | 11 +-
.../media/platform/microchip/microchip-isc.h | 56 +-
.../microchip/microchip-sama5d2-isc.c | 2 +-
.../microchip/microchip-sama7g5-isc.c | 101 ++-
include/linux/atmel-isc-media.h | 31 +
9 files changed, 896 insertions(+), 108 deletions(-)
create mode 100644 Documentation/userspace-api/media/drivers/microchip-isc.rst
--
2.34.1
^ permalink raw reply [flat|nested] 65+ messages in thread
* [PATCH v2 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 02/15] media: microchip-isc: mask WB offset and gain register fields Balakrishnan Sambath
` (14 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
stable
SBGGR10 was mapped to ISC_BAY_CFG_RGRG instead of ISC_BAY_CFG_BGBG,
causing red/blue channel swap.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-sama7g5-isc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index b0302dfc3278..ca23e8adecbd 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -156,7 +156,7 @@ static struct isc_format sama7g5_formats_list[] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
},
{
.fourcc = V4L2_PIX_FMT_SGBRG10,
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 02/15] media: microchip-isc: mask WB offset and gain register fields
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 03/15] media: microchip-isc: fix race condition on stream stop Balakrishnan Sambath
` (13 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
stable
ISC_WB_O_* and ISC_WB_G_* pack two 13-bit fields per register. Sign
extension from negative offsets corrupts the upper field. Mask both
fields to 13 bits before packing.
Fixes: 3308bec11098 ("at91: isc: integrate pipeline")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 21 ++++++++++++-------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index a7cdc743fda7..45b94f1e89d8 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -61,18 +61,23 @@ static inline void isc_update_awb_ctrls(struct isc_device *isc)
/* In here we set our actual hw pipeline config */
+ /*
+ * Mask offset fields to 13 bits. Sign extension of negative s32
+ * values would otherwise corrupt the adjacent field.
+ */
regmap_write(isc->regmap, ISC_WB_O_RGR,
- ((ctrls->offset[ISC_HIS_CFG_MODE_R])) |
- ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
+ ((u32)ctrls->offset[ISC_HIS_CFG_MODE_R] & GENMASK(12, 0)) |
+ (((u32)ctrls->offset[ISC_HIS_CFG_MODE_GR] & GENMASK(12, 0)) << 16));
regmap_write(isc->regmap, ISC_WB_O_BGB,
- ((ctrls->offset[ISC_HIS_CFG_MODE_B])) |
- ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16));
+ ((u32)ctrls->offset[ISC_HIS_CFG_MODE_B] & GENMASK(12, 0)) |
+ (((u32)ctrls->offset[ISC_HIS_CFG_MODE_GB] & GENMASK(12, 0)) << 16));
+ /* Gains are 13-bit unsigned fields [12:0] and [28:16] */
regmap_write(isc->regmap, ISC_WB_G_RGR,
- ctrls->gain[ISC_HIS_CFG_MODE_R] |
- (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16));
+ (ctrls->gain[ISC_HIS_CFG_MODE_R] & GENMASK(12, 0)) |
+ ((ctrls->gain[ISC_HIS_CFG_MODE_GR] & GENMASK(12, 0)) << 16));
regmap_write(isc->regmap, ISC_WB_G_BGB,
- ctrls->gain[ISC_HIS_CFG_MODE_B] |
- (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16));
+ (ctrls->gain[ISC_HIS_CFG_MODE_B] & GENMASK(12, 0)) |
+ ((ctrls->gain[ISC_HIS_CFG_MODE_GB] & GENMASK(12, 0)) << 16));
}
static inline void isc_reset_awb_ctrls(struct isc_device *isc)
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 03/15] media: microchip-isc: fix race condition on stream stop
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 02/15] media: microchip-isc: mask WB offset and gain register fields Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler Balakrishnan Sambath
` (12 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
stable
Disable histogram and drain AWB work queue before releasing DMA
buffers to prevent use-after-free if histogram IRQ fires during
stream stop.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 45b94f1e89d8..b19c5a63b4bd 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -427,6 +427,14 @@ static void isc_stop_streaming(struct vb2_queue *vq)
mutex_unlock(&isc->awb_mutex);
+ /*
+ * Disable the histogram so the ISR stops firing HISREQ, then drain
+ * any work that was already queued before returning. This must happen
+ * after releasing awb_mutex because isc_awb_work also takes it.
+ */
+ isc_set_histogram(isc, false);
+ cancel_work_sync(&isc->awb_work);
+
/* Disable DMA interrupt */
regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
@@ -1519,10 +1527,17 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
}
mutex_unlock(&isc->awb_mutex);
- /* if we have autowhitebalance on, start histogram procedure */
+ /*
+ * If AWB auto mode is requested and we are streaming RAW,
+ * start the histogram procedure, but only if it is not
+ * already running. Repeated enable requests would reset
+ * hist_id, preventing the 4-channel Bayer cycle from
+ * completing.
+ */
if (ctrls->awb == ISC_WB_AUTO &&
vb2_is_streaming(&isc->vb2_vidq) &&
- ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code) &&
+ ctrls->hist_stat != HIST_ENABLED)
isc_set_histogram(isc, true);
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (2 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 03/15] media: microchip-isc: fix race condition on stream stop Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 05/15] media: microchip-isc: add driver documentation Balakrishnan Sambath
` (11 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
stable
Early return when streaming stops skips pm_runtime_put_sync(),
leaking the reference and preventing runtime suspend.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index b19c5a63b4bd..f61a5d5a3e04 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1429,7 +1429,7 @@ static void isc_awb_work(struct work_struct *w)
/* streaming is not active anymore */
if (isc->stop) {
mutex_unlock(&isc->awb_mutex);
- return;
+ goto out_pm_put;
}
isc_update_profile(isc);
@@ -1440,6 +1440,7 @@ static void isc_awb_work(struct work_struct *w)
if (ctrls->awb)
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+out_pm_put:
pm_runtime_put_sync(isc->dev);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 05/15] media: microchip-isc: add driver documentation
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (3 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920 Balakrishnan Sambath
` (10 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
Document V4L2 controls and pipeline modes for ISC/XISC camera interface
on SAMA5D2, SAMA7G5, and SAM9X7.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../userspace-api/media/drivers/index.rst | 1 +
.../media/drivers/microchip-isc.rst | 71 +++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 73 insertions(+)
create mode 100644 Documentation/userspace-api/media/drivers/microchip-isc.rst
diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index 02967c9b18d6..65ef6ba3523e 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -34,6 +34,7 @@ For more details see the file COPYING in the source distribution of Linux.
imx-uapi
mali-c55
max2175
+ microchip-isc
npcm-video
omap3isp-uapi
thp7312
diff --git a/Documentation/userspace-api/media/drivers/microchip-isc.rst b/Documentation/userspace-api/media/drivers/microchip-isc.rst
new file mode 100644
index 000000000000..2a436fd19272
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/microchip-isc.rst
@@ -0,0 +1,71 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Microchip ISC/XISC Driver
+=========================
+
+The Image Sensor Controller (ISC) on SAMA5D2 and eXtended ISC (XISC) on
+SAMA7G5/SAM9X7 provide camera capture with hardware image processing.
+
+Supported Hardware
+------------------
+
+========== ========== ============== ================ ===============
+SoC Controller Max Resolution Interface Hue/Saturation
+========== ========== ============== ================ ===============
+SAMA5D2 ISC 2592x1944 12-bit parallel No
+SAMA7G5 XISC 3264x2464 12-bit + CSI-2 Yes
+SAM9X7 XISC 2560x1920 12-bit + CSI-2 Yes
+========== ========== ============== ================ ===============
+
+SAM9X7 shares the XISC pipeline with SAMA7G5 but has a smaller internal
+line buffer, limiting horizontal resolution to 2560 pixels.
+
+Controls
+--------
+
+Standard V4L2 controls:
+
+* ``V4L2_CID_BRIGHTNESS``: -1024..1023, default 0
+* ``V4L2_CID_CONTRAST``: -2048..2047, default 256 (1.0x)
+* ``V4L2_CID_GAMMA``: 0..2 selects curve (0=2.4, 1=2.2, 2=1.8)
+* ``V4L2_CID_AUTO_WHITE_BALANCE``: Enable kernel Grey World AWB
+* ``V4L2_CID_DO_WHITE_BALANCE``: Trigger one-shot AWB
+
+SAMA7G5/SAM9X7 add:
+
+* ``V4L2_CID_HUE``: -180..180 degrees
+* ``V4L2_CID_SATURATION``: 0..255, default 16
+
+Custom controls (defined in ``atmel-isc-media.h``):
+
+* ``ISC_CID_R_GAIN``, ``ISC_CID_B_GAIN``, ``ISC_CID_GR_GAIN``,
+ ``ISC_CID_GB_GAIN``: WB gains, 0..8191, Q2.9 (512 = 1.0x)
+* ``ISC_CID_R_OFFSET``, ``ISC_CID_B_OFFSET``, ``ISC_CID_GR_OFFSET``,
+ ``ISC_CID_GB_OFFSET``: WB offsets, -4096..4095
+* ``ISC_CID_CC_RR`` ... ``ISC_CID_CC_BB``: 3x3 color correction matrix,
+ signed Q4.8 (256 = 1.0)
+* ``ISC_CID_CC_OR``, ``ISC_CID_CC_OG``, ``ISC_CID_CC_OB``: RGB offsets
+* ``ISC_CID_GAMMA_R_LUT``, ``ISC_CID_GAMMA_G_LUT``,
+ ``ISC_CID_GAMMA_B_LUT``: Per-channel gamma LUTs, 64-entry arrays
+
+Pipeline
+--------
+
+Pipeline modules: DPC -> WB -> CFA -> CC -> GAM -> CBHS/CBC -> CSC -> SUB
+
+* DPC: Defective Pixel Correction (XISC only), black level subtraction
+ to sensor bit depth, green disparity correction
+* WB: White Balance gains/offsets
+* CFA: Color Filter Array interpolation (demosaic)
+* CC: Color Correction matrix
+* GAM: Gamma correction (preset or per-channel LUT)
+* CBHS: Contrast/Brightness/Hue/Saturation (XISC only)
+* CBC: Contrast/Brightness (ISC only)
+* CSC: Color Space Conversion (RGB to YCbCr)
+* SUB: Chroma subsampling (4:2:2, 4:2:0)
+
+Pipeline usage depends on input and output formats:
+
+* Raw Bayer input, RGB output: DPC, WB, CFA, CC, GAM
+* Raw Bayer input, YUV output: Full pipeline including CSC, CBHS/CBC, SUB
+* Non-RAW input (YUV/RGB sensor): Pipeline bypassed
diff --git a/MAINTAINERS b/MAINTAINERS
index 0efa8cc6775b..fe5c3bb03e60 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17052,6 +17052,7 @@ L: linux-media@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/media/atmel,isc.yaml
F: Documentation/devicetree/bindings/media/microchip,xisc.yaml
+F: Documentation/userspace-api/media/drivers/microchip-isc.rst
F: drivers/media/platform/microchip/microchip-isc*
F: drivers/media/platform/microchip/microchip-sama*-isc*
F: drivers/staging/media/deprecated/atmel/atmel-isc*
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (4 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 05/15] media: microchip-isc: add driver documentation Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5 Balakrishnan Sambath
` (9 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
SAM9X7 XISC uses the same image processing pipeline as SAMA7G5 but has
a smaller internal line buffer. The reduced RAM constrains the maximum
horizontal resolution to 2560 pixels (compared to 3264 on SAMA7G5),
resulting in a maximum capture resolution of 2560x1920.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../media/platform/microchip/microchip-sama7g5-isc.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index ca23e8adecbd..4119cfe12cdf 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -55,6 +55,9 @@
#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH 3264
#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
+#define ISC_SAM9X7_MAX_SUPPORT_WIDTH 2560
+#define ISC_SAM9X7_MAX_SUPPORT_HEIGHT 1920
+
#define ISC_SAMA7G5_PIPELINE \
(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
@@ -432,8 +435,13 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 0;
- isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
- isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+ if (of_machine_is_compatible("microchip,sam9x7")) {
+ isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAM9X7_MAX_SUPPORT_HEIGHT;
+ } else {
+ isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+ }
isc->config_dpc = isc_sama7g5_config_dpc;
isc->config_csc = isc_sama7g5_config_csc;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (5 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920 Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves Balakrishnan Sambath
` (8 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
Enable DPC_GDCENABLE for RGB output. Disable pipeline for raw Bayer
passthrough to provide unmodified sensor data for software ISP.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 7 ++-----
drivers/media/platform/microchip/microchip-sama7g5-isc.c | 3 ++-
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index f61a5d5a3e04..23a09ed12946 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -800,7 +800,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
- CC_ENABLE;
+ DPC_GDCENABLE | CC_ENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -850,10 +850,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
}
break;
default:
- if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
- isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
- else
- isc->try_config.bits_pipeline = 0x0;
+ isc->try_config.bits_pipeline = 0x0;
}
/* Tune the pipeline to product specific */
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 4119cfe12cdf..04930aa0f289 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -59,7 +59,8 @@
#define ISC_SAM9X7_MAX_SUPPORT_HEIGHT 1920
#define ISC_SAMA7G5_PIPELINE \
- (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ (DPC_DPCENABLE | DPC_GDCENABLE | DPC_BLCENABLE | \
+ WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (6 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5 Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls Balakrishnan Sambath
` (7 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
Add gamma 1.8 and 2.4 curves alongside the existing 2.2 (sRGB).
V4L2_CID_GAMMA selects preset curves: 0=2.4, 1=2.2, 2=1.8.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 3 +-
.../microchip/microchip-sama7g5-isc.c | 54 ++++++++++++++-----
2 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 23a09ed12946..ae2a0c6ba566 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1647,8 +1647,7 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->brightness = 0;
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
- isc->gamma_max);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1, 1);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
0, 1, 1, 1);
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 04930aa0f289..8b73b625d92b 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -320,21 +320,47 @@ static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
}
-/* Gamma table with gamma 1/2.2 */
+/* Gamma tables with gamma values 0.42, 0.45(Default), 0.56 */
static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
- /* index 0 --> gamma bipartite */
+ /* index 0 --> gamma bipartite 1/2.4(=0.42) */
{
- 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
- 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
- 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
- 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
- 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
- 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
- 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
- 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
- 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
- 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
- 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+ 0x940, 0x4b0310, 0x630250, 0x7601d0, 0x840190, 0x910170,
+ 0x9d0150, 0xa80110, 0xb10110, 0xba0110, 0xc300f0, 0xcb00f0,
+ 0xd300e0, 0xda00e0, 0xe100c0, 0xe800c0, 0xee00c0, 0xf400c0,
+ 0xfa00a0, 0x10000a0, 0x10500a0, 0x10b00a0, 0x11000a0, 0x11500a0,
+ 0x11a0080, 0x11f0080, 0x1240080, 0x1290080, 0x12e0080, 0x1330070,
+ 0x1380070, 0x13c0070, 0x1410070, 0x17a0060, 0x1aa0052, 0x1d40046,
+ 0x1f90042, 0x21b003c, 0x23a0038, 0x2570034, 0x2720030, 0x28b002e,
+ 0x2a3002c, 0x2ba002a, 0x2d0002a, 0x2e60028, 0x2fa0026, 0x30e0026,
+ 0x3210024, 0x3330022, 0x3450022, 0x3560020, 0x3670020, 0x3770020,
+ 0x387001e, 0x396001e, 0x3a5001c, 0x3b3001c, 0x3c1001c, 0x3cf001a,
+ 0x3dd001a, 0x3eb0018, 0x3f90018, 0x4070016 },
+ /* index 1 --> gamma bipartite 1/2.2(=0.45) */
+ {
+ 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
+ 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
+ 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
+ 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
+ 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
+ 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
+ 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
+ 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
+ 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
+ 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
+ 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+ /* index 2 --> gamma bipartite 1/1.8(=0.56) */
+ {
+ 0xa62, 0x4f0350, 0x680280, 0x7e0200, 0x8d01c0, 0x9a01a0,
+ 0xa50180, 0xb00140, 0xb90140, 0xc20120, 0xcb0120, 0xd30100,
+ 0xdb0100, 0xe300e0, 0xea00e0, 0xf100e0, 0xf700c0, 0xfd00c0,
+ 0x10300c0, 0x10900a0, 0x10e00a0, 0x11400a0, 0x11900a0, 0x11e00a0,
+ 0x12300a0, 0x12800a0, 0x12d0080, 0x1320080, 0x1370080, 0x13c0080,
+ 0x1410080, 0x1460080, 0x14a0070, 0x1830060, 0x1b40052, 0x1df0048,
+ 0x2040042, 0x2250040, 0x2440038, 0x2600036, 0x27b0032, 0x2940030,
+ 0x2ac002e, 0x2c4002c, 0x2da002a, 0x2f0002a, 0x3050028, 0x3190026,
+ 0x32c0026, 0x33e0024, 0x3500024, 0x3610022, 0x3720020, 0x3820020,
+ 0x3920020, 0x3a2001e, 0x3b1001e, 0x3c0001c, 0x3ce001c, 0x3dc001c,
+ 0x3ea001a, 0x3f8001a, 0x4060018, 0x4130018 },
};
static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
@@ -434,7 +460,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
}
isc->gamma_table = isc_sama7g5_gamma_table;
- isc->gamma_max = 0;
+ isc->gamma_max = 2;
if (of_machine_is_compatible("microchip,sam9x7")) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (7 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls Balakrishnan Sambath
` (6 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
SAMA7G5 extends CBC with hue and saturation. Add V4L2_CID_HUE and
V4L2_CID_SATURATION controls. Disable CBHS for RGB output since it
operates in YCbCr domain.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 86 ++++++++++++++++++-
.../platform/microchip/microchip-isc-regs.h | 11 ++-
.../media/platform/microchip/microchip-isc.h | 5 +-
.../microchip/microchip-sama5d2-isc.c | 2 +-
.../microchip/microchip-sama7g5-isc.c | 8 +-
5 files changed, 98 insertions(+), 14 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index ae2a0c6ba566..7e140af51912 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -810,7 +810,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
- SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
+ SUB420_ENABLE | SUB422_ENABLE | CBHS_ENABLE |
DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
@@ -821,7 +821,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ SUB422_ENABLE | CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -833,7 +833,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ SUB422_ENABLE | CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -844,7 +844,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- CBC_ENABLE | DPC_BLCENABLE;
+ CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -859,6 +859,56 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
return 0;
}
+static bool isc_format_has_chroma(u32 fourcc)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * isc_update_cbc_ctrl_activity() - Activate/deactivate CBC controls
+ *
+ * Called from isc_set_fmt(), isc_link_validate(), and isc_ctrl_init().
+ * At isc_ctrl_init() time isc->config.bits_pipeline is zero (no format
+ * has been negotiated yet), so all CBC controls are initially marked
+ * inactive. They become active once a format that includes CBHS in the
+ * pipeline is configured via VIDIOC_S_FMT or link validation.
+ */
+static void isc_update_cbc_ctrl_activity(struct isc_device *isc)
+{
+ struct v4l2_ctrl_handler *hdl = &isc->ctrls.handler;
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *hue;
+ struct v4l2_ctrl *saturation;
+ bool cbc_active = isc->config.bits_pipeline & CBHS_ENABLE;
+ bool chroma_active = cbc_active && isc_format_has_chroma(isc->config.fourcc);
+
+ brightness = v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS);
+ if (brightness)
+ v4l2_ctrl_activate(brightness, cbc_active);
+
+ contrast = v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST);
+ if (contrast)
+ v4l2_ctrl_activate(contrast, cbc_active);
+
+ hue = v4l2_ctrl_find(hdl, V4L2_CID_HUE);
+ if (hue)
+ v4l2_ctrl_activate(hue, chroma_active);
+
+ saturation = v4l2_ctrl_find(hdl, V4L2_CID_SATURATION);
+ if (saturation)
+ v4l2_ctrl_activate(saturation, chroma_active);
+}
+
static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f)
{
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
@@ -902,6 +952,7 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
/* make the try configuration active */
isc->config = isc->try_config;
isc->fmt = isc->try_fmt;
+ isc_update_cbc_ctrl_activity(isc);
dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n",
(char *)&f->fmt.pix.pixelformat,
@@ -989,6 +1040,7 @@ static int isc_link_validate(struct media_link *link)
return ret;
isc->config = isc->try_config;
+ isc_update_cbc_ctrl_activity(isc);
dev_dbg(isc->dev, "New ISC configuration in place\n");
@@ -1453,9 +1505,30 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, ctrls->brightness);
break;
case V4L2_CID_CONTRAST:
ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, ctrls->contrast);
+ break;
+ case V4L2_CID_HUE:
+ if (isc->has_cbhs) {
+ ctrls->hue = ctrl->val & ISC_CBHS_HUE_MASK;
+ regmap_write(regmap, ISC_CBHS_HUE, ctrls->hue);
+ }
+ break;
+ case V4L2_CID_SATURATION:
+ if (isc->has_cbhs) {
+ /*
+ * The ISC CBHS SAT register holds a Q4 fixed-point
+ * coefficient: 0 = grayscale, 16 = 1.0 (no change),
+ * values above 16 boost saturation. The V4L2 range
+ * 0-100 (default 16) maps directly to this hardware
+ * value; no unit conversion is applied.
+ */
+ ctrls->saturation = ctrl->val & ISC_CBHS_SAT_MASK;
+ regmap_write(regmap, ISC_CBHS_SAT, ctrls->saturation);
+ }
break;
case V4L2_CID_GAMMA:
ctrls->gamma_index = ctrl->val;
@@ -1647,6 +1720,10 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->brightness = 0;
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
+ if (isc->has_cbhs) {
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, -180, 180, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 0, 100, 1, 16);
+ }
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1, 1);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
@@ -1664,6 +1741,7 @@ static int isc_ctrl_init(struct isc_device *isc)
}
v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+ isc_update_cbc_ctrl_activity(isc);
isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
diff --git a/drivers/media/platform/microchip/microchip-isc-regs.h b/drivers/media/platform/microchip/microchip-isc-regs.h
index e77e1d9a1db8..2fd8916abf21 100644
--- a/drivers/media/platform/microchip/microchip-isc-regs.h
+++ b/drivers/media/platform/microchip/microchip-isc-regs.h
@@ -268,10 +268,13 @@
#define ISC_CBC_CONTRAST 0x000003c0
#define ISC_CBC_CONTRAST_MASK GENMASK(11, 0)
-/* Hue Register */
-#define ISC_CBCHS_HUE 0x4e0
-/* Saturation Register */
-#define ISC_CBCHS_SAT 0x4e4
+/* Hue Register: signed 9-bit two's complement, covers -180 to +180 degrees */
+#define ISC_CBHS_HUE 0x4e0
+#define ISC_CBHS_HUE_MASK GENMASK(8, 0)
+
+/* Saturation Register: unsigned Q4 fixed-point (1.0 = 16, V4L2 range 0-100) */
+#define ISC_CBHS_SAT 0x4e4
+#define ISC_CBHS_SAT_MASK GENMASK(6, 0)
/* Offset for SUB422 register specific to sama5d2 product */
#define ISC_SAMA5D2_SUB422_OFFSET 0
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index ad4e98a1dd8f..2c8bcaaa26ea 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -88,7 +88,7 @@ struct isc_format {
#define GAM_RENABLE BIT(9)
#define VHXS_ENABLE BIT(10)
#define CSC_ENABLE BIT(11)
-#define CBC_ENABLE BIT(12)
+#define CBHS_ENABLE BIT(12)
#define SUB422_ENABLE BIT(13)
#define SUB420_ENABLE BIT(14)
@@ -139,6 +139,8 @@ struct isc_ctrls {
u32 brightness;
u32 contrast;
+ u32 hue;
+ u32 saturation;
u8 gamma_index;
#define ISC_WB_NONE 0
#define ISC_WB_AUTO 1
@@ -342,6 +344,7 @@ struct isc_device {
/* pointer to the defined gamma table */
const u32 (*gamma_table)[GAMMA_ENTRIES];
u32 gamma_max;
+ bool has_cbhs;
u32 max_width;
u32 max_height;
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index 66d3d7891991..239aac170472 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -54,7 +54,7 @@
#define ISC_SAMA5D2_PIPELINE \
(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
- CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+ CBHS_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
static const struct isc_format sama5d2_controller_formats[] = {
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 8b73b625d92b..6705011edc2a 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -61,7 +61,7 @@
#define ISC_SAMA7G5_PIPELINE \
(DPC_DPCENABLE | DPC_GDCENABLE | DPC_BLCENABLE | \
WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
- CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+ CBHS_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
static const struct isc_format sama7g5_controller_formats[] = {
@@ -257,9 +257,8 @@ static void isc_sama7g5_config_cbc(struct isc_device *isc)
/* Configure what is set via v4l2 ctrls */
regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
- /* Configure Hue and Saturation as neutral midpoint */
- regmap_write(regmap, ISC_CBCHS_HUE, 0);
- regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
+ regmap_write(regmap, ISC_CBHS_HUE, isc->ctrls.hue);
+ regmap_write(regmap, ISC_CBHS_SAT, isc->ctrls.saturation);
}
static void isc_sama7g5_config_cc(struct isc_device *isc)
@@ -461,6 +460,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 2;
+ isc->has_cbhs = true;
if (of_machine_is_compatible("microchip,sam9x7")) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (8 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
` (5 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media
Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
Add custom controls for 3x3 color correction matrix and RGB offsets.
Used by libcamera IPA for sensor color calibration.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 247 +++++++++++++++++-
.../media/platform/microchip/microchip-isc.h | 23 ++
include/linux/atmel-isc-media.h | 13 +
3 files changed, 281 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 7e140af51912..f78145820e40 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -32,7 +32,7 @@
#include "microchip-isc-regs.h"
#include "microchip-isc.h"
-#define ISC_IS_FORMAT_RAW(mbus_code) \
+#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
#define ISC_IS_FORMAT_GREY(mbus_code) \
@@ -55,6 +55,46 @@ static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GB]);
}
+static void isc_apply_gamma(struct isc_device *isc);
+
+/* commit CC shadow to hardware; called while ISC is powered */
+static void isc_update_cc_ctrls(struct isc_device *isc)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct regmap *regmap = isc->regmap;
+ u32 m = GENMASK(11, 0);
+
+ if (!ctrls->cc_dirty)
+ return;
+
+ regmap_update_bits(regmap, ISC_CC_RR_RG, m,
+ (u32)ctrls->cc_coeff[0] & m);
+ regmap_update_bits(regmap, ISC_CC_RR_RG, GENMASK(27, 16),
+ ((u32)ctrls->cc_coeff[1] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_RB_OR, m,
+ (u32)ctrls->cc_coeff[2] & m);
+ regmap_update_bits(regmap, ISC_CC_RB_OR, GENMASK(27, 16),
+ ((u32)ctrls->cc_offset[0] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_GR_GG, m,
+ (u32)ctrls->cc_coeff[3] & m);
+ regmap_update_bits(regmap, ISC_CC_GR_GG, GENMASK(27, 16),
+ ((u32)ctrls->cc_coeff[4] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_GB_OG, m,
+ (u32)ctrls->cc_coeff[5] & m);
+ regmap_update_bits(regmap, ISC_CC_GB_OG, GENMASK(27, 16),
+ ((u32)ctrls->cc_offset[1] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_BR_BG, m,
+ (u32)ctrls->cc_coeff[6] & m);
+ regmap_update_bits(regmap, ISC_CC_BR_BG, GENMASK(27, 16),
+ ((u32)ctrls->cc_coeff[7] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_BB_OB, m,
+ (u32)ctrls->cc_coeff[8] & m);
+ regmap_update_bits(regmap, ISC_CC_BB_OB, GENMASK(27, 16),
+ ((u32)ctrls->cc_offset[2] & m) << 16);
+
+ ctrls->cc_dirty = false;
+}
+
static inline void isc_update_awb_ctrls(struct isc_device *isc)
{
struct isc_ctrls *ctrls = &isc->ctrls;
@@ -90,6 +130,14 @@ static inline void isc_reset_awb_ctrls(struct isc_device *isc)
/* offsets are in 2's complements */
isc->ctrls.offset[c] = 0;
}
+
+ /* identity matrix: diagonal = 1.0 in Q4.8 = 256, off-diagonal = 0 */
+ memset(isc->ctrls.cc_coeff, 0, sizeof(isc->ctrls.cc_coeff));
+ isc->ctrls.cc_coeff[0] = 256; /* RR */
+ isc->ctrls.cc_coeff[4] = 256; /* GG */
+ isc->ctrls.cc_coeff[8] = 256; /* BB */
+ memset(isc->ctrls.cc_offset, 0, sizeof(isc->ctrls.cc_offset));
+ isc->ctrls.cc_dirty = false;
}
static int isc_queue_setup(struct vb2_queue *vq,
@@ -235,7 +283,8 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
isc->config_dpc(isc);
isc->config_csc(isc);
isc->config_cbc(isc);
- isc->config_cc(isc);
+ /* use shadow; config_cc() always resets to identity */
+ isc_update_cc_ctrls(isc);
isc->config_gam(isc);
}
@@ -1481,6 +1530,8 @@ static void isc_awb_work(struct work_struct *w)
goto out_pm_put;
}
+ /* write pending CC matrix from shadow to hardware registers */
+ isc_update_cc_ctrls(isc);
isc_update_profile(isc);
mutex_unlock(&isc->awb_mutex);
@@ -1659,6 +1710,161 @@ static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int isc_cc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ /*
+ * CC registers need pm_runtime active for access.
+ * Store to shadow here; isc_update_cc_ctrls() writes to hardware
+ * from isc_awb_work() where ISC is powered.
+ */
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ ctrls->cc_coeff[0] = ctrl->val;
+ break;
+ case ISC_CID_CC_RG:
+ ctrls->cc_coeff[1] = ctrl->val;
+ break;
+ case ISC_CID_CC_RB:
+ ctrls->cc_coeff[2] = ctrl->val;
+ break;
+ case ISC_CID_CC_OR:
+ ctrls->cc_offset[0] = ctrl->val;
+ break;
+ case ISC_CID_CC_GR:
+ ctrls->cc_coeff[3] = ctrl->val;
+ break;
+ case ISC_CID_CC_GG:
+ ctrls->cc_coeff[4] = ctrl->val;
+ break;
+ case ISC_CID_CC_GB:
+ ctrls->cc_coeff[5] = ctrl->val;
+ break;
+ case ISC_CID_CC_OG:
+ ctrls->cc_offset[1] = ctrl->val;
+ break;
+ case ISC_CID_CC_BR:
+ ctrls->cc_coeff[6] = ctrl->val;
+ break;
+ case ISC_CID_CC_BG:
+ ctrls->cc_coeff[7] = ctrl->val;
+ break;
+ case ISC_CID_CC_BB:
+ ctrls->cc_coeff[8] = ctrl->val;
+ break;
+ case ISC_CID_CC_OB:
+ ctrls->cc_offset[2] = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ctrls->cc_dirty = true;
+ return 0;
+}
+
+static int isc_cc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct regmap *regmap = isc->regmap;
+ unsigned int reg;
+
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_RG:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_RB:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OR:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GR:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_GG:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GB:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OG:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BR:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_BG:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_cc_ops = {
+ .s_ctrl = isc_cc_s_ctrl,
+ .g_volatile_ctrl = isc_cc_g_volatile_ctrl,
+};
+
+#define ISC_CTRL_CC(_name, _id, _name_str, _def) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_cc_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .flags = V4L2_CTRL_FLAG_SLIDER | V4L2_CTRL_FLAG_VOLATILE | \
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, \
+ .min = -2048, \
+ .max = 2047, \
+ .step = 1, \
+ .def = _def, \
+ }
+
+ISC_CTRL_CC(isc_cc_rr_ctrl, ISC_CID_CC_RR, "CC RR", 256);
+ISC_CTRL_CC(isc_cc_rg_ctrl, ISC_CID_CC_RG, "CC RG", 0);
+ISC_CTRL_CC(isc_cc_rb_ctrl, ISC_CID_CC_RB, "CC RB", 0);
+ISC_CTRL_CC(isc_cc_or_ctrl, ISC_CID_CC_OR, "CC OR", 0);
+ISC_CTRL_CC(isc_cc_gr_ctrl, ISC_CID_CC_GR, "CC GR", 0);
+ISC_CTRL_CC(isc_cc_gg_ctrl, ISC_CID_CC_GG, "CC GG", 256);
+ISC_CTRL_CC(isc_cc_gb_ctrl, ISC_CID_CC_GB, "CC GB", 0);
+ISC_CTRL_CC(isc_cc_og_ctrl, ISC_CID_CC_OG, "CC OG", 0);
+ISC_CTRL_CC(isc_cc_br_ctrl, ISC_CID_CC_BR, "CC BR", 0);
+ISC_CTRL_CC(isc_cc_bg_ctrl, ISC_CID_CC_BG, "CC BG", 0);
+ISC_CTRL_CC(isc_cc_bb_ctrl, ISC_CID_CC_BB, "CC BB", 256);
+ISC_CTRL_CC(isc_cc_ob_ctrl, ISC_CID_CC_OB, "CC OB", 0);
+
static const struct v4l2_ctrl_ops isc_awb_ops = {
.s_ctrl = isc_s_awb_ctrl,
.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
@@ -1700,6 +1906,29 @@ ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
+/*
+ * Per-channel gamma LUT controls (64-element U32 arrays, range 0-1023).
+ * Setting any of these activates the custom tone curve and overrides the
+ * preset V4L2_CID_GAMMA curve. One macro expands to a static v4l2_ctrl_config.
+ */
+#define ISC_CTRL_GAMMA_LUT(_name, _id, _name_str) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_ctrl_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_U32, \
+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, \
+ .dims = { GAMMA_ENTRIES }, \
+ .min = 0, \
+ .max = 1023, \
+ .step = 1, \
+ .def = 0, \
+ }
+
+ISC_CTRL_GAMMA_LUT(isc_gamma_b_lut_ctrl, ISC_CID_GAMMA_B_LUT, "Blue Gamma LUT");
+ISC_CTRL_GAMMA_LUT(isc_gamma_g_lut_ctrl, ISC_CID_GAMMA_G_LUT, "Green Gamma LUT");
+ISC_CTRL_GAMMA_LUT(isc_gamma_r_lut_ctrl, ISC_CID_GAMMA_R_LUT, "Red Gamma LUT");
+
static int isc_ctrl_init(struct isc_device *isc)
{
const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
@@ -1752,6 +1981,20 @@ static int isc_ctrl_init(struct isc_device *isc)
isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
+ /* Color correction control */
+ isc->cc_rr = v4l2_ctrl_new_custom(hdl, &isc_cc_rr_ctrl, NULL);
+ isc->cc_rg = v4l2_ctrl_new_custom(hdl, &isc_cc_rg_ctrl, NULL);
+ isc->cc_rb = v4l2_ctrl_new_custom(hdl, &isc_cc_rb_ctrl, NULL);
+ isc->cc_or = v4l2_ctrl_new_custom(hdl, &isc_cc_or_ctrl, NULL);
+ isc->cc_gr = v4l2_ctrl_new_custom(hdl, &isc_cc_gr_ctrl, NULL);
+ isc->cc_gg = v4l2_ctrl_new_custom(hdl, &isc_cc_gg_ctrl, NULL);
+ isc->cc_gb = v4l2_ctrl_new_custom(hdl, &isc_cc_gb_ctrl, NULL);
+ isc->cc_og = v4l2_ctrl_new_custom(hdl, &isc_cc_og_ctrl, NULL);
+ isc->cc_br = v4l2_ctrl_new_custom(hdl, &isc_cc_br_ctrl, NULL);
+ isc->cc_bg = v4l2_ctrl_new_custom(hdl, &isc_cc_bg_ctrl, NULL);
+ isc->cc_bb = v4l2_ctrl_new_custom(hdl, &isc_cc_bb_ctrl, NULL);
+ isc->cc_ob = v4l2_ctrl_new_custom(hdl, &isc_cc_ob_ctrl, NULL);
+
/*
* The cluster is in auto mode with autowhitebalance enabled
* and manual mode otherwise.
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 2c8bcaaa26ea..db651c9f1387 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -134,6 +134,12 @@ enum{
HIST_DISABLED,
};
+#define GAMMA_ENTRIES 64
+
+/* CC matrix coefficients (3x3 row-major) and per-channel offsets */
+#define ISC_CC_COEFF_NUM 9
+#define ISC_CC_OFFSET_NUM 3
+
struct isc_ctrls {
struct v4l2_ctrl_handler handler;
@@ -158,6 +164,11 @@ struct isc_ctrls {
#define HIST_MIN_INDEX 0
#define HIST_MAX_INDEX 1
u32 hist_minmax[HIST_BAYER][2];
+
+ /* CC matrix shadow; committed from isc_set_pipeline() and isc_awb_work() */
+ s32 cc_coeff[ISC_CC_COEFF_NUM];
+ s32 cc_offset[ISC_CC_OFFSET_NUM];
+ bool cc_dirty;
};
#define ISC_PIPE_LINE_NODE_NUM 15
@@ -338,6 +349,18 @@ struct isc_device {
struct v4l2_ctrl *b_off_ctrl;
struct v4l2_ctrl *gr_off_ctrl;
struct v4l2_ctrl *gb_off_ctrl;
+ struct v4l2_ctrl *cc_rr;
+ struct v4l2_ctrl *cc_rg;
+ struct v4l2_ctrl *cc_rb;
+ struct v4l2_ctrl *cc_or;
+ struct v4l2_ctrl *cc_gr;
+ struct v4l2_ctrl *cc_gg;
+ struct v4l2_ctrl *cc_gb;
+ struct v4l2_ctrl *cc_og;
+ struct v4l2_ctrl *cc_br;
+ struct v4l2_ctrl *cc_bg;
+ struct v4l2_ctrl *cc_bb;
+ struct v4l2_ctrl *cc_ob;
};
#define GAMMA_ENTRIES 64
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
index 79a320fb724e..028d34c8de81 100644
--- a/include/linux/atmel-isc-media.h
+++ b/include/linux/atmel-isc-media.h
@@ -53,6 +53,19 @@ enum atmel_isc_ctrl_id {
ISC_CID_GR_OFFSET,
/* Green Blue component offset control */
ISC_CID_GB_OFFSET,
+ /* Color correction registers */
+ ISC_CID_CC_RR,
+ ISC_CID_CC_RG,
+ ISC_CID_CC_RB,
+ ISC_CID_CC_OR,
+ ISC_CID_CC_GR,
+ ISC_CID_CC_GG,
+ ISC_CID_CC_GB,
+ ISC_CID_CC_OG,
+ ISC_CID_CC_BR,
+ ISC_CID_CC_BG,
+ ISC_CID_CC_BB,
+ ISC_CID_CC_OB,
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 11/15] media: microchip-isc: add per-channel gamma LUT controls
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (9 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-15 10:26 ` Sakari Ailus
2026-05-12 15:43 ` [PATCH v2 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable Balakrishnan Sambath
` (4 subsequent siblings)
15 siblings, 1 reply; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
Add 64-entry gamma LUT controls for R/G/B channels. Setting any LUT
overrides V4L2_CID_GAMMA; writing V4L2_CID_GAMMA restores presets.
Supports SAMA7G5 bipartite encoding.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 148 +++++++++++++++++-
.../media/platform/microchip/microchip-isc.h | 25 ++-
.../microchip/microchip-sama7g5-isc.c | 1 +
include/linux/atmel-isc-media.h | 18 +++
4 files changed, 184 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index f78145820e40..3749f473c3c6 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/math64.h>
#include <linux/module.h>
+#include <linux/string.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
@@ -250,12 +251,83 @@ static void isc_start_dma(struct isc_device *isc)
spin_unlock(&isc->awb_lock);
}
-static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
+/**
+ * isc_lut_to_hw() - Convert a 64-entry 10-bit LUT to ISC register format
+ * @lut: 64-element array of 10-bit output values (0-1023); element i
+ * is the desired output for input range [i*16 .. (i+1)*16 - 1].
+ * @hw: 64-element output array to receive the packed hardware values.
+ * @bipartite: true for SAMA7G5 (ISC_GAM_CTRL_BIPART active): delta is stored
+ * as a Q9 per-step increment (multiply by 32 = 512/16).
+ * false for SAMA5D2: delta is a plain per-segment increment.
+ *
+ * Each hardware register word packs two fields:
+ * bits[31:16] = 10-bit output value at the start of segment i
+ * bits[15:0] = interpolation delta
+ *
+ * In bipartite mode the hardware uses the delta to linearly interpolate
+ * across all 16 input steps within the segment (Q9 fixed-point: delta/512
+ * per step). In non-bipartite mode the hardware applies a constant output
+ * across the whole segment.
+ */
+static void isc_lut_to_hw(const u32 *lut, u32 *hw, bool bipartite)
+{
+ unsigned int i;
+ u32 cur, next, delta;
+
+ for (i = 0; i < GAMMA_ENTRIES; i++) {
+ cur = lut[i];
+ next = (i < GAMMA_ENTRIES - 1) ? lut[i + 1] : 1023;
+
+ /*
+ * Bipartite (SAMA7G5): delta = per-step increment in Q9
+ * = (next - cur) * 512 / 16 = (next - cur) * 32
+ * Non-bipartite (SAMA5D2): delta = per-segment increment
+ * = (next - cur)
+ */
+ delta = bipartite ? (next - cur) * 32 : (next - cur);
+
+ hw[i] = (cur << 16) | (delta & 0xffff);
+ }
+}
+
+/**
+ * isc_apply_gamma() - Write gamma LUT registers from current ctrls state
+ * @isc: ISC device
+ *
+ * Converts ctrls->gamma_lut_{b,g,r}[] to hardware format via isc_lut_to_hw()
+ * and writes all three ISC_GAM_*ENTRY register banks. Falls back to the
+ * preset gamma_table when gamma_lut_override is false.
+ *
+ * Must be called before isc_update_profile() whenever the gamma curve changes
+ * mid-stream, since isc_update_profile() only commits whatever is already in
+ * the registers to the active pipeline shadow.
+ */
+static void isc_apply_gamma(struct isc_device *isc)
{
struct regmap *regmap = isc->regmap;
struct isc_ctrls *ctrls = &isc->ctrls;
- u32 val, bay_cfg;
const u32 *gamma;
+ u32 hw[GAMMA_ENTRIES];
+
+ if (ctrls->gamma_lut_override) {
+ isc_lut_to_hw(ctrls->gamma_lut_b, hw, isc->gamma_bipartite);
+ regmap_bulk_write(regmap, ISC_GAM_BENTRY, hw, GAMMA_ENTRIES);
+ isc_lut_to_hw(ctrls->gamma_lut_g, hw, isc->gamma_bipartite);
+ regmap_bulk_write(regmap, ISC_GAM_GENTRY, hw, GAMMA_ENTRIES);
+ isc_lut_to_hw(ctrls->gamma_lut_r, hw, isc->gamma_bipartite);
+ regmap_bulk_write(regmap, ISC_GAM_RENTRY, hw, GAMMA_ENTRIES);
+ } else {
+ gamma = &isc->gamma_table[ctrls->gamma_index][0];
+ regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
+ regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
+ regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
+ }
+}
+
+static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 val, bay_cfg;
unsigned int i;
/* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
@@ -275,10 +347,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
- gamma = &isc->gamma_table[ctrls->gamma_index][0];
- regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
- regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
- regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
+ isc_apply_gamma(isc);
isc->config_dpc(isc);
isc->config_csc(isc);
@@ -1544,11 +1613,35 @@ static void isc_awb_work(struct work_struct *w)
pm_runtime_put_sync(isc->dev);
}
+/*
+ * isc_update_gamma_lut_override() - Evaluate gamma LUT override flag
+ *
+ * Activates the per-channel LUT override only when at least one entry
+ * across any channel is non-zero. An all-zero write (including the
+ * default initialisation from v4l2_ctrl_handler_setup) disables the
+ * override so the built-in gamma table remains active.
+ */
+static void isc_update_gamma_lut_override(struct isc_ctrls *ctrls)
+{
+ unsigned int i;
+ bool any_nonzero = false;
+
+ for (i = 0; i < GAMMA_ENTRIES && !any_nonzero; i++) {
+ if (ctrls->gamma_lut_b[i] ||
+ ctrls->gamma_lut_g[i] ||
+ ctrls->gamma_lut_r[i])
+ any_nonzero = true;
+ }
+ ctrls->gamma_lut_override = any_nonzero;
+}
+
static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct isc_device *isc = container_of(ctrl->handler,
struct isc_device, ctrls.handler);
struct isc_ctrls *ctrls = &isc->ctrls;
+ struct regmap *regmap = isc->regmap;
+ bool apply_gamma = false;
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
return 0;
@@ -1583,11 +1676,42 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_GAMMA:
ctrls->gamma_index = ctrl->val;
+ ctrls->gamma_lut_override = false;
+ apply_gamma = true;
+ break;
+ case ISC_CID_GAMMA_B_LUT:
+ memcpy(ctrls->gamma_lut_b, ctrl->p_new.p_u32,
+ GAMMA_ENTRIES * sizeof(u32));
+ isc_update_gamma_lut_override(ctrls);
+ apply_gamma = true;
+ break;
+ case ISC_CID_GAMMA_G_LUT:
+ memcpy(ctrls->gamma_lut_g, ctrl->p_new.p_u32,
+ GAMMA_ENTRIES * sizeof(u32));
+ isc_update_gamma_lut_override(ctrls);
+ apply_gamma = true;
+ break;
+ case ISC_CID_GAMMA_R_LUT:
+ memcpy(ctrls->gamma_lut_r, ctrl->p_new.p_u32,
+ GAMMA_ENTRIES * sizeof(u32));
+ isc_update_gamma_lut_override(ctrls);
+ apply_gamma = true;
break;
default:
return -EINVAL;
}
+ /*
+ * isc_apply_gamma() writes gamma LUT registers; it must be called
+ * under awb_mutex so it does not race with isc_awb_work() which also
+ * calls isc_update_profile() under the same lock.
+ */
+ mutex_lock(&isc->awb_mutex);
+ if (apply_gamma)
+ isc_apply_gamma(isc);
+ isc_update_profile(isc);
+ mutex_unlock(&isc->awb_mutex);
+
return 0;
}
@@ -1939,7 +2063,12 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->hist_stat = HIST_INIT;
isc_reset_awb_ctrls(isc);
- ret = v4l2_ctrl_handler_init(hdl, 13);
+ /*
+ * 30 controls maximum (SAMA7G5 with CBHS):
+ * contrast(1) + brightness(1) + hue+saturation(2) + gamma(1) +
+ * awb+do_wb(2) + 4×gain + 4×offset + 12×CC + 3×gamma_LUT
+ */
+ ret = v4l2_ctrl_handler_init(hdl, 30);
if (ret < 0)
return ret;
@@ -1995,6 +2124,11 @@ static int isc_ctrl_init(struct isc_device *isc)
isc->cc_bb = v4l2_ctrl_new_custom(hdl, &isc_cc_bb_ctrl, NULL);
isc->cc_ob = v4l2_ctrl_new_custom(hdl, &isc_cc_ob_ctrl, NULL);
+ /* Per-channel gamma LUT controls */
+ isc->gamma_b_lut_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gamma_b_lut_ctrl, NULL);
+ isc->gamma_g_lut_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gamma_g_lut_ctrl, NULL);
+ isc->gamma_r_lut_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gamma_r_lut_ctrl, NULL);
+
/*
* The cluster is in auto mode with autowhitebalance enabled
* and manual mode otherwise.
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index db651c9f1387..a4f1e6c22e44 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -165,6 +165,17 @@ struct isc_ctrls {
#define HIST_MAX_INDEX 1
u32 hist_minmax[HIST_BAYER][2];
+ /*
+ * Custom per-channel gamma LUT (10-bit output values, 64 entries).
+ * Set via ISC_CID_GAMMA_{R,G,B}_LUT controls. When gamma_lut_override
+ * is true these arrays are converted to hardware format at pipeline
+ * start-up, overriding the preset curve from gamma_index.
+ */
+ u32 gamma_lut_r[GAMMA_ENTRIES];
+ u32 gamma_lut_g[GAMMA_ENTRIES];
+ u32 gamma_lut_b[GAMMA_ENTRIES];
+ bool gamma_lut_override;
+
/* CC matrix shadow; committed from isc_set_pipeline() and isc_awb_work() */
s32 cc_coeff[ISC_CC_COEFF_NUM];
s32 cc_offset[ISC_CC_OFFSET_NUM];
@@ -363,12 +374,24 @@ struct isc_device {
struct v4l2_ctrl *cc_ob;
};
-#define GAMMA_ENTRIES 64
/* pointer to the defined gamma table */
const u32 (*gamma_table)[GAMMA_ENTRIES];
u32 gamma_max;
bool has_cbhs;
+ /*
+ * When true the GAM block operates in bipartite piecewise-linear
+ * interpolation mode (ISC_GAM_CTRL_BIPART set). The LUT-to-hardware
+ * conversion uses a Q9 per-step delta; without bipartite mode the
+ * delta is a plain per-segment increment.
+ */
+ bool gamma_bipartite;
+
+ /* V4L2 ctrl handles for the per-channel gamma LUT override */
+ struct v4l2_ctrl *gamma_b_lut_ctrl;
+ struct v4l2_ctrl *gamma_g_lut_ctrl;
+ struct v4l2_ctrl *gamma_r_lut_ctrl;
+
u32 max_width;
u32 max_height;
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 6705011edc2a..9110690a49e4 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -461,6 +461,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 2;
isc->has_cbhs = true;
+ isc->gamma_bipartite = true;
if (of_machine_is_compatible("microchip,sam9x7")) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
index 028d34c8de81..459e96170d9e 100644
--- a/include/linux/atmel-isc-media.h
+++ b/include/linux/atmel-isc-media.h
@@ -66,6 +66,24 @@ enum atmel_isc_ctrl_id {
ISC_CID_CC_BG,
ISC_CID_CC_BB,
ISC_CID_CC_OB,
+
+ /*
+ * Per-channel gamma LUT override controls.
+ *
+ * Each control is a 64-element U32 array. Element i holds the
+ * desired 10-bit output value (0-1023) for sensor input values in
+ * the range [i*16 .. (i+1)*16 - 1]. The driver converts the
+ * simple linear array to the hardware piecewise-linear (bipartite)
+ * register format internally.
+ *
+ * Setting any of these controls activates the custom LUT for all
+ * three channels and overrides the preset curve selected by
+ * V4L2_CID_GAMMA. Writing V4L2_CID_GAMMA deactivates the custom
+ * LUT and restores the selected preset curve.
+ */
+ ISC_CID_GAMMA_B_LUT,
+ ISC_CID_GAMMA_G_LUT,
+ ISC_CID_GAMMA_R_LUT,
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (10 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 13/15] media: microchip-isc: use weighted averages for Grey World AWB Balakrishnan Sambath
` (3 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
gamma_lut_override and cc_coeff[] persist across control writes. When
kernel AWB is enabled after userspace has customized the gamma curve or
color correction matrix, the stale settings produce incorrect color.
Clear gamma_lut_override and reset cc_coeff[] to identity when
V4L2_CID_AUTO_WHITE_BALANCE is set to 1.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 3749f473c3c6..e6386f8852e5 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1730,10 +1730,22 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
- if (ctrl->val == 1)
+ if (ctrl->val == 1) {
ctrls->awb = ISC_WB_AUTO;
- else
+ /*
+ * Reset gamma and CC to defaults when enabling kernel
+ * AWB so it starts with a clean pipeline.
+ */
+ ctrls->gamma_lut_override = false;
+ memset(ctrls->cc_coeff, 0, sizeof(ctrls->cc_coeff));
+ ctrls->cc_coeff[0] = 256; /* RR */
+ ctrls->cc_coeff[4] = 256; /* GG */
+ ctrls->cc_coeff[8] = 256; /* BB */
+ memset(ctrls->cc_offset, 0, sizeof(ctrls->cc_offset));
+ ctrls->cc_dirty = true;
+ } else {
ctrls->awb = ISC_WB_NONE;
+ }
/* configure the controls with new values from v4l2 */
if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 13/15] media: microchip-isc: use weighted averages for Grey World AWB
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (11 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 14/15] media: microchip-isc: smooth AWB gains with EMA filter Balakrishnan Sambath
` (2 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
Replace pixel counts with intensity-weighted averages. Add 2% outlier
rejection at histogram tails.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 167 +++++++++++++-----
.../media/platform/microchip/microchip-isc.h | 2 +
2 files changed, 125 insertions(+), 44 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index e6386f8852e5..8fcf64708dc8 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -40,6 +40,12 @@
(((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
(((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
+/* 4.0 in Q9 fixed-point: cap grey-world correction at 4x. */
+#define ISC_AWB_GW_GAIN_MAX (4u << 9)
+
+/* Outlier rejection: skip darkest/brightest 2% of histogram. */
+#define ISC_AWB_OUTLIER_DIV 50
+
static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
{
struct isc_ctrls *ctrls = &isc->ctrls;
@@ -1404,6 +1410,11 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
u32 *hist_entry = &ctrls->hist_entry[0];
u32 i;
+ u32 total_pixels;
+ u32 dark_threshold, bright_threshold;
+ u32 cumulative;
+ u64 weighted_sum;
+ u32 pixel_count;
*min = 0;
*max = HIST_ENTRIES;
@@ -1411,44 +1422,103 @@ 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 */
+ 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\n",
+ ctrls->hist_id);
+ return;
+ }
+
+ /* Outlier rejection: skip darkest/brightest 2% of histogram */
+ dark_threshold = total_pixels / ISC_AWB_OUTLIER_DIV;
+ bright_threshold = total_pixels / ISC_AWB_OUTLIER_DIV;
+ 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;
+ weighted_sum = 0;
+
+ for (i = *min; i <= *max; i++) {
+ 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\n",
+ ctrls->hist_id, ctrls->channel_avg[ctrls->hist_id],
+ *hist_count, *min, *max, total_pixels);
}
static void isc_wb_update(struct isc_ctrls *ctrls)
{
struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
- u32 *hist_count = &ctrls->hist_count[0];
u32 c, offset[4];
u64 avg = 0;
- /* We compute two gains, stretch gain and grey world gain */
- u32 s_gain[4], gw_gain[4];
+ u32 gain, gw_gain, s_gain;
+ u32 min_pixels;
+ u32 frame_pixels;
/*
* According to Grey World, we need to set gains for R/B to normalize
* them towards the green channel.
- * Thus we want to keep Green as fixed and adjust only Red/Blue
- * Compute the average of the both green channels first
+ * Thus we want to keep Green as fixed and adjust only Red/Blue.
+ * Compute the average of the both green channels first.
*/
- avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
- (u64)hist_count[ISC_HIS_CFG_MODE_GB];
- avg >>= 1;
+ avg = (ctrls->channel_avg[ISC_HIS_CFG_MODE_GR] +
+ ctrls->channel_avg[ISC_HIS_CFG_MODE_GB]) >> 1;
dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
@@ -1456,7 +1526,23 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
if (!avg)
return;
+ /*
+ * Require a minimum pixel count for both black-level offset and
+ * grey-world gain: 1/64 of the frame area, which equals ~6.25% of
+ * one Bayer channel's expected pixel count. This scales with sensor
+ * resolution and prevents noise-dominated histograms (from very small
+ * crops or a nearly-empty frame) from producing wild corrections.
+ * A floor of 64 ensures the guard is non-zero for tiny crops.
+ */
+ frame_pixels = isc->fmt.fmt.pix.width * isc->fmt.fmt.pix.height;
+ min_pixels = frame_pixels ? max(frame_pixels >> 6, 64u) : 64u;
+
for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ u32 hist_min = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ u32 hist_max = ctrls->hist_minmax[c][HIST_MAX_INDEX];
+ u32 channel_avg = ctrls->channel_avg[c];
+ u32 total_pixels = ctrls->total_pixels[c];
+
/*
* the color offset is the minimum value of the histogram.
* we stretch this color to the full range by substracting
@@ -1482,40 +1568,33 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
ctrls->offset[c] = -ctrls->offset[c];
/*
- * the stretch gain is the total number of histogram bins
- * divided by the actual range of color component (Max - Min)
- * If we compute gain like this, the actual color component
- * will be stretched to the full histogram.
- * We need to shift 9 bits for precision, we have 9 bits for
- * decimals
+ * Stretch gain: scale the histogram range [hist_min, hist_max]
+ * to the full 512-bin span. Result is in Q9 fixed-point
+ * (1.0 = 512).
*/
- s_gain[c] = (HIST_ENTRIES << 9) /
- (ctrls->hist_minmax[c][HIST_MAX_INDEX] -
- ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
+ s_gain = (HIST_ENTRIES << 9) / (hist_max - hist_min + 1);
/*
- * Now we have to compute the gain w.r.t. the average.
- * Add/lose gain to the component towards the average.
- * If it happens that the component is zero, use the
- * fixed point value : 1.0 gain.
+ * Grey-world gain: scale each channel towards the green
+ * average. Require a minimum pixel count so noise-dominated
+ * channels do not produce wild corrections.
*/
- if (hist_count[c])
- gw_gain[c] = div_u64(avg << 9, hist_count[c]);
+ if (channel_avg > 0 && total_pixels >= min_pixels)
+ gw_gain = div64_u64((avg << 9), channel_avg);
else
- gw_gain[c] = 1 << 9;
+ gw_gain = 1 << 9;
- dev_dbg(isc->dev,
- "isc wb: component %d, s_gain %u, gw_gain %u\n",
- c, s_gain[c], gw_gain[c]);
- /* multiply both gains and adjust for decimals */
- ctrls->gain[c] = s_gain[c] * gw_gain[c];
- ctrls->gain[c] >>= 9;
+ /* Cap grey-world correction at 4x to avoid over-amplification. */
+ gw_gain = min_t(u32, gw_gain, ISC_AWB_GW_GAIN_MAX);
- /* make sure we are not out of range */
- ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
+ /* Combine stretch and grey-world gains; result stays in Q9. */
+ gain = (s_gain * gw_gain) >> 9;
- dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
- c, ctrls->gain[c]);
+ ctrls->gain[c] = clamp_val(gain, 0, GENMASK(12, 0));
+
+ dev_dbg(isc->dev,
+ "isc wb: c=%u black=%u avg=%u s_gain=%u gw_gain=%u gain=%u",
+ c, hist_min, channel_avg, s_gain, gw_gain, gain);
}
}
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index a4f1e6c22e44..44d54404250d 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -164,6 +164,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 */
/*
* Custom per-channel gamma LUT (10-bit output values, 64 entries).
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 14/15] media: microchip-isc: smooth AWB gains with EMA filter
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (12 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 13/15] media: microchip-isc: use weighted averages for Grey World AWB Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 15/15] media: microchip-isc: scale DPC black level to sensor bit depth Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
Apply exponential moving average (alpha=0.25) to reduce per-frame
flicker from sensor noise.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 19 ++++++++++++++++---
.../media/platform/microchip/microchip-isc.h | 1 +
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 8fcf64708dc8..072386aa2d73 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -134,6 +134,7 @@ static inline void isc_reset_awb_ctrls(struct isc_device *isc)
for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
/* gains have a fixed point at 9 decimals */
isc->ctrls.gain[c] = 1 << 9;
+ isc->ctrls.gain_smooth[c] = 1 << 9;
/* offsets are in 2's complements */
isc->ctrls.offset[c] = 0;
}
@@ -1590,11 +1591,23 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
/* Combine stretch and grey-world gains; result stays in Q9. */
gain = (s_gain * gw_gain) >> 9;
- ctrls->gain[c] = clamp_val(gain, 0, GENMASK(12, 0));
+ /*
+ * Smooth gain updates with an exponential weighted average
+ * to suppress per-frame flicker:
+ * smooth[n] = (3 * smooth[n-1] + gain) / 4
+ * Clamp to the hardware register width to prevent unbounded
+ * accumulation under degenerate (near-empty histogram) inputs.
+ */
+ ctrls->gain_smooth[c] = (3 * ctrls->gain_smooth[c] + gain) / 4;
+ ctrls->gain_smooth[c] = min_t(u32, ctrls->gain_smooth[c],
+ GENMASK(12, 0));
+
+ ctrls->gain[c] = ctrls->gain_smooth[c];
dev_dbg(isc->dev,
- "isc wb: c=%u black=%u avg=%u s_gain=%u gw_gain=%u gain=%u",
- c, hist_min, channel_avg, s_gain, gw_gain, gain);
+ "isc wb: c=%u black=%u avg=%u s_gain=%u gw_gain=%u gain=%u smooth=%u\n",
+ c, hist_min, channel_avg, s_gain, gw_gain, gain,
+ ctrls->gain_smooth[c]);
}
}
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 44d54404250d..e558f1a65b33 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -155,6 +155,7 @@ struct isc_ctrls {
/* one for each component : GR, R, GB, B */
u32 gain[HIST_BAYER];
+ u32 gain_smooth[HIST_BAYER];
s32 offset[HIST_BAYER];
u32 hist_entry[HIST_ENTRIES];
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v2 15/15] media: microchip-isc: scale DPC black level to sensor bit depth
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (13 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 14/15] media: microchip-isc: smooth AWB gains with EMA filter Balakrishnan Sambath
@ 2026-05-12 15:43 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-12 15:43 UTC (permalink / raw)
To: linux-media; +Cc: eugen.hristev, mchehab, hverkuil, nicolas.ferre, linux-kernel
Scale the nominal 10-bit black level (64 counts) to match 8/10/12-bit
sensor bus width.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../microchip/microchip-sama7g5-isc.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 9110690a49e4..46a721d76453 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -26,6 +26,7 @@
* HIS: Histogram module performs statistic counters on the frames
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -289,9 +290,25 @@ static void isc_sama7g5_config_dpc(struct isc_device *isc)
{
u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
struct regmap *regmap = isc->regmap;
+ u32 bps, bloff;
+
+ /*
+ * Scale the nominal 10-bit black level offset (64 counts) to the
+ * actual sensor bus width.
+ * ISC_PFE_CFG0_BPS encodes (12 - bit_depth) / 2 in bits[30:28]:
+ * BPS_EIGHT = 4 -> 8-bit -> bloff = 64 >> 2 = 16
+ * BPS_TEN = 2 -> 10-bit -> bloff = 64
+ * BPS_TWELVE = 0 -> 12-bit -> bloff = min(64 << 2, 255) = 255
+ * The BLOFF hardware field is 8-bit so values are clamped to 255.
+ */
+ bps = FIELD_GET(ISC_PFE_CFG0_BPS_MASK, isc->config.sd_format->pfe_cfg0_bps);
+ if (bps >= 2)
+ bloff = 64u >> (bps - 2);
+ else
+ bloff = min(64u << (2 - bps), 255u);
regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
- (64 << ISC_DPC_CFG_BLOFF_SHIFT));
+ (bloff << ISC_DPC_CFG_BLOFF_SHIFT));
regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
(bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 00/15] media: microchip-isc: fixes and enhancements
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (14 preceding siblings ...)
2026-05-12 15:43 ` [PATCH v2 15/15] media: microchip-isc: scale DPC black level to sensor bit depth Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
` (15 more replies)
15 siblings, 16 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
Bug fixes and feature additions for the Microchip ISC/XISC driver.
Fixes:
- SBGGR10 Bayer pattern was mapped incorrectly (red/blue swap)
- WB register fields corrupted by sign extension
- Race between histogram IRQ and stream stop
- PM runtime reference leak in AWB work handler
Features:
- Driver documentation
- Gamma 1.8/2.4 curves, per-channel gamma LUT
- Hue/saturation controls for SAMA7G5
- Color correction matrix controls
- Grey World AWB with EMA smoothing
Split from v1 per review. Histogram stats follow as Series 2.
Tested on SAMA7G5-EK with IMX219 (RAW10 Bayer capture, AWB, color
controls verified).
Based on v6.19-rc8 (18f7fcd5e69a).
v1: https://lore.kernel.org/linux-media/20251009155251.102472-1-balamanikandan.gunasundar@microchip.com/
v3:
- Fix bisect failures in patches 9-11 (regmap declaration, gamma LUT
macro ordering)
- Fix Fixes: tag in patch 2 (use mainline commit, not staging)
- Add Co-developed-by for patches co-authored with Balamanikandan Gunasundar
v2:
- Split series (histogram stats moved to Series 2)
- Bug fixes first, then features
- New fixes and features as listed above
- Commit message cleanups
- Rebased on v6.19-rc8
Balakrishnan Sambath (15):
media: microchip-isc: fix SBGGR10 Bayer pattern
media: microchip-isc: mask WB offset and gain register fields
media: microchip-isc: fix race condition on stream stop
media: microchip-isc: fix PM runtime leak in AWB work handler
media: microchip-isc: add driver documentation
media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920
media: microchip-isc: configure DPC and pipeline for SAMA7G5
media: microchip-isc: add gamma 1.8 and 2.4 correction curves
media: microchip-isc: add SAMA7G5 hue and saturation controls
media: microchip-isc: expose color correction matrix as V4L2 controls
media: microchip-isc: add per-channel gamma LUT controls
media: microchip-isc: reset pipeline state on kernel AWB enable
media: microchip-isc: use weighted averages for Grey World AWB
media: microchip-isc: smooth AWB gains with EMA filter
media: microchip-isc: scale DPC black level to sensor bit depth
.../userspace-api/media/drivers/index.rst | 1 +
.../media/drivers/microchip-isc.rst | 71 ++
MAINTAINERS | 1 +
.../platform/microchip/microchip-isc-base.c | 728 ++++++++++++++++--
.../platform/microchip/microchip-isc-regs.h | 11 +-
.../media/platform/microchip/microchip-isc.h | 56 +-
.../microchip/microchip-sama5d2-isc.c | 2 +-
.../microchip/microchip-sama7g5-isc.c | 101 ++-
include/linux/atmel-isc-media.h | 31 +
9 files changed, 894 insertions(+), 108 deletions(-)
create mode 100644 Documentation/userspace-api/media/drivers/microchip-isc.rst
--
2.34.1
^ permalink raw reply [flat|nested] 65+ messages in thread
* [PATCH v3 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 02/15] media: microchip-isc: mask WB offset and gain register fields Balakrishnan Sambath
` (14 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel, stable
SBGGR10 was mapped to ISC_BAY_CFG_RGRG instead of ISC_BAY_CFG_BGBG,
causing red/blue channel swap.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-sama7g5-isc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index b0302dfc3278..ca23e8adecbd 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -156,7 +156,7 @@ static struct isc_format sama7g5_formats_list[] = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
},
{
.fourcc = V4L2_PIX_FMT_SGBRG10,
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 02/15] media: microchip-isc: mask WB offset and gain register fields
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 03/15] media: microchip-isc: fix race condition on stream stop Balakrishnan Sambath
` (13 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel, stable
ISC_WB_O_* and ISC_WB_G_* pack two 13-bit fields per register. Sign
extension from negative offsets corrupts the upper field. Mask both
fields to 13 bits before packing.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 21 ++++++++++++-------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index a7cdc743fda7..45b94f1e89d8 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -61,18 +61,23 @@ static inline void isc_update_awb_ctrls(struct isc_device *isc)
/* In here we set our actual hw pipeline config */
+ /*
+ * Mask offset fields to 13 bits. Sign extension of negative s32
+ * values would otherwise corrupt the adjacent field.
+ */
regmap_write(isc->regmap, ISC_WB_O_RGR,
- ((ctrls->offset[ISC_HIS_CFG_MODE_R])) |
- ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
+ ((u32)ctrls->offset[ISC_HIS_CFG_MODE_R] & GENMASK(12, 0)) |
+ (((u32)ctrls->offset[ISC_HIS_CFG_MODE_GR] & GENMASK(12, 0)) << 16));
regmap_write(isc->regmap, ISC_WB_O_BGB,
- ((ctrls->offset[ISC_HIS_CFG_MODE_B])) |
- ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16));
+ ((u32)ctrls->offset[ISC_HIS_CFG_MODE_B] & GENMASK(12, 0)) |
+ (((u32)ctrls->offset[ISC_HIS_CFG_MODE_GB] & GENMASK(12, 0)) << 16));
+ /* Gains are 13-bit unsigned fields [12:0] and [28:16] */
regmap_write(isc->regmap, ISC_WB_G_RGR,
- ctrls->gain[ISC_HIS_CFG_MODE_R] |
- (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16));
+ (ctrls->gain[ISC_HIS_CFG_MODE_R] & GENMASK(12, 0)) |
+ ((ctrls->gain[ISC_HIS_CFG_MODE_GR] & GENMASK(12, 0)) << 16));
regmap_write(isc->regmap, ISC_WB_G_BGB,
- ctrls->gain[ISC_HIS_CFG_MODE_B] |
- (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16));
+ (ctrls->gain[ISC_HIS_CFG_MODE_B] & GENMASK(12, 0)) |
+ ((ctrls->gain[ISC_HIS_CFG_MODE_GB] & GENMASK(12, 0)) << 16));
}
static inline void isc_reset_awb_ctrls(struct isc_device *isc)
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 03/15] media: microchip-isc: fix race condition on stream stop
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 02/15] media: microchip-isc: mask WB offset and gain register fields Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler Balakrishnan Sambath
` (12 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel, stable
Disable histogram and drain AWB work queue before releasing DMA
buffers to prevent use-after-free if histogram IRQ fires during
stream stop.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 45b94f1e89d8..b19c5a63b4bd 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -427,6 +427,14 @@ static void isc_stop_streaming(struct vb2_queue *vq)
mutex_unlock(&isc->awb_mutex);
+ /*
+ * Disable the histogram so the ISR stops firing HISREQ, then drain
+ * any work that was already queued before returning. This must happen
+ * after releasing awb_mutex because isc_awb_work also takes it.
+ */
+ isc_set_histogram(isc, false);
+ cancel_work_sync(&isc->awb_work);
+
/* Disable DMA interrupt */
regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
@@ -1519,10 +1527,17 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
}
mutex_unlock(&isc->awb_mutex);
- /* if we have autowhitebalance on, start histogram procedure */
+ /*
+ * If AWB auto mode is requested and we are streaming RAW,
+ * start the histogram procedure, but only if it is not
+ * already running. Repeated enable requests would reset
+ * hist_id, preventing the 4-channel Bayer cycle from
+ * completing.
+ */
if (ctrls->awb == ISC_WB_AUTO &&
vb2_is_streaming(&isc->vb2_vidq) &&
- ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code) &&
+ ctrls->hist_stat != HIST_ENABLED)
isc_set_histogram(isc, true);
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (2 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 03/15] media: microchip-isc: fix race condition on stream stop Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 05/15] media: microchip-isc: add driver documentation Balakrishnan Sambath
` (11 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel, stable
Early return when streaming stops skips pm_runtime_put_sync(),
leaking the reference and preventing runtime suspend.
Fixes: 91b4e487b0c6 ("media: microchip: add ISC driver as Microchip ISC")
Cc: stable@vger.kernel.org
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index b19c5a63b4bd..f61a5d5a3e04 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1429,7 +1429,7 @@ static void isc_awb_work(struct work_struct *w)
/* streaming is not active anymore */
if (isc->stop) {
mutex_unlock(&isc->awb_mutex);
- return;
+ goto out_pm_put;
}
isc_update_profile(isc);
@@ -1440,6 +1440,7 @@ static void isc_awb_work(struct work_struct *w)
if (ctrls->awb)
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+out_pm_put:
pm_runtime_put_sync(isc->dev);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 05/15] media: microchip-isc: add driver documentation
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (3 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920 Balakrishnan Sambath
` (10 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
Document V4L2 controls and pipeline modes for ISC/XISC camera interface
on SAMA5D2, SAMA7G5, and SAM9X7.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../userspace-api/media/drivers/index.rst | 1 +
.../media/drivers/microchip-isc.rst | 71 +++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 73 insertions(+)
create mode 100644 Documentation/userspace-api/media/drivers/microchip-isc.rst
diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index 02967c9b18d6..65ef6ba3523e 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -34,6 +34,7 @@ For more details see the file COPYING in the source distribution of Linux.
imx-uapi
mali-c55
max2175
+ microchip-isc
npcm-video
omap3isp-uapi
thp7312
diff --git a/Documentation/userspace-api/media/drivers/microchip-isc.rst b/Documentation/userspace-api/media/drivers/microchip-isc.rst
new file mode 100644
index 000000000000..2a436fd19272
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/microchip-isc.rst
@@ -0,0 +1,71 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Microchip ISC/XISC Driver
+=========================
+
+The Image Sensor Controller (ISC) on SAMA5D2 and eXtended ISC (XISC) on
+SAMA7G5/SAM9X7 provide camera capture with hardware image processing.
+
+Supported Hardware
+------------------
+
+========== ========== ============== ================ ===============
+SoC Controller Max Resolution Interface Hue/Saturation
+========== ========== ============== ================ ===============
+SAMA5D2 ISC 2592x1944 12-bit parallel No
+SAMA7G5 XISC 3264x2464 12-bit + CSI-2 Yes
+SAM9X7 XISC 2560x1920 12-bit + CSI-2 Yes
+========== ========== ============== ================ ===============
+
+SAM9X7 shares the XISC pipeline with SAMA7G5 but has a smaller internal
+line buffer, limiting horizontal resolution to 2560 pixels.
+
+Controls
+--------
+
+Standard V4L2 controls:
+
+* ``V4L2_CID_BRIGHTNESS``: -1024..1023, default 0
+* ``V4L2_CID_CONTRAST``: -2048..2047, default 256 (1.0x)
+* ``V4L2_CID_GAMMA``: 0..2 selects curve (0=2.4, 1=2.2, 2=1.8)
+* ``V4L2_CID_AUTO_WHITE_BALANCE``: Enable kernel Grey World AWB
+* ``V4L2_CID_DO_WHITE_BALANCE``: Trigger one-shot AWB
+
+SAMA7G5/SAM9X7 add:
+
+* ``V4L2_CID_HUE``: -180..180 degrees
+* ``V4L2_CID_SATURATION``: 0..255, default 16
+
+Custom controls (defined in ``atmel-isc-media.h``):
+
+* ``ISC_CID_R_GAIN``, ``ISC_CID_B_GAIN``, ``ISC_CID_GR_GAIN``,
+ ``ISC_CID_GB_GAIN``: WB gains, 0..8191, Q2.9 (512 = 1.0x)
+* ``ISC_CID_R_OFFSET``, ``ISC_CID_B_OFFSET``, ``ISC_CID_GR_OFFSET``,
+ ``ISC_CID_GB_OFFSET``: WB offsets, -4096..4095
+* ``ISC_CID_CC_RR`` ... ``ISC_CID_CC_BB``: 3x3 color correction matrix,
+ signed Q4.8 (256 = 1.0)
+* ``ISC_CID_CC_OR``, ``ISC_CID_CC_OG``, ``ISC_CID_CC_OB``: RGB offsets
+* ``ISC_CID_GAMMA_R_LUT``, ``ISC_CID_GAMMA_G_LUT``,
+ ``ISC_CID_GAMMA_B_LUT``: Per-channel gamma LUTs, 64-entry arrays
+
+Pipeline
+--------
+
+Pipeline modules: DPC -> WB -> CFA -> CC -> GAM -> CBHS/CBC -> CSC -> SUB
+
+* DPC: Defective Pixel Correction (XISC only), black level subtraction
+ to sensor bit depth, green disparity correction
+* WB: White Balance gains/offsets
+* CFA: Color Filter Array interpolation (demosaic)
+* CC: Color Correction matrix
+* GAM: Gamma correction (preset or per-channel LUT)
+* CBHS: Contrast/Brightness/Hue/Saturation (XISC only)
+* CBC: Contrast/Brightness (ISC only)
+* CSC: Color Space Conversion (RGB to YCbCr)
+* SUB: Chroma subsampling (4:2:2, 4:2:0)
+
+Pipeline usage depends on input and output formats:
+
+* Raw Bayer input, RGB output: DPC, WB, CFA, CC, GAM
+* Raw Bayer input, YUV output: Full pipeline including CSC, CBHS/CBC, SUB
+* Non-RAW input (YUV/RGB sensor): Pipeline bypassed
diff --git a/MAINTAINERS b/MAINTAINERS
index 0efa8cc6775b..fe5c3bb03e60 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17052,6 +17052,7 @@ L: linux-media@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/media/atmel,isc.yaml
F: Documentation/devicetree/bindings/media/microchip,xisc.yaml
+F: Documentation/userspace-api/media/drivers/microchip-isc.rst
F: drivers/media/platform/microchip/microchip-isc*
F: drivers/media/platform/microchip/microchip-sama*-isc*
F: drivers/staging/media/deprecated/atmel/atmel-isc*
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (4 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 05/15] media: microchip-isc: add driver documentation Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5 Balakrishnan Sambath
` (9 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
SAM9X7 XISC uses the same image processing pipeline as SAMA7G5 but has
a smaller internal line buffer. The reduced RAM constrains the maximum
horizontal resolution to 2560 pixels (compared to 3264 on SAMA7G5),
resulting in a maximum capture resolution of 2560x1920.
Co-developed-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../media/platform/microchip/microchip-sama7g5-isc.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index ca23e8adecbd..4119cfe12cdf 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -55,6 +55,9 @@
#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH 3264
#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
+#define ISC_SAM9X7_MAX_SUPPORT_WIDTH 2560
+#define ISC_SAM9X7_MAX_SUPPORT_HEIGHT 1920
+
#define ISC_SAMA7G5_PIPELINE \
(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
@@ -432,8 +435,13 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 0;
- isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
- isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+ if (of_machine_is_compatible("microchip,sam9x7")) {
+ isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAM9X7_MAX_SUPPORT_HEIGHT;
+ } else {
+ isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+ }
isc->config_dpc = isc_sama7g5_config_dpc;
isc->config_csc = isc_sama7g5_config_csc;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (5 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920 Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves Balakrishnan Sambath
` (8 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
Enable DPC_GDCENABLE for RGB output. Disable pipeline for raw Bayer
passthrough to provide unmodified sensor data for software ISP.
Co-developed-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
drivers/media/platform/microchip/microchip-isc-base.c | 7 ++-----
drivers/media/platform/microchip/microchip-sama7g5-isc.c | 3 ++-
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index f61a5d5a3e04..23a09ed12946 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -800,7 +800,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
- CC_ENABLE;
+ DPC_GDCENABLE | CC_ENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -850,10 +850,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
}
break;
default:
- if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
- isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
- else
- isc->try_config.bits_pipeline = 0x0;
+ isc->try_config.bits_pipeline = 0x0;
}
/* Tune the pipeline to product specific */
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 4119cfe12cdf..04930aa0f289 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -59,7 +59,8 @@
#define ISC_SAM9X7_MAX_SUPPORT_HEIGHT 1920
#define ISC_SAMA7G5_PIPELINE \
- (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ (DPC_DPCENABLE | DPC_GDCENABLE | DPC_BLCENABLE | \
+ WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (6 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5 Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls Balakrishnan Sambath
` (7 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
Add gamma 1.8 and 2.4 curves alongside the existing 2.2 (sRGB).
V4L2_CID_GAMMA selects preset curves: 0=2.4, 1=2.2, 2=1.8.
Co-developed-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 3 +-
.../microchip/microchip-sama7g5-isc.c | 54 ++++++++++++++-----
2 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 23a09ed12946..ae2a0c6ba566 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1647,8 +1647,7 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->brightness = 0;
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
- isc->gamma_max);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1, 1);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
0, 1, 1, 1);
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 04930aa0f289..8b73b625d92b 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -320,21 +320,47 @@ static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
}
-/* Gamma table with gamma 1/2.2 */
+/* Gamma tables with gamma values 0.42, 0.45(Default), 0.56 */
static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
- /* index 0 --> gamma bipartite */
+ /* index 0 --> gamma bipartite 1/2.4(=0.42) */
{
- 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
- 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
- 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
- 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
- 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
- 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
- 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
- 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
- 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
- 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
- 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+ 0x940, 0x4b0310, 0x630250, 0x7601d0, 0x840190, 0x910170,
+ 0x9d0150, 0xa80110, 0xb10110, 0xba0110, 0xc300f0, 0xcb00f0,
+ 0xd300e0, 0xda00e0, 0xe100c0, 0xe800c0, 0xee00c0, 0xf400c0,
+ 0xfa00a0, 0x10000a0, 0x10500a0, 0x10b00a0, 0x11000a0, 0x11500a0,
+ 0x11a0080, 0x11f0080, 0x1240080, 0x1290080, 0x12e0080, 0x1330070,
+ 0x1380070, 0x13c0070, 0x1410070, 0x17a0060, 0x1aa0052, 0x1d40046,
+ 0x1f90042, 0x21b003c, 0x23a0038, 0x2570034, 0x2720030, 0x28b002e,
+ 0x2a3002c, 0x2ba002a, 0x2d0002a, 0x2e60028, 0x2fa0026, 0x30e0026,
+ 0x3210024, 0x3330022, 0x3450022, 0x3560020, 0x3670020, 0x3770020,
+ 0x387001e, 0x396001e, 0x3a5001c, 0x3b3001c, 0x3c1001c, 0x3cf001a,
+ 0x3dd001a, 0x3eb0018, 0x3f90018, 0x4070016 },
+ /* index 1 --> gamma bipartite 1/2.2(=0.45) */
+ {
+ 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
+ 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
+ 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
+ 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
+ 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
+ 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
+ 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
+ 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
+ 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
+ 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
+ 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+ /* index 2 --> gamma bipartite 1/1.8(=0.56) */
+ {
+ 0xa62, 0x4f0350, 0x680280, 0x7e0200, 0x8d01c0, 0x9a01a0,
+ 0xa50180, 0xb00140, 0xb90140, 0xc20120, 0xcb0120, 0xd30100,
+ 0xdb0100, 0xe300e0, 0xea00e0, 0xf100e0, 0xf700c0, 0xfd00c0,
+ 0x10300c0, 0x10900a0, 0x10e00a0, 0x11400a0, 0x11900a0, 0x11e00a0,
+ 0x12300a0, 0x12800a0, 0x12d0080, 0x1320080, 0x1370080, 0x13c0080,
+ 0x1410080, 0x1460080, 0x14a0070, 0x1830060, 0x1b40052, 0x1df0048,
+ 0x2040042, 0x2250040, 0x2440038, 0x2600036, 0x27b0032, 0x2940030,
+ 0x2ac002e, 0x2c4002c, 0x2da002a, 0x2f0002a, 0x3050028, 0x3190026,
+ 0x32c0026, 0x33e0024, 0x3500024, 0x3610022, 0x3720020, 0x3820020,
+ 0x3920020, 0x3a2001e, 0x3b1001e, 0x3c0001c, 0x3ce001c, 0x3dc001c,
+ 0x3ea001a, 0x3f8001a, 0x4060018, 0x4130018 },
};
static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
@@ -434,7 +460,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
}
isc->gamma_table = isc_sama7g5_gamma_table;
- isc->gamma_max = 0;
+ isc->gamma_max = 2;
if (of_machine_is_compatible("microchip,sam9x7")) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (7 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls Balakrishnan Sambath
` (6 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
SAMA7G5 extends CBC with hue and saturation. Add V4L2_CID_HUE and
V4L2_CID_SATURATION controls. Disable CBHS for RGB output since it
operates in YCbCr domain.
Co-developed-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 87 ++++++++++++++++++-
.../platform/microchip/microchip-isc-regs.h | 11 ++-
.../media/platform/microchip/microchip-isc.h | 5 +-
.../microchip/microchip-sama5d2-isc.c | 2 +-
.../microchip/microchip-sama7g5-isc.c | 8 +-
5 files changed, 99 insertions(+), 14 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index ae2a0c6ba566..1727c98665d1 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -810,7 +810,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
- SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
+ SUB420_ENABLE | SUB422_ENABLE | CBHS_ENABLE |
DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
@@ -821,7 +821,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ SUB422_ENABLE | CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -833,7 +833,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
+ SUB422_ENABLE | CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -844,7 +844,7 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- CBC_ENABLE | DPC_BLCENABLE;
+ CBHS_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -859,6 +859,56 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
return 0;
}
+static bool isc_format_has_chroma(u32 fourcc)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * isc_update_cbc_ctrl_activity() - Activate/deactivate CBC controls
+ *
+ * Called from isc_set_fmt(), isc_link_validate(), and isc_ctrl_init().
+ * At isc_ctrl_init() time isc->config.bits_pipeline is zero (no format
+ * has been negotiated yet), so all CBC controls are initially marked
+ * inactive. They become active once a format that includes CBHS in the
+ * pipeline is configured via VIDIOC_S_FMT or link validation.
+ */
+static void isc_update_cbc_ctrl_activity(struct isc_device *isc)
+{
+ struct v4l2_ctrl_handler *hdl = &isc->ctrls.handler;
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *hue;
+ struct v4l2_ctrl *saturation;
+ bool cbc_active = isc->config.bits_pipeline & CBHS_ENABLE;
+ bool chroma_active = cbc_active && isc_format_has_chroma(isc->config.fourcc);
+
+ brightness = v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS);
+ if (brightness)
+ v4l2_ctrl_activate(brightness, cbc_active);
+
+ contrast = v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST);
+ if (contrast)
+ v4l2_ctrl_activate(contrast, cbc_active);
+
+ hue = v4l2_ctrl_find(hdl, V4L2_CID_HUE);
+ if (hue)
+ v4l2_ctrl_activate(hue, chroma_active);
+
+ saturation = v4l2_ctrl_find(hdl, V4L2_CID_SATURATION);
+ if (saturation)
+ v4l2_ctrl_activate(saturation, chroma_active);
+}
+
static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f)
{
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
@@ -902,6 +952,7 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
/* make the try configuration active */
isc->config = isc->try_config;
isc->fmt = isc->try_fmt;
+ isc_update_cbc_ctrl_activity(isc);
dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n",
(char *)&f->fmt.pix.pixelformat,
@@ -989,6 +1040,7 @@ static int isc_link_validate(struct media_link *link)
return ret;
isc->config = isc->try_config;
+ isc_update_cbc_ctrl_activity(isc);
dev_dbg(isc->dev, "New ISC configuration in place\n");
@@ -1446,6 +1498,7 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
struct isc_device *isc = container_of(ctrl->handler,
struct isc_device, ctrls.handler);
struct isc_ctrls *ctrls = &isc->ctrls;
+ struct regmap *regmap = isc->regmap;
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
return 0;
@@ -1453,9 +1506,30 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, ctrls->brightness);
break;
case V4L2_CID_CONTRAST:
ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, ctrls->contrast);
+ break;
+ case V4L2_CID_HUE:
+ if (isc->has_cbhs) {
+ ctrls->hue = ctrl->val & ISC_CBHS_HUE_MASK;
+ regmap_write(regmap, ISC_CBHS_HUE, ctrls->hue);
+ }
+ break;
+ case V4L2_CID_SATURATION:
+ if (isc->has_cbhs) {
+ /*
+ * The ISC CBHS SAT register holds a Q4 fixed-point
+ * coefficient: 0 = grayscale, 16 = 1.0 (no change),
+ * values above 16 boost saturation. The V4L2 range
+ * 0-100 (default 16) maps directly to this hardware
+ * value; no unit conversion is applied.
+ */
+ ctrls->saturation = ctrl->val & ISC_CBHS_SAT_MASK;
+ regmap_write(regmap, ISC_CBHS_SAT, ctrls->saturation);
+ }
break;
case V4L2_CID_GAMMA:
ctrls->gamma_index = ctrl->val;
@@ -1647,6 +1721,10 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->brightness = 0;
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
+ if (isc->has_cbhs) {
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, -180, 180, 1, 0);
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 0, 100, 1, 16);
+ }
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1, 1);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
@@ -1664,6 +1742,7 @@ static int isc_ctrl_init(struct isc_device *isc)
}
v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+ isc_update_cbc_ctrl_activity(isc);
isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
diff --git a/drivers/media/platform/microchip/microchip-isc-regs.h b/drivers/media/platform/microchip/microchip-isc-regs.h
index e77e1d9a1db8..2fd8916abf21 100644
--- a/drivers/media/platform/microchip/microchip-isc-regs.h
+++ b/drivers/media/platform/microchip/microchip-isc-regs.h
@@ -268,10 +268,13 @@
#define ISC_CBC_CONTRAST 0x000003c0
#define ISC_CBC_CONTRAST_MASK GENMASK(11, 0)
-/* Hue Register */
-#define ISC_CBCHS_HUE 0x4e0
-/* Saturation Register */
-#define ISC_CBCHS_SAT 0x4e4
+/* Hue Register: signed 9-bit two's complement, covers -180 to +180 degrees */
+#define ISC_CBHS_HUE 0x4e0
+#define ISC_CBHS_HUE_MASK GENMASK(8, 0)
+
+/* Saturation Register: unsigned Q4 fixed-point (1.0 = 16, V4L2 range 0-100) */
+#define ISC_CBHS_SAT 0x4e4
+#define ISC_CBHS_SAT_MASK GENMASK(6, 0)
/* Offset for SUB422 register specific to sama5d2 product */
#define ISC_SAMA5D2_SUB422_OFFSET 0
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index ad4e98a1dd8f..2c8bcaaa26ea 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -88,7 +88,7 @@ struct isc_format {
#define GAM_RENABLE BIT(9)
#define VHXS_ENABLE BIT(10)
#define CSC_ENABLE BIT(11)
-#define CBC_ENABLE BIT(12)
+#define CBHS_ENABLE BIT(12)
#define SUB422_ENABLE BIT(13)
#define SUB420_ENABLE BIT(14)
@@ -139,6 +139,8 @@ struct isc_ctrls {
u32 brightness;
u32 contrast;
+ u32 hue;
+ u32 saturation;
u8 gamma_index;
#define ISC_WB_NONE 0
#define ISC_WB_AUTO 1
@@ -342,6 +344,7 @@ struct isc_device {
/* pointer to the defined gamma table */
const u32 (*gamma_table)[GAMMA_ENTRIES];
u32 gamma_max;
+ bool has_cbhs;
u32 max_width;
u32 max_height;
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index 66d3d7891991..239aac170472 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -54,7 +54,7 @@
#define ISC_SAMA5D2_PIPELINE \
(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
- CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+ CBHS_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
static const struct isc_format sama5d2_controller_formats[] = {
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 8b73b625d92b..6705011edc2a 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -61,7 +61,7 @@
#define ISC_SAMA7G5_PIPELINE \
(DPC_DPCENABLE | DPC_GDCENABLE | DPC_BLCENABLE | \
WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
- CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+ CBHS_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
/* This is a list of the formats that the ISC can *output* */
static const struct isc_format sama7g5_controller_formats[] = {
@@ -257,9 +257,8 @@ static void isc_sama7g5_config_cbc(struct isc_device *isc)
/* Configure what is set via v4l2 ctrls */
regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
- /* Configure Hue and Saturation as neutral midpoint */
- regmap_write(regmap, ISC_CBCHS_HUE, 0);
- regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
+ regmap_write(regmap, ISC_CBHS_HUE, isc->ctrls.hue);
+ regmap_write(regmap, ISC_CBHS_SAT, isc->ctrls.saturation);
}
static void isc_sama7g5_config_cc(struct isc_device *isc)
@@ -461,6 +460,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 2;
+ isc->has_cbhs = true;
if (of_machine_is_compatible("microchip,sam9x7")) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (8 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
` (5 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media
Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel,
Balamanikandan Gunasundar
Add custom controls for 3x3 color correction matrix and RGB offsets.
Used by libcamera IPA for sensor color calibration.
Co-developed-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 222 +++++++++++++++++-
.../media/platform/microchip/microchip-isc.h | 23 ++
include/linux/atmel-isc-media.h | 13 +
3 files changed, 256 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 1727c98665d1..c24a03f9a843 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -32,7 +32,7 @@
#include "microchip-isc-regs.h"
#include "microchip-isc.h"
-#define ISC_IS_FORMAT_RAW(mbus_code) \
+#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
#define ISC_IS_FORMAT_GREY(mbus_code) \
@@ -55,6 +55,44 @@ static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GB]);
}
+/* commit CC shadow to hardware; called while ISC is powered */
+static void isc_update_cc_ctrls(struct isc_device *isc)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct regmap *regmap = isc->regmap;
+ u32 m = GENMASK(11, 0);
+
+ if (!ctrls->cc_dirty)
+ return;
+
+ regmap_update_bits(regmap, ISC_CC_RR_RG, m,
+ (u32)ctrls->cc_coeff[0] & m);
+ regmap_update_bits(regmap, ISC_CC_RR_RG, GENMASK(27, 16),
+ ((u32)ctrls->cc_coeff[1] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_RB_OR, m,
+ (u32)ctrls->cc_coeff[2] & m);
+ regmap_update_bits(regmap, ISC_CC_RB_OR, GENMASK(27, 16),
+ ((u32)ctrls->cc_offset[0] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_GR_GG, m,
+ (u32)ctrls->cc_coeff[3] & m);
+ regmap_update_bits(regmap, ISC_CC_GR_GG, GENMASK(27, 16),
+ ((u32)ctrls->cc_coeff[4] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_GB_OG, m,
+ (u32)ctrls->cc_coeff[5] & m);
+ regmap_update_bits(regmap, ISC_CC_GB_OG, GENMASK(27, 16),
+ ((u32)ctrls->cc_offset[1] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_BR_BG, m,
+ (u32)ctrls->cc_coeff[6] & m);
+ regmap_update_bits(regmap, ISC_CC_BR_BG, GENMASK(27, 16),
+ ((u32)ctrls->cc_coeff[7] & m) << 16);
+ regmap_update_bits(regmap, ISC_CC_BB_OB, m,
+ (u32)ctrls->cc_coeff[8] & m);
+ regmap_update_bits(regmap, ISC_CC_BB_OB, GENMASK(27, 16),
+ ((u32)ctrls->cc_offset[2] & m) << 16);
+
+ ctrls->cc_dirty = false;
+}
+
static inline void isc_update_awb_ctrls(struct isc_device *isc)
{
struct isc_ctrls *ctrls = &isc->ctrls;
@@ -90,6 +128,14 @@ static inline void isc_reset_awb_ctrls(struct isc_device *isc)
/* offsets are in 2's complements */
isc->ctrls.offset[c] = 0;
}
+
+ /* identity matrix: diagonal = 1.0 in Q4.8 = 256, off-diagonal = 0 */
+ memset(isc->ctrls.cc_coeff, 0, sizeof(isc->ctrls.cc_coeff));
+ isc->ctrls.cc_coeff[0] = 256; /* RR */
+ isc->ctrls.cc_coeff[4] = 256; /* GG */
+ isc->ctrls.cc_coeff[8] = 256; /* BB */
+ memset(isc->ctrls.cc_offset, 0, sizeof(isc->ctrls.cc_offset));
+ isc->ctrls.cc_dirty = false;
}
static int isc_queue_setup(struct vb2_queue *vq,
@@ -235,7 +281,8 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
isc->config_dpc(isc);
isc->config_csc(isc);
isc->config_cbc(isc);
- isc->config_cc(isc);
+ /* use shadow; config_cc() always resets to identity */
+ isc_update_cc_ctrls(isc);
isc->config_gam(isc);
}
@@ -1481,6 +1528,8 @@ static void isc_awb_work(struct work_struct *w)
goto out_pm_put;
}
+ /* write pending CC matrix from shadow to hardware registers */
+ isc_update_cc_ctrls(isc);
isc_update_profile(isc);
mutex_unlock(&isc->awb_mutex);
@@ -1660,6 +1709,161 @@ static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int isc_cc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct isc_ctrls *ctrls = &isc->ctrls;
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ /*
+ * CC registers need pm_runtime active for access.
+ * Store to shadow here; isc_update_cc_ctrls() writes to hardware
+ * from isc_awb_work() where ISC is powered.
+ */
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ ctrls->cc_coeff[0] = ctrl->val;
+ break;
+ case ISC_CID_CC_RG:
+ ctrls->cc_coeff[1] = ctrl->val;
+ break;
+ case ISC_CID_CC_RB:
+ ctrls->cc_coeff[2] = ctrl->val;
+ break;
+ case ISC_CID_CC_OR:
+ ctrls->cc_offset[0] = ctrl->val;
+ break;
+ case ISC_CID_CC_GR:
+ ctrls->cc_coeff[3] = ctrl->val;
+ break;
+ case ISC_CID_CC_GG:
+ ctrls->cc_coeff[4] = ctrl->val;
+ break;
+ case ISC_CID_CC_GB:
+ ctrls->cc_coeff[5] = ctrl->val;
+ break;
+ case ISC_CID_CC_OG:
+ ctrls->cc_offset[1] = ctrl->val;
+ break;
+ case ISC_CID_CC_BR:
+ ctrls->cc_coeff[6] = ctrl->val;
+ break;
+ case ISC_CID_CC_BG:
+ ctrls->cc_coeff[7] = ctrl->val;
+ break;
+ case ISC_CID_CC_BB:
+ ctrls->cc_coeff[8] = ctrl->val;
+ break;
+ case ISC_CID_CC_OB:
+ ctrls->cc_offset[2] = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ctrls->cc_dirty = true;
+ return 0;
+}
+
+static int isc_cc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct regmap *regmap = isc->regmap;
+ unsigned int reg;
+
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_RG:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_RB:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OR:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GR:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_GG:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GB:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OG:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BR:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_BG:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_cc_ops = {
+ .s_ctrl = isc_cc_s_ctrl,
+ .g_volatile_ctrl = isc_cc_g_volatile_ctrl,
+};
+
+#define ISC_CTRL_CC(_name, _id, _name_str, _def) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_cc_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .flags = V4L2_CTRL_FLAG_SLIDER | V4L2_CTRL_FLAG_VOLATILE | \
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, \
+ .min = -2048, \
+ .max = 2047, \
+ .step = 1, \
+ .def = _def, \
+ }
+
+ISC_CTRL_CC(isc_cc_rr_ctrl, ISC_CID_CC_RR, "CC RR", 256);
+ISC_CTRL_CC(isc_cc_rg_ctrl, ISC_CID_CC_RG, "CC RG", 0);
+ISC_CTRL_CC(isc_cc_rb_ctrl, ISC_CID_CC_RB, "CC RB", 0);
+ISC_CTRL_CC(isc_cc_or_ctrl, ISC_CID_CC_OR, "CC OR", 0);
+ISC_CTRL_CC(isc_cc_gr_ctrl, ISC_CID_CC_GR, "CC GR", 0);
+ISC_CTRL_CC(isc_cc_gg_ctrl, ISC_CID_CC_GG, "CC GG", 256);
+ISC_CTRL_CC(isc_cc_gb_ctrl, ISC_CID_CC_GB, "CC GB", 0);
+ISC_CTRL_CC(isc_cc_og_ctrl, ISC_CID_CC_OG, "CC OG", 0);
+ISC_CTRL_CC(isc_cc_br_ctrl, ISC_CID_CC_BR, "CC BR", 0);
+ISC_CTRL_CC(isc_cc_bg_ctrl, ISC_CID_CC_BG, "CC BG", 0);
+ISC_CTRL_CC(isc_cc_bb_ctrl, ISC_CID_CC_BB, "CC BB", 256);
+ISC_CTRL_CC(isc_cc_ob_ctrl, ISC_CID_CC_OB, "CC OB", 0);
+
static const struct v4l2_ctrl_ops isc_awb_ops = {
.s_ctrl = isc_s_awb_ctrl,
.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
@@ -1753,6 +1957,20 @@ static int isc_ctrl_init(struct isc_device *isc)
isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
+ /* Color correction control */
+ isc->cc_rr = v4l2_ctrl_new_custom(hdl, &isc_cc_rr_ctrl, NULL);
+ isc->cc_rg = v4l2_ctrl_new_custom(hdl, &isc_cc_rg_ctrl, NULL);
+ isc->cc_rb = v4l2_ctrl_new_custom(hdl, &isc_cc_rb_ctrl, NULL);
+ isc->cc_or = v4l2_ctrl_new_custom(hdl, &isc_cc_or_ctrl, NULL);
+ isc->cc_gr = v4l2_ctrl_new_custom(hdl, &isc_cc_gr_ctrl, NULL);
+ isc->cc_gg = v4l2_ctrl_new_custom(hdl, &isc_cc_gg_ctrl, NULL);
+ isc->cc_gb = v4l2_ctrl_new_custom(hdl, &isc_cc_gb_ctrl, NULL);
+ isc->cc_og = v4l2_ctrl_new_custom(hdl, &isc_cc_og_ctrl, NULL);
+ isc->cc_br = v4l2_ctrl_new_custom(hdl, &isc_cc_br_ctrl, NULL);
+ isc->cc_bg = v4l2_ctrl_new_custom(hdl, &isc_cc_bg_ctrl, NULL);
+ isc->cc_bb = v4l2_ctrl_new_custom(hdl, &isc_cc_bb_ctrl, NULL);
+ isc->cc_ob = v4l2_ctrl_new_custom(hdl, &isc_cc_ob_ctrl, NULL);
+
/*
* The cluster is in auto mode with autowhitebalance enabled
* and manual mode otherwise.
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 2c8bcaaa26ea..db651c9f1387 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -134,6 +134,12 @@ enum{
HIST_DISABLED,
};
+#define GAMMA_ENTRIES 64
+
+/* CC matrix coefficients (3x3 row-major) and per-channel offsets */
+#define ISC_CC_COEFF_NUM 9
+#define ISC_CC_OFFSET_NUM 3
+
struct isc_ctrls {
struct v4l2_ctrl_handler handler;
@@ -158,6 +164,11 @@ struct isc_ctrls {
#define HIST_MIN_INDEX 0
#define HIST_MAX_INDEX 1
u32 hist_minmax[HIST_BAYER][2];
+
+ /* CC matrix shadow; committed from isc_set_pipeline() and isc_awb_work() */
+ s32 cc_coeff[ISC_CC_COEFF_NUM];
+ s32 cc_offset[ISC_CC_OFFSET_NUM];
+ bool cc_dirty;
};
#define ISC_PIPE_LINE_NODE_NUM 15
@@ -338,6 +349,18 @@ struct isc_device {
struct v4l2_ctrl *b_off_ctrl;
struct v4l2_ctrl *gr_off_ctrl;
struct v4l2_ctrl *gb_off_ctrl;
+ struct v4l2_ctrl *cc_rr;
+ struct v4l2_ctrl *cc_rg;
+ struct v4l2_ctrl *cc_rb;
+ struct v4l2_ctrl *cc_or;
+ struct v4l2_ctrl *cc_gr;
+ struct v4l2_ctrl *cc_gg;
+ struct v4l2_ctrl *cc_gb;
+ struct v4l2_ctrl *cc_og;
+ struct v4l2_ctrl *cc_br;
+ struct v4l2_ctrl *cc_bg;
+ struct v4l2_ctrl *cc_bb;
+ struct v4l2_ctrl *cc_ob;
};
#define GAMMA_ENTRIES 64
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
index 79a320fb724e..028d34c8de81 100644
--- a/include/linux/atmel-isc-media.h
+++ b/include/linux/atmel-isc-media.h
@@ -53,6 +53,19 @@ enum atmel_isc_ctrl_id {
ISC_CID_GR_OFFSET,
/* Green Blue component offset control */
ISC_CID_GB_OFFSET,
+ /* Color correction registers */
+ ISC_CID_CC_RR,
+ ISC_CID_CC_RG,
+ ISC_CID_CC_RB,
+ ISC_CID_CC_OR,
+ ISC_CID_CC_GR,
+ ISC_CID_CC_GG,
+ ISC_CID_CC_GB,
+ ISC_CID_CC_OG,
+ ISC_CID_CC_BR,
+ ISC_CID_CC_BG,
+ ISC_CID_CC_BB,
+ ISC_CID_CC_OB,
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 11/15] media: microchip-isc: add per-channel gamma LUT controls
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (9 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable Balakrishnan Sambath
` (4 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
Add ISC_CID_GAMMA_R_LUT, ISC_CID_GAMMA_G_LUT, ISC_CID_GAMMA_B_LUT custom
controls for per-channel gamma tables (64 entries x 10 bits each).
Used by libcamera IPA for sensor-specific tone mapping.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 170 +++++++++++++++++-
.../media/platform/microchip/microchip-isc.h | 25 ++-
.../microchip/microchip-sama7g5-isc.c | 1 +
include/linux/atmel-isc-media.h | 18 ++
4 files changed, 206 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index c24a03f9a843..04c53ec18fdd 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/math64.h>
#include <linux/module.h>
+#include <linux/string.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
@@ -248,12 +249,83 @@ static void isc_start_dma(struct isc_device *isc)
spin_unlock(&isc->awb_lock);
}
-static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
+/**
+ * isc_lut_to_hw() - Convert a 64-entry 10-bit LUT to ISC register format
+ * @lut: 64-element array of 10-bit output values (0-1023); element i
+ * is the desired output for input range [i*16 .. (i+1)*16 - 1].
+ * @hw: 64-element output array to receive the packed hardware values.
+ * @bipartite: true for SAMA7G5 (ISC_GAM_CTRL_BIPART active): delta is stored
+ * as a Q9 per-step increment (multiply by 32 = 512/16).
+ * false for SAMA5D2: delta is a plain per-segment increment.
+ *
+ * Each hardware register word packs two fields:
+ * bits[31:16] = 10-bit output value at the start of segment i
+ * bits[15:0] = interpolation delta
+ *
+ * In bipartite mode the hardware uses the delta to linearly interpolate
+ * across all 16 input steps within the segment (Q9 fixed-point: delta/512
+ * per step). In non-bipartite mode the hardware applies a constant output
+ * across the whole segment.
+ */
+static void isc_lut_to_hw(const u32 *lut, u32 *hw, bool bipartite)
+{
+ unsigned int i;
+ u32 cur, next, delta;
+
+ for (i = 0; i < GAMMA_ENTRIES; i++) {
+ cur = lut[i];
+ next = (i < GAMMA_ENTRIES - 1) ? lut[i + 1] : 1023;
+
+ /*
+ * Bipartite (SAMA7G5): delta = per-step increment in Q9
+ * = (next - cur) * 512 / 16 = (next - cur) * 32
+ * Non-bipartite (SAMA5D2): delta = per-segment increment
+ * = (next - cur)
+ */
+ delta = bipartite ? (next - cur) * 32 : (next - cur);
+
+ hw[i] = (cur << 16) | (delta & 0xffff);
+ }
+}
+
+/**
+ * isc_apply_gamma() - Write gamma LUT registers from current ctrls state
+ * @isc: ISC device
+ *
+ * Converts ctrls->gamma_lut_{b,g,r}[] to hardware format via isc_lut_to_hw()
+ * and writes all three ISC_GAM_*ENTRY register banks. Falls back to the
+ * preset gamma_table when gamma_lut_override is false.
+ *
+ * Must be called before isc_update_profile() whenever the gamma curve changes
+ * mid-stream, since isc_update_profile() only commits whatever is already in
+ * the registers to the active pipeline shadow.
+ */
+static void isc_apply_gamma(struct isc_device *isc)
{
struct regmap *regmap = isc->regmap;
struct isc_ctrls *ctrls = &isc->ctrls;
- u32 val, bay_cfg;
const u32 *gamma;
+ u32 hw[GAMMA_ENTRIES];
+
+ if (ctrls->gamma_lut_override) {
+ isc_lut_to_hw(ctrls->gamma_lut_b, hw, isc->gamma_bipartite);
+ regmap_bulk_write(regmap, ISC_GAM_BENTRY, hw, GAMMA_ENTRIES);
+ isc_lut_to_hw(ctrls->gamma_lut_g, hw, isc->gamma_bipartite);
+ regmap_bulk_write(regmap, ISC_GAM_GENTRY, hw, GAMMA_ENTRIES);
+ isc_lut_to_hw(ctrls->gamma_lut_r, hw, isc->gamma_bipartite);
+ regmap_bulk_write(regmap, ISC_GAM_RENTRY, hw, GAMMA_ENTRIES);
+ } else {
+ gamma = &isc->gamma_table[ctrls->gamma_index][0];
+ regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
+ regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
+ regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
+ }
+}
+
+static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 val, bay_cfg;
unsigned int i;
/* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
@@ -273,10 +345,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
- gamma = &isc->gamma_table[ctrls->gamma_index][0];
- regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
- regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
- regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
+ isc_apply_gamma(isc);
isc->config_dpc(isc);
isc->config_csc(isc);
@@ -1542,12 +1611,35 @@ static void isc_awb_work(struct work_struct *w)
pm_runtime_put_sync(isc->dev);
}
+/*
+ * isc_update_gamma_lut_override() - Evaluate gamma LUT override flag
+ *
+ * Activates the per-channel LUT override only when at least one entry
+ * across any channel is non-zero. An all-zero write (including the
+ * default initialisation from v4l2_ctrl_handler_setup) disables the
+ * override so the built-in gamma table remains active.
+ */
+static void isc_update_gamma_lut_override(struct isc_ctrls *ctrls)
+{
+ unsigned int i;
+ bool any_nonzero = false;
+
+ for (i = 0; i < GAMMA_ENTRIES && !any_nonzero; i++) {
+ if (ctrls->gamma_lut_b[i] ||
+ ctrls->gamma_lut_g[i] ||
+ ctrls->gamma_lut_r[i])
+ any_nonzero = true;
+ }
+ ctrls->gamma_lut_override = any_nonzero;
+}
+
static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct isc_device *isc = container_of(ctrl->handler,
struct isc_device, ctrls.handler);
struct isc_ctrls *ctrls = &isc->ctrls;
struct regmap *regmap = isc->regmap;
+ bool apply_gamma = false;
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
return 0;
@@ -1582,11 +1674,42 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_GAMMA:
ctrls->gamma_index = ctrl->val;
+ ctrls->gamma_lut_override = false;
+ apply_gamma = true;
+ break;
+ case ISC_CID_GAMMA_B_LUT:
+ memcpy(ctrls->gamma_lut_b, ctrl->p_new.p_u32,
+ GAMMA_ENTRIES * sizeof(u32));
+ isc_update_gamma_lut_override(ctrls);
+ apply_gamma = true;
+ break;
+ case ISC_CID_GAMMA_G_LUT:
+ memcpy(ctrls->gamma_lut_g, ctrl->p_new.p_u32,
+ GAMMA_ENTRIES * sizeof(u32));
+ isc_update_gamma_lut_override(ctrls);
+ apply_gamma = true;
+ break;
+ case ISC_CID_GAMMA_R_LUT:
+ memcpy(ctrls->gamma_lut_r, ctrl->p_new.p_u32,
+ GAMMA_ENTRIES * sizeof(u32));
+ isc_update_gamma_lut_override(ctrls);
+ apply_gamma = true;
break;
default:
return -EINVAL;
}
+ /*
+ * isc_apply_gamma() writes gamma LUT registers; it must be called
+ * under awb_mutex so it does not race with isc_awb_work() which also
+ * calls isc_update_profile() under the same lock.
+ */
+ mutex_lock(&isc->awb_mutex);
+ if (apply_gamma)
+ isc_apply_gamma(isc);
+ isc_update_profile(isc);
+ mutex_unlock(&isc->awb_mutex);
+
return 0;
}
@@ -1905,6 +2028,29 @@ ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
+/*
+ * Per-channel gamma LUT controls (64-element U32 arrays, range 0-1023).
+ * Setting any of these activates the custom tone curve and overrides the
+ * preset V4L2_CID_GAMMA curve. One macro expands to a static v4l2_ctrl_config.
+ */
+#define ISC_CTRL_GAMMA_LUT(_name, _id, _name_str) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_ctrl_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_U32, \
+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, \
+ .dims = { GAMMA_ENTRIES }, \
+ .min = 0, \
+ .max = 1023, \
+ .step = 1, \
+ .def = 0, \
+ }
+
+ISC_CTRL_GAMMA_LUT(isc_gamma_b_lut_ctrl, ISC_CID_GAMMA_B_LUT, "Blue Gamma LUT");
+ISC_CTRL_GAMMA_LUT(isc_gamma_g_lut_ctrl, ISC_CID_GAMMA_G_LUT, "Green Gamma LUT");
+ISC_CTRL_GAMMA_LUT(isc_gamma_r_lut_ctrl, ISC_CID_GAMMA_R_LUT, "Red Gamma LUT");
+
static int isc_ctrl_init(struct isc_device *isc)
{
const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
@@ -1915,7 +2061,12 @@ static int isc_ctrl_init(struct isc_device *isc)
ctrls->hist_stat = HIST_INIT;
isc_reset_awb_ctrls(isc);
- ret = v4l2_ctrl_handler_init(hdl, 13);
+ /*
+ * 30 controls maximum (SAMA7G5 with CBHS):
+ * contrast(1) + brightness(1) + hue+saturation(2) + gamma(1) +
+ * awb+do_wb(2) + 4×gain + 4×offset + 12×CC + 3×gamma_LUT
+ */
+ ret = v4l2_ctrl_handler_init(hdl, 30);
if (ret < 0)
return ret;
@@ -1971,6 +2122,11 @@ static int isc_ctrl_init(struct isc_device *isc)
isc->cc_bb = v4l2_ctrl_new_custom(hdl, &isc_cc_bb_ctrl, NULL);
isc->cc_ob = v4l2_ctrl_new_custom(hdl, &isc_cc_ob_ctrl, NULL);
+ /* Per-channel gamma LUT controls */
+ isc->gamma_b_lut_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gamma_b_lut_ctrl, NULL);
+ isc->gamma_g_lut_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gamma_g_lut_ctrl, NULL);
+ isc->gamma_r_lut_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gamma_r_lut_ctrl, NULL);
+
/*
* The cluster is in auto mode with autowhitebalance enabled
* and manual mode otherwise.
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index db651c9f1387..a4f1e6c22e44 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -165,6 +165,17 @@ struct isc_ctrls {
#define HIST_MAX_INDEX 1
u32 hist_minmax[HIST_BAYER][2];
+ /*
+ * Custom per-channel gamma LUT (10-bit output values, 64 entries).
+ * Set via ISC_CID_GAMMA_{R,G,B}_LUT controls. When gamma_lut_override
+ * is true these arrays are converted to hardware format at pipeline
+ * start-up, overriding the preset curve from gamma_index.
+ */
+ u32 gamma_lut_r[GAMMA_ENTRIES];
+ u32 gamma_lut_g[GAMMA_ENTRIES];
+ u32 gamma_lut_b[GAMMA_ENTRIES];
+ bool gamma_lut_override;
+
/* CC matrix shadow; committed from isc_set_pipeline() and isc_awb_work() */
s32 cc_coeff[ISC_CC_COEFF_NUM];
s32 cc_offset[ISC_CC_OFFSET_NUM];
@@ -363,12 +374,24 @@ struct isc_device {
struct v4l2_ctrl *cc_ob;
};
-#define GAMMA_ENTRIES 64
/* pointer to the defined gamma table */
const u32 (*gamma_table)[GAMMA_ENTRIES];
u32 gamma_max;
bool has_cbhs;
+ /*
+ * When true the GAM block operates in bipartite piecewise-linear
+ * interpolation mode (ISC_GAM_CTRL_BIPART set). The LUT-to-hardware
+ * conversion uses a Q9 per-step delta; without bipartite mode the
+ * delta is a plain per-segment increment.
+ */
+ bool gamma_bipartite;
+
+ /* V4L2 ctrl handles for the per-channel gamma LUT override */
+ struct v4l2_ctrl *gamma_b_lut_ctrl;
+ struct v4l2_ctrl *gamma_g_lut_ctrl;
+ struct v4l2_ctrl *gamma_r_lut_ctrl;
+
u32 max_width;
u32 max_height;
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 6705011edc2a..9110690a49e4 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -461,6 +461,7 @@ static int microchip_xisc_probe(struct platform_device *pdev)
isc->gamma_table = isc_sama7g5_gamma_table;
isc->gamma_max = 2;
isc->has_cbhs = true;
+ isc->gamma_bipartite = true;
if (of_machine_is_compatible("microchip,sam9x7")) {
isc->max_width = ISC_SAM9X7_MAX_SUPPORT_WIDTH;
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
index 028d34c8de81..459e96170d9e 100644
--- a/include/linux/atmel-isc-media.h
+++ b/include/linux/atmel-isc-media.h
@@ -66,6 +66,24 @@ enum atmel_isc_ctrl_id {
ISC_CID_CC_BG,
ISC_CID_CC_BB,
ISC_CID_CC_OB,
+
+ /*
+ * Per-channel gamma LUT override controls.
+ *
+ * Each control is a 64-element U32 array. Element i holds the
+ * desired 10-bit output value (0-1023) for sensor input values in
+ * the range [i*16 .. (i+1)*16 - 1]. The driver converts the
+ * simple linear array to the hardware piecewise-linear (bipartite)
+ * register format internally.
+ *
+ * Setting any of these controls activates the custom LUT for all
+ * three channels and overrides the preset curve selected by
+ * V4L2_CID_GAMMA. Writing V4L2_CID_GAMMA deactivates the custom
+ * LUT and restores the selected preset curve.
+ */
+ ISC_CID_GAMMA_B_LUT,
+ ISC_CID_GAMMA_G_LUT,
+ ISC_CID_GAMMA_R_LUT,
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (10 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 13/15] media: microchip-isc: use weighted averages for Grey World AWB Balakrishnan Sambath
` (3 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
gamma_lut_override and cc_coeff[] persist across control writes. When
kernel AWB is enabled after userspace has customized the gamma curve or
color correction matrix, the stale settings produce incorrect color.
Clear gamma_lut_override and reset cc_coeff[] to identity when
V4L2_CID_AUTO_WHITE_BALANCE is set to 1.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 04c53ec18fdd..28957c2169b7 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -1728,10 +1728,22 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
- if (ctrl->val == 1)
+ if (ctrl->val == 1) {
ctrls->awb = ISC_WB_AUTO;
- else
+ /*
+ * Reset gamma and CC to defaults when enabling kernel
+ * AWB so it starts with a clean pipeline.
+ */
+ ctrls->gamma_lut_override = false;
+ memset(ctrls->cc_coeff, 0, sizeof(ctrls->cc_coeff));
+ ctrls->cc_coeff[0] = 256; /* RR */
+ ctrls->cc_coeff[4] = 256; /* GG */
+ ctrls->cc_coeff[8] = 256; /* BB */
+ memset(ctrls->cc_offset, 0, sizeof(ctrls->cc_offset));
+ ctrls->cc_dirty = true;
+ } else {
ctrls->awb = ISC_WB_NONE;
+ }
/* configure the controls with new values from v4l2 */
if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 13/15] media: microchip-isc: use weighted averages for Grey World AWB
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (11 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 14/15] media: microchip-isc: smooth AWB gains with EMA filter Balakrishnan Sambath
` (2 subsequent siblings)
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
Replace pixel counts with intensity-weighted averages. Add 2% outlier
rejection at histogram tails.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 167 +++++++++++++-----
.../media/platform/microchip/microchip-isc.h | 2 +
2 files changed, 125 insertions(+), 44 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 28957c2169b7..ea71cf50eb58 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -40,6 +40,12 @@
(((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
(((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
+/* 4.0 in Q9 fixed-point: cap grey-world correction at 4x. */
+#define ISC_AWB_GW_GAIN_MAX (4u << 9)
+
+/* Outlier rejection: skip darkest/brightest 2% of histogram. */
+#define ISC_AWB_OUTLIER_DIV 50
+
static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
{
struct isc_ctrls *ctrls = &isc->ctrls;
@@ -1402,6 +1408,11 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
u32 *hist_entry = &ctrls->hist_entry[0];
u32 i;
+ u32 total_pixels;
+ u32 dark_threshold, bright_threshold;
+ u32 cumulative;
+ u64 weighted_sum;
+ u32 pixel_count;
*min = 0;
*max = HIST_ENTRIES;
@@ -1409,44 +1420,103 @@ 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 */
+ 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\n",
+ ctrls->hist_id);
+ return;
+ }
+
+ /* Outlier rejection: skip darkest/brightest 2% of histogram */
+ dark_threshold = total_pixels / ISC_AWB_OUTLIER_DIV;
+ bright_threshold = total_pixels / ISC_AWB_OUTLIER_DIV;
+ 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;
+ weighted_sum = 0;
+
+ for (i = *min; i <= *max; i++) {
+ 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\n",
+ ctrls->hist_id, ctrls->channel_avg[ctrls->hist_id],
+ *hist_count, *min, *max, total_pixels);
}
static void isc_wb_update(struct isc_ctrls *ctrls)
{
struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
- u32 *hist_count = &ctrls->hist_count[0];
u32 c, offset[4];
u64 avg = 0;
- /* We compute two gains, stretch gain and grey world gain */
- u32 s_gain[4], gw_gain[4];
+ u32 gain, gw_gain, s_gain;
+ u32 min_pixels;
+ u32 frame_pixels;
/*
* According to Grey World, we need to set gains for R/B to normalize
* them towards the green channel.
- * Thus we want to keep Green as fixed and adjust only Red/Blue
- * Compute the average of the both green channels first
+ * Thus we want to keep Green as fixed and adjust only Red/Blue.
+ * Compute the average of the both green channels first.
*/
- avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
- (u64)hist_count[ISC_HIS_CFG_MODE_GB];
- avg >>= 1;
+ avg = (ctrls->channel_avg[ISC_HIS_CFG_MODE_GR] +
+ ctrls->channel_avg[ISC_HIS_CFG_MODE_GB]) >> 1;
dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
@@ -1454,7 +1524,23 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
if (!avg)
return;
+ /*
+ * Require a minimum pixel count for both black-level offset and
+ * grey-world gain: 1/64 of the frame area, which equals ~6.25% of
+ * one Bayer channel's expected pixel count. This scales with sensor
+ * resolution and prevents noise-dominated histograms (from very small
+ * crops or a nearly-empty frame) from producing wild corrections.
+ * A floor of 64 ensures the guard is non-zero for tiny crops.
+ */
+ frame_pixels = isc->fmt.fmt.pix.width * isc->fmt.fmt.pix.height;
+ min_pixels = frame_pixels ? max(frame_pixels >> 6, 64u) : 64u;
+
for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ u32 hist_min = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ u32 hist_max = ctrls->hist_minmax[c][HIST_MAX_INDEX];
+ u32 channel_avg = ctrls->channel_avg[c];
+ u32 total_pixels = ctrls->total_pixels[c];
+
/*
* the color offset is the minimum value of the histogram.
* we stretch this color to the full range by substracting
@@ -1480,40 +1566,33 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
ctrls->offset[c] = -ctrls->offset[c];
/*
- * the stretch gain is the total number of histogram bins
- * divided by the actual range of color component (Max - Min)
- * If we compute gain like this, the actual color component
- * will be stretched to the full histogram.
- * We need to shift 9 bits for precision, we have 9 bits for
- * decimals
+ * Stretch gain: scale the histogram range [hist_min, hist_max]
+ * to the full 512-bin span. Result is in Q9 fixed-point
+ * (1.0 = 512).
*/
- s_gain[c] = (HIST_ENTRIES << 9) /
- (ctrls->hist_minmax[c][HIST_MAX_INDEX] -
- ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
+ s_gain = (HIST_ENTRIES << 9) / (hist_max - hist_min + 1);
/*
- * Now we have to compute the gain w.r.t. the average.
- * Add/lose gain to the component towards the average.
- * If it happens that the component is zero, use the
- * fixed point value : 1.0 gain.
+ * Grey-world gain: scale each channel towards the green
+ * average. Require a minimum pixel count so noise-dominated
+ * channels do not produce wild corrections.
*/
- if (hist_count[c])
- gw_gain[c] = div_u64(avg << 9, hist_count[c]);
+ if (channel_avg > 0 && total_pixels >= min_pixels)
+ gw_gain = div64_u64((avg << 9), channel_avg);
else
- gw_gain[c] = 1 << 9;
+ gw_gain = 1 << 9;
- dev_dbg(isc->dev,
- "isc wb: component %d, s_gain %u, gw_gain %u\n",
- c, s_gain[c], gw_gain[c]);
- /* multiply both gains and adjust for decimals */
- ctrls->gain[c] = s_gain[c] * gw_gain[c];
- ctrls->gain[c] >>= 9;
+ /* Cap grey-world correction at 4x to avoid over-amplification. */
+ gw_gain = min_t(u32, gw_gain, ISC_AWB_GW_GAIN_MAX);
- /* make sure we are not out of range */
- ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
+ /* Combine stretch and grey-world gains; result stays in Q9. */
+ gain = (s_gain * gw_gain) >> 9;
- dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
- c, ctrls->gain[c]);
+ ctrls->gain[c] = clamp_val(gain, 0, GENMASK(12, 0));
+
+ dev_dbg(isc->dev,
+ "isc wb: c=%u black=%u avg=%u s_gain=%u gw_gain=%u gain=%u",
+ c, hist_min, channel_avg, s_gain, gw_gain, gain);
}
}
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index a4f1e6c22e44..44d54404250d 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -164,6 +164,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 */
/*
* Custom per-channel gamma LUT (10-bit output values, 64 entries).
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 14/15] media: microchip-isc: smooth AWB gains with EMA filter
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (12 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 13/15] media: microchip-isc: use weighted averages for Grey World AWB Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 15/15] media: microchip-isc: scale DPC black level to sensor bit depth Balakrishnan Sambath
2026-05-15 10:27 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Sakari Ailus
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
Apply exponential moving average (alpha=0.25) to reduce per-frame
flicker from sensor noise.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../platform/microchip/microchip-isc-base.c | 19 ++++++++++++++++---
.../media/platform/microchip/microchip-isc.h | 1 +
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index ea71cf50eb58..80ae8db1ce01 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -132,6 +132,7 @@ static inline void isc_reset_awb_ctrls(struct isc_device *isc)
for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
/* gains have a fixed point at 9 decimals */
isc->ctrls.gain[c] = 1 << 9;
+ isc->ctrls.gain_smooth[c] = 1 << 9;
/* offsets are in 2's complements */
isc->ctrls.offset[c] = 0;
}
@@ -1588,11 +1589,23 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
/* Combine stretch and grey-world gains; result stays in Q9. */
gain = (s_gain * gw_gain) >> 9;
- ctrls->gain[c] = clamp_val(gain, 0, GENMASK(12, 0));
+ /*
+ * Smooth gain updates with an exponential weighted average
+ * to suppress per-frame flicker:
+ * smooth[n] = (3 * smooth[n-1] + gain) / 4
+ * Clamp to the hardware register width to prevent unbounded
+ * accumulation under degenerate (near-empty histogram) inputs.
+ */
+ ctrls->gain_smooth[c] = (3 * ctrls->gain_smooth[c] + gain) / 4;
+ ctrls->gain_smooth[c] = min_t(u32, ctrls->gain_smooth[c],
+ GENMASK(12, 0));
+
+ ctrls->gain[c] = ctrls->gain_smooth[c];
dev_dbg(isc->dev,
- "isc wb: c=%u black=%u avg=%u s_gain=%u gw_gain=%u gain=%u",
- c, hist_min, channel_avg, s_gain, gw_gain, gain);
+ "isc wb: c=%u black=%u avg=%u s_gain=%u gw_gain=%u gain=%u smooth=%u\n",
+ c, hist_min, channel_avg, s_gain, gw_gain, gain,
+ ctrls->gain_smooth[c]);
}
}
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index 44d54404250d..e558f1a65b33 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -155,6 +155,7 @@ struct isc_ctrls {
/* one for each component : GR, R, GB, B */
u32 gain[HIST_BAYER];
+ u32 gain_smooth[HIST_BAYER];
s32 offset[HIST_BAYER];
u32 hist_entry[HIST_ENTRIES];
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v3 15/15] media: microchip-isc: scale DPC black level to sensor bit depth
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (13 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 14/15] media: microchip-isc: smooth AWB gains with EMA filter Balakrishnan Sambath
@ 2026-05-13 7:17 ` Balakrishnan Sambath
2026-05-15 10:27 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Sakari Ailus
15 siblings, 0 replies; 65+ messages in thread
From: Balakrishnan Sambath @ 2026-05-13 7:17 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, hverkuil, nicolas.ferre, linux-kernel
Scale the nominal 10-bit black level (64 counts) to match 8/10/12-bit
sensor bus width.
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
---
.../microchip/microchip-sama7g5-isc.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index 9110690a49e4..46a721d76453 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -26,6 +26,7 @@
* HIS: Histogram module performs statistic counters on the frames
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -289,9 +290,25 @@ static void isc_sama7g5_config_dpc(struct isc_device *isc)
{
u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
struct regmap *regmap = isc->regmap;
+ u32 bps, bloff;
+
+ /*
+ * Scale the nominal 10-bit black level offset (64 counts) to the
+ * actual sensor bus width.
+ * ISC_PFE_CFG0_BPS encodes (12 - bit_depth) / 2 in bits[30:28]:
+ * BPS_EIGHT = 4 -> 8-bit -> bloff = 64 >> 2 = 16
+ * BPS_TEN = 2 -> 10-bit -> bloff = 64
+ * BPS_TWELVE = 0 -> 12-bit -> bloff = min(64 << 2, 255) = 255
+ * The BLOFF hardware field is 8-bit so values are clamped to 255.
+ */
+ bps = FIELD_GET(ISC_PFE_CFG0_BPS_MASK, isc->config.sd_format->pfe_cfg0_bps);
+ if (bps >= 2)
+ bloff = 64u >> (bps - 2);
+ else
+ bloff = min(64u << (2 - bps), 255u);
regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
- (64 << ISC_DPC_CFG_BLOFF_SHIFT));
+ (bloff << ISC_DPC_CFG_BLOFF_SHIFT));
regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
(bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
}
--
2.34.1
^ permalink raw reply related [flat|nested] 65+ messages in thread
* Re: [PATCH v2 11/15] media: microchip-isc: add per-channel gamma LUT controls
2026-05-12 15:43 ` [PATCH v2 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
@ 2026-05-15 10:26 ` Sakari Ailus
0 siblings, 0 replies; 65+ messages in thread
From: Sakari Ailus @ 2026-05-15 10:26 UTC (permalink / raw)
To: Balakrishnan Sambath
Cc: linux-media, eugen.hristev, mchehab, hverkuil, nicolas.ferre,
linux-kernel
Hi Balakrishnan,
Thanks for the set.
On Tue, May 12, 2026 at 09:13:35PM +0530, Balakrishnan Sambath wrote:
> Add 64-entry gamma LUT controls for R/G/B channels. Setting any LUT
> overrides V4L2_CID_GAMMA; writing V4L2_CID_GAMMA restores presets.
> Supports SAMA7G5 bipartite encoding.
I'd say hardware this complicated should use parameter buffers like other
similar hardware does. The reasoning is that the userspace gets an
interface that allows passing all relevant parameters to the driver at one
go, with a reasonable expectation on which frame it can be applied to.
Controls provide neither of these.
On top of this, the control framework, while useful for high level
configuration parameters, introduces quite a bit of validation overhead
that can affect performance while the effect of a bad parameter value is
simply bad output and the software setting these values is purpose-built so
it can already take the ranges and steps into account.
--
Kind regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v3 00/15] media: microchip-isc: fixes and enhancements
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
` (14 preceding siblings ...)
2026-05-13 7:17 ` [PATCH v3 15/15] media: microchip-isc: scale DPC black level to sensor bit depth Balakrishnan Sambath
@ 2026-05-15 10:27 ` Sakari Ailus
15 siblings, 0 replies; 65+ messages in thread
From: Sakari Ailus @ 2026-05-15 10:27 UTC (permalink / raw)
To: Balakrishnan Sambath
Cc: linux-media, mchehab, hverkuil, nicolas.ferre, linux-kernel
Hi Balakhrisnan,
On Wed, May 13, 2026 at 12:47:27PM +0530, Balakrishnan Sambath wrote:
> Bug fixes and feature additions for the Microchip ISC/XISC driver.
Please avoid using git send-email --in-reply-to argument when posting new
versions. You could add a reference to the old series using the Message-ID:
header though.
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 65+ messages in thread
end of thread, other threads:[~2026-05-15 10:27 UTC | newest]
Thread overview: 65+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-09 15:52 [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 01/18] media: platform: microchip: set maximum resolution for sam9x7 Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 02/18] media: platform: microchip: Include DPC modules flags in pipeline Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 03/18] media: microchip-isc: Enable GDC and CBC module flags for RGB formats Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 04/18] media: microchip-isc: Improve histogram calculation with outlier rejection Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 05/18] media: microchip-isc: Use channel averages for Grey World AWB Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 06/18] media: microchip-isc: Add range based black level correction Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 07/18] media: platform: microchip: Extend gamma table and control range Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 08/18] media: platform: microchip: Add new histogram submodule Balamanikandan Gunasundar
2025-11-10 8:41 ` Hans Verkuil
2025-11-10 8:55 ` Hans Verkuil
2025-10-09 15:52 ` [PATCH 09/18] media: microchip-isc: Register and unregister statistics device Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 10/18] media: microchip-isc: Always enable histogram for all RAW formats Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 11/18] media: microchip-isc: expose hue and saturation as v4l2 controls Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 12/18] media: microchip-isc: Rename CBC to CBHS Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 13/18] media: microchip-isc: Store histogram data of all channels Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 14/18] media: microchip-isc: fix histogram state initialization order Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 15/18] media: microchip-isc: decouple histogram cycling from AWB mode Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 16/18] media: microchip-isc: enable userspace histogram statistics export Balamanikandan Gunasundar
2025-10-09 15:52 ` [PATCH 17/18] media: videodev2.h, v4l2-ioctl: Add microchip statistics format Balamanikandan Gunasundar
2025-11-10 8:49 ` Hans Verkuil
2025-10-09 15:52 ` [PATCH 18/18] media: microchip-isc: expose color correction registers as v4l2 controls Balamanikandan Gunasundar
2025-10-09 20:11 ` [PATCH 00/18] media: microchip-isc: Color correction and histogram stats Eugen Hristev
2025-10-10 8:21 ` Kieran Bingham
2025-10-10 8:27 ` Laurent Pinchart
2025-10-15 6:05 ` Balamanikandan.Gunasundar
2025-10-15 6:45 ` Balamanikandan.Gunasundar
2025-10-15 6:33 ` Balamanikandan.Gunasundar
2025-10-15 5:26 ` Balamanikandan.Gunasundar
2025-11-10 9:01 ` Hans Verkuil
2025-11-10 9:26 ` Hans Verkuil
2026-05-12 15:43 ` [PATCH v2 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 02/15] media: microchip-isc: mask WB offset and gain register fields Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 03/15] media: microchip-isc: fix race condition on stream stop Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 05/15] media: microchip-isc: add driver documentation Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920 Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5 Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
2026-05-15 10:26 ` Sakari Ailus
2026-05-12 15:43 ` [PATCH v2 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 13/15] media: microchip-isc: use weighted averages for Grey World AWB Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 14/15] media: microchip-isc: smooth AWB gains with EMA filter Balakrishnan Sambath
2026-05-12 15:43 ` [PATCH v2 15/15] media: microchip-isc: scale DPC black level to sensor bit depth Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 01/15] media: microchip-isc: fix SBGGR10 Bayer pattern Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 02/15] media: microchip-isc: mask WB offset and gain register fields Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 03/15] media: microchip-isc: fix race condition on stream stop Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 04/15] media: microchip-isc: fix PM runtime leak in AWB work handler Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 05/15] media: microchip-isc: add driver documentation Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 06/15] media: microchip-isc: set SAM9X7 maximum resolution to 2560x1920 Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 07/15] media: microchip-isc: configure DPC and pipeline for SAMA7G5 Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 08/15] media: microchip-isc: add gamma 1.8 and 2.4 correction curves Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 09/15] media: microchip-isc: add SAMA7G5 hue and saturation controls Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 10/15] media: microchip-isc: expose color correction matrix as V4L2 controls Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 11/15] media: microchip-isc: add per-channel gamma LUT controls Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 12/15] media: microchip-isc: reset pipeline state on kernel AWB enable Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 13/15] media: microchip-isc: use weighted averages for Grey World AWB Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 14/15] media: microchip-isc: smooth AWB gains with EMA filter Balakrishnan Sambath
2026-05-13 7:17 ` [PATCH v3 15/15] media: microchip-isc: scale DPC black level to sensor bit depth Balakrishnan Sambath
2026-05-15 10:27 ` [PATCH v3 00/15] media: microchip-isc: fixes and enhancements Sakari Ailus
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.