* [Patch 12/16] OMAP3 camera driver LSC support
@ 2008-07-01 4:09 Mohit Jalori
0 siblings, 0 replies; only message in thread
From: Mohit Jalori @ 2008-07-01 4:09 UTC (permalink / raw)
To: video4linux-list
From: Mohit Jalori <mjalori@ti.com>
ARM: OMAP: OMAP34XXCAM: ISP CCDC LSC support.
Adding support for CCDC Lens Shading Compensator.
Signed-off-by: Mohit Jalori <mjalori@ti.com>
---
drivers/media/video/isp/isp.c | 28 +++++
drivers/media/video/isp/ispccdc.c | 195 ++++++++++++++++++++++++++++++++++-
drivers/media/video/isp/ispccdc.h | 8 +
include/asm-arm/arch-omap/isp_user.h | 31 +++++
4 files changed, 261 insertions(+), 1 deletion(-)
--- a/drivers/media/video/isp/isp.c 2008-06-29 13:19:12.000000000 -0500
+++ b/drivers/media/video/isp/isp.c 2008-06-29 14:12:09.000000000 -0500
@@ -324,6 +324,17 @@ int isp_set_callback(enum isp_callback_t
IRQENABLE_TLBMISS,
ISPMMU_IRQENABLE);
break;
+ case CBK_LSC_ISR:
+ omap_writel(IRQ0ENABLE_CCDC_LSC_DONE_IRQ |
+ IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ |
+ IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ,
+ ISP_IRQ0STATUS);
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) |
+ IRQ0ENABLE_CCDC_LSC_DONE_IRQ |
+ IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ |
+ IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ,
+ ISP_IRQ0ENABLE);
+ break;
default:
break;
}
@@ -374,6 +385,13 @@ int isp_unset_callback(enum isp_callback
~IRQ0ENABLE_HS_VS_IRQ,
ISP_IRQ0ENABLE);
break;
+ case CBK_LSC_ISR:
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) &
+ ~(IRQ0ENABLE_CCDC_LSC_DONE_IRQ |
+ IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ |
+ IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ),
+ ISP_IRQ0ENABLE);
+ break;
default:
break;
}
@@ -848,6 +866,15 @@ static irqreturn_t omap34xx_isp_isr(int
is_irqhandled = 1;
}
+ if (irqstatus & LSC_PRE_ERR) {
+ printk(KERN_ERR "isp_sr: LSC_PRE_ERR \n");
+ omap_writel(irqstatus, ISP_IRQ0STATUS);
+ ispccdc_enable_lsc(0);
+ ispccdc_enable_lsc(1);
+ spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+ return IRQ_HANDLED;
+ }
+
if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
u32 ispcsi1_irqstatus;
@@ -929,6 +956,7 @@ void isp_stop()
omapisp_unset_callback();
if (ispmodule_obj.isp_pipeline & OMAP_ISP_CCDC) {
+ ispccdc_enable_lsc(0);
ispccdc_enable(0);
timeout = 0;
while (ispccdc_busy() && (timeout < 20)) {
--- a/drivers/media/video/isp/ispccdc.c 2008-06-29 14:08:16.000000000 -0500
+++ b/drivers/media/video/isp/ispccdc.c 2008-06-29 13:31:19.000000000 -0500
@@ -83,6 +83,16 @@ static struct isp_ccdc {
struct mutex mutexlock;
} ispccdc_obj;
+static struct ispccdc_lsc_config lsc_config;
+static u8 *lsc_gain_table;
+static unsigned long lsc_ispmmu_addr;
+static int lsc_initialized;
+static int size_mismatch;
+static u8 ccdc_use_lsc;
+static u8 ispccdc_lsc_tbl[] = {
+ #include "ispccd_lsc.dat"
+};
+
/* Structure for saving/restoring CCDC module registers*/
static struct isp_reg ispccdc_reg_list[] = {
{ISPCCDC_SYN_MODE, 0},
@@ -143,6 +153,7 @@ int omap34xx_isp_ccdc_config(void *users
struct ispccdc_fpc fpc_t;
struct ispccdc_culling cull_t;
struct ispccdc_update_config *ccdc_struct;
+ u32 old_size;
if (userspace_add == NULL)
return -EINVAL;
@@ -230,6 +241,60 @@ int omap34xx_isp_ccdc_config(void *users
ispccdc_config_culling(cull_t);
}
+ if (is_isplsc_activated()) {
+ if ((ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->flag) ==
+ ISP_ABS_CCDC_CONFIG_LSC) {
+ if ((ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) ==
+ ISP_ABS_CCDC_CONFIG_LSC) {
+ old_size = lsc_config.size;
+ if (copy_from_user(&lsc_config,
+ (struct ispccdc_lsc_config *)
+ (ccdc_struct->lsc_cfg),
+ sizeof(struct
+ ispccdc_lsc_config)))
+ goto copy_from_user_err;
+ lsc_initialized = 0;
+ if (lsc_config.size <= old_size)
+ size_mismatch = 0;
+ else
+ size_mismatch = 1;
+ ispccdc_config_lsc(&lsc_config);
+ }
+ ccdc_use_lsc = 1;
+ } else if ((ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) ==
+ ISP_ABS_CCDC_CONFIG_LSC) {
+ ispccdc_enable_lsc(0);
+ ccdc_use_lsc = 0;
+ }
+ if ((ISP_ABS_TBL_LSC & ccdc_struct->update)
+ == ISP_ABS_TBL_LSC) {
+ if (size_mismatch) {
+ ispmmu_unmap(lsc_ispmmu_addr);
+ kfree(lsc_gain_table);
+ lsc_gain_table = kmalloc(
+ lsc_config.size,
+ GFP_KERNEL | GFP_DMA);
+ if (!lsc_gain_table) {
+ printk(KERN_ERR
+ "Cannot allocate\
+ memory for \
+ gain tables \n");
+ return -ENOMEM;
+ }
+ lsc_ispmmu_addr = ispmmu_map(
+ virt_to_phys(lsc_gain_table),
+ lsc_config.size);
+ omap_writel(lsc_ispmmu_addr,
+ ISPCCDC_LSC_TABLE_BASE);
+ lsc_initialized = 1;
+ size_mismatch = 0;
+ }
+ if (copy_from_user(lsc_gain_table,
+ (ccdc_struct->lsc), lsc_config.size))
+ goto copy_from_user_err;
+ }
+ }
+
if ((ISP_ABS_CCDC_COLPTN & ccdc_struct->update) == ISP_ABS_CCDC_COLPTN)
ispccdc_config_imgattr(ccdc_struct->colptn);
@@ -294,6 +359,92 @@ int ispccdc_free(void)
EXPORT_SYMBOL(ispccdc_free);
/**
+ * ispccdc_load_lsc - Load Lens Shading Compensation table.
+ * @table_size: LSC gain table size.
+ *
+ * Returns 0 if successful, or -ENOMEM of its no memory available.
+ **/
+int ispccdc_load_lsc(u32 table_size)
+{
+ if (!is_isplsc_activated())
+ return 0;
+
+ if (table_size == 0)
+ return -EINVAL;
+
+ if (lsc_initialized)
+ return 0;
+
+ ispccdc_enable_lsc(0);
+ lsc_gain_table = kmalloc(table_size, GFP_KERNEL | GFP_DMA);
+
+ if (!lsc_gain_table) {
+ printk(KERN_ERR "Cannot allocate memory for gain tables \n");
+ return -ENOMEM;
+ }
+
+ memcpy(lsc_gain_table, ispccdc_lsc_tbl, table_size);
+ lsc_ispmmu_addr = ispmmu_map(virt_to_phys(lsc_gain_table), table_size);
+ omap_writel(lsc_ispmmu_addr, ISPCCDC_LSC_TABLE_BASE);
+ lsc_initialized = 1;
+ return 0;
+}
+EXPORT_SYMBOL(ispccdc_load_lsc);
+
+/**
+ * ispccdc_config_lsc - Configures the lens shading compensation module
+ * @lsc_cfg: LSC configuration structure
+ **/
+void ispccdc_config_lsc(struct ispccdc_lsc_config *lsc_cfg)
+{
+ int reg;
+
+ if (!is_isplsc_activated())
+ return;
+
+ ispccdc_enable_lsc(0);
+ omap_writel(lsc_cfg->offset, ISPCCDC_LSC_TABLE_OFFSET);
+
+ reg = 0;
+ reg |= (lsc_cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT);
+ reg |= (lsc_cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT);
+ reg |= (lsc_cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT);
+ omap_writel(reg, ISPCCDC_LSC_CONFIG);
+
+ reg = 0;
+ reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
+ reg |= (lsc_cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT);
+ reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
+ reg |= (lsc_cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT);
+ omap_writel(reg, ISPCCDC_LSC_INITIAL);
+}
+EXPORT_SYMBOL(ispccdc_config_lsc);
+
+/**
+ * ispccdc_enable_lsc - Enables/Disables the Lens Shading Compensation module.
+ * @enable: 0 Disables LSC, 1 Enables LSC.
+ **/
+void ispccdc_enable_lsc(u8 enable)
+{
+ if (!is_isplsc_activated())
+ return;
+
+ if (enable) {
+ omap_writel(omap_readl(ISP_CTRL) | ISPCTRL_SBL_SHARED_RPORTB |
+ ISPCTRL_SBL_RD_RAM_EN, ISP_CTRL);
+ omap_writel(omap_readl(ISPCCDC_LSC_CONFIG) | 0x1,
+ ISPCCDC_LSC_CONFIG);
+ ispccdc_obj.lsc_en = 1;
+ } else {
+ omap_writel(omap_readl(ISPCCDC_LSC_CONFIG) & 0xFFFE,
+ ISPCCDC_LSC_CONFIG);
+ ispccdc_obj.lsc_en = 0;
+ }
+}
+EXPORT_SYMBOL(ispccdc_enable_lsc);
+
+
+/**
* ispccdc_config_crop - Configures crop parameters for the ISP CCDC.
* @left: Left offset of the crop area.
* @top: Top offset of the crop area.
@@ -420,6 +571,19 @@ int ispccdc_config_datapath(enum ccdc_in
return -EINVAL;
};
+ if (is_isplsc_activated()) {
+ if (input == CCDC_RAW) {
+ lsc_config.initial_x = 0;
+ lsc_config.initial_y = 0;
+ lsc_config.gain_mode_n = 0x6;
+ lsc_config.gain_mode_m = 0x6;
+ lsc_config.gain_format = 0x4;
+ lsc_config.offset = 0x60;
+ ispccdc_config_lsc(&lsc_config);
+ ispccdc_load_lsc((u32)sizeof(ispccdc_lsc_tbl));
+ }
+ }
+
omap_writel(syn_mode, ISPCCDC_SYN_MODE);
switch (input) {
@@ -884,7 +1048,10 @@ EXPORT_SYMBOL(ispccdc_config_imgattr);
**/
void ispccdc_config_shadow_registers(void)
{
- return;
+ if (ccdc_use_lsc && !ispccdc_obj.lsc_en && (ispccdc_obj.ccdc_inpfmt ==
+ CCDC_RAW))
+ ispccdc_enable_lsc(1);
+
}
EXPORT_SYMBOL(ispccdc_config_shadow_registers);
@@ -1044,6 +1211,13 @@ int ispccdc_config_size(u32 input_w, u32
ISPCCDC_VDINT_1_SHIFT), ISPCCDC_VDINT);
}
+ if (is_isplsc_activated()) {
+ if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) {
+ ispccdc_config_lsc(&lsc_config);
+ ispccdc_load_lsc(lsc_config.size);
+ }
+ }
+
return 0;
}
EXPORT_SYMBOL(ispccdc_config_size);
@@ -1274,6 +1448,17 @@ static int __init isp_ccdc_init(void)
ispccdc_config_crop(0, 0, 0, 0);
mutex_init(&ispccdc_obj.mutexlock);
+ if (is_isplsc_activated()) {
+ lsc_config.initial_x = 0;
+ lsc_config.initial_y = 0;
+ lsc_config.gain_mode_n = 0x6;
+ lsc_config.gain_mode_m = 0x6;
+ lsc_config.gain_format = 0x4;
+ lsc_config.offset = 0x60;
+ lsc_config.size = sizeof(ispccdc_lsc_tbl);
+ ccdc_use_lsc = 1;
+ }
+
return 0;
}
@@ -1282,6 +1467,14 @@ static int __init isp_ccdc_init(void)
**/
static void isp_ccdc_cleanup(void)
{
+ if (is_isplsc_activated()) {
+ if (lsc_initialized) {
+ ispmmu_unmap(lsc_ispmmu_addr);
+ kfree(lsc_gain_table);
+ lsc_initialized = 0;
+ }
+ }
+
if (fpc_table_add_m != 0) {
ispmmu_unmap(fpc_table_add_m);
kfree(fpc_table_add);
--- a/drivers/media/video/isp/ispccdc.h 2008-06-29 14:08:16.000000000 -0500
+++ b/drivers/media/video/isp/ispccdc.h 2008-06-29 13:38:12.000000000 -0500
@@ -23,6 +23,14 @@
#include <asm/arch/isp_user.h>
+#ifndef CONFIG_ARCH_OMAP3410
+# define cpu_is_omap3410() 0
+# define is_isplsc_activated() 1
+#else
+# define cpu_is_omap3410() 1
+# define is_isplsc_activated() 0
+#endif
+
#ifdef OMAP_ISPCCDC_DEBUG
# define is_ispccdc_debug_enabled() 1
#else
--- a/include/asm-arm/arch-omap/isp_user.h 2008-06-29 14:08:16.000000000 -0500
+++ b/include/asm-arm/arch-omap/isp_user.h 2008-06-29 13:35:05.000000000 -0500
@@ -60,6 +60,37 @@ enum vpif_freq {
};
/**
+ * struct ispccdc_lsc_config - Structure for LSC configuration.
+ * @offset: Table Offset of the gain table.
+ * @gain_mode_n: Vertical dimension of a paxel in LSC configuration.
+ * @gain_mode_m: Horizontal dimension of a paxel in LSC configuration.
+ * @gain_format: Gain table format.
+ * @fmtsph: Start pixel horizontal from start of the HS sync pulse.
+ * @fmtlnh: Number of pixels in horizontal direction to use for the data
+ * reformatter.
+ * @fmtslv: Start line from start of VS sync pulse for the data reformatter.
+ * @fmtlnv: Number of lines in vertical direction for the data reformatter.
+ * @initial_x: X position, in pixels, of the first active pixel in reference
+ * to the first active paxel. Must be an even number.
+ * @initial_y: Y position, in pixels, of the first active pixel in reference
+ * to the first active paxel. Must be an even number.
+ * @size: Size of LSC gain table. Filled when loaded from userspace.
+ */
+struct ispccdc_lsc_config {
+ u8 offset;
+ u8 gain_mode_n;
+ u8 gain_mode_m;
+ u8 gain_format;
+ u16 fmtsph;
+ u16 fmtlnh;
+ u16 fmtslv;
+ u16 fmtlnv;
+ u8 initial_x;
+ u8 initial_y;
+ u32 size;
+};
+
+/**
* struct ispccdc_bclamp - Structure for Optical & Digital black clamp subtract
* @obgain: Optical black average gain.
* @obstpixel: Start Pixel w.r.t. HS pulse in Optical black sample.
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2008-07-01 4:09 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-01 4:09 [Patch 12/16] OMAP3 camera driver LSC support Mohit Jalori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox