From m-karicheri2 at ti.com Tue Dec 1 09:30:14 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 10:30:14 -0500 Subject: [PATCH] V4L - Fix videobuf_dma_contig_user_get() getting page aligned physical address Message-ID: <1259681414-30246-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri If a USERPTR address that is not aligned to page boundary is passed to the videobuf_dma_contig_user_get() function, it saves a page aligned address to the dma_handle. This is not correct. This issue is observed when using USERPTR IO machism for buffer exchange. Signed-off-by: Muralidharan Karicheri --- Applies to V4L-DVB linux-next branch drivers/media/video/videobuf-dma-contig.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index d25f284..928dfa1 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -166,7 +166,8 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, break; if (pages_done == 0) - mem->dma_handle = this_pfn << PAGE_SHIFT; + mem->dma_handle = (this_pfn << PAGE_SHIFT) + + (vb->baddr & ~PAGE_MASK); else if (this_pfn != (prev_pfn + 1)) ret = -EFAULT; -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 09:42:12 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Tue, 1 Dec 2009 09:42:12 -0600 Subject: architecture part of video driver patch Message-ID: Kevin, Following patch merged to v4l-dvb linux-next has an architectural part as attached. If you have not merged it to your next branch for linux-davinci tree, please do so at your earliest convenience so that they are in sync. Patch merged to linux-next is available at http://git.kernel.org/?p=linux/kernel/git/mchehab/linux-next.git;a=commitdiff;h=600cc66f7f3ec93ab4f09cf6b63980f4c5e8f8db I will be pushing some more patches to upstream that are having changes to arch part. I will notify once they are merged to linux-next. Thanks. Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com -------------- next part -------------- An embedded message was scrubbed... From: "Hiremath, Vaibhav" Subject: [PATCH 3/6] Davinci VPFE Capture: Take i2c adapter id through platform data Date: Tue, 13 Oct 2009 10:08:54 -0500 Size: 4476 URL: From m-karicheri2 at ti.com Tue Dec 1 11:19:00 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 12:19:00 -0500 Subject: [PATCH - v0 2/2] DaVinci - vpfe capture - Make clocks configurable In-Reply-To: <1259687940-31435-1-git-send-email-m-karicheri2@ti.com> References: <1259687940-31435-1-git-send-email-m-karicheri2@ti.com> Message-ID: <1259687940-31435-2-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri Adding the clocks in vpfe capture configuration Signed-off-by: Muralidharan Karicheri --- arch/arm/mach-davinci/board-dm355-evm.c | 2 ++ arch/arm/mach-davinci/board-dm644x-evm.c | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index a9b650d..a28985c 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -239,6 +239,8 @@ static struct vpfe_config vpfe_cfg = { .sub_devs = vpfe_sub_devs, .card_name = "DM355 EVM", .ccdc = "DM355 CCDC", + .num_clocks = 2, + .clocks = {"vpss_master", "vpss_slave"}, }; static struct platform_device *davinci_evm_devices[] __initdata = { diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index fd0398b..45beb99 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -250,6 +250,8 @@ static struct vpfe_config vpfe_cfg = { .sub_devs = vpfe_sub_devs, .card_name = "DM6446 EVM", .ccdc = "DM6446 CCDC", + .num_clocks = 2, + .clocks = {"vpss_master", "vpss_slave"}, }; static struct platform_device rtc_dev = { -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 11:18:59 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 12:18:59 -0500 Subject: [PATCH - v1 1/2] V4L - vpfe capture - make clocks configurable Message-ID: <1259687940-31435-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri v1 - updated based on comments from Vaibhav Hiremath. On DM365 we use only vpss master clock, where as on DM355 and DM6446, we use vpss master and slave clocks for vpfe capture and AM3517 we use internal clock and pixel clock. So this patch makes it configurable on a per platform basis. This is needed for supporting DM365 for which patches will be available soon. Tested-by: Vaibhav Hiremath , Muralidharan Karicheri Acked-by: Vaibhav Hiremath Signed-off-by: Muralidharan Karicheri --- drivers/media/video/davinci/vpfe_capture.c | 98 +++++++++++++++++---------- include/media/davinci/vpfe_capture.h | 11 ++- 2 files changed, 70 insertions(+), 39 deletions(-) diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 12a1b3d..c3468ee 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -1787,61 +1787,87 @@ static struct vpfe_device *vpfe_initialize(void) return vpfe_dev; } +/** + * vpfe_disable_clock() - Disable clocks for vpfe capture driver + * @vpfe_dev - ptr to vpfe capture device + * + * Disables clocks defined in vpfe configuration. + */ static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) { struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; + int i; - clk_disable(vpfe_cfg->vpssclk); - clk_put(vpfe_cfg->vpssclk); - clk_disable(vpfe_cfg->slaveclk); - clk_put(vpfe_cfg->slaveclk); - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master & slave clocks disabled\n"); + for (i = 0; i < vpfe_cfg->num_clocks; i++) { + clk_disable(vpfe_dev->clks[i]); + clk_put(vpfe_dev->clks[i]); + } + kfree(vpfe_dev->clks); + v4l2_info(vpfe_dev->pdev->driver, "vpfe capture clocks disabled\n"); } +/** + * vpfe_enable_clock() - Enable clocks for vpfe capture driver + * @vpfe_dev - ptr to vpfe capture device + * + * Enables clocks defined in vpfe configuration. The function + * assumes that at least one clock is to be defined which is + * true as of now. re-visit this if this assumption is not true + */ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) { struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int ret = -ENOENT; + int i; - vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master"); - if (NULL == vpfe_cfg->vpssclk) { - v4l2_err(vpfe_dev->pdev->driver, "No clock defined for" - "vpss_master\n"); - return ret; - } + if (!vpfe_cfg->num_clocks) + return 0; - if (clk_enable(vpfe_cfg->vpssclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss master clock not enabled\n"); - goto out; - } - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master clock enabled\n"); + vpfe_dev->clks = kzalloc(vpfe_cfg->num_clocks * + sizeof(struct clock *), GFP_KERNEL); - vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave"); - if (NULL == vpfe_cfg->slaveclk) { - v4l2_err(vpfe_dev->pdev->driver, - "No clock defined for vpss slave\n"); - goto out; + if (NULL == vpfe_dev->clks) { + v4l2_err(vpfe_dev->pdev->driver, "Memory allocation failed\n"); + return -ENOMEM; } - if (clk_enable(vpfe_cfg->slaveclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss slave clock not enabled\n"); - goto out; + for (i = 0; i < vpfe_cfg->num_clocks; i++) { + if (NULL == vpfe_cfg->clocks[i]) { + v4l2_err(vpfe_dev->pdev->driver, + "clock %s is not defined in vpfe config\n", + vpfe_cfg->clocks[i]); + goto out; + } + + vpfe_dev->clks[i] = clk_get(vpfe_dev->pdev, + vpfe_cfg->clocks[i]); + if (NULL == vpfe_dev->clks[i]) { + v4l2_err(vpfe_dev->pdev->driver, + "Failed to get clock %s\n", + vpfe_cfg->clocks[i]); + goto out; + } + + if (clk_enable(vpfe_dev->clks[i])) { + v4l2_err(vpfe_dev->pdev->driver, + "vpfe clock %s not enabled\n", + vpfe_cfg->clocks[i]); + goto out; + } + + v4l2_info(vpfe_dev->pdev->driver, "vpss clock %s enabled", + vpfe_cfg->clocks[i]); } - v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n"); return 0; out: - if (vpfe_cfg->vpssclk) - clk_put(vpfe_cfg->vpssclk); - if (vpfe_cfg->slaveclk) - clk_put(vpfe_cfg->slaveclk); - - return -1; + for (i = 0; i < vpfe_cfg->num_clocks; i++) { + if (vpfe_dev->clks[i]) + clk_put(vpfe_dev->clks[i]); + } + kfree(vpfe_dev->clks); + return -EFAULT; } + /* * vpfe_probe : This function creates device entries by register * itself to the V4L2 driver and initializes fields of each diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h index d863e5e..7b62a5c 100644 --- a/include/media/davinci/vpfe_capture.h +++ b/include/media/davinci/vpfe_capture.h @@ -31,8 +31,6 @@ #include #include -#define VPFE_CAPTURE_NUM_DECODERS 5 - /* Macros */ #define VPFE_MAJOR_RELEASE 0 #define VPFE_MINOR_RELEASE 0 @@ -91,9 +89,14 @@ struct vpfe_config { char *card_name; /* ccdc name */ char *ccdc; - /* vpfe clock */ + /* vpfe clock. Obsolete! Will be removed in next patch */ struct clk *vpssclk; + /* Obsolete! Will be removed in next patch */ struct clk *slaveclk; + /* number of clocks */ + int num_clocks; + /* clocks used for vpfe capture */ + char *clocks[]; }; struct vpfe_device { @@ -104,6 +107,8 @@ struct vpfe_device { struct v4l2_subdev **sd; /* vpfe cfg */ struct vpfe_config *cfg; + /* clock ptrs for vpfe capture */ + struct clk **clks; /* V4l2 device */ struct v4l2_device v4l2_dev; /* parent device */ -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 12:15:32 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 13:15:32 -0500 Subject: [PATCH v0 1/2] V4L - vpfe capture - convert ccdc drivers to platform drivers Message-ID: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri Current implementation defines ccdc memory map in vpfe capture platform file and update the same in ccdc through a function call. This will not scale well. For example for DM365 CCDC, there are are additional memory map for Linear table. So it is cleaner to define memory map for ccdc driver in the platform file and read it by the ccdc platform driver during probe. Signed-off-by: Muralidharan Karicheri --- Applies to V4L-DVB linux-next tree drivers/media/video/davinci/dm355_ccdc.c | 89 ++++++++++++++++++++++++---- drivers/media/video/davinci/dm644x_ccdc.c | 78 ++++++++++++++++++++---- drivers/media/video/davinci/vpfe_capture.c | 49 +-------------- 3 files changed, 145 insertions(+), 71 deletions(-) diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index 56fbefe..aacb95f 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include "dm355_ccdc_regs.h" @@ -105,7 +106,6 @@ static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { static enum vpfe_hw_if_type ccdc_if_type; static void *__iomem ccdc_base_addr; -static int ccdc_addr_size; /* Raw Bayer formats */ static u32 ccdc_raw_bayer_pix_formats[] = @@ -126,12 +126,6 @@ static inline void regw(u32 val, u32 offset) __raw_writel(val, ccdc_base_addr + offset); } -static void ccdc_set_ccdc_base(void *addr, int size) -{ - ccdc_base_addr = addr; - ccdc_addr_size = size; -} - static void ccdc_enable(int en) { unsigned int temp; @@ -938,7 +932,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { .hw_ops = { .open = ccdc_open, .close = ccdc_close, - .set_ccdc_base = ccdc_set_ccdc_base, .enable = ccdc_enable, .enable_out_to_sdram = ccdc_enable_output_to_sdram, .set_hw_if_params = ccdc_set_hw_if_params, @@ -959,19 +952,89 @@ static struct ccdc_hw_device ccdc_hw_dev = { }, }; -static int __init dm355_ccdc_init(void) +static int __init dm355_ccdc_probe(struct platform_device *pdev) { - printk(KERN_NOTICE "dm355_ccdc_init\n"); - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) - return -1; + static resource_size_t res_len; + struct resource *res; + int status = 0; + + /** + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENOENT; + goto fail_nores; + } + res_len = res->end - res->start + 1; + + res = request_mem_region(res->start, res_len, res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_base_addr = ioremap_nocache(res->start, res_len); + if (!ccdc_base_addr) { + status = -EBUSY; + goto fail; + } + /** + * setup Mux configuration for vpfe input and register + * vpfe capture platform device + */ + davinci_cfg_reg(DM355_VIN_PCLK); + davinci_cfg_reg(DM355_VIN_CAM_WEN); + davinci_cfg_reg(DM355_VIN_CAM_VD); + davinci_cfg_reg(DM355_VIN_CAM_HD); + davinci_cfg_reg(DM355_VIN_YIN_EN); + davinci_cfg_reg(DM355_VIN_CINL_EN); + davinci_cfg_reg(DM355_VIN_CINH_EN); + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; +fail: + release_mem_region(res->start, res_len); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; } -static void __exit dm355_ccdc_exit(void) +static int dm355_ccdc_remove(struct platform_device *pdev) { + struct resource *res; + + iounmap(ccdc_base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, res->end - res->start + 1); vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm355_ccdc_driver = { + .driver = { + .name = "dm355_ccdc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm355_ccdc_remove), + .probe = dm355_ccdc_probe, +}; + +static int __init dm355_ccdc_init(void) +{ + return platform_driver_register(&dm355_ccdc_driver); +} + +static void __exit dm355_ccdc_exit(void) +{ + platform_driver_unregister(&dm355_ccdc_driver); } module_init(dm355_ccdc_init); diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index d5fa193..89ea6ae 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -85,7 +85,6 @@ static u32 ccdc_raw_yuv_pix_formats[] = {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; static void *__iomem ccdc_base_addr; -static int ccdc_addr_size; static enum vpfe_hw_if_type ccdc_if_type; /* register access routines */ @@ -99,12 +98,6 @@ static inline void regw(u32 val, u32 offset) __raw_writel(val, ccdc_base_addr + offset); } -static void ccdc_set_ccdc_base(void *addr, int size) -{ - ccdc_base_addr = addr; - ccdc_addr_size = size; -} - static void ccdc_enable(int flag) { regw(flag, CCDC_PCR); @@ -838,7 +831,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { .hw_ops = { .open = ccdc_open, .close = ccdc_close, - .set_ccdc_base = ccdc_set_ccdc_base, .reset = ccdc_sbl_reset, .enable = ccdc_enable, .set_hw_if_params = ccdc_set_hw_if_params, @@ -859,19 +851,79 @@ static struct ccdc_hw_device ccdc_hw_dev = { }, }; -static int __init dm644x_ccdc_init(void) +static int __init dm644x_ccdc_probe(struct platform_device *pdev) { - printk(KERN_NOTICE "dm644x_ccdc_init\n"); - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) - return -1; + static resource_size_t res_len; + struct resource *res; + int status = 0; + + /** + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENOENT; + goto fail_nores; + } + + res_len = res->end - res->start + 1; + + res = request_mem_region(res->start, res_len, res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_base_addr = ioremap_nocache(res->start, res_len); + if (!ccdc_base_addr) { + status = -EBUSY; + goto fail; + } + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; +fail: + release_mem_region(res->start, res_len); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; +} + +static int dm644x_ccdc_remove(struct platform_device *pdev) +{ + struct resource *res; + + iounmap(ccdc_base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, res->end - res->start + 1); + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm644x_ccdc_driver = { + .driver = { + .name = "dm644x_ccdc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm644x_ccdc_remove), + .probe = dm644x_ccdc_probe, +}; + +static int __init dm644x_ccdc_init(void) +{ + return platform_driver_register(&dm644x_ccdc_driver); } static void __exit dm644x_ccdc_exit(void) { - vpfe_unregister_ccdc_device(&ccdc_hw_dev); + platform_driver_unregister(&dm644x_ccdc_driver); } module_init(dm644x_ccdc_init); diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index c3468ee..35bbb08 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -108,9 +108,6 @@ struct ccdc_config { int vpfe_probed; /* name of ccdc device */ char name[32]; - /* for storing mem maps for CCDC */ - int ccdc_addr_size; - void *__iomem ccdc_addr; }; /* data structures */ @@ -230,7 +227,6 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) BUG_ON(!dev->hw_ops.set_image_window); BUG_ON(!dev->hw_ops.get_image_window); BUG_ON(!dev->hw_ops.get_line_length); - BUG_ON(!dev->hw_ops.setfbaddr); BUG_ON(!dev->hw_ops.getfid); mutex_lock(&ccdc_lock); @@ -241,25 +237,23 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) * walk through it during vpfe probe */ printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -1; + ret = -EFAULT; goto unlock; } if (strcmp(dev->name, ccdc_cfg->name)) { /* ignore this ccdc */ - ret = -1; + ret = -EINVAL; goto unlock; } if (ccdc_dev) { printk(KERN_ERR "ccdc already registered\n"); - ret = -1; + ret = -EINVAL; goto unlock; } ccdc_dev = dev; - dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr, - ccdc_cfg->ccdc_addr_size); unlock: mutex_unlock(&ccdc_lock); return ret; @@ -1947,37 +1941,12 @@ static __init int vpfe_probe(struct platform_device *pdev) } vpfe_dev->ccdc_irq1 = res1->start; - /* Get address base of CCDC */ - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get register address map\n"); - ret = -ENOENT; - goto probe_disable_clock; - } - - ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1; - if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size, - pdev->dev.driver->name)) { - v4l2_err(pdev->dev.driver, - "Failed request_mem_region for ccdc base\n"); - ret = -ENXIO; - goto probe_disable_clock; - } - ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start, - ccdc_cfg->ccdc_addr_size); - if (!ccdc_cfg->ccdc_addr) { - v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n"); - ret = -ENXIO; - goto probe_out_release_mem1; - } - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, "vpfe_capture0", vpfe_dev); if (0 != ret) { v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_out_unmap1; + goto probe_disable_clock; } /* Allocate memory for video device */ @@ -2101,10 +2070,6 @@ probe_out_video_release: video_device_release(vpfe_dev->video_dev); probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_out_unmap1: - iounmap(ccdc_cfg->ccdc_addr); -probe_out_release_mem1: - release_mem_region(res1->start, res1->end - res1->start + 1); probe_disable_clock: vpfe_disable_clock(vpfe_dev); mutex_unlock(&ccdc_lock); @@ -2120,7 +2085,6 @@ probe_free_dev_mem: static int vpfe_remove(struct platform_device *pdev) { struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - struct resource *res; v4l2_info(pdev->dev.driver, "vpfe_remove\n"); @@ -2128,11 +2092,6 @@ static int vpfe_remove(struct platform_device *pdev) kfree(vpfe_dev->sd); v4l2_device_unregister(&vpfe_dev->v4l2_dev); video_unregister_device(vpfe_dev->video_dev); - mutex_lock(&ccdc_lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); - iounmap(ccdc_cfg->ccdc_addr); - mutex_unlock(&ccdc_lock); vpfe_disable_clock(vpfe_dev); kfree(vpfe_dev); kfree(ccdc_cfg); -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 12:15:33 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 13:15:33 -0500 Subject: [PATCH 2/2] DaVinci - vpfe capture - converting ccdc to platform driver In-Reply-To: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> Message-ID: <1259691333-32164-2-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This is the platform part for converting ccdc to platform driver. Signed-off-by: Muralidharan Karicheri --- Applies to linux-davinci tree arch/arm/mach-davinci/dm355.c | 27 +++++++++++++++------------ arch/arm/mach-davinci/dm644x.c | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index dedf4d4..045cb0d 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -701,6 +701,10 @@ static struct resource vpfe_resources[] = { .end = IRQ_VDINT1, .flags = IORESOURCE_IRQ, }, +}; + +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); +static struct resource dm355_ccdc_resource[] = { /* CCDC Base address */ { .flags = IORESOURCE_MEM, @@ -708,8 +712,17 @@ static struct resource vpfe_resources[] = { .end = 0x01c70600 + 0x1ff, }, }; +static struct platform_device dm355_ccdc_dev = { + .name = "dm355_ccdc", + .id = -1, + .num_resources = ARRAY_SIZE(dm355_ccdc_resource), + .resource = dm355_ccdc_resource, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; -static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); static struct platform_device vpfe_capture_dev = { .name = CAPTURE_DRV_NAME, .id = -1, @@ -860,17 +873,7 @@ static int __init dm355_init_devices(void) davinci_cfg_reg(DM355_INT_EDMA_CC); platform_device_register(&dm355_edma_device); platform_device_register(&dm355_vpss_device); - /* - * setup Mux configuration for vpfe input and register - * vpfe capture platform device - */ - davinci_cfg_reg(DM355_VIN_PCLK); - davinci_cfg_reg(DM355_VIN_CAM_WEN); - davinci_cfg_reg(DM355_VIN_CAM_VD); - davinci_cfg_reg(DM355_VIN_CAM_HD); - davinci_cfg_reg(DM355_VIN_YIN_EN); - davinci_cfg_reg(DM355_VIN_CINL_EN); - davinci_cfg_reg(DM355_VIN_CINH_EN); + platform_device_register(&dm355_ccdc_dev); platform_device_register(&vpfe_capture_dev); return 0; diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 2cd0081..982be1f 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -612,6 +612,11 @@ static struct resource vpfe_resources[] = { .end = IRQ_VDINT1, .flags = IORESOURCE_IRQ, }, +}; + +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); +static struct resource dm644x_ccdc_resource[] = { + /* CCDC Base address */ { .start = 0x01c70400, .end = 0x01c70400 + 0xff, @@ -619,7 +624,17 @@ static struct resource vpfe_resources[] = { }, }; -static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); +static struct platform_device dm644x_ccdc_dev = { + .name = "dm644x_ccdc", + .id = -1, + .num_resources = ARRAY_SIZE(dm644x_ccdc_resource), + .resource = dm644x_ccdc_resource, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + static struct platform_device vpfe_capture_dev = { .name = CAPTURE_DRV_NAME, .id = -1, @@ -772,6 +787,7 @@ static int __init dm644x_init_devices(void) platform_device_register(&dm644x_edma_device); platform_device_register(&dm644x_emac_device); platform_device_register(&dm644x_vpss_device); + platform_device_register(&dm644x_ccdc_dev); platform_device_register(&vpfe_capture_dev); return 0; -- 1.6.0.4 From hvaibhav at ti.com Tue Dec 1 13:28:36 2009 From: hvaibhav at ti.com (Hiremath, Vaibhav) Date: Wed, 2 Dec 2009 00:58:36 +0530 Subject: [PATCH v0 1/2] V4L - vpfe capture - convert ccdc drivers to platform drivers In-Reply-To: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> Message-ID: <19F8576C6E063C45BE387C64729E7394043716AE11@dbde02.ent.ti.com> > -----Original Message----- > From: Karicheri, Muralidharan > Sent: Tuesday, December 01, 2009 11:46 PM > To: linux-media at vger.kernel.org; hverkuil at xs4all.nl; > khilman at deeprootsystems.com > Cc: davinci-linux-open-source at linux.davincidsp.com; Hiremath, > Vaibhav; Karicheri, Muralidharan > Subject: [PATCH v0 1/2] V4L - vpfe capture - convert ccdc drivers to > platform drivers > > From: Muralidharan Karicheri > > Current implementation defines ccdc memory map in vpfe capture > platform > file and update the same in ccdc through a function call. This will > not > scale well. For example for DM365 CCDC, there are are additional > memory > map for Linear table. So it is cleaner to define memory map for ccdc > driver in the platform file and read it by the ccdc platform driver > during > probe. > > Signed-off-by: Muralidharan Karicheri > --- > Applies to V4L-DVB linux-next tree > drivers/media/video/davinci/dm355_ccdc.c | 89 > ++++++++++++++++++++++++---- > drivers/media/video/davinci/dm644x_ccdc.c | 78 > ++++++++++++++++++++---- > drivers/media/video/davinci/vpfe_capture.c | 49 +-------------- > 3 files changed, 145 insertions(+), 71 deletions(-) > > diff --git a/drivers/media/video/davinci/dm355_ccdc.c > b/drivers/media/video/davinci/dm355_ccdc.c > index 56fbefe..aacb95f 100644 > --- a/drivers/media/video/davinci/dm355_ccdc.c > +++ b/drivers/media/video/davinci/dm355_ccdc.c > @@ -37,6 +37,7 @@ > #include > #include > #include > +#include [Hiremath, Vaibhav] This should not be here, this should get handled in board file. The driver should be generic. > #include > #include > #include "dm355_ccdc_regs.h" > @@ -105,7 +106,6 @@ static struct ccdc_params_ycbcr > ccdc_hw_params_ycbcr = { > > static enum vpfe_hw_if_type ccdc_if_type; > static void *__iomem ccdc_base_addr; > -static int ccdc_addr_size; > > /* Raw Bayer formats */ > static u32 ccdc_raw_bayer_pix_formats[] = > @@ -126,12 +126,6 @@ static inline void regw(u32 val, u32 offset) > __raw_writel(val, ccdc_base_addr + offset); > } > > -static void ccdc_set_ccdc_base(void *addr, int size) > -{ > - ccdc_base_addr = addr; > - ccdc_addr_size = size; > -} > - > static void ccdc_enable(int en) > { > unsigned int temp; > @@ -938,7 +932,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { > .hw_ops = { > .open = ccdc_open, > .close = ccdc_close, > - .set_ccdc_base = ccdc_set_ccdc_base, > .enable = ccdc_enable, > .enable_out_to_sdram = ccdc_enable_output_to_sdram, > .set_hw_if_params = ccdc_set_hw_if_params, > @@ -959,19 +952,89 @@ static struct ccdc_hw_device ccdc_hw_dev = { > }, > }; > > -static int __init dm355_ccdc_init(void) > +static int __init dm355_ccdc_probe(struct platform_device *pdev) > { > - printk(KERN_NOTICE "dm355_ccdc_init\n"); > - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) > - return -1; > + static resource_size_t res_len; > + struct resource *res; > + int status = 0; > + > + /** > + * first try to register with vpfe. If not correct platform, > then we > + * don't have to iomap > + */ > + status = vpfe_register_ccdc_device(&ccdc_hw_dev); > + if (status < 0) > + return status; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + status = -ENOENT; [Hiremath, Vaibhav] I think right return value is -ENODEV. > + goto fail_nores; > + } > + res_len = res->end - res->start + 1; > + > + res = request_mem_region(res->start, res_len, res->name); [Hiremath, Vaibhav] You should use "resource_size" here for res_len here. > + if (!res) { > + status = -EBUSY; > + goto fail_nores; > + } > + > + ccdc_base_addr = ioremap_nocache(res->start, res_len); > + if (!ccdc_base_addr) { > + status = -EBUSY; [Hiremath, Vaibhav] Is -EBUSY right return value, I think it should be -ENXIO or -ENOMEM. > + goto fail; > + } > + /** > + * setup Mux configuration for vpfe input and register > + * vpfe capture platform device > + */ > + davinci_cfg_reg(DM355_VIN_PCLK); > + davinci_cfg_reg(DM355_VIN_CAM_WEN); > + davinci_cfg_reg(DM355_VIN_CAM_VD); > + davinci_cfg_reg(DM355_VIN_CAM_HD); > + davinci_cfg_reg(DM355_VIN_YIN_EN); > + davinci_cfg_reg(DM355_VIN_CINL_EN); > + davinci_cfg_reg(DM355_VIN_CINH_EN); > + [Hiremath, Vaibhav] This should not be here, this code must be generic and might get used in another SoC. > printk(KERN_NOTICE "%s is registered with vpfe.\n", > ccdc_hw_dev.name); > return 0; > +fail: > + release_mem_region(res->start, res_len); > +fail_nores: > + vpfe_unregister_ccdc_device(&ccdc_hw_dev); > + return status; > } > > -static void __exit dm355_ccdc_exit(void) > +static int dm355_ccdc_remove(struct platform_device *pdev) > { > + struct resource *res; > + > + iounmap(ccdc_base_addr); > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (res) > + release_mem_region(res->start, res->end - res->start + > 1); [Hiremath, Vaibhav] Please use "resource_size" here for size. > vpfe_unregister_ccdc_device(&ccdc_hw_dev); > + return 0; > +} > + > +static struct platform_driver dm355_ccdc_driver = { > + .driver = { > + .name = "dm355_ccdc", > + .owner = THIS_MODULE, > + }, > + .remove = __devexit_p(dm355_ccdc_remove), > + .probe = dm355_ccdc_probe, > +}; > + > +static int __init dm355_ccdc_init(void) > +{ > + return platform_driver_register(&dm355_ccdc_driver); > +} > + > +static void __exit dm355_ccdc_exit(void) > +{ > + platform_driver_unregister(&dm355_ccdc_driver); > } > > module_init(dm355_ccdc_init); > diff --git a/drivers/media/video/davinci/dm644x_ccdc.c > b/drivers/media/video/davinci/dm644x_ccdc.c > index d5fa193..89ea6ae 100644 > --- a/drivers/media/video/davinci/dm644x_ccdc.c > +++ b/drivers/media/video/davinci/dm644x_ccdc.c > @@ -85,7 +85,6 @@ static u32 ccdc_raw_yuv_pix_formats[] = > {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; > > static void *__iomem ccdc_base_addr; > -static int ccdc_addr_size; > static enum vpfe_hw_if_type ccdc_if_type; > > /* register access routines */ > @@ -99,12 +98,6 @@ static inline void regw(u32 val, u32 offset) > __raw_writel(val, ccdc_base_addr + offset); > } > > -static void ccdc_set_ccdc_base(void *addr, int size) > -{ > - ccdc_base_addr = addr; > - ccdc_addr_size = size; > -} > - > static void ccdc_enable(int flag) > { > regw(flag, CCDC_PCR); > @@ -838,7 +831,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { > .hw_ops = { > .open = ccdc_open, > .close = ccdc_close, > - .set_ccdc_base = ccdc_set_ccdc_base, > .reset = ccdc_sbl_reset, > .enable = ccdc_enable, > .set_hw_if_params = ccdc_set_hw_if_params, > @@ -859,19 +851,79 @@ static struct ccdc_hw_device ccdc_hw_dev = { > }, > }; > > -static int __init dm644x_ccdc_init(void) > +static int __init dm644x_ccdc_probe(struct platform_device *pdev) > { > - printk(KERN_NOTICE "dm644x_ccdc_init\n"); > - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) > - return -1; > + static resource_size_t res_len; > + struct resource *res; > + int status = 0; > + > + /** > + * first try to register with vpfe. If not correct platform, > then we > + * don't have to iomap > + */ > + status = vpfe_register_ccdc_device(&ccdc_hw_dev); > + if (status < 0) > + return status; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + status = -ENOENT; > + goto fail_nores; > + } > + > + res_len = res->end - res->start + 1; > + > + res = request_mem_region(res->start, res_len, res->name); > + if (!res) { > + status = -EBUSY; > + goto fail_nores; > + } > + > + ccdc_base_addr = ioremap_nocache(res->start, res_len); > + if (!ccdc_base_addr) { > + status = -EBUSY; > + goto fail; > + } > + > printk(KERN_NOTICE "%s is registered with vpfe.\n", > ccdc_hw_dev.name); > return 0; > +fail: > + release_mem_region(res->start, res_len); > +fail_nores: > + vpfe_unregister_ccdc_device(&ccdc_hw_dev); > + return status; > +} > + > +static int dm644x_ccdc_remove(struct platform_device *pdev) > +{ > + struct resource *res; > + > + iounmap(ccdc_base_addr); > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (res) > + release_mem_region(res->start, res->end - res->start + > 1); > + vpfe_unregister_ccdc_device(&ccdc_hw_dev); > + return 0; > +} > + > +static struct platform_driver dm644x_ccdc_driver = { > + .driver = { > + .name = "dm644x_ccdc", > + .owner = THIS_MODULE, > + }, > + .remove = __devexit_p(dm644x_ccdc_remove), > + .probe = dm644x_ccdc_probe, > +}; > + > +static int __init dm644x_ccdc_init(void) > +{ > + return platform_driver_register(&dm644x_ccdc_driver); > } > > static void __exit dm644x_ccdc_exit(void) > { > - vpfe_unregister_ccdc_device(&ccdc_hw_dev); > + platform_driver_unregister(&dm644x_ccdc_driver); > } [Hiremath, Vaibhav] All above comments mentioned for DM355 applicable here too. Thanks, Vaibhav > > module_init(dm644x_ccdc_init); > diff --git a/drivers/media/video/davinci/vpfe_capture.c > b/drivers/media/video/davinci/vpfe_capture.c > index c3468ee..35bbb08 100644 > --- a/drivers/media/video/davinci/vpfe_capture.c > +++ b/drivers/media/video/davinci/vpfe_capture.c > @@ -108,9 +108,6 @@ struct ccdc_config { > int vpfe_probed; > /* name of ccdc device */ > char name[32]; > - /* for storing mem maps for CCDC */ > - int ccdc_addr_size; > - void *__iomem ccdc_addr; > }; > > /* data structures */ > @@ -230,7 +227,6 @@ int vpfe_register_ccdc_device(struct > ccdc_hw_device *dev) > BUG_ON(!dev->hw_ops.set_image_window); > BUG_ON(!dev->hw_ops.get_image_window); > BUG_ON(!dev->hw_ops.get_line_length); > - BUG_ON(!dev->hw_ops.setfbaddr); > BUG_ON(!dev->hw_ops.getfid); > > mutex_lock(&ccdc_lock); > @@ -241,25 +237,23 @@ int vpfe_register_ccdc_device(struct > ccdc_hw_device *dev) > * walk through it during vpfe probe > */ > printk(KERN_ERR "vpfe capture not initialized\n"); > - ret = -1; > + ret = -EFAULT; > goto unlock; > } > > if (strcmp(dev->name, ccdc_cfg->name)) { > /* ignore this ccdc */ > - ret = -1; > + ret = -EINVAL; > goto unlock; > } > > if (ccdc_dev) { > printk(KERN_ERR "ccdc already registered\n"); > - ret = -1; > + ret = -EINVAL; > goto unlock; > } > > ccdc_dev = dev; > - dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr, > - ccdc_cfg->ccdc_addr_size); > unlock: > mutex_unlock(&ccdc_lock); > return ret; > @@ -1947,37 +1941,12 @@ static __init int vpfe_probe(struct > platform_device *pdev) > } > vpfe_dev->ccdc_irq1 = res1->start; > > - /* Get address base of CCDC */ > - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); > - if (!res1) { > - v4l2_err(pdev->dev.driver, > - "Unable to get register address map\n"); > - ret = -ENOENT; > - goto probe_disable_clock; > - } > - > - ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1; > - if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size, > - pdev->dev.driver->name)) { > - v4l2_err(pdev->dev.driver, > - "Failed request_mem_region for ccdc base\n"); > - ret = -ENXIO; > - goto probe_disable_clock; > - } > - ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start, > - ccdc_cfg->ccdc_addr_size); > - if (!ccdc_cfg->ccdc_addr) { > - v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc > addr\n"); > - ret = -ENXIO; > - goto probe_out_release_mem1; > - } > - > ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, > IRQF_DISABLED, > "vpfe_capture0", vpfe_dev); > > if (0 != ret) { > v4l2_err(pdev->dev.driver, "Unable to request > interrupt\n"); > - goto probe_out_unmap1; > + goto probe_disable_clock; > } > > /* Allocate memory for video device */ > @@ -2101,10 +2070,6 @@ probe_out_video_release: > video_device_release(vpfe_dev->video_dev); > probe_out_release_irq: > free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); > -probe_out_unmap1: > - iounmap(ccdc_cfg->ccdc_addr); > -probe_out_release_mem1: > - release_mem_region(res1->start, res1->end - res1->start + 1); > probe_disable_clock: > vpfe_disable_clock(vpfe_dev); > mutex_unlock(&ccdc_lock); > @@ -2120,7 +2085,6 @@ probe_free_dev_mem: > static int vpfe_remove(struct platform_device *pdev) > { > struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); > - struct resource *res; > > v4l2_info(pdev->dev.driver, "vpfe_remove\n"); > > @@ -2128,11 +2092,6 @@ static int vpfe_remove(struct platform_device > *pdev) > kfree(vpfe_dev->sd); > v4l2_device_unregister(&vpfe_dev->v4l2_dev); > video_unregister_device(vpfe_dev->video_dev); > - mutex_lock(&ccdc_lock); > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > - release_mem_region(res->start, res->end - res->start + 1); > - iounmap(ccdc_cfg->ccdc_addr); > - mutex_unlock(&ccdc_lock); > vpfe_disable_clock(vpfe_dev); > kfree(vpfe_dev); > kfree(ccdc_cfg); > -- > 1.6.0.4 From hvaibhav at ti.com Tue Dec 1 13:30:40 2009 From: hvaibhav at ti.com (Hiremath, Vaibhav) Date: Wed, 2 Dec 2009 01:00:40 +0530 Subject: [PATCH 2/2] DaVinci - vpfe capture - converting ccdc to platform driver In-Reply-To: <1259691333-32164-2-git-send-email-m-karicheri2@ti.com> References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> <1259691333-32164-2-git-send-email-m-karicheri2@ti.com> Message-ID: <19F8576C6E063C45BE387C64729E7394043716AE12@dbde02.ent.ti.com> > -----Original Message----- > From: Karicheri, Muralidharan > Sent: Tuesday, December 01, 2009 11:46 PM > To: linux-media at vger.kernel.org; hverkuil at xs4all.nl; > khilman at deeprootsystems.com > Cc: davinci-linux-open-source at linux.davincidsp.com; Hiremath, > Vaibhav; Karicheri, Muralidharan > Subject: [PATCH 2/2] DaVinci - vpfe capture - converting ccdc to > platform driver > > From: Muralidharan Karicheri > > This is the platform part for converting ccdc to platform driver. > > Signed-off-by: Muralidharan Karicheri > --- > Applies to linux-davinci tree > arch/arm/mach-davinci/dm355.c | 27 +++++++++++++++------------ > arch/arm/mach-davinci/dm644x.c | 18 +++++++++++++++++- > 2 files changed, 32 insertions(+), 13 deletions(-) > > diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach- > davinci/dm355.c > index dedf4d4..045cb0d 100644 > --- a/arch/arm/mach-davinci/dm355.c > +++ b/arch/arm/mach-davinci/dm355.c > @@ -701,6 +701,10 @@ static struct resource vpfe_resources[] = { > .end = IRQ_VDINT1, > .flags = IORESOURCE_IRQ, > }, > +}; > + > +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); > +static struct resource dm355_ccdc_resource[] = { > /* CCDC Base address */ > { > .flags = IORESOURCE_MEM, > @@ -708,8 +712,17 @@ static struct resource vpfe_resources[] = { > .end = 0x01c70600 + 0x1ff, > }, > }; > +static struct platform_device dm355_ccdc_dev = { > + .name = "dm355_ccdc", > + .id = -1, > + .num_resources = ARRAY_SIZE(dm355_ccdc_resource), > + .resource = dm355_ccdc_resource, > + .dev = { > + .dma_mask = &vpfe_capture_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > +}; > > -static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); > static struct platform_device vpfe_capture_dev = { > .name = CAPTURE_DRV_NAME, > .id = -1, > @@ -860,17 +873,7 @@ static int __init dm355_init_devices(void) > davinci_cfg_reg(DM355_INT_EDMA_CC); > platform_device_register(&dm355_edma_device); > platform_device_register(&dm355_vpss_device); > - /* > - * setup Mux configuration for vpfe input and register > - * vpfe capture platform device > - */ > - davinci_cfg_reg(DM355_VIN_PCLK); > - davinci_cfg_reg(DM355_VIN_CAM_WEN); > - davinci_cfg_reg(DM355_VIN_CAM_VD); > - davinci_cfg_reg(DM355_VIN_CAM_HD); > - davinci_cfg_reg(DM355_VIN_YIN_EN); > - davinci_cfg_reg(DM355_VIN_CINL_EN); > - davinci_cfg_reg(DM355_VIN_CINH_EN); [Hiremath, Vaibhav] Why have you removed mux configuration from here and moved to CCDC driver? Any specific reason? > + platform_device_register(&dm355_ccdc_dev); > platform_device_register(&vpfe_capture_dev); > > return 0; > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach- > davinci/dm644x.c > index 2cd0081..982be1f 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c > @@ -612,6 +612,11 @@ static struct resource vpfe_resources[] = { > .end = IRQ_VDINT1, > .flags = IORESOURCE_IRQ, > }, > +}; > + > +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); > +static struct resource dm644x_ccdc_resource[] = { > + /* CCDC Base address */ > { > .start = 0x01c70400, > .end = 0x01c70400 + 0xff, > @@ -619,7 +624,17 @@ static struct resource vpfe_resources[] = { > }, > }; > > -static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); > +static struct platform_device dm644x_ccdc_dev = { > + .name = "dm644x_ccdc", > + .id = -1, > + .num_resources = ARRAY_SIZE(dm644x_ccdc_resource), > + .resource = dm644x_ccdc_resource, > + .dev = { > + .dma_mask = &vpfe_capture_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > +}; > + > static struct platform_device vpfe_capture_dev = { > .name = CAPTURE_DRV_NAME, > .id = -1, > @@ -772,6 +787,7 @@ static int __init dm644x_init_devices(void) > platform_device_register(&dm644x_edma_device); > platform_device_register(&dm644x_emac_device); > platform_device_register(&dm644x_vpss_device); > + platform_device_register(&dm644x_ccdc_dev); > platform_device_register(&vpfe_capture_dev); > > return 0; > -- > 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 15:38:50 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 16:38:50 -0500 Subject: [PATCH 2/5 - v0] V4L - vpfe capture enhancements to support DM365 In-Reply-To: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> References: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> Message-ID: <1259703533-1789-2-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This patch adds support for handling CCDC configuration ioctl. A new IOCTL added to support reading current configuration at CCDC. NOTE: This is the initial version for review. Signed-off-by: Muralidharan Karicheri --- drivers/media/video/davinci/vpfe_capture.c | 74 +++++++++++++++++++++++++++- include/media/davinci/vpfe_capture.h | 5 ++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 35bbb08..ae8f993 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -759,12 +759,83 @@ static unsigned int vpfe_poll(struct file *file, poll_table *wait) return 0; } +static long vpfe_param_handler(struct file *file, void *priv, + int cmd, void *param) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); + + if (NULL == param) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "Invalid user ptr\n"); + } + + if (vpfe_dev->started) { + /* only allowed if streaming is not started */ + v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n"); + return -EBUSY; + } + + + switch (cmd) { + case VPFE_CMD_S_CCDC_RAW_PARAMS: + v4l2_warn(&vpfe_dev->v4l2_dev, + "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + ret = ccdc_dev->hw_ops.set_params(param); + if (ret) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "Error in setting parameters in CCDC\n"); + goto unlock_out; + } + + if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Invalid image format at CCDC\n"); + ret = -EINVAL; + } +unlock_out: + mutex_unlock(&vpfe_dev->lock); + break; + case VPFE_CMD_G_CCDC_RAW_PARAMS: + v4l2_warn(&vpfe_dev->v4l2_dev, + "VPFE_CMD_G_CCDC_RAW_PARAMS: experimental ioctl\n"); + if (!ccdc_dev->hw_ops.get_params) { + ret = -EINVAL; + break; + } + ret = ccdc_dev->hw_ops.get_params(param); + if (ret) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "Error in getting parameters from CCDC\n"); + } + break; + + default: + ret = -EINVAL; + } + return ret; +} + +static long vpfe_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + if (cmd == VPFE_CMD_S_CCDC_RAW_PARAMS || + cmd == VPFE_CMD_G_CCDC_RAW_PARAMS) + return vpfe_param_handler(file, file->private_data, cmd, + (void *)arg); + return video_ioctl2(file, cmd, arg); +} + /* vpfe capture driver file operations */ static const struct v4l2_file_operations vpfe_fops = { .owner = THIS_MODULE, .open = vpfe_open, .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, + .unlocked_ioctl = vpfe_ioctl, .mmap = vpfe_mmap, .poll = vpfe_poll }; @@ -1751,7 +1822,6 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { .vidioc_cropcap = vpfe_cropcap, .vidioc_g_crop = vpfe_g_crop, .vidioc_s_crop = vpfe_s_crop, - .vidioc_default = vpfe_param_handler, }; static struct vpfe_device *vpfe_initialize(void) diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h index 7b62a5c..1e6817c 100644 --- a/include/media/davinci/vpfe_capture.h +++ b/include/media/davinci/vpfe_capture.h @@ -71,7 +71,7 @@ struct vpfe_subdev_info { /* Sub dev routing information for each input */ struct vpfe_route *routes; /* check if sub dev supports routing */ - int can_route; + int can_route:1; /* ccdc bus/interface configuration */ struct vpfe_hw_if_param ccdc_if_params; /* i2c subdevice board info */ @@ -202,4 +202,7 @@ struct vpfe_config_params { **/ #define VPFE_CMD_S_CCDC_RAW_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 1, \ void *) +#define VPFE_CMD_G_CCDC_RAW_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 2, \ + void *) + #endif /* _DAVINCI_VPFE_H */ -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 15:38:51 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 16:38:51 -0500 Subject: [PATCH 3/5] V4L - vpfe-capture - updates to vpss module to support DM365 In-Reply-To: <1259703533-1789-2-git-send-email-m-karicheri2@ti.com> References: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> <1259703533-1789-2-git-send-email-m-karicheri2@ti.com> Message-ID: <1259703533-1789-3-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This patch does following changes:- 1) Added support for ISP5 and VPSS modules configuration for DM365 2) renamed few variables to make it more generic NOTE: This is the initial version for review. Signed-off-by: Muralidharan Karicheri --- drivers/media/video/davinci/vpss.c | 290 +++++++++++++++++++++++++++++------- include/media/davinci/vpss.h | 41 +++++- 2 files changed, 277 insertions(+), 54 deletions(-) diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c index 6d709ca..3820e13 100644 --- a/drivers/media/video/davinci/vpss.c +++ b/drivers/media/video/davinci/vpss.c @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * common vpss driver for all video drivers. + * common vpss system module platform driver for all video drivers. */ #include #include @@ -35,12 +35,52 @@ MODULE_AUTHOR("Texas Instruments"); /* DM644x defines */ #define DM644X_SBL_PCR_VPSS (4) +#define DM355_VPSSBL_INTSEL 0x10 +#define DM355_VPSSBL_EVTSEL 0x14 /* vpss BL register offsets */ #define DM355_VPSSBL_CCDCMUX 0x1c /* vpss CLK register offsets */ #define DM355_VPSSCLK_CLKCTRL 0x04 /* masks and shifts */ #define VPSS_HSSISEL_SHIFT 4 +/* + * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, + * IPIPE_INT1_SDR - vpss_int5 + */ +#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 +/* VENCINT - vpss_int8 */ +#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 + +#define DM365_ISP5_PCCR 0x04 +#define DM365_ISP5_INTSEL1 0x10 +#define DM365_ISP5_INTSEL2 0x14 +#define DM365_ISP5_INTSEL3 0x18 +#define DM365_ISP5_CCDCMUX 0x20 +#define DM365_ISP5_PG_FRAME_SIZE 0x28 +#define DM365_VPBE_CLK_CTRL 0x00 +/* + * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, + * AF - vpss_int3 + */ +#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 +/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ +#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f +/* VENC - vpss_int8 */ +#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 + +/* masks and shifts for DM365*/ +#define DM365_CCDC_PG_VD_POL_SHIFT 0 +#define DM365_CCDC_PG_HD_POL_SHIFT 1 + +#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) +#define CCD_SRC_SEL_SHIFT 4 + +/* Different SoC platforms supported by this driver */ +enum vpss_platform_type { + DM644X, + DM355, + DM365, +}; /* * vpss operations. Depends on platform. Not all functions are available @@ -59,13 +99,9 @@ struct vpss_hw_ops { /* vpss configuration */ struct vpss_oper_config { - __iomem void *vpss_bl_regs_base; - __iomem void *vpss_regs_base; - struct resource *r1; - resource_size_t len1; - struct resource *r2; - resource_size_t len2; - char vpss_name[32]; + __iomem void *vpss_regs_base0; + __iomem void *vpss_regs_base1; + enum vpss_platform_type platform; spinlock_t vpss_lock; struct vpss_hw_ops hw_ops; }; @@ -75,22 +111,46 @@ static struct vpss_oper_config oper_cfg; /* register access routines */ static inline u32 bl_regr(u32 offset) { - return __raw_readl(oper_cfg.vpss_bl_regs_base + offset); + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); } static inline void bl_regw(u32 val, u32 offset) { - __raw_writel(val, oper_cfg.vpss_bl_regs_base + offset); + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); } static inline u32 vpss_regr(u32 offset) { - return __raw_readl(oper_cfg.vpss_regs_base + offset); + return __raw_readl(oper_cfg.vpss_regs_base1 + offset); } static inline void vpss_regw(u32 val, u32 offset) { - __raw_writel(val, oper_cfg.vpss_regs_base + offset); + __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); +} + +/* For DM365 only */ +static inline u32 isp5_read(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); +} + +/* For DM365 only */ +static inline void isp5_write(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); +} + +static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; + + /* if we are using pattern generator, enable it */ + if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) + temp |= 0x08; + + temp |= (src_sel << CCD_SRC_SEL_SHIFT); + isp5_write(temp, DM365_ISP5_CCDCMUX); } static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) @@ -101,9 +161,9 @@ static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) { if (!oper_cfg.hw_ops.select_ccdc_source) - return -1; + return -EINVAL; - dm355_select_ccdc_source(src_sel); + oper_cfg.hw_ops.select_ccdc_source(src_sel); return 0; } EXPORT_SYMBOL(vpss_select_ccdc_source); @@ -114,7 +174,7 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) if (wbl_sel < VPSS_PCR_AEW_WBL_0 || wbl_sel > VPSS_PCR_CCDC_WBL_O) - return -1; + return -EINVAL; /* writing a 0 clear the overflow */ mask = ~(mask << wbl_sel); @@ -126,7 +186,7 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) { if (!oper_cfg.hw_ops.clear_wbl_overflow) - return -1; + return -EINVAL; return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); } @@ -166,7 +226,7 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) default: printk(KERN_ERR "dm355_enable_clock:" " Invalid selector: %d\n", clock_sel); - return -1; + return -EINVAL; } spin_lock_irqsave(&oper_cfg.vpss_lock, flags); @@ -181,100 +241,224 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) return 0; } +static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + unsigned long flags; + u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; + u32 (*read)(u32 offset) = isp5_read; + void(*write)(u32 val, u32 offset) = isp5_write; + + switch (clock_sel) { + case VPSS_BL_CLOCK: + break; + case VPSS_CCDC_CLOCK: + shift = 1; + break; + case VPSS_H3A_CLOCK: + shift = 2; + break; + case VPSS_RSZ_CLOCK: + shift = 3; + break; + case VPSS_IPIPE_CLOCK: + shift = 4; + break; + case VPSS_IPIPEIF_CLOCK: + shift = 5; + break; + case VPSS_PCLK_INTERNAL: + shift = 6; + break; + case VPSS_PSYNC_CLOCK_SEL: + shift = 7; + break; + case VPSS_VPBE_CLOCK: + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_VENC_CLOCK_SEL: + shift = 2; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK: + shift = 3; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_FDIF_CLOCK: + shift = 4; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_OSD_CLOCK_SEL: + shift = 6; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK_SEL: + shift = 7; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + default: + printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", + clock_sel); + return -1; + } + + spin_lock_irqsave(&oper_cfg.vpss_lock, flags); + utemp = read(offset); + if (!en) { + mask = ~mask; + utemp &= (mask << shift); + } else + utemp |= (mask << shift); + + write(utemp, offset); + spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); + + return 0; +} + int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) { if (!oper_cfg.hw_ops.enable_clock) - return -1; + return -EINVAL; return oper_cfg.hw_ops.enable_clock(clock_sel, en); } EXPORT_SYMBOL(vpss_enable_clock); +void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) +{ + int val = 0; + val = isp5_read(DM365_ISP5_CCDCMUX); + + val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); + val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); + + isp5_write(val, DM365_ISP5_CCDCMUX); +} +EXPORT_SYMBOL(dm365_vpss_set_sync_pol); + +void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) +{ + int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; + + current_reg |= (frame_size.pplen - 1); + isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); +} +EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); + static int __init vpss_probe(struct platform_device *pdev) { - int status, dm355 = 0; + resource_size_t len1, len2; + struct resource *r1, *r2; + char *platform_name; + int status; if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "no platform data\n"); return -ENOENT; } - strcpy(oper_cfg.vpss_name, pdev->dev.platform_data); - if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) - dm355 = 1; - else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) { + platform_name = pdev->dev.platform_data; + if (!strcmp(platform_name, "dm355_vpss")) + oper_cfg.platform = DM355; + else if (!strcmp(platform_name, "dm365_vpss")) + oper_cfg.platform = DM365; + else if (!strcmp(platform_name, "dm644x_vpss")) + oper_cfg.platform = DM644X; + else { dev_err(&pdev->dev, "vpss driver not supported on" " this platform\n"); return -ENODEV; } - dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name); - oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!oper_cfg.r1) + dev_info(&pdev->dev, "%s vpss probed\n", platform_name); + r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r1) return -ENOENT; - oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1; + len1 = r1->end - r1->start + 1; - oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1, - oper_cfg.r1->name); - if (!oper_cfg.r1) + r1 = request_mem_region(r1->start, len1, r1->name); + if (!r1) return -EBUSY; - oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1); - if (!oper_cfg.vpss_bl_regs_base) { + oper_cfg.vpss_regs_base0 = ioremap(r1->start, len1); + if (!oper_cfg.vpss_regs_base0) { status = -EBUSY; goto fail1; } - if (dm355) { - oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!oper_cfg.r2) { + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!r2) { status = -ENOENT; goto fail2; } - oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1; - oper_cfg.r2 = request_mem_region(oper_cfg.r2->start, - oper_cfg.len2, - oper_cfg.r2->name); - if (!oper_cfg.r2) { + len2 = r2->end - r2->start + 1; + r2 = request_mem_region(r2->start, len2, r2->name); + if (!r2) { status = -EBUSY; goto fail2; } - oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start, - oper_cfg.len2); - if (!oper_cfg.vpss_regs_base) { + oper_cfg.vpss_regs_base1 = ioremap(r2->start, len2); + if (!oper_cfg.vpss_regs_base1) { status = -EBUSY; goto fail3; } } - if (dm355) { + if (oper_cfg.platform == DM355) { oper_cfg.hw_ops.enable_clock = dm355_enable_clock; oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; + /* Setup vpss interrupts */ + bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); + bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); + } else if (oper_cfg.platform == DM365) { + oper_cfg.hw_ops.enable_clock = dm365_enable_clock; + oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; + /* Setup vpss interrupts */ + isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); + isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); + isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); } else oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; spin_lock_init(&oper_cfg.vpss_lock); - dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name); + dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); return 0; fail3: - release_mem_region(oper_cfg.r2->start, oper_cfg.len2); + release_mem_region(r2->start, len2); fail2: - iounmap(oper_cfg.vpss_bl_regs_base); + iounmap(oper_cfg.vpss_regs_base0); fail1: - release_mem_region(oper_cfg.r1->start, oper_cfg.len1); + release_mem_region(r1->start, len1); return status; } static int vpss_remove(struct platform_device *pdev) { - iounmap(oper_cfg.vpss_bl_regs_base); - release_mem_region(oper_cfg.r1->start, oper_cfg.len1); - if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) { - iounmap(oper_cfg.vpss_regs_base); - release_mem_region(oper_cfg.r2->start, oper_cfg.len2); + struct resource *res; + + iounmap(oper_cfg.vpss_regs_base0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + iounmap(oper_cfg.vpss_regs_base1); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(res->start, res->end - res->start + 1); } return 0; } diff --git a/include/media/davinci/vpss.h b/include/media/davinci/vpss.h index fcdff74..c59cc02 100644 --- a/include/media/davinci/vpss.h +++ b/include/media/davinci/vpss.h @@ -29,7 +29,19 @@ /* selector for ccdc input selection on DM355 */ enum vpss_ccdc_source_sel { VPSS_CCDCIN, - VPSS_HSSIIN + VPSS_HSSIIN, + VPSS_PGLPBK, /* for DM365 only */ + VPSS_CCDCPG /* for DM365 only */ +}; + +struct vpss_sync_pol { + unsigned int ccdpg_hdpol:1; + unsigned int ccdpg_vdpol:1; +}; + +struct vpss_pg_frame_size { + short hlpfr; + short pplen; }; /* Used for enable/diable VPSS Clock */ @@ -47,12 +59,38 @@ enum vpss_clock_sel { */ VPSS_VENC_CLOCK_SEL, VPSS_VPBE_CLOCK, + /* DM365 only clocks */ + VPSS_IPIPEIF_CLOCK, + VPSS_RSZ_CLOCK, + VPSS_BL_CLOCK, + /* + * When using VPSS_PCLK_INTERNAL in vpss_enable_clock() api + * following applies:- + * en = 0 disable internal PCLK + * en = 1 enables internal PCLK + */ + VPSS_PCLK_INTERNAL, + /* + * When using VPSS_PSYNC_CLOCK_SEL in vpss_enable_clock() api + * following applies:- + * en = 0 enables MMR clock + * en = 1 enables VPSS clock + */ + VPSS_PSYNC_CLOCK_SEL, + VPSS_LDC_CLOCK_SEL, + VPSS_OSD_CLOCK_SEL, + VPSS_FDIF_CLOCK, + VPSS_LDC_CLOCK }; /* select input to ccdc on dm355 */ int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel); /* enable/disable a vpss clock, 0 - success, -1 - failure */ int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en); +/* set sync polarity, only for DM365*/ +void dm365_vpss_set_sync_pol(struct vpss_sync_pol); +/* set the PG_FRAME_SIZE register, only for DM365 */ +void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size); /* wbl reset for dm644x */ enum vpss_wbl_sel { @@ -65,5 +103,6 @@ enum vpss_wbl_sel { VPSS_PCR_PREV_WBL_0, VPSS_PCR_CCDC_WBL_O, }; +/* clear wbl overflow flag for DM6446 */ int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel); #endif -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 15:38:52 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 16:38:52 -0500 Subject: [PATCH 4/5 - v0] V4L - vpfe capture - build environment to support DM365 CCDC In-Reply-To: <1259703533-1789-3-git-send-email-m-karicheri2@ti.com> References: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> <1259703533-1789-2-git-send-email-m-karicheri2@ti.com> <1259703533-1789-3-git-send-email-m-karicheri2@ti.com> Message-ID: <1259703533-1789-4-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri Added support for building DM365 CCDC module. Also made VPSS module default configuration variable value to n. NOTE: This patch is for review purpose only Signed-off-by: Muralidharan Karicheri --- drivers/media/video/Kconfig | 15 ++++++++++++++- drivers/media/video/davinci/Makefile | 1 + 2 files changed, 15 insertions(+), 1 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9dc74c9..6d3ae06 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -552,7 +552,7 @@ config VIDEO_VPSS_SYSTEM depends on ARCH_DAVINCI help Support for vpss system module for video driver - default y + default n config VIDEO_VPFE_CAPTURE tristate "VPFE Video Capture Driver" @@ -596,6 +596,19 @@ config VIDEO_DM355_CCDC To compile this driver as a module, choose M here: the module will be called vpfe. +config VIDEO_DM365_ISIF + tristate "DM365 CCDC/ISIF HW module" + depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default y + help + Enables DM365 ISIF hw module. This is the hardware module for + configuring ISIF in VPFE to capture Raw Bayer RGB data from + a image sensor or YUV data from a YUV source. + + To compile this driver as a module, choose M here: the + module will be called vpfe. + source "drivers/media/video/bt8xx/Kconfig" config VIDEO_PMS diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index 1a8b8f3..3642d79 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o +obj-$(CONFIG_VIDEO_DM365_ISIF) += dm365_ccdc.o -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 15:38:53 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 16:38:53 -0500 Subject: [PATCH 5/5 - v0] DaVinci - vpfe capture - platform changes for DM365 CCDC In-Reply-To: <1259703533-1789-4-git-send-email-m-karicheri2@ti.com> References: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> <1259703533-1789-2-git-send-email-m-karicheri2@ti.com> <1259703533-1789-3-git-send-email-m-karicheri2@ti.com> <1259703533-1789-4-git-send-email-m-karicheri2@ti.com> Message-ID: <1259703533-1789-5-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri Adds platform and board specific changes to support YUV video capture on DM365. NOTE: This patch is for review purpose only Signed-off-by: Muralidharan Karicheri --- arch/arm/mach-davinci/board-dm365-evm.c | 74 +++++++++++++++++++++++ arch/arm/mach-davinci/dm365.c | 90 +++++++++++++++++++++++++++- arch/arm/mach-davinci/include/mach/dm365.h | 2 + 3 files changed, 165 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 8d23972..c9f09e5 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,9 @@ #include #include +#include +#include + static inline int have_imager(void) { /* REVISIT when it's supported, trigger via Kconfig */ @@ -305,6 +309,74 @@ static void dm365evm_mmc_configure(void) davinci_cfg_reg(DM365_SD1_DATA0); } +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1 +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) +/* Inputs available at the TVP5146 */ +static struct v4l2_input tvp5146_inputs[] = { + { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, + { + .index = 1, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, +}; + +/* + * this is the route info for connecting each input to decoder + * ouput that goes to vpfe. There is a one to one correspondence + * with tvp5146_inputs + */ +static struct vpfe_route tvp5146_routes[] = { + { + .input = INPUT_CVBS_VI2B, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + }, +{ + .input = INPUT_SVIDEO_VI2C_VI1C, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + }, +}; + +static struct vpfe_subdev_info vpfe_sub_devs[] = { + { + .name = "tvp5146", + .grp_id = 0, + .num_inputs = ARRAY_SIZE(tvp5146_inputs), + .inputs = tvp5146_inputs, + .routes = tvp5146_routes, + .can_route = 1, + .ccdc_if_params = { + .if_type = VPFE_BT656, + .hdpol = VPFE_PINPOL_POSITIVE, + .vdpol = VPFE_PINPOL_POSITIVE, + }, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + }, +}; + +static struct vpfe_config vpfe_cfg = { + .num_subdevs = ARRAY_SIZE(vpfe_sub_devs), + .sub_devs = vpfe_sub_devs, + .card_name = "DM365 EVM", + .ccdc = "DM365 ISIF", + .num_clocks = 1, + .clocks = {"vpss_master"}, +}; + static void __init evm_init_i2c(void) { davinci_init_i2c(&i2c_pdata); @@ -496,6 +568,8 @@ static struct davinci_uart_config uart_config __initdata = { static void __init dm365_evm_map_io(void) { + /* setup input configuration for VPFE input devices */ + dm365_set_vpfe_config(&vpfe_cfg); dm365_init(); } diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 2ec619e..d9718aa 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1009,6 +1009,87 @@ void __init dm365_init(void) davinci_common_init(&davinci_soc_info_dm365); } +static struct resource dm365_vpss_resources[] = { + { + /* VPSS ISP5 Base address */ + .name = "vpss", + .start = 0x01c70000, + .end = 0x01c70000 + 0xff, + .flags = IORESOURCE_MEM, + }, + { + /* VPSS CLK Base address */ + .name = "vpss", + .start = 0x01c70200, + .end = 0x01c70200 + 0xff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device dm365_vpss_device = { + .name = "vpss", + .id = -1, + .dev.platform_data = "dm365_vpss", + .num_resources = ARRAY_SIZE(dm365_vpss_resources), + .resource = dm365_vpss_resources, +}; + +static struct resource vpfe_resources[] = { + { + .start = IRQ_VDINT0, + .end = IRQ_VDINT0, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_VDINT1, + .end = IRQ_VDINT1, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); +static struct platform_device vpfe_capture_dev = { + .name = CAPTURE_DRV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(vpfe_resources), + .resource = vpfe_resources, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource isif_resource[] = { + /* ISIF Base address */ + { + .start = 0x01c71000, + .end = 0x01c71000 + 0x1ff, + .flags = IORESOURCE_MEM, + }, + /* ISIF Linearization table 0 */ + { + .start = 0x1C7C000, + .end = 0x1C7C000 + 0x2ff, + .flags = IORESOURCE_MEM, + }, + /* ISIF Linearization table 1 */ + { + .start = 0x1C7C400, + .end = 0x1C7C400 + 0x2ff, + .flags = IORESOURCE_MEM, + }, +}; +static struct platform_device dm365_isif_dev = { + .name = "dm365_isif", + .id = -1, + .num_resources = ARRAY_SIZE(isif_resource), + .resource = isif_resource, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + static int __init dm365_init_devices(void) { if (!cpu_is_davinci_dm365()) @@ -1017,7 +1098,14 @@ static int __init dm365_init_devices(void) davinci_cfg_reg(DM365_INT_EDMA_CC); platform_device_register(&dm365_edma_device); platform_device_register(&dm365_emac_device); - + platform_device_register(&dm365_vpss_device); + platform_device_register(&dm365_isif_dev); + platform_device_register(&vpfe_capture_dev); return 0; } postcore_initcall(dm365_init_devices); + +void dm365_set_vpfe_config(struct vpfe_config *cfg) +{ + vpfe_capture_dev.dev.platform_data = cfg; +} diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h index f1710a3..1191a08 100644 --- a/arch/arm/mach-davinci/include/mach/dm365.h +++ b/arch/arm/mach-davinci/include/mach/dm365.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -36,4 +37,5 @@ void __init dm365_init_asp(struct snd_platform_data *pdata); void __init dm365_init_ks(struct davinci_ks_platform_data *pdata); void __init dm365_init_rtc(void); +void dm365_set_vpfe_config(struct vpfe_config *cfg); #endif /* __ASM_ARCH_DM365_H */ -- 1.6.0.4 From m-karicheri2 at ti.com Tue Dec 1 15:38:49 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Tue, 1 Dec 2009 16:38:49 -0500 Subject: [PATCH 1/5 - v0] V4L-vpfe capture - adding CCDC driver for DM365 Message-ID: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This patch is for adding support for DM365 CCDC. This will allow to capture YUV video frames from TVP5146 video decoder on DM365 EVM. The vpfe capture driver will use this module to configure ISIF (a.k.a CCDC) module to allow YUV data capture. This driver is written for ccdc_hw_device interface used by vpfe capture driver to configure the ccdc module. This patch is tested using NTSC & PAL video sources and verified for both formats. NOTE: This is the initial version for review. Signed-off-by: Muralidharan Karicheri --- drivers/media/video/davinci/dm365_ccdc.c | 1529 +++++++++++++++++++++++++ drivers/media/video/davinci/dm365_ccdc_regs.h | 293 +++++ include/media/davinci/dm365_ccdc.h | 555 +++++++++ 3 files changed, 2377 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/dm365_ccdc.c create mode 100644 drivers/media/video/davinci/dm365_ccdc_regs.h create mode 100644 include/media/davinci/dm365_ccdc.h diff --git a/drivers/media/video/davinci/dm365_ccdc.c b/drivers/media/video/davinci/dm365_ccdc.c new file mode 100644 index 0000000..2f27696 --- /dev/null +++ b/drivers/media/video/davinci/dm365_ccdc.c @@ -0,0 +1,1529 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This is the isif hardware module for DM365. + * TODO: 1) Raw bayer parameter settings and bayer capture + * 2) Add support for control ioctl + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dm365_ccdc_regs.h" +#include "ccdc_hw_device.h" + +static struct device *dev; + +/* Defauts for module configuation paramaters */ +static struct ccdc_config_params_raw ccdc_config_defaults = { + .linearize = { + .en = 0, + .corr_shft = CCDC_NO_SHIFT, + .scale_fact = {1, 0}, + }, + .df_csc = { + .df_or_csc = 0, + .csc = { + .en = 0 + }, + }, + .dfc = { + .en = 0 + }, + .bclamp = { + .en = 0 + }, + .gain_offset = { + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + }, + .culling = { + .hcpat_odd = 0xff, + .hcpat_even = 0xff, + .vcpat = 0xff + }, + .compress = { + .alg = CCDC_ALAW, + }, +}; + +/* ISIF operation configuration */ +struct ccdc_oper_config { + enum vpfe_hw_if_type if_type; + struct ccdc_ycbcr_config ycbcr; + struct ccdc_params_raw bayer; + enum ccdc_data_pack data_pack; + void *__iomem base_addr; + void *__iomem linear_tbl0_addr; + void *__iomem linear_tbl1_addr; +}; + +static struct ccdc_oper_config ccdc_cfg = { + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = CCDC_WIN_NTSC, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, + }, + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + .cfa_pat = CCDC_CFA_PAT_MOSAIC, + .data_msb = CCDC_BIT_MSB_11, + .config_params = { + .data_shift = CCDC_NO_SHIFT, + .col_pat_field0 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED, + }, + .col_pat_field1 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED, + }, + .test_pat_gen = 0, + }, + }, + .data_pack = CCDC_DATA_PACK8, +}; + +/* Raw Bayer formats */ +static u32 ccdc_raw_bayer_pix_formats[] = + {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; + +/* Raw YUV formats */ +static u32 ccdc_raw_yuv_pix_formats[] = + {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(ccdc_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, ccdc_cfg.base_addr + offset); +} + +static inline u32 ccdc_merge(u32 mask, u32 val, u32 offset) +{ + u32 new_val = (regr(offset) & ~mask) | (val & mask); + + regw(new_val, offset); + return new_val; +} + +static inline void regw_lin_tbl(u32 val, u32 offset, int i) +{ + if (!i) + __raw_writel(val, ccdc_cfg.linear_tbl0_addr + offset); + else + __raw_writel(val, ccdc_cfg.linear_tbl1_addr + offset); +} + +static void ccdc_disable_all_modules(void) +{ + /* disable BC */ + regw(0, CLAMPCFG); + /* disable vdfc */ + regw(0, DFCCTL); + /* disable CSC */ + regw(0, CSCCTL); + /* disable linearization */ + regw(0, LINCFG0); + /* disable other modules here as they are supported */ +} + +static void ccdc_enable(int en) +{ + if (!en) { + /* Before disable isif, disable all ISIF modules */ + ccdc_disable_all_modules(); + /** + * wait for next VD. Assume lowest scan rate is 12 Hz. So + * 100 msec delay is good enough + */ + } + msleep(100); + ccdc_merge(CCDC_SYNCEN_VDHDEN_MASK, en, SYNCEN); +} + +static void ccdc_enable_output_to_sdram(int en) +{ + ccdc_merge(CCDC_SYNCEN_WEN_MASK, en << CCDC_SYNCEN_WEN_SHIFT, SYNCEN); +} + +static void ccdc_config_culling(struct ccdc_cul *cul) +{ + u32 val; + + /* Horizontal pattern */ + val = (cul->hcpat_even) << CULL_PAT_EVEN_LINE_SHIFT; + val |= cul->hcpat_odd; + regw(val, CULH); + + /* vertical pattern */ + regw(cul->vcpat, CULV); + + /* LPF */ + ccdc_merge((CCDC_LPF_MASK << CCDC_LPF_SHIFT), + (cul->en_lpf << CCDC_LPF_SHIFT), MODESET); +} + +static void ccdc_config_gain_offset(void) +{ + struct ccdc_gain_offsets_adj *gain_off_ptr = + &ccdc_cfg.bayer.config_params.gain_offset; + u32 val; + + val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) | + ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) | + ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) | + ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) | + ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) | + ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT); + + ccdc_merge(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); + + val = ((gain_off_ptr->gain.r_ye.integer & GAIN_INTEGER_MASK) + << GAIN_INTEGER_SHIFT); + val |= (ccdc_cfg.bayer. + config_params.gain_offset.gain.r_ye.decimal & + GAIN_DECIMAL_MASK); + regw(val, CRGAIN); + + val = ((gain_off_ptr->gain.gr_cy + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); + val |= (gain_off_ptr->gain.gr_cy + .decimal & GAIN_DECIMAL_MASK); + regw(val, CGRGAIN); + + val = ((gain_off_ptr->gain.gb_g + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); + val |= (gain_off_ptr->gain.gb_g + .decimal & GAIN_DECIMAL_MASK); + regw(val, CGBGAIN); + + val = ((gain_off_ptr->gain.b_mg + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); + val |= (gain_off_ptr->gain.b_mg + .decimal & GAIN_DECIMAL_MASK); + regw(val, CBGAIN); + + regw((gain_off_ptr->offset & + OFFSET_MASK), COFSTA); +} + +static void ccdc_restore_defaults(void) +{ + enum vpss_ccdc_source_sel source = VPSS_CCDCIN; + int i; + + memcpy(&ccdc_cfg.bayer.config_params, &ccdc_config_defaults, + sizeof(struct ccdc_config_params_raw)); + + dev_dbg(dev, "\nstarting ccdc_restore_defaults..."); + /* Enable clock to ISIF, IPIPEIF and BL */ + vpss_enable_clock(VPSS_CCDC_CLOCK, 1); + vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); + vpss_enable_clock(VPSS_BL_CLOCK, 1); + + /* set all registers to default value */ + for (i = 0; i <= 0x1f8; i += 4) + regw(0, i); + + /* no culling support */ + regw(0xffff, CULH); + regw(0xff, CULV); + + /* Set default offset and gain */ + ccdc_config_gain_offset(); + + vpss_select_ccdc_source(source); + + dev_dbg(dev, "\nEnd of ccdc_restore_defaults..."); +} + +static int ccdc_open(struct device *device) +{ + dev = device; + ccdc_restore_defaults(); + return 0; +} + +/* This function will configure the window size to be capture in CCDC reg */ +static void ccdc_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, int ppc) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int mid_img = 0; + + dev_dbg(dev, "\nStarting ccdc_setwin..."); + /** + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left << (ppc - 1); + horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; + + /* Writing the horizontal info into the registers */ + regw(horz_start & START_PX_HOR_MASK, SPH); + regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + } else { + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* configure VDINT0 and VDINT1 */ + mid_img = vert_start + (image_win->height / 2); + regw(mid_img, VDINT1); + } + + regw(0, VDINT0); + regw(vert_start & START_VER_ONE_MASK, SLV0); + regw(vert_start & START_VER_TWO_MASK, SLV1); + regw(vert_nr_lines & NUM_LINES_VER, LNV); +} + +static void ccdc_config_bclamp(struct ccdc_black_clamp *bc) +{ + u32 val; + + /** + * DC Offset is always added to image data irrespective of bc enable + * status + */ + val = bc->dc_offset & CCDC_BC_DCOFFSET_MASK; + regw(val, CLDCOFST); + + if (bc->en) { + val = (bc->bc_mode_color & CCDC_BC_MODE_COLOR_MASK) << + CCDC_BC_MODE_COLOR_SHIFT; + + /* Enable BC and horizontal clamp caculation paramaters */ + val = val | 1 | ((bc->horz.mode & CCDC_HORZ_BC_MODE_MASK) << + CCDC_HORZ_BC_MODE_SHIFT); + + regw(val, CLAMPCFG); + + if (bc->horz.mode != CCDC_HORZ_BC_DISABLE) { + /** + * Window count for calculation + * Base window selection + * pixel limit + * Horizontal size of window + * vertical size of the window + * Horizontal start position of the window + * Vertical start position of the window + */ + val = (bc->horz.win_count_calc & + CCDC_HORZ_BC_WIN_COUNT_MASK) | + ((bc->horz.base_win_sel_calc & 1) + << CCDC_HORZ_BC_WIN_SEL_SHIFT) | + ((bc->horz.clamp_pix_limit & 1) + << CCDC_HORZ_BC_PIX_LIMIT_SHIFT) | + ((bc->horz.win_h_sz_calc & + CCDC_HORZ_BC_WIN_H_SIZE_MASK) + << CCDC_HORZ_BC_WIN_H_SIZE_SHIFT) | + ((bc->horz.win_v_sz_calc & + CCDC_HORZ_BC_WIN_V_SIZE_MASK) + << CCDC_HORZ_BC_WIN_V_SIZE_SHIFT); + + regw(val, CLHWIN0); + + val = (bc->horz.win_start_h_calc & + CCDC_HORZ_BC_WIN_START_H_MASK); + regw(val, CLHWIN1); + + val = + (bc->horz. + win_start_v_calc & CCDC_HORZ_BC_WIN_START_V_MASK); + regw(val, CLHWIN2); + } + + /* vertical clamp caculation paramaters */ + + /* OB H Valid */ + val = (bc->vert.ob_h_sz_calc & CCDC_VERT_BC_OB_H_SZ_MASK); + + /* Reset clamp value sel for previous line */ + val |= ((bc->vert.reset_val_sel & + CCDC_VERT_BC_RST_VAL_SEL_MASK) + << CCDC_VERT_BC_RST_VAL_SEL_SHIFT); + + /* Line average coefficient */ + val |= (bc->vert.line_ave_coef << + CCDC_VERT_BC_LINE_AVE_COEF_SHIFT); + regw(val, CLVWIN0); + + /* Configured reset value */ + if (bc->vert.reset_val_sel == + CCDC_VERT_BC_USE_CONFIG_CLAMP_VAL) { + val = + (bc->vert. + reset_clamp_val & CCDC_VERT_BC_RST_VAL_MASK); + regw(val, CLVRV); + } + + /* Optical Black horizontal start position */ + val = (bc->vert.ob_start_h & CCDC_VERT_BC_OB_START_HORZ_MASK); + regw(val, CLVWIN1); + + /* Optical Black vertical start position */ + val = (bc->vert.ob_start_v & CCDC_VERT_BC_OB_START_VERT_MASK); + regw(val, CLVWIN2); + + val = (bc->vert.ob_v_sz_calc & CCDC_VERT_BC_OB_VERT_SZ_MASK); + regw(val, CLVWIN3); + + /* Vertical start position for BC subtraction */ + val = (bc->vert_start_sub & CCDC_BC_VERT_START_SUB_V_MASK); + regw(val, CLSV); + } +} + +static void ccdc_config_linearization(struct ccdc_linearize *linearize) +{ + u32 val, i; + if (!linearize->en) { + regw(0, LINCFG0); + return; + } + + /* shift value for correction */ + val = (linearize->corr_shft & CCDC_LIN_CORRSFT_MASK) + << CCDC_LIN_CORRSFT_SHIFT; + /* enable */ + val |= 1; + regw(val, LINCFG0); + + /* Scale factor */ + val = (linearize->scale_fact.integer & 1) + << CCDC_LIN_SCALE_FACT_INTEG_SHIFT; + val |= (linearize->scale_fact.decimal & + CCDC_LIN_SCALE_FACT_DECIMAL_MASK); + regw(val, LINCFG1); + + for (i = 0; i < CCDC_LINEAR_TAB_SIZE; i++) { + val = linearize->table[i] & CCDC_LIN_ENTRY_MASK; + if (i%2) + regw_lin_tbl(val, ((i >> 1) << 2), 1); + else + regw_lin_tbl(val, ((i >> 1) << 2), 0); + } +} + +static void ccdc_config_dfc(struct ccdc_dfc *vdfc) +{ +#define DFC_WRITE_WAIT_COUNT 1000 + u32 val, count = DFC_WRITE_WAIT_COUNT; + int i; + + if (!vdfc->en) + return; + + /* Correction mode */ + val = ((vdfc->corr_mode & CCDC_VDFC_CORR_MOD_MASK) + << CCDC_VDFC_CORR_MOD_SHIFT); + + /* Correct whole line or partial */ + if (vdfc->corr_whole_line) + val |= 1 << CCDC_VDFC_CORR_WHOLE_LN_SHIFT; + + /* level shift value */ + val |= (vdfc->def_level_shift & CCDC_VDFC_LEVEL_SHFT_MASK) << + CCDC_VDFC_LEVEL_SHFT_SHIFT; + + regw(val, DFCCTL); + + /* Defect saturation level */ + val = vdfc->def_sat_level & CCDC_VDFC_SAT_LEVEL_MASK; + regw(val, VDFSATLV); + + regw(vdfc->table[0].pos_vert & CCDC_VDFC_POS_MASK, DFCMEM0); + regw(vdfc->table[0].pos_horz & CCDC_VDFC_POS_MASK, DFCMEM1); + if (vdfc->corr_mode == CCDC_VDFC_NORMAL || + vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[0].level_at_pos, DFCMEM2); + regw(vdfc->table[0].level_up_pixels, DFCMEM3); + regw(vdfc->table[0].level_low_pixels, DFCMEM4); + } + + val = regr(DFCMEMCTL); + /* set DFCMARST and set DFCMWR */ + val |= 1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT; + val |= 1; + regw(val, DFCMEMCTL); + + while (count && (regr(DFCMEMCTL) & 0x01)) + count--; + + val = regr(DFCMEMCTL); + if (!count) { + dev_dbg(dev, "defect table write timeout !!!\n"); + return; + } + + for (i = 1; i < vdfc->num_vdefects; i++) { + regw(vdfc->table[i].pos_vert & CCDC_VDFC_POS_MASK, + DFCMEM0); + regw(vdfc->table[i].pos_horz & CCDC_VDFC_POS_MASK, + DFCMEM1); + if (vdfc->corr_mode == CCDC_VDFC_NORMAL || + vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[i].level_at_pos, DFCMEM2); + regw(vdfc->table[i].level_up_pixels, DFCMEM3); + regw(vdfc->table[i].level_low_pixels, DFCMEM4); + } + val = regr(DFCMEMCTL); + /* clear DFCMARST and set DFCMWR */ + val &= ~(1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT); + val |= 1; + regw(val, DFCMEMCTL); + + count = DFC_WRITE_WAIT_COUNT; + while (count && (regr(DFCMEMCTL) & 0x01)) + count--; + + val = regr(DFCMEMCTL); + if (!count) { + dev_err(dev, "defect table write timeout !!!\n"); + return; + } + } + if (vdfc->num_vdefects < CCDC_VDFC_TABLE_SIZE) { + /* Extra cycle needed */ + regw(0, DFCMEM0); + regw(0x1FFF, DFCMEM1); + val = 1; + regw(val, DFCMEMCTL); + } + + /* enable VDFC */ + ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (1 << CCDC_VDFC_EN_SHIFT), + DFCCTL); + + ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (0 << CCDC_VDFC_EN_SHIFT), + DFCCTL); + + regw(0x6, DFCMEMCTL); + for (i = 0 ; i < vdfc->num_vdefects; i++) { + count = DFC_WRITE_WAIT_COUNT; + while (count && (regr(DFCMEMCTL) & 0x2)) + count--; + + val = regr(DFCMEMCTL); + if (!count) { + dev_err(dev, "defect table write timeout !!!\n"); + return; + } + + val = regr(DFCMEM0) | regr(DFCMEM1) | regr(DFCMEM2) | + regr(DFCMEM3) | regr(DFCMEM4); + regw(0x2, DFCMEMCTL); + } +} + +static void ccdc_config_csc(struct ccdc_df_csc *df_csc) +{ + u32 val1 = 0, val2 = 0, i; + + if (!df_csc->csc.en) { + regw(0, CSCCTL); + return; + } + for (i = 0; i < CCDC_CSC_NUM_COEFF; i++) { + if ((i % 2) == 0) { + /* CSCM - LSB */ + val1 = + ((df_csc->csc.coeff[i].integer & + CCDC_CSC_COEF_INTEG_MASK) + << CCDC_CSC_COEF_INTEG_SHIFT) | + ((df_csc->csc.coeff[i].decimal & + CCDC_CSC_COEF_DECIMAL_MASK)); + } else { + + /* CSCM - MSB */ + val2 = + ((df_csc->csc.coeff[i].integer & + CCDC_CSC_COEF_INTEG_MASK) + << CCDC_CSC_COEF_INTEG_SHIFT) | + ((df_csc->csc.coeff[i].decimal & + CCDC_CSC_COEF_DECIMAL_MASK)); + val2 <<= CCDC_CSCM_MSB_SHIFT; + val2 |= val1; + regw(val2, (CSCM0 + ((i-1) << 1))); + } + } + + /* program the active area */ + regw(df_csc->start_pix & CCDC_DF_CSC_SPH_MASK, FMTSPH); + /** + * one extra pixel as required for CSC. Actually number of + * pixel - 1 should be configured in this register. So we + * need to subtract 1 before writing to FMTSPH, but we will + * not do this since csc requires one extra pixel + */ + regw((df_csc->num_pixels) & CCDC_DF_CSC_SPH_MASK, FMTLNH); + regw(df_csc->start_line & CCDC_DF_CSC_SPH_MASK, FMTSLV); + /** + * one extra line as required for CSC. See reason documented for + * num_pixels + */ + regw((df_csc->num_lines) & CCDC_DF_CSC_SPH_MASK, FMTLNV); + + /* Enable CSC */ + regw(1, CSCCTL); +} + +static int ccdc_config_raw(void) +{ + struct ccdc_params_raw *params = &ccdc_cfg.bayer; + struct ccdc_config_params_raw *module_params = + &ccdc_cfg.bayer.config_params; + struct vpss_pg_frame_size frame_size; + struct vpss_sync_pol sync; + u32 val; + + dev_dbg(dev, "\nStarting ccdc_config_raw..\n"); + + /* Configure CCDCFG register */ + + /** + * Set CCD Not to swap input since input is RAW data + * Set FID detection function to Latch at V-Sync + * Set WENLOG - ccdc valid area + * Set TRGSEL + * Set EXTRG + * Packed to 8 or 16 bits + */ + + val = CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | + CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | + CCDC_CCDCFG_EXTRG_DISABLE | (ccdc_cfg.data_pack & + CCDC_DATA_PACK_MASK); + + dev_dbg(dev, "Writing 0x%x to ...CCDCFG \n", val); + regw(val, CCDCFG); + + /** + * Configure the vertical sync polarity(MODESET.VDPOL) + * Configure the horizontal sync polarity (MODESET.HDPOL) + * Configure frame id polarity (MODESET.FLDPOL) + * Configure data polarity + * Configure External WEN Selection + * Configure frame format(progressive or interlace) + * Configure pixel format (Input mode) + * Configure the data shift + */ + + val = CCDC_VDHDOUT_INPUT | + ((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | + ((CCDC_DATAPOL_NORMAL & CCDC_DATAPOL_MASK) + << CCDC_DATAPOL_SHIFT) | + ((CCDC_EXWEN_DISABLE & CCDC_EXWEN_MASK) << CCDC_EXWEN_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | + ((params->pix_fmt & CCDC_INPUT_MASK) << CCDC_INPUT_SHIFT) | + ((params->config_params.data_shift & CCDC_DATASFT_MASK) + << CCDC_DATASFT_SHIFT); + + regw(val, MODESET); + dev_dbg(dev, "Writing 0x%x to MODESET...\n", val); + + /** + * Configure GAMMAWD register + * CFA pattern setting + */ + val = (params->cfa_pat & CCDC_GAMMAWD_CFA_MASK) << + CCDC_GAMMAWD_CFA_SHIFT; + + /* Gamma msb */ + if (module_params->compress.alg == CCDC_ALAW) + val = val | CCDC_ALAW_ENABLE; + + val = val | ((params->data_msb & CCDC_ALAW_GAMA_WD_MASK) << + CCDC_ALAW_GAMA_WD_SHIFT); + + regw(val, CGAMMAWD); + + /* Configure DPCM compression settings */ + if (module_params->compress.alg == CCDC_DPCM) { + val = 1 << CCDC_DPCM_EN_SHIFT; + val |= (module_params->compress.pred & + CCDC_DPCM_PREDICTOR_MASK) << CCDC_DPCM_PREDICTOR_SHIFT; + } + + regw(val, MISC); + /* Configure Gain & Offset */ + + ccdc_config_gain_offset(); + + /* Configure Color pattern */ + val = (params->config_params.col_pat_field0.olop) | + (params->config_params.col_pat_field0.olep << 2) | + (params->config_params.col_pat_field0.elop << 4) | + (params->config_params.col_pat_field0.elep << 6) | + (params->config_params.col_pat_field1.olop << 8) | + (params->config_params.col_pat_field1.olep << 10) | + (params->config_params.col_pat_field1.elop << 12) | + (params->config_params.col_pat_field1.elep << 14); + regw(val, CCOLP); + dev_dbg(dev, "Writing %x to CCOLP ...\n", val); + + /* Configure HSIZE register */ + val = + (params-> + horz_flip_en & CCDC_HSIZE_FLIP_MASK) << CCDC_HSIZE_FLIP_SHIFT; + + /* calculate line offset in 32 bytes based on pack value */ + if (ccdc_cfg.data_pack == CCDC_PACK_8BIT) + val |= (((params->win.width + 31) >> 5) & CCDC_LINEOFST_MASK); + else if (ccdc_cfg.data_pack == CCDC_PACK_12BIT) + val |= ((((params->win.width + + (params->win.width >> 2)) + + 31) >> 5) & CCDC_LINEOFST_MASK); + else + val |= + ((((params->win.width * 2) + + 31) >> 5) & CCDC_LINEOFST_MASK); + regw(val, HSIZE); + + /* Configure SDOFST register */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_en) { + /* For interlace inverse mode */ + regw(0x4B6D, SDOFST); + dev_dbg(dev, "Writing 0x4B6D to SDOFST...\n"); + } else { + /* For interlace non inverse mode */ + regw(0x0B6D, SDOFST); + dev_dbg(dev, "Writing 0x0B6D to SDOFST...\n"); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + if (params->image_invert_en) { + /* For progessive inverse mode */ + regw(0x4000, SDOFST); + dev_dbg(dev, "Writing 0x4000 to SDOFST...\n"); + } else { + /* For progessive non inverse mode */ + regw(0x0000, SDOFST); + dev_dbg(dev, "Writing 0x0000 to SDOFST...\n"); + } + } + + /* Configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 1); + + /* Configure Black Clamp */ + ccdc_config_bclamp(&module_params->bclamp); + + /* Configure Vertical Defection Pixel Correction */ + ccdc_config_dfc(&module_params->dfc); + + if (!module_params->df_csc.df_or_csc) + /* Configure Color Space Conversion */ + ccdc_config_csc(&module_params->df_csc); + + ccdc_config_linearization(&module_params->linearize); + + /* Configure Culling */ + ccdc_config_culling(&module_params->culling); + + /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */ + val = module_params->horz_offset & CCDC_DATA_H_OFFSET_MASK; + regw(val, DATAHOFST); + + val = module_params->vert_offset & CCDC_DATA_V_OFFSET_MASK; + regw(val, DATAVOFST); + + /* Setup test pattern if enabled */ + if (params->config_params.test_pat_gen) { + /* Use the HD/VD pol settings from user */ + sync.ccdpg_hdpol = params->hd_pol & CCDC_HD_POL_MASK; + sync.ccdpg_vdpol = params->vd_pol & CCDC_VD_POL_MASK; + + dm365_vpss_set_sync_pol(sync); + + frame_size.hlpfr = ccdc_cfg.bayer.win.width; + frame_size.pplen = ccdc_cfg.bayer.win.height; + dm365_vpss_set_pg_frame_size(frame_size); + vpss_select_ccdc_source(VPSS_PGLPBK); + } + + dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); + return 0; +} + +static int ccdc_validate_df_csc_params(struct ccdc_df_csc *df_csc) +{ + struct ccdc_color_space_conv *csc; + int i, csc_df_en = 0; + int err = -EINVAL; + + if (!df_csc->df_or_csc) { + /* csc configuration */ + csc = &df_csc->csc; + if (csc->en) { + csc_df_en = 1; + for (i = 0; i < CCDC_CSC_NUM_COEFF; i++) { + if (csc->coeff[i].integer > + CCDC_CSC_COEF_INTEG_MASK || + csc->coeff[i].decimal > + CCDC_CSC_COEF_DECIMAL_MASK) { + dev_dbg(dev, + "invalid csc coefficients \n"); + return err; + } + } + } + } + + if (df_csc->start_pix > CCDC_DF_CSC_SPH_MASK) { + dev_dbg(dev, "invalid df_csc start pix value \n"); + return err; + } + if (df_csc->num_pixels > CCDC_DF_NUMPIX) { + dev_dbg(dev, "invalid df_csc num pixels value \n"); + return err; + } + if (df_csc->start_line > CCDC_DF_CSC_LNH_MASK) { + dev_dbg(dev, "invalid df_csc start_line value \n"); + return err; + } + if (df_csc->num_lines > CCDC_DF_NUMLINES) { + dev_dbg(dev, "invalid df_csc num_lines value \n"); + return err; + } + return 0; +} + +static int ccdc_validate_dfc_params(struct ccdc_dfc *dfc) +{ + int err = -EINVAL; + int i; + + if (dfc->en) { + if (dfc->corr_whole_line > 1) { + dev_dbg(dev, "invalid corr_whole_line value \n"); + return err; + } + + if (dfc->def_level_shift > 4) { + dev_dbg(dev, "invalid def_level_shift value \n"); + return err; + } + + if (dfc->def_sat_level > 4095) { + dev_dbg(dev, "invalid def_sat_level value \n"); + return err; + } + if ((!dfc->num_vdefects) || (dfc->num_vdefects > 8)) { + dev_dbg(dev, "invalid num_vdefects value \n"); + return err; + } + for (i = 0; i < CCDC_VDFC_TABLE_SIZE; i++) { + if (dfc->table[i].pos_vert > 0x1fff) { + dev_dbg(dev, "invalid pos_vert value \n"); + return err; + } + if (dfc->table[i].pos_horz > 0x1fff) { + dev_dbg(dev, "invalid pos_horz value \n"); + return err; + } + } + } + return 0; +} + +static int ccdc_validate_bclamp_params(struct ccdc_black_clamp *bclamp) +{ + int err = -EINVAL; + + if (bclamp->dc_offset > 0x1fff) { + dev_dbg(dev, "invalid bclamp dc_offset value \n"); + return err; + } + + if (bclamp->en) { + if (bclamp->horz.clamp_pix_limit > 1) { + dev_dbg(dev, + "invalid bclamp horz clamp_pix_limit value \n"); + return err; + } + + if (bclamp->horz.win_count_calc < 1 || + bclamp->horz.win_count_calc > 32) { + dev_dbg(dev, + "invalid bclamp horz win_count_calc value \n"); + return err; + } + + if (bclamp->horz.win_start_h_calc > 0x1fff) { + dev_dbg(dev, + "invalid bclamp win_start_v_calc value \n"); + return err; + } + + if (bclamp->horz.win_start_v_calc > 0x1fff) { + dev_dbg(dev, + "invalid bclamp win_start_v_calc value \n"); + return err; + } + + if (bclamp->vert.reset_clamp_val > 0xfff) { + dev_dbg(dev, + "invalid bclamp reset_clamp_val value \n"); + return err; + } + + if (bclamp->vert.ob_v_sz_calc > 0x1fff) { + dev_dbg(dev, "invalid bclamp ob_v_sz_calc value \n"); + return err; + } + + if (bclamp->vert.ob_start_h > 0x1fff) { + dev_dbg(dev, "invalid bclamp ob_start_h value \n"); + return err; + } + + if (bclamp->vert.ob_start_v > 0x1fff) { + dev_dbg(dev, "invalid bclamp ob_start_h value \n"); + return err; + } + } + return 0; +} + +static int ccdc_validate_gain_ofst_params(struct ccdc_gain_offsets_adj + *gain_offset) +{ + int err = -EINVAL; + + if (gain_offset->gain_sdram_en || + gain_offset->gain_ipipe_en || + gain_offset->gain_h3a_en) { + if ((gain_offset->gain.r_ye.integer > 7) || + (gain_offset->gain.r_ye.decimal > 0x1ff)) { + dev_dbg(dev, "invalid gain r_ye\n"); + return err; + } + if ((gain_offset->gain.gr_cy.integer > 7) || + (gain_offset->gain.gr_cy.decimal > 0x1ff)) { + dev_dbg(dev, "invalid gain gr_cy\n"); + return err; + } + if ((gain_offset->gain.gb_g.integer > 7) || + (gain_offset->gain.gb_g.decimal > 0x1ff)) { + dev_dbg(dev, "invalid gain gb_g\n"); + return err; + } + if ((gain_offset->gain.b_mg.integer > 7) || + (gain_offset->gain.b_mg.decimal > 0x1ff)) { + dev_dbg(dev, "invalid gain b_mg\n"); + return err; + } + } + if (gain_offset->offset_sdram_en || + gain_offset->offset_ipipe_en || + gain_offset->offset_h3a_en) { + if (gain_offset->offset > 0xfff) { + dev_dbg(dev, "invalid gain b_mg\n"); + return err; + } + } + + return 0; +} + +static int +validate_ccdc_config_params_raw(struct ccdc_config_params_raw *params) +{ + int err; + + err = ccdc_validate_df_csc_params(¶ms->df_csc); + if (err) + goto exit; + err = ccdc_validate_dfc_params(¶ms->dfc); + if (err) + goto exit; + err = ccdc_validate_bclamp_params(¶ms->bclamp); + if (err) + goto exit; + err = ccdc_validate_gain_ofst_params(¶ms->gain_offset); +exit: + return err; +} + +static int ccdc_set_buftype(enum ccdc_buftype buf_type) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc_cfg.ycbcr.buf_type = buf_type; + + return 0; + +} +static enum ccdc_buftype ccdc_get_buftype(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + + return ccdc_cfg.ycbcr.buf_type; +} + +static int ccdc_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { + *pix = ccdc_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { + *pix = ccdc_raw_yuv_pix_formats[i]; + ret = 0; + } + } + + return ret; +} + +static int ccdc_set_pixel_format(unsigned int pixfmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (pixfmt == V4L2_PIX_FMT_SBGGR8) { + if ((ccdc_cfg.bayer.config_params.compress.alg != + CCDC_ALAW) && + (ccdc_cfg.bayer.config_params.compress.alg != + CCDC_DPCM)) { + dev_dbg(dev, "Either configure A-Law or" + "DPCM\n"); + return -EINVAL; + } + ccdc_cfg.data_pack = CCDC_PACK_8BIT; + } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { + ccdc_cfg.bayer.config_params.compress.alg = + CCDC_NO_COMPRESSION; + ccdc_cfg.data_pack = CCDC_PACK_16BIT; + } else + return -EINVAL; + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + ccdc_cfg.data_pack = CCDC_PACK_8BIT; + } + return 0; +} + +static u32 ccdc_get_pixel_format(void) +{ + u32 pixfmt; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.bayer.config_params.compress.alg + == CCDC_ALAW + || ccdc_cfg.bayer.config_params.compress.alg + == CCDC_DPCM) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} + +static int ccdc_set_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.win.top = win->top; + ccdc_cfg.bayer.win.left = win->left; + ccdc_cfg.bayer.win.width = win->width; + ccdc_cfg.bayer.win.height = win->height; + } else { + ccdc_cfg.ycbcr.win.top = win->top; + ccdc_cfg.ycbcr.win.left = win->left; + ccdc_cfg.ycbcr.win.width = win->width; + ccdc_cfg.ycbcr.win.height = win->height; + } + return 0; +} + +static void ccdc_get_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; + else + *win = ccdc_cfg.ycbcr.win; +} + +static unsigned int ccdc_get_line_length(void) +{ + unsigned int len; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (ccdc_cfg.data_pack == CCDC_PACK_8BIT) + len = ((ccdc_cfg.bayer.win.width)); + else if (ccdc_cfg.data_pack == CCDC_PACK_12BIT) + len = (((ccdc_cfg.bayer.win.width * 2) + + (ccdc_cfg.bayer.win.width >> 2))); + else + len = (((ccdc_cfg.bayer.win.width * 2))); + } else + len = (((ccdc_cfg.ycbcr.win.width * 2))); + + return ALIGN(len, 32); +} + +static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + + return 0; +} +static enum ccdc_frmfmt ccdc_get_frame_format(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; + else + return ccdc_cfg.ycbcr.frm_fmt; +} + +static int ccdc_getfid(void) +{ + return (regr(MODESET) >> 15) & 0x1; +} + +/* misc operations */ +static void ccdc_setfbaddr(unsigned long addr) +{ + regw((addr >> 21) & 0x07ff, CADU); + regw((addr >> 5) & 0x0ffff, CADL); +} + +static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_BT656_10BIT: + case VPFE_YCBCR_SYNC_8: + ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_BT1120: + case VPFE_YCBCR_SYNC_16: + ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_RAW_BAYER: + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + break; + default: + dev_dbg(dev, "Invalid interface type\n"); + return -EINVAL; + } + + return 0; +} + +/* Parameter operations */ +static int ccdc_get_params(void __user *params) +{ + /* only raw module parameters can be set through the IOCTL */ + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + if (copy_to_user(params, + &ccdc_cfg.bayer.config_params, + sizeof(ccdc_cfg.bayer.config_params))) { + dev_dbg(dev, "ccdc_get_params: error in copying ccdc params\n"); + return -EFAULT; + } + return 0; +} + +/* Parameter operations */ +static int ccdc_set_params(void __user *params) +{ + struct ccdc_config_params_raw *ccdc_raw_params; + int ret = -EINVAL; + + /* only raw module parameters can be set through the IOCTL */ + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) + return ret; + + ccdc_raw_params = kzalloc(sizeof(*ccdc_raw_params), GFP_KERNEL); + + if (NULL == ccdc_raw_params) + return -ENOMEM; + + ret = copy_from_user(ccdc_raw_params, + params, sizeof(*ccdc_raw_params)); + if (ret) { + dev_dbg(dev, "ccdc_set_params: error in copying ccdc" + "params, %d\n", ret); + ret = -EFAULT; + goto free_out; + } + + if (!validate_ccdc_config_params_raw(ccdc_raw_params)) { + memcpy(&ccdc_cfg.bayer.config_params, + ccdc_raw_params, + sizeof(*ccdc_raw_params)); + ret = 0; + } else + ret = -EINVAL; +free_out: + kfree(ccdc_raw_params); + return ret; +} + +/* This function will configure CCDC for YCbCr parameters. */ +static int ccdc_config_ycbcr(void) +{ + struct ccdc_ycbcr_config *params = &ccdc_cfg.ycbcr; + struct vpss_pg_frame_size frame_size; + u32 modeset = 0, ccdcfg = 0; + struct vpss_sync_pol sync; + + /** + * first reset the CCDC + * all registers have default values after reset + * This is important since we assume default values to be set in + * a lot of registers that we didn't touch + */ + dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); + + /* configure pixel format or input mode */ + modeset = modeset | ((params->pix_fmt & CCDC_INPUT_MASK) + << CCDC_INPUT_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | + (((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT)) | + (((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT)) | + (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT)); + + /* pack the data to 8-bit CCDCCFG */ + switch (ccdc_cfg.if_type) { + case VPFE_BT656: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(dev, "Invalid pix_fmt(input mode)\n"); + return -1; + } + modeset |= + ((VPFE_PINPOL_NEGATIVE & CCDC_VD_POL_MASK) + << CCDC_VD_POL_SHIFT); + regw(3, REC656IF); + ccdcfg = ccdcfg | CCDC_DATA_PACK8 | CCDC_YCINSWP_YCBCR; + break; + case VPFE_BT656_10BIT: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(dev, "Invalid pix_fmt(input mode)\n"); + return -1; + } + /* setup BT.656, embedded sync */ + regw(3, REC656IF); + /* enable 10 bit mode in ccdcfg */ + ccdcfg = ccdcfg | CCDC_DATA_PACK8 | CCDC_YCINSWP_YCBCR | + CCDC_BW656_ENABLE; + break; + case VPFE_BT1120: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + regw(3, REC656IF); + break; + + case VPFE_YCBCR_SYNC_8: + ccdcfg |= CCDC_DATA_PACK8; + ccdcfg |= CCDC_YCINSWP_YCBCR; + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + case VPFE_YCBCR_SYNC_16: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + default: + /* should never come here */ + dev_dbg(dev, "Invalid interface type\n"); + return -EINVAL; + } + + regw(modeset, MODESET); + + /* Set up pix order */ + ccdcfg |= (params->pix_order & CCDC_PIX_ORDER_MASK) << + CCDC_PIX_ORDER_SHIFT; + + regw(ccdcfg, CCDCFG); + + /* configure video window */ + if ((ccdc_cfg.if_type == VPFE_BT1120) || + (ccdc_cfg.if_type == VPFE_YCBCR_SYNC_16)) + ccdc_setwin(¶ms->win, params->frm_fmt, 1); + else + ccdc_setwin(¶ms->win, params->frm_fmt, 2); + + /** + * configure the horizontal line offset + * this is done by rounding up width to a multiple of 16 pixels + * and multiply by two to account for y:cb:cr 4:2:2 data + */ + regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); + + /* configure the memory line offset */ + if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && + (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) + /* two fields are interleaved in memory */ + regw(0x00000249, SDOFST); + + /* Setup test pattern if enabled */ + if (ccdc_cfg.bayer.config_params.test_pat_gen) { + sync.ccdpg_hdpol = (params->hd_pol & CCDC_HD_POL_MASK); + sync.ccdpg_vdpol = (params->vd_pol & CCDC_VD_POL_MASK); + dm365_vpss_set_sync_pol(sync); + dm365_vpss_set_pg_frame_size(frame_size); + } + + return 0; +} + +static int ccdc_configure(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_config_raw(); + else + ccdc_config_ycbcr(); + + return 0; +} + +static int ccdc_close(struct device *device) +{ + /* copy defaults to module params */ + memcpy(&ccdc_cfg.bayer.config_params, + &ccdc_config_defaults, + sizeof(struct ccdc_config_params_raw)); + + return 0; +} + +static struct ccdc_hw_device ccdc_hw_dev = { + .name = "DM365 ISIF", + .owner = THIS_MODULE, + .hw_ops = { + .open = ccdc_open, + .close = ccdc_close, + .enable = ccdc_enable, + .enable_out_to_sdram = ccdc_enable_output_to_sdram, + .set_hw_if_params = ccdc_set_hw_if_params, + .set_params = ccdc_set_params, + .get_params = ccdc_get_params, + .configure = ccdc_configure, + .set_buftype = ccdc_set_buftype, + .get_buftype = ccdc_get_buftype, + .enum_pix = ccdc_enum_pix, + .set_pixel_format = ccdc_set_pixel_format, + .get_pixel_format = ccdc_get_pixel_format, + .set_frame_format = ccdc_set_frame_format, + .get_frame_format = ccdc_get_frame_format, + .set_image_window = ccdc_set_image_window, + .get_image_window = ccdc_get_image_window, + .get_line_length = ccdc_get_line_length, + .setfbaddr = ccdc_setfbaddr, + .getfid = ccdc_getfid, + }, +}; + +static int __init dm365_ccdc_probe(struct platform_device *pdev) +{ + static resource_size_t res_len; + struct resource *res; + void *__iomem addr; + int status = 0, i; + + /** + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + i = 0; + /* Get the ISIF base address, linearization table0 and table1 addr. */ + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) { + status = -ENOENT; + goto fail_nobase_res; + } + res_len = res->end - res->start + 1; + res = request_mem_region(res->start, res_len, res->name); + if (!res) { + status = -EBUSY; + goto fail_nobase_res; + } + addr = ioremap_nocache(res->start, res_len); + if (!addr) { + status = -EBUSY; + goto fail_base_iomap; + } + switch (i) { + case 0: + /* ISIF base address */ + ccdc_cfg.base_addr = addr; + break; + case 1: + /* ISIF linear tbl0 address */ + ccdc_cfg.linear_tbl0_addr = addr; + break; + default: + /* ISIF linear tbl0 address */ + ccdc_cfg.linear_tbl1_addr = addr; + break; + } + i++; + } + + davinci_cfg_reg(DM365_VIN_CAM_WEN); + davinci_cfg_reg(DM365_VIN_CAM_VD); + davinci_cfg_reg(DM365_VIN_CAM_HD); + davinci_cfg_reg(DM365_VIN_YIN4_7_EN); + davinci_cfg_reg(DM365_VIN_YIN0_3_EN); + + printk(KERN_NOTICE "%s is registered with vpfe.\n", + ccdc_hw_dev.name); + return 0; +fail_base_iomap: + release_mem_region(res->start, res_len); + i--; +fail_nobase_res: + if (ccdc_cfg.base_addr) + iounmap(ccdc_cfg.base_addr); + if (ccdc_cfg.linear_tbl0_addr) + iounmap(ccdc_cfg.linear_tbl0_addr); + + while (i >= 0) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + release_mem_region(res->start, res_len); + i--; + } + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; +} + +static int dm365_ccdc_remove(struct platform_device *pdev) +{ + struct resource *res; + int i = 0; + + iounmap(ccdc_cfg.base_addr); + iounmap(ccdc_cfg.linear_tbl0_addr); + iounmap(ccdc_cfg.linear_tbl1_addr); + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (res) + release_mem_region(res->start, + res->end - res->start + 1); + i++; + } + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm365_ccdc_driver = { + .driver = { + .name = "dm365_isif", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm365_ccdc_remove), + .probe = dm365_ccdc_probe, +}; + +static int dm365_ccdc_init(void) +{ + return platform_driver_register(&dm365_ccdc_driver); +} + + +static void dm365_ccdc_exit(void) +{ + platform_driver_unregister(&dm365_ccdc_driver); +} + +module_init(dm365_ccdc_init); +module_exit(dm365_ccdc_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/dm365_ccdc_regs.h b/drivers/media/video/davinci/dm365_ccdc_regs.h new file mode 100644 index 0000000..d3f4b13 --- /dev/null +++ b/drivers/media/video/davinci/dm365_ccdc_regs.h @@ -0,0 +1,293 @@ +#ifndef _DM365_CCDC_REGS_H +#define _DM365_CCDC_REGS_H + +/* ISIF registers relative offsets */ +#define SYNCEN 0x00 +#define MODESET 0x04 +#define HDW 0x08 +#define VDW 0x0c +#define PPLN 0x10 +#define LPFR 0x14 +#define SPH 0x18 +#define LNH 0x1c +#define SLV0 0x20 +#define SLV1 0x24 +#define LNV 0x28 +#define CULH 0x2c +#define CULV 0x30 +#define HSIZE 0x34 +#define SDOFST 0x38 +#define CADU 0x3c +#define CADL 0x40 +#define LINCFG0 0x44 +#define LINCFG1 0x48 +#define CCOLP 0x4c +#define CRGAIN 0x50 +#define CGRGAIN 0x54 +#define CGBGAIN 0x58 +#define CBGAIN 0x5c +#define COFSTA 0x60 +#define FLSHCFG0 0x64 +#define FLSHCFG1 0x68 +#define FLSHCFG2 0x6c +#define VDINT0 0x70 +#define VDINT1 0x74 +#define VDINT2 0x78 +#define MISC 0x7c +#define CGAMMAWD 0x80 +#define REC656IF 0x84 +#define CCDCFG 0x88 +/***************************************************** +* Defect Correction registers +*****************************************************/ +#define DFCCTL 0x8c +#define VDFSATLV 0x90 +#define DFCMEMCTL 0x94 +#define DFCMEM0 0x98 +#define DFCMEM1 0x9c +#define DFCMEM2 0xa0 +#define DFCMEM3 0xa4 +#define DFCMEM4 0xa8 +/**************************************************** +* Black Clamp registers +****************************************************/ +#define CLAMPCFG 0xac +#define CLDCOFST 0xb0 +#define CLSV 0xb4 +#define CLHWIN0 0xb8 +#define CLHWIN1 0xbc +#define CLHWIN2 0xc0 +#define CLVRV 0xc4 +#define CLVWIN0 0xc8 +#define CLVWIN1 0xcc +#define CLVWIN2 0xd0 +#define CLVWIN3 0xd4 +/**************************************************** +* Lense Shading Correction +****************************************************/ +#define DATAHOFST 0xd8 +#define DATAVOFST 0xdc +#define LSCHVAL 0xe0 +#define LSCVVAL 0xe4 +#define TWODLSCCFG 0xe8 +#define TWODLSCOFST 0xec +#define TWODLSCINI 0xf0 +#define TWODLSCGRBU 0xf4 +#define TWODLSCGRBL 0xf8 +#define TWODLSCGROF 0xfc +#define TWODLSCORBU 0x100 +#define TWODLSCORBL 0x104 +#define TWODLSCOROF 0x108 +#define TWODLSCIRQEN 0x10c +#define TWODLSCIRQST 0x110 +/**************************************************** +* Data formatter +****************************************************/ +#define FMTCFG 0x114 +#define FMTPLEN 0x118 +#define FMTSPH 0x11c +#define FMTLNH 0x120 +#define FMTSLV 0x124 +#define FMTLNV 0x128 +#define FMTRLEN 0x12c +#define FMTHCNT 0x130 +#define FMTAPTR_BASE 0x134 +/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ +#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) +#define FMTPGMVF0 0x174 +#define FMTPGMVF1 0x178 +#define FMTPGMAPU0 0x17c +#define FMTPGMAPU1 0x180 +#define FMTPGMAPS0 0x184 +#define FMTPGMAPS1 0x188 +#define FMTPGMAPS2 0x18c +#define FMTPGMAPS3 0x190 +#define FMTPGMAPS4 0x194 +#define FMTPGMAPS5 0x198 +#define FMTPGMAPS6 0x19c +#define FMTPGMAPS7 0x1a0 +/************************************************ +* Color Space Converter +************************************************/ +#define CSCCTL 0x1a4 +#define CSCM0 0x1a8 +#define CSCM1 0x1ac +#define CSCM2 0x1b0 +#define CSCM3 0x1b4 +#define CSCM4 0x1b8 +#define CSCM5 0x1bc +#define CSCM6 0x1c0 +#define CSCM7 0x1c4 +#define OBWIN0 0x1c8 +#define OBWIN1 0x1cc +#define OBWIN2 0x1d0 +#define OBWIN3 0x1d4 +#define OBVAL0 0x1d8 +#define OBVAL1 0x1dc +#define OBVAL2 0x1e0 +#define OBVAL3 0x1e4 +#define OBVAL4 0x1e8 +#define OBVAL5 0x1ec +#define OBVAL6 0x1f0 +#define OBVAL7 0x1f4 +#define CLKCTL 0x1f8 + +#define CCDC_LINEAR_LUT0_ADDR 0x1C7C000 +#define CCDC_LINEAR_LUT1_ADDR 0x1C7C400 + +/* Masks & Shifts below */ +#define START_PX_HOR_MASK (0x7FFF) +#define NUM_PX_HOR_MASK (0x7FFF) +#define START_VER_ONE_MASK (0x7FFF) +#define START_VER_TWO_MASK (0x7FFF) +#define NUM_LINES_VER (0x7FFF) + +/* gain - offset masks */ +#define GAIN_INTEGER_MASK (0x7) +#define GAIN_INTEGER_SHIFT (0x9) +#define GAIN_DECIMAL_MASK (0x1FF) +#define OFFSET_MASK (0xFFF) +#define GAIN_SDRAM_EN_SHIFT (12) +#define GAIN_IPIPE_EN_SHIFT (13) +#define GAIN_H3A_EN_SHIFT (14) +#define OFST_SDRAM_EN_SHIFT (8) +#define OFST_IPIPE_EN_SHIFT (9) +#define OFST_H3A_EN_SHIFT (10) +#define GAIN_OFFSET_EN_MASK (0x7700) + +/* Culling */ +#define CULL_PAT_EVEN_LINE_SHIFT (8) + +/* CCDCFG register */ +#define CCDC_YCINSWP_RAW (0x00 << 4) +#define CCDC_YCINSWP_YCBCR (0x01 << 4) +#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) +#define CCDC_CCDCFG_WENLOG_AND (0x00 << 8) +#define CCDC_CCDCFG_TRGSEL_WEN (0x00 << 9) +#define CCDC_CCDCFG_EXTRG_DISABLE (0x00 << 10) +#define CCDC_LATCH_ON_VSYNC_DISABLE (0x01 << 15) +#define CCDC_LATCH_ON_VSYNC_ENABLE (0x00 << 15) +#define CCDC_DATA_PACK_MASK (0x03) +#define CCDC_DATA_PACK16 (0x0) +#define CCDC_DATA_PACK12 (0x1) +#define CCDC_DATA_PACK8 (0x2) +#define CCDC_PIX_ORDER_SHIFT (11) +#define CCDC_PIX_ORDER_MASK (0x01) +#define CCDC_BW656_ENABLE (0x01 << 5) + +/* MODESET registers */ +#define CCDC_VDHDOUT_INPUT (0x00 << 0) +#define CCDC_INPUT_MASK (0x03) +#define CCDC_INPUT_SHIFT (12) +#define CCDC_RAW_INPUT_MODE (0x00) +#define CCDC_FID_POL_MASK (0x01) +#define CCDC_FID_POL_SHIFT (4) +#define CCDC_HD_POL_MASK (0x01) +#define CCDC_HD_POL_SHIFT (3) +#define CCDC_VD_POL_MASK (0x01) +#define CCDC_VD_POL_SHIFT (2) +#define CCDC_DATAPOL_NORMAL (0x00) +#define CCDC_DATAPOL_MASK (0x01) +#define CCDC_DATAPOL_SHIFT (6) +#define CCDC_EXWEN_DISABLE (0x00) +#define CCDC_EXWEN_MASK (0x01) +#define CCDC_EXWEN_SHIFT (5) +#define CCDC_FRM_FMT_MASK (0x01) +#define CCDC_FRM_FMT_SHIFT (7) +#define CCDC_DATASFT_MASK (0x07) +#define CCDC_DATASFT_SHIFT (8) +#define CCDC_LPF_SHIFT (14) +#define CCDC_LPF_MASK (0x1) + +/* GAMMAWD registers */ +#define CCDC_ALAW_GAMA_WD_MASK (0xF) +#define CCDC_ALAW_GAMA_WD_SHIFT (1) +#define CCDC_ALAW_ENABLE (0x01) +#define CCDC_GAMMAWD_CFA_MASK (0x01) +#define CCDC_GAMMAWD_CFA_SHIFT (5) + +/* HSIZE registers */ +#define CCDC_HSIZE_FLIP_MASK (0x01) +#define CCDC_HSIZE_FLIP_SHIFT (12) +#define CCDC_LINEOFST_MASK (0xFFF) + +/* MISC registers */ +#define CCDC_DPCM_EN_SHIFT (12) +#define CCDC_DPCM_EN_MASK (1) +#define CCDC_DPCM_PREDICTOR_SHIFT (13) +#define CCDC_DPCM_PREDICTOR_MASK (1) + +/* Black clamp related */ +#define CCDC_BC_DCOFFSET_MASK (0x1FFF) +#define CCDC_BC_MODE_COLOR_MASK (1) +#define CCDC_BC_MODE_COLOR_SHIFT (4) +#define CCDC_HORZ_BC_MODE_MASK (3) +#define CCDC_HORZ_BC_MODE_SHIFT (1) +#define CCDC_HORZ_BC_WIN_COUNT_MASK (0x1F) +#define CCDC_HORZ_BC_WIN_SEL_SHIFT (5) +#define CCDC_HORZ_BC_PIX_LIMIT_SHIFT (6) +#define CCDC_HORZ_BC_WIN_H_SIZE_MASK (3) +#define CCDC_HORZ_BC_WIN_H_SIZE_SHIFT (8) +#define CCDC_HORZ_BC_WIN_V_SIZE_MASK (3) +#define CCDC_HORZ_BC_WIN_V_SIZE_SHIFT (12) +#define CCDC_HORZ_BC_WIN_START_H_MASK (0x1FFF) +#define CCDC_HORZ_BC_WIN_START_V_MASK (0x1FFF) +#define CCDC_VERT_BC_OB_H_SZ_MASK (7) +#define CCDC_VERT_BC_RST_VAL_SEL_MASK (3) +#define CCDC_VERT_BC_RST_VAL_SEL_SHIFT (4) +#define CCDC_VERT_BC_LINE_AVE_COEF_SHIFT (8) +#define CCDC_VERT_BC_OB_START_HORZ_MASK (0x1FFF) +#define CCDC_VERT_BC_OB_START_VERT_MASK (0x1FFF) +#define CCDC_VERT_BC_OB_VERT_SZ_MASK (0x1FFF) +#define CCDC_VERT_BC_RST_VAL_MASK (0xFFF) +#define CCDC_BC_VERT_START_SUB_V_MASK (0x1FFF) + +/* VDFC registers */ +#define CCDC_VDFC_EN_SHIFT (4) +#define CCDC_VDFC_CORR_MOD_MASK (3) +#define CCDC_VDFC_CORR_MOD_SHIFT (5) +#define CCDC_VDFC_CORR_WHOLE_LN_SHIFT (7) +#define CCDC_VDFC_LEVEL_SHFT_MASK (7) +#define CCDC_VDFC_LEVEL_SHFT_SHIFT (8) +#define CCDC_VDFC_SAT_LEVEL_MASK (0xFFF) +#define CCDC_VDFC_POS_MASK (0x1FFF) +#define CCDC_DFCMEMCTL_DFCMARST_SHIFT (2) + +/* CSC registers */ +#define CCDC_CSC_COEF_INTEG_MASK (7) +#define CCDC_CSC_COEF_DECIMAL_MASK (0x1f) +#define CCDC_CSC_COEF_INTEG_SHIFT (5) +#define CCDC_CSCM_MSB_SHIFT (8) +#define CCDC_DF_CSC_SPH_MASK (0x1FFF) +#define CCDC_DF_CSC_LNH_MASK (0x1FFF) +#define CCDC_DF_CSC_SLV_MASK (0x1FFF) +#define CCDC_DF_CSC_LNV_MASK (0x1FFF) +#define CCDC_DF_NUMLINES (0x7FFF) +#define CCDC_DF_NUMPIX (0x1FFF) + +/* Offsets for LSC/DFC/Gain */ +#define CCDC_DATA_H_OFFSET_MASK (0x1FFF) +#define CCDC_DATA_V_OFFSET_MASK (0x1FFF) + +/* Linearization */ +#define CCDC_LIN_CORRSFT_MASK (7) +#define CCDC_LIN_CORRSFT_SHIFT (4) +#define CCDC_LIN_SCALE_FACT_INTEG_SHIFT (10) +#define CCDC_LIN_SCALE_FACT_DECIMAL_MASK (0x3FF) +#define CCDC_LIN_ENTRY_MASK (0x3FF) + +#define CCDC_DF_FMTRLEN_MASK (0x1FFF) +#define CCDC_DF_FMTHCNT_MASK (0x1FFF) + +/* Pattern registers */ +#define CCDC_PG_EN (1 << 3) +#define CCDC_SEL_PG_SRC (3 << 4) +#define CCDC_PG_VD_POL_SHIFT (0) +#define CCDC_PG_HD_POL_SHIFT (1) + +/*random other junk*/ +#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) +#define CCDC_SYNCEN_WEN_MASK (1 << 1) +#define CCDC_SYNCEN_WEN_SHIFT 1 + +#endif diff --git a/include/media/davinci/dm365_ccdc.h b/include/media/davinci/dm365_ccdc.h new file mode 100644 index 0000000..1ce52a7 --- /dev/null +++ b/include/media/davinci/dm365_ccdc.h @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ccdc header file for DM365 ISIF + */ +#ifndef _DM365_CCDC_H +#define _DM365_CCDC_H +#include +#include +/* ccdc float type S8Q8/U8Q8 */ +struct ccdc_float_8 { + /* 8 bit integer part */ + __u8 integer; + /* 8 bit decimal part */ + __u8 decimal; +}; + +/* brief ccdc float type U16Q16/S16Q16 */ +struct ccdc_float_16 { + /* 16 bit integer part */ + __u16 integer; + /* 16 bit decimal part */ + __u16 decimal; +}; + +/************************************************************************ + * Vertical Defect Correction parameters + ***********************************************************************/ +/* Defect Correction (DFC) table entry */ +struct ccdc_vdfc_entry { + /* vertical position of defect */ + __u16 pos_vert; + /* horizontal position of defect */ + __u16 pos_horz; + /* + * Defect level of Vertical line defect position. This is subtracted + * from the data at the defect position + */ + __u8 level_at_pos; + /* + * Defect level of the pixels upper than the vertical line defect. + * This is subtracted from the data + */ + __u8 level_up_pixels; + /* + * Defect level of the pixels lower than the vertical line defect. + * This is subtracted from the data + */ + __u8 level_low_pixels; +}; + +#define CCDC_VDFC_TABLE_SIZE 8 +struct ccdc_dfc { + /* enable vertical defect correction */ + __u8 en; + /* Defect level subtraction. Just fed through if saturating */ +#define CCDC_VDFC_NORMAL 0 + /* + * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 + * if data saturating + */ +#define CCDC_VDFC_HORZ_INTERPOL_IF_SAT 1 + /* Horizontal interpolation (((i-2)+(i+2))/2) */ +#define CCDC_VDFC_HORZ_INTERPOL 2 + /* one of the vertical defect correction modes above */ + __u8 corr_mode; + /* 0 - whole line corrected, 1 - not pixels upper than the defect */ + __u8 corr_whole_line; +#define CCDC_VDFC_NO_SHIFT 0 +#define CCDC_VDFC_SHIFT_1 1 +#define CCDC_VDFC_SHIFT_2 2 +#define CCDC_VDFC_SHIFT_3 3 +#define CCDC_VDFC_SHIFT_4 4 + /* + * defect level shift value. level_at_pos, level_upper_pos, + * and level_lower_pos can be shifted up by this value. Choose + * one of the values above + */ + __u8 def_level_shift; + /* defect saturation level */ + __u16 def_sat_level; + /* number of vertical defects. Max is CCDC_VDFC_TABLE_SIZE */ + __u16 num_vdefects; + /* VDFC table ptr */ + struct ccdc_vdfc_entry table[CCDC_VDFC_TABLE_SIZE]; +}; + +struct ccdc_horz_bclamp { + + /* Horizontal clamp disabled. Only vertical clamp value is subtracted */ +#define CCDC_HORZ_BC_DISABLE 0 + /* + * Horizontal clamp value is calculated and subtracted from image data + * along with vertical clamp value + */ +#define CCDC_HORZ_BC_CLAMP_CALC_ENABLED 1 + /* + * Horizontal clamp value calculated from previous image is subtracted + * from image data along with vertical clamp value. + */ +#define CCDC_HORZ_BC_CLAMP_NOT_UPDATED 2 + /* horizontal clamp mode. One of the values above */ + __u8 mode; + /* + * pixel value limit enable. + * 0 - limit disabled + * 1 - pixel value limited to 1023 + */ + __u8 clamp_pix_limit; + /* Select Most left window for bc calculation */ +#define CCDC_SEL_MOST_LEFT_WIN 0 + /* Select Most right window for bc calculation */ +#define CCDC_SEL_MOST_RIGHT_WIN 1 + /* Select most left or right window for clamp val calculation */ + __u8 base_win_sel_calc; + /* Window count per color for calculation. range 1-32 */ + __u8 win_count_calc; + /* Window start position - horizontal for calculation. 0 - 8191 */ + __u16 win_start_h_calc; + /* Window start position - vertical for calculation 0 - 8191 */ + __u16 win_start_v_calc; +#define CCDC_HORZ_BC_SZ_H_2PIXELS 0 +#define CCDC_HORZ_BC_SZ_H_4PIXELS 1 +#define CCDC_HORZ_BC_SZ_H_8PIXELS 2 +#define CCDC_HORZ_BC_SZ_H_16PIXELS 3 + /* Width of the sample window in pixels for calculation */ + __u8 win_h_sz_calc; +#define CCDC_HORZ_BC_SZ_V_32PIXELS 0 +#define CCDC_HORZ_BC_SZ_V_64PIXELS 1 +#define CCDC_HORZ_BC_SZ_V_128PIXELS 2 +#define CCDC_HORZ_BC_SZ_V_256PIXELS 3 + /* Height of the sample window in pixels for calculation */ + __u8 win_v_sz_calc; +}; + +/************************************************************************ + * Black Clamp parameters + ***********************************************************************/ +struct ccdc_vert_bclamp { + /* Reset value used is the clamp value calculated */ +#define CCDC_VERT_BC_USE_HORZ_CLAMP_VAL 0 + /* Reset value used is reset_clamp_val configured */ +#define CCDC_VERT_BC_USE_CONFIG_CLAMP_VAL 1 + /* No update, previous image value is used */ +#define CCDC_VERT_BC_NO_UPDATE 2 + /* + * Reset value selector for vertical clamp calculation. Use one of + * the above values + */ + __u8 reset_val_sel; + /* U12 value if reset_val_sel = CCDC_BC_VERT_USE_CONFIG_CLAMP_VAL */ + __u16 reset_clamp_val; + /* U8Q8. Line average coefficient used in vertical clamp calculation */ + __u8 line_ave_coef; +#define CCDC_VERT_BC_SZ_H_2PIXELS 0 +#define CCDC_VERT_BC_SZ_H_4PIXELS 1 +#define CCDC_VERT_BC_SZ_H_8PIXELS 2 +#define CCDC_VERT_BC_SZ_H_16PIXELS 3 +#define CCDC_VERT_BC_SZ_H_32PIXELS 4 +#define CCDC_VERT_BC_SZ_H_64PIXELS 5 + /* Width in pixels of the optical black region used for calculation */ + __u8 ob_h_sz_calc; + /* Height of the optical black region for calculation */ + __u16 ob_v_sz_calc; + /* Optical black region start position - horizontal. 0 - 8191 */ + __u16 ob_start_h; + /* Optical black region start position - vertical 0 - 8191 */ + __u16 ob_start_v; +}; + +struct ccdc_black_clamp { + /* + * This offset value is added irrespective of the clamp enable status. + * S13 + */ + __u16 dc_offset; + /* + * Enable black/digital clamp value to be subtracted from the image data + */ + __u8 en; + /* + * black clamp mode. same/separate clamp for 4 colors + * 0 - disable - same clamp value for all colors + * 1 - clamp value calculated separately for all colors + */ + __u8 bc_mode_color; + /* Vrtical start position for bc subtraction */ + __u16 vert_start_sub; + /* Black clamp for horizontal direction */ + struct ccdc_horz_bclamp horz; + /* Black clamp for vertical direction */ + struct ccdc_vert_bclamp vert; +}; + +/************************************************************************* +** Color Space Convertion (CSC) +*************************************************************************/ +#define CCDC_CSC_NUM_COEFF 16 +struct ccdc_color_space_conv { + /* Enable color space conversion */ + __u8 en; + /* + * csc coeffient table. S8Q5, M00 at index 0, M01 at index 1, and + * so forth + */ + struct ccdc_float_8 coeff[CCDC_CSC_NUM_COEFF]; +}; + + +/************************************************************************* +** Black Compensation parameters +*************************************************************************/ +struct ccdc_black_comp { + /* Comp for Red */ + __s8 r_comp; + /* Comp for Gr */ + __s8 gr_comp; + /* Comp for Blue */ + __s8 b_comp; + /* Comp for Gb */ + __s8 gb_comp; +}; + +/************************************************************************* +** Gain parameters +*************************************************************************/ +struct ccdc_gain { + /* Gain for Red or ye */ + struct ccdc_float_16 r_ye; + /* Gain for Gr or cy */ + struct ccdc_float_16 gr_cy; + /* Gain for Gb or g */ + struct ccdc_float_16 gb_g; + /* Gain for Blue or mg */ + struct ccdc_float_16 b_mg; +}; + +#define CCDC_LINEAR_TAB_SIZE 192 +/************************************************************************* +** Linearization parameters +*************************************************************************/ +struct ccdc_linearize { + /* Enable or Disable linearization of data */ + __u8 en; + /* Shift value applied */ + __u8 corr_shft; + /* scale factor applied U11Q10 */ + struct ccdc_float_16 scale_fact; + /* Size of the linear table */ + __u16 table[CCDC_LINEAR_TAB_SIZE]; +}; + +/* Color patterns */ +#define CCDC_RED 0 +#define CCDC_GREEN_RED 1 +#define CCDC_GREEN_BLUE 2 +#define CCDC_BLUE 3 +struct ccdc_col_pat { + __u8 olop; + __u8 olep; + __u8 elop; + __u8 elep; +}; + +/************************************************************************* +** Data formatter parameters +*************************************************************************/ +struct ccdc_fmtplen { + /* + * number of program entries for SET0, range 1 - 16 + * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is + * CCDC_COMBINE + */ + __u16 plen0; + /* + * number of program entries for SET1, range 1 - 16 + * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is + * CCDC_COMBINE + */ + __u16 plen1; + /** + * number of program entries for SET2, range 1 - 16 + * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is + * CCDC_COMBINE + */ + __u16 plen2; + /** + * number of program entries for SET3, range 1 - 16 + * when fmtmode is CCDC_SPLIT, 1 - 8 when fmtmode is + * CCDC_COMBINE + */ + __u16 plen3; +}; + +struct ccdc_fmt_cfg { +#define CCDC_SPLIT 0 +#define CCDC_COMBINE 1 + /* Split or combine or line alternate */ + __u8 fmtmode; + /* enable or disable line alternating mode */ + __u8 ln_alter_en; +#define CCDC_1LINE 0 +#define CCDC_2LINES 1 +#define CCDC_3LINES 2 +#define CCDC_4LINES 3 + /* Split/combine line number */ + __u8 lnum; + /* Address increment Range 1 - 16 */ + __u8 addrinc; +}; + +struct ccdc_fmt_addr_ptr { + /* Initial address */ + __u32 init_addr; + /* output line number */ +#define CCDC_1STLINE 0 +#define CCDC_2NDLINE 1 +#define CCDC_3RDLINE 2 +#define CCDC_4THLINE 3 + __u8 out_line; +}; + +struct ccdc_fmtpgm_ap { + /* program address pointer */ + __u8 pgm_aptr; + /* program address increment or decrement */ + __u8 pgmupdt; +}; + +struct ccdc_data_formatter { + /* Enable/Disable data formatter */ + __u8 en; + /* data formatter configuration */ + struct ccdc_fmt_cfg cfg; + /* Formatter program entries length */ + struct ccdc_fmtplen plen; + /* first pixel in a line fed to formatter */ + __u16 fmtrlen; + /* HD interval for output line. Only valid when split line */ + __u16 fmthcnt; + /* formatter address pointers */ + struct ccdc_fmt_addr_ptr fmtaddr_ptr[16]; + /* program enable/disable */ + __u8 pgm_en[32]; + /* program address pointers */ + struct ccdc_fmtpgm_ap fmtpgm_ap[32]; +}; + +struct ccdc_df_csc { + /* Color Space Conversion confguration, 0 - csc, 1 - df */ + __u8 df_or_csc; + /* csc configuration valid if df_or_csc is 0 */ + struct ccdc_color_space_conv csc; + /* data formatter configuration valid if df_or_csc is 1 */ + struct ccdc_data_formatter df; + /* start pixel in a line at the input */ + __u32 start_pix; + /* number of pixels in input line */ + __u32 num_pixels; + /* start line at the input */ + __u32 start_line; + /* number of lines at the input */ + __u32 num_lines; +}; + +struct ccdc_gain_offsets_adj { + /* Gain adjustment per color */ + struct ccdc_gain gain; + /* Offset adjustment */ + __u16 offset; + /* Enable or Disable Gain adjustment for SDRAM data */ + __u8 gain_sdram_en; + /* Enable or Disable Gain adjustment for IPIPE data */ + __u8 gain_ipipe_en; + /* Enable or Disable Gain adjustment for H3A data */ + __u8 gain_h3a_en; + /* Enable or Disable Gain adjustment for SDRAM data */ + __u8 offset_sdram_en; + /* Enable or Disable Gain adjustment for IPIPE data */ + __u8 offset_ipipe_en; + /* Enable or Disable Gain adjustment for H3A data */ + __u8 offset_h3a_en; +}; + +struct ccdc_cul { + /* Horizontal Cull pattern for odd lines */ + __u8 hcpat_odd; + /* Horizontal Cull pattern for even lines */ + __u8 hcpat_even; + /* Vertical Cull pattern */ + __u8 vcpat; + /* Enable or disable lpf. Apply when cull is enabled */ + __u8 en_lpf; +}; + +struct ccdc_compress { +#define CCDC_ALAW 0 +#define CCDC_DPCM 1 +#define CCDC_NO_COMPRESSION 2 + /* Compression Algorithm used */ + __u8 alg; + /* Choose Predictor1 for DPCM compression */ +#define CCDC_DPCM_PRED1 0 + /* Choose Predictor2 for DPCM compression */ +#define CCDC_DPCM_PRED2 1 + /* Predictor for DPCM compression */ + __u8 pred; +}; + +/* all the stuff in this struct will be provided by userland */ +struct ccdc_config_params_raw { + /* Linearization parameters for image sensor data input */ + struct ccdc_linearize linearize; + /* Data formatter or CSC */ + struct ccdc_df_csc df_csc; + /* Defect Pixel Correction (DFC) confguration */ + struct ccdc_dfc dfc; + /* Black/Digital Clamp configuration */ + struct ccdc_black_clamp bclamp; + /* Gain, offset adjustments */ + struct ccdc_gain_offsets_adj gain_offset; + /* Culling */ + struct ccdc_cul culling; + /* A-Law and DPCM compression options */ + struct ccdc_compress compress; + /* horizontal offset for Gain/LSC/DFC */ + __u16 horz_offset; + /* vertical offset for Gain/LSC/DFC */ + __u16 vert_offset; + /* color pattern for field 0 */ + struct ccdc_col_pat col_pat_field0; + /* color pattern for field 1 */ + struct ccdc_col_pat col_pat_field1; + /* No Shift */ +#define CCDC_NO_SHIFT 0 + /* 1 bit Shift */ +#define CCDC_1BIT_SHIFT 1 + /* 2 bit Shift */ +#define CCDC_2BIT_SHIFT 2 + /* 3 bit Shift */ +#define CCDC_3BIT_SHIFT 3 + /* 4 bit Shift */ +#define CCDC_4BIT_SHIFT 4 + /* 5 bit Shift */ +#define CCDC_5BIT_SHIFT 5 + /* 6 bit Shift */ +#define CCDC_6BIT_SHIFT 6 + /* Data shift applied before storing to SDRAM */ + __u8 data_shift; + /* enable input test pattern generation */ + __u8 test_pat_gen; +}; + +#ifdef __KERNEL__ +struct ccdc_ycbcr_config { + /* ccdc pixel format */ + enum ccdc_pixfmt pix_fmt; + /* ccdc frame format */ + enum ccdc_frmfmt frm_fmt; + /* CCDC crop window */ + struct v4l2_rect win; + /* field polarity */ + enum vpfe_pin_pol fid_pol; + /* interface VD polarity */ + enum vpfe_pin_pol vd_pol; + /* interface HD polarity */ + enum vpfe_pin_pol hd_pol; + /* ccdc pix order. Only used for ycbcr capture */ + enum ccdc_pixorder pix_order; + /* ccdc buffer type. Only used for ycbcr capture */ + enum ccdc_buftype buf_type; +}; + +/* MSB of image data connected to sensor port */ +enum ccdc_data_msb { + /* MSB b15 */ + CCDC_BIT_MSB_15, + /* MSB b14 */ + CCDC_BIT_MSB_14, + /* MSB b13 */ + CCDC_BIT_MSB_13, + /* MSB b12 */ + CCDC_BIT_MSB_12, + /* MSB b11 */ + CCDC_BIT_MSB_11, + /* MSB b10 */ + CCDC_BIT_MSB_10, + /* MSB b9 */ + CCDC_BIT_MSB_9, + /* MSB b8 */ + CCDC_BIT_MSB_8, + /* MSB b7 */ + CCDC_BIT_MSB_7 +}; + +enum ccdc_cfa_pattern { + CCDC_CFA_PAT_MOSAIC, + CCDC_CFA_PAT_STRIPE +}; + +struct ccdc_params_raw { + /* ccdc pixel format */ + enum ccdc_pixfmt pix_fmt; + /* ccdc frame format */ + enum ccdc_frmfmt frm_fmt; + /* video window */ + struct v4l2_rect win; + /* field polarity */ + enum vpfe_pin_pol fid_pol; + /* interface VD polarity */ + enum vpfe_pin_pol vd_pol; + /* interface HD polarity */ + enum vpfe_pin_pol hd_pol; + /* buffer type. Applicable for interlaced mode */ + enum ccdc_buftype buf_type; + /* Gain values */ + struct ccdc_gain gain; + /* cfa pattern */ + enum ccdc_cfa_pattern cfa_pat; + /* Data MSB position */ + enum ccdc_data_msb data_msb; + /* Enable horizontal flip */ + unsigned char horz_flip_en; + /* Enable image invert vertically */ + unsigned char image_invert_en; + + /* all the userland defined stuff*/ + struct ccdc_config_params_raw config_params; +}; + +enum ccdc_data_pack { + CCDC_PACK_16BIT, + CCDC_PACK_12BIT, + CCDC_PACK_8BIT +}; + +#define CCDC_WIN_NTSC {0, 0, 720, 480} +#define CCDC_WIN_VGA {0, 0, 640, 480} +#define ISP5_CCDCMUX 0x20 +#endif +#endif -- 1.6.0.4 From sudhakar.raj at ti.com Tue Dec 1 23:32:58 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:02:58 +0530 Subject: [PATCH 0/9] davinci: EDMA updates Message-ID: <1259731978-13147-1-git-send-email-sudhakar.raj@ti.com> This patch set corrects some issues with the existing EDMA driver and also adds support for EDMA resource (channel/slots) sharing between two processors (say ARM and DSP). The patch set has been tested on DM646x, OMAP-L137 and OMAP-L138 EVM boards. Sudhakar Rajashekhara (9): davinci: Correct return value of edma_alloc_channel api davinci: Keep count of channel controllers on a platform davinci: Fix edma_alloc_channel api for EDMA_CHANNEL_ANY case davinci: build list of unused EDMA events dynamically davinci: support for EDMA resource sharing davinci: da8xx/omap-l1xx: Add EDMA platform data for da850/omap-l138 davinci: da830/omapl137: Specify reserved channels/slots davinci: da850/omapl138: Specify reserved channels/slots davinci: dm646x: Specify reserved EDMA channel/slots for DM646x arch/arm/mach-davinci/devices-da8xx.c | 181 ++++++++++++++++++++++++++-- arch/arm/mach-davinci/dm355.c | 8 -- arch/arm/mach-davinci/dm644x.c | 10 -- arch/arm/mach-davinci/dm646x.c | 28 ++++- arch/arm/mach-davinci/dma.c | 101 ++++++++++++++--- arch/arm/mach-davinci/include/mach/edma.h | 4 +- 6 files changed, 276 insertions(+), 56 deletions(-) From sudhakar.raj at ti.com Tue Dec 1 23:33:07 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:03:07 +0530 Subject: [PATCH 1/9] davinci: Correct return value of edma_alloc_channel api Message-ID: <1259731987-13180-1-git-send-email-sudhakar.raj@ti.com> Currently, edma_alloc_channel api is returning the channel number without prepending the controller on which the channel was allocated. So, if a channel is allocated on 2nd controller, calls subsequent to edma_alloc_channel would never know that channel was allocated on the 2nd controller, and continue to operate on 1st controller, resulting in edma failure. This patch fixes this issue. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/dma.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 648fbb7..5a71f4d 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -642,7 +642,7 @@ int edma_alloc_channel(int channel, map_dmach_queue(ctlr, channel, eventq_no); - return channel; + return EDMA_CTLR_CHAN(ctlr, channel); } EXPORT_SYMBOL(edma_alloc_channel); -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:33:39 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:03:39 +0530 Subject: [PATCH 2/9] davinci: Keep count of channel controllers on a platform Message-ID: <1259732019-13216-1-git-send-email-sudhakar.raj@ti.com> Some architectures have only one channel controller, but the edma_alloc_channel api loops twice to findout the free channel available in EDMA_CHANNEL_ANY case. A new variable has been introduced to keep count of number of channel controllers being used on a particular architecture. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/dma.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 5a71f4d..97a49f9 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -243,6 +243,7 @@ struct edma { }; static struct edma *edma_info[EDMA_MAX_CC]; +static int arch_num_cc; /* dummy param set used to (re)initialize parameter RAM slots */ static const struct edmacc_param dummy_paramset = { @@ -602,7 +603,7 @@ int edma_alloc_channel(int channel, } if (channel < 0) { - for (i = 0; i < EDMA_MAX_CC; i++) { + for (i = 0; i < arch_num_cc; i++) { channel = 0; for (;;) { channel = find_next_bit(edma_info[i]-> @@ -1467,6 +1468,7 @@ static int __init edma_probe(struct platform_device *pdev) edma_write_array2(j, EDMA_DRAE, i, 1, 0x0); edma_write_array(j, EDMA_QRAE, i, 0x0); } + arch_num_cc++; } if (tc_errs_handled) { -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:33:49 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:03:49 +0530 Subject: [PATCH 3/9] davinci: Fix edma_alloc_channel api for EDMA_CHANNEL_ANY case Message-ID: <1259732029-13243-1-git-send-email-sudhakar.raj@ti.com> Though edma_alloc_channel api was looping through the available channel controllers in EDMA_CHANNEL_ANY case, it was never returning the channel for 2nd channel controller, if 1st channel controller had no free channels. This issue has been fixed with this patch. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/dma.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 97a49f9..89a3dcc 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -595,7 +595,7 @@ int edma_alloc_channel(int channel, void *data, enum dma_event_q eventq_no) { - unsigned i, done, ctlr = 0; + unsigned i, done = 0, ctlr = 0; if (channel >= 0) { ctlr = EDMA_CTLR(channel); @@ -611,7 +611,7 @@ int edma_alloc_channel(int channel, edma_info[i]->num_channels, channel); if (channel == edma_info[i]->num_channels) - return -ENOMEM; + break; if (!test_and_set_bit(channel, edma_info[i]->edma_inuse)) { done = 1; @@ -623,6 +623,8 @@ int edma_alloc_channel(int channel, if (done) break; } + if (!done) + return -ENOMEM; } else if (channel >= edma_info[ctlr]->num_channels) { return -EINVAL; } else if (test_and_set_bit(channel, edma_info[ctlr]->edma_inuse)) { -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:34:09 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:04:09 +0530 Subject: [PATCH 4/9] davinci: build list of unused EDMA events dynamically Message-ID: <1259732049-13279-1-git-send-email-sudhakar.raj@ti.com> Currently, the edma_noevent list is passed from platform data. But on some architectures, there will be many EDMA channels which will not be used at all. This patch scans all the platform devices and then builds a list of events which are not being used. The unused event list will be used to allocate EDMA channels in case of EDMA_CHANNEL_ANY usage instead of the edma_noevent being used earlier for this purpose. This patch is based on David Brownells's suggestion at http://article.gmane.org/gmane.linux.davinci/15176. Signed-off-by: Sudhakar Rajashekhara Cc: David Brownell --- arch/arm/mach-davinci/devices-da8xx.c | 6 --- arch/arm/mach-davinci/dm355.c | 8 ---- arch/arm/mach-davinci/dm644x.c | 10 ----- arch/arm/mach-davinci/dm646x.c | 9 ----- arch/arm/mach-davinci/dma.c | 55 ++++++++++++++++++++++------ arch/arm/mach-davinci/include/mach/edma.h | 2 - 6 files changed, 43 insertions(+), 47 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index dd2d32c..6860067 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -82,11 +82,6 @@ struct platform_device da8xx_serial_device = { }, }; -static const s8 da8xx_dma_chan_no_event[] = { - 20, 21, - -1 -}; - static const s8 da8xx_queue_tc_mapping[][2] = { /* {event queue no, TC no} */ {0, 0}, @@ -108,7 +103,6 @@ static struct edma_soc_info da8xx_edma_info[] = { .n_slot = 128, .n_tc = 2, .n_cc = 1, - .noevent = da8xx_dma_chan_no_event, .queue_tc_mapping = da8xx_queue_tc_mapping, .queue_priority_mapping = da8xx_queue_priority_mapping, }, diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index dedf4d4..b1185f8 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -564,13 +564,6 @@ static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = { /*----------------------------------------------------------------------*/ -static const s8 dma_chan_dm355_no_event[] = { - 12, 13, 24, 56, 57, - 58, 59, 60, 61, 62, - 63, - -1 -}; - static const s8 queue_tc_mapping[][2] = { /* {event queue no, TC no} */ @@ -594,7 +587,6 @@ static struct edma_soc_info dm355_edma_info[] = { .n_slot = 128, .n_tc = 2, .n_cc = 1, - .noevent = dma_chan_dm355_no_event, .queue_tc_mapping = queue_tc_mapping, .queue_priority_mapping = queue_priority_mapping, }, diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 2cd0081..fc060e7 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -479,15 +479,6 @@ static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = { /*----------------------------------------------------------------------*/ -static const s8 dma_chan_dm644x_no_event[] = { - 0, 1, 12, 13, 14, - 15, 25, 30, 31, 45, - 46, 47, 55, 56, 57, - 58, 59, 60, 61, 62, - 63, - -1 -}; - static const s8 queue_tc_mapping[][2] = { /* {event queue no, TC no} */ @@ -511,7 +502,6 @@ static struct edma_soc_info dm644x_edma_info[] = { .n_slot = 128, .n_tc = 2, .n_cc = 1, - .noevent = dma_chan_dm644x_no_event, .queue_tc_mapping = queue_tc_mapping, .queue_priority_mapping = queue_priority_mapping, }, diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 829a44b..eb2e518 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -513,14 +513,6 @@ static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = { /*----------------------------------------------------------------------*/ -static const s8 dma_chan_dm646x_no_event[] = { - 0, 1, 2, 3, 13, - 14, 15, 24, 25, 26, - 27, 30, 31, 54, 55, - 56, - -1 -}; - /* Four Transfer Controllers on DM646x */ static const s8 dm646x_queue_tc_mapping[][2] = { @@ -549,7 +541,6 @@ static struct edma_soc_info dm646x_edma_info[] = { .n_slot = 512, .n_tc = 4, .n_cc = 1, - .noevent = dma_chan_dm646x_no_event, .queue_tc_mapping = dm646x_queue_tc_mapping, .queue_priority_mapping = dm646x_queue_priority_mapping, }, diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 89a3dcc..15dd886 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -226,11 +226,11 @@ struct edma { */ DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY); - /* The edma_noevent bit for each channel is clear unless - * it doesn't trigger DMA events on this platform. It uses a - * bit of SOC-specific initialization code. + /* The edma_unused bit for each channel is clear unless + * it is not being used on this platform. It uses a bit + * of SOC-specific initialization code. */ - DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH); + DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH); unsigned irq_res_start; unsigned irq_res_end; @@ -556,8 +556,27 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id, return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1); } +static int prepare_unused_channel_list(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + int i, ctlr; + + for (i = 0; i < pdev->num_resources; i++) { + if ((pdev->resource[i].flags & IORESOURCE_DMA) && + (int)pdev->resource[i].start >= 0) { + ctlr = EDMA_CTLR(pdev->resource[i].start); + clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start), + edma_info[ctlr]->edma_unused); + } + } + + return 0; +} + /*-----------------------------------------------------------------------*/ +static bool unused_chan_list_done; + /* Resource alloc/free: dma channels, parameter RAM slots */ /** @@ -596,6 +615,21 @@ int edma_alloc_channel(int channel, enum dma_event_q eventq_no) { unsigned i, done = 0, ctlr = 0; + int ret = 0; + + if (!unused_chan_list_done) { + /* + * Scan all the platform devices to find out the EDMA channels + * used and clear them in the unused list, making the rest + * available for ARM usage. + */ + ret = bus_for_each_dev(&platform_bus_type, NULL, NULL, + prepare_unused_channel_list); + if (ret < 0) + return ret; + + unused_chan_list_done = true; + } if (channel >= 0) { ctlr = EDMA_CTLR(channel); @@ -607,7 +641,7 @@ int edma_alloc_channel(int channel, channel = 0; for (;;) { channel = find_next_bit(edma_info[i]-> - edma_noevent, + edma_unused, edma_info[i]->num_channels, channel); if (channel == edma_info[i]->num_channels) @@ -1222,7 +1256,7 @@ int edma_start(unsigned channel) unsigned int mask = (1 << (channel & 0x1f)); /* EDMA channels without event association */ - if (test_bit(channel, edma_info[ctlr]->edma_noevent)) { + if (test_bit(channel, edma_info[ctlr]->edma_unused)) { pr_debug("EDMA: ESR%d %08x\n", j, edma_shadow0_read_array(ctlr, SH_ESR, j)); edma_shadow0_write_array(ctlr, SH_ESR, j, mask); @@ -1347,7 +1381,6 @@ static int __init edma_probe(struct platform_device *pdev) const s8 (*queue_tc_mapping)[2]; int i, j, found = 0; int status = -1; - const s8 *noevent; int irq[EDMA_MAX_CC] = {0, 0}; int err_irq[EDMA_MAX_CC] = {0, 0}; struct resource *r[EDMA_MAX_CC] = {NULL}; @@ -1410,11 +1443,9 @@ static int __init edma_probe(struct platform_device *pdev) memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i), &dummy_paramset, PARM_SIZE); - noevent = info[j].noevent; - if (noevent) { - while (*noevent != -1) - set_bit(*noevent++, edma_info[j]->edma_noevent); - } + /* Mark all channels as unused */ + memset(edma_info[j]->edma_unused, 0xff, + sizeof(edma_info[j]->edma_unused)); sprintf(irq_name, "edma%d", j); irq[j] = platform_get_irq_byname(pdev, irq_name); diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h index eb8bfd7..ced3092 100644 --- a/arch/arm/mach-davinci/include/mach/edma.h +++ b/arch/arm/mach-davinci/include/mach/edma.h @@ -280,8 +280,6 @@ struct edma_soc_info { unsigned n_cc; enum dma_event_q default_queue; - /* list of channels with no even trigger; terminated by "-1" */ - const s8 *noevent; const s8 (*queue_tc_mapping)[2]; const s8 (*queue_priority_mapping)[2]; }; -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:34:18 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:04:18 +0530 Subject: [PATCH 5/9] davinci: support for EDMA resource sharing Message-ID: <1259732058-13305-1-git-send-email-sudhakar.raj@ti.com> Current EDMA driver is not taking care of EDMA channels/slots which are allocated from other processor, say DSP. If a channel/slot is allocated from DSP, the existing EDMA driver can still allocate the same resource on ARM. This patch enables the user to pass the channel/slots reserved for DSP as platform data. EDMA driver scans this list during probe and prepares a bitmap of channel/slots which can be used on ARM side. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/dma.c | 36 ++++++++++++++++++++++++++++- arch/arm/mach-davinci/include/mach/edma.h | 2 + 2 files changed, 37 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 15dd886..d3e1702 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -206,6 +206,18 @@ static inline void edma_parm_or(unsigned ctlr, int offset, int param_no, edma_or(ctlr, EDMA_PARM + offset + (param_no << 5), or); } +static inline void set_bits(int offset, int len, unsigned long *p) +{ + for (; len > 0; len--) + set_bit(offset + (len - 1), p); +} + +static inline void clear_bits(int offset, int len, unsigned long *p) +{ + for (; len > 0; len--) + clear_bit(offset + (len - 1), p); +} + /*****************************************************************************/ /* actual number of DMA channels and slots on this silicon */ @@ -1379,8 +1391,10 @@ static int __init edma_probe(struct platform_device *pdev) struct edma_soc_info *info = pdev->dev.platform_data; const s8 (*queue_priority_mapping)[2]; const s8 (*queue_tc_mapping)[2]; - int i, j, found = 0; + int i, j, off, ln, found = 0; int status = -1; + const s16 (*rsv_chans)[2]; + const s16 (*rsv_slots)[2]; int irq[EDMA_MAX_CC] = {0, 0}; int err_irq[EDMA_MAX_CC] = {0, 0}; struct resource *r[EDMA_MAX_CC] = {NULL}; @@ -1447,6 +1461,26 @@ static int __init edma_probe(struct platform_device *pdev) memset(edma_info[j]->edma_unused, 0xff, sizeof(edma_info[j]->edma_unused)); + /* Clear the reserved channels in unused list */ + rsv_chans = info[j].rsv_chans; + if (rsv_chans) { + for (i = 0; rsv_chans[i][0] != -1; i++) { + off = rsv_chans[i][0]; + ln = rsv_chans[i][1]; + clear_bits(off, ln, edma_info[j]->edma_unused); + } + } + + /* Set the reserved channels/slots in inuse list */ + rsv_slots = info[j].rsv_slots; + if (rsv_slots) { + for (i = 0; rsv_slots[i][0] != -1; i++) { + off = rsv_slots[i][0]; + ln = rsv_slots[i][1]; + set_bits(off, ln, edma_info[j]->edma_inuse); + } + } + sprintf(irq_name, "edma%d", j); irq[j] = platform_get_irq_byname(pdev, irq_name); edma_info[j]->irq_res_start = irq[j]; diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h index ced3092..55e217e 100644 --- a/arch/arm/mach-davinci/include/mach/edma.h +++ b/arch/arm/mach-davinci/include/mach/edma.h @@ -280,6 +280,8 @@ struct edma_soc_info { unsigned n_cc; enum dma_event_q default_queue; + const s16 (*rsv_chans)[2]; + const s16 (*rsv_slots)[2]; const s8 (*queue_tc_mapping)[2]; const s8 (*queue_priority_mapping)[2]; }; -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:34:25 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:04:25 +0530 Subject: [PATCH 6/9] davinci: da8xx/omap-l1xx: Add EDMA platform data for da850/omap-l138 Message-ID: <1259732065-13328-1-git-send-email-sudhakar.raj@ti.com> Currently da850/omap-l138 supports only one channel controller instance of EDMA though EDMA driver as such supports multiple channel controller instances. This patch adds platform data for the 2nd EDMA channel controller. As, the platform data differ between da830/omap-l137 and da850/omap-l138, existing code has been re-shuffled to accommodate this. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/devices-da8xx.c | 121 +++++++++++++++++++++++++++++++-- 1 files changed, 114 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 6860067..f6c6453 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -24,8 +24,10 @@ #include "clock.h" #define DA8XX_TPCC_BASE 0x01c00000 +#define DA850_TPCC1_BASE 0x01e30000 #define DA8XX_TPTC0_BASE 0x01c08000 #define DA8XX_TPTC1_BASE 0x01c08400 +#define DA850_TPTC2_BASE 0x01e38000 #define DA8XX_WDOG_BASE 0x01c21000 /* DA8XX_TIMER64P1_BASE */ #define DA8XX_I2C0_BASE 0x01c22000 #define DA8XX_RTC_BASE 0x01C23000 @@ -96,7 +98,31 @@ static const s8 da8xx_queue_priority_mapping[][2] = { {-1, -1} }; -static struct edma_soc_info da8xx_edma_info[] = { +static const s8 da850_queue_tc_mapping[][2] = { + /* {event queue no, TC no} */ + {0, 0}, + {-1, -1} +}; + +static const s8 da850_queue_priority_mapping[][2] = { + /* {event queue no, Priority} */ + {0, 3}, + {-1, -1} +}; + +static struct edma_soc_info da830_edma_info[] = { + { + .n_channel = 32, + .n_region = 4, + .n_slot = 128, + .n_tc = 2, + .n_cc = 1, + .queue_tc_mapping = da8xx_queue_tc_mapping, + .queue_priority_mapping = da8xx_queue_priority_mapping, + }, +}; + +static struct edma_soc_info da850_edma_info[] = { { .n_channel = 32, .n_region = 4, @@ -106,9 +132,49 @@ static struct edma_soc_info da8xx_edma_info[] = { .queue_tc_mapping = da8xx_queue_tc_mapping, .queue_priority_mapping = da8xx_queue_priority_mapping, }, + { + .n_channel = 32, + .n_region = 4, + .n_slot = 128, + .n_tc = 1, + .n_cc = 1, + .queue_tc_mapping = da850_queue_tc_mapping, + .queue_priority_mapping = da850_queue_priority_mapping, + }, +}; + +static struct resource da830_edma_resources[] = { + { + .name = "edma_cc0", + .start = DA8XX_TPCC_BASE, + .end = DA8XX_TPCC_BASE + SZ_32K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc0", + .start = DA8XX_TPTC0_BASE, + .end = DA8XX_TPTC0_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc1", + .start = DA8XX_TPTC1_BASE, + .end = DA8XX_TPTC1_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma0", + .start = IRQ_DA8XX_CCINT0, + .flags = IORESOURCE_IRQ, + }, + { + .name = "edma0_err", + .start = IRQ_DA8XX_CCERRINT, + .flags = IORESOURCE_IRQ, + }, }; -static struct resource da8xx_edma_resources[] = { +static struct resource da850_edma_resources[] = { { .name = "edma_cc0", .start = DA8XX_TPCC_BASE, @@ -128,6 +194,18 @@ static struct resource da8xx_edma_resources[] = { .flags = IORESOURCE_MEM, }, { + .name = "edma_cc1", + .start = DA850_TPCC1_BASE, + .end = DA850_TPCC1_BASE + SZ_32K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc2", + .start = DA850_TPTC2_BASE, + .end = DA850_TPTC2_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { .name = "edma0", .start = IRQ_DA8XX_CCINT0, .flags = IORESOURCE_IRQ, @@ -137,21 +215,50 @@ static struct resource da8xx_edma_resources[] = { .start = IRQ_DA8XX_CCERRINT, .flags = IORESOURCE_IRQ, }, + { + .name = "edma1", + .start = IRQ_DA850_CCINT1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "edma1_err", + .start = IRQ_DA850_CCERRINT1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da830_edma_device = { + .name = "edma", + .id = -1, + .dev = { + .platform_data = da830_edma_info, + }, + .num_resources = ARRAY_SIZE(da830_edma_resources), + .resource = da830_edma_resources, }; -static struct platform_device da8xx_edma_device = { +static struct platform_device da850_edma_device = { .name = "edma", .id = -1, .dev = { - .platform_data = da8xx_edma_info, + .platform_data = da850_edma_info, }, - .num_resources = ARRAY_SIZE(da8xx_edma_resources), - .resource = da8xx_edma_resources, + .num_resources = ARRAY_SIZE(da850_edma_resources), + .resource = da850_edma_resources, }; int __init da8xx_register_edma(void) { - return platform_device_register(&da8xx_edma_device); + struct platform_device *pdev; + + if (cpu_is_davinci_da830()) + pdev = &da830_edma_device; + else if (cpu_is_davinci_da850()) + pdev = &da850_edma_device; + else + return -ENODEV; + + return platform_device_register(pdev); } static struct resource da8xx_i2c_resources0[] = { -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:34:31 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:04:31 +0530 Subject: [PATCH 7/9] davinci: da830/omapl137: Specify reserved channels/slots Message-ID: <1259732071-13354-1-git-send-email-sudhakar.raj@ti.com> Pass reserved EDMA channel/slots as platform data for da830/omap-l137. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/devices-da8xx.c | 20 ++++++++++++++++++++ 1 files changed, 20 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index f6c6453..0f34c91 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -110,6 +110,24 @@ static const s8 da850_queue_priority_mapping[][2] = { {-1, -1} }; +static const s16 da830_dma_rsv_chans[][2] = { + /* (offset, number) */ + { 8, 2}, + {12, 2}, + {24, 4}, + {30, 2}, + {-1, -1} +}; + +static const s16 da830_dma_rsv_slots[][2] = { + /* (offset, number) */ + { 8, 2}, + {12, 2}, + {24, 4}, + {30, 26}, + {-1, -1} +}; + static struct edma_soc_info da830_edma_info[] = { { .n_channel = 32, @@ -117,6 +135,8 @@ static struct edma_soc_info da830_edma_info[] = { .n_slot = 128, .n_tc = 2, .n_cc = 1, + .rsv_chans = da830_dma_rsv_chans, + .rsv_slots = da830_dma_rsv_slots, .queue_tc_mapping = da8xx_queue_tc_mapping, .queue_priority_mapping = da8xx_queue_priority_mapping, }, -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:34:38 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:04:38 +0530 Subject: [PATCH 8/9] davinci: da850/omapl138: Specify reserved channels/slots Message-ID: <1259732078-13377-1-git-send-email-sudhakar.raj@ti.com> Pass reserved EDMA channel/slots as platform data for da850/omap-l138. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/devices-da8xx.c | 34 +++++++++++++++++++++++++++++++++ 1 files changed, 34 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 0f34c91..3a5e86c 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -128,6 +128,36 @@ static const s16 da830_dma_rsv_slots[][2] = { {-1, -1} }; +static const s16 da850_dma0_rsv_chans[][2] = { + /* (offset, number) */ + { 8, 6}, + {24, 4}, + {30, 2}, + {-1, -1} +}; + +static const s16 da850_dma0_rsv_slots[][2] = { + /* (offset, number) */ + { 8, 6}, + {24, 4}, + {30, 50}, + {-1, -1} +}; + +static const s16 da850_dma1_rsv_chans[][2] = { + /* (offset, number) */ + { 0, 28}, + {30, 2}, + {-1, -1} +}; + +static const s16 da850_dma1_rsv_slots[][2] = { + /* (offset, number) */ + { 0, 28}, + {30, 90}, + {-1, -1} +}; + static struct edma_soc_info da830_edma_info[] = { { .n_channel = 32, @@ -149,6 +179,8 @@ static struct edma_soc_info da850_edma_info[] = { .n_slot = 128, .n_tc = 2, .n_cc = 1, + .rsv_chans = da850_dma0_rsv_chans, + .rsv_slots = da850_dma0_rsv_slots, .queue_tc_mapping = da8xx_queue_tc_mapping, .queue_priority_mapping = da8xx_queue_priority_mapping, }, @@ -158,6 +190,8 @@ static struct edma_soc_info da850_edma_info[] = { .n_slot = 128, .n_tc = 1, .n_cc = 1, + .rsv_chans = da850_dma1_rsv_chans, + .rsv_slots = da850_dma1_rsv_slots, .queue_tc_mapping = da850_queue_tc_mapping, .queue_priority_mapping = da850_queue_priority_mapping, }, -- 1.5.6 From sudhakar.raj at ti.com Tue Dec 1 23:34:44 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Wed, 2 Dec 2009 11:04:44 +0530 Subject: [PATCH 9/9] davinci: dm646x: Specify reserved EDMA channel/slots for DM646x Message-ID: <1259732084-13403-1-git-send-email-sudhakar.raj@ti.com> Pass reserved EDMA channel/slots as platform data for dm646x. Signed-off-by: Sudhakar Rajashekhara --- arch/arm/mach-davinci/dm646x.c | 23 +++++++++++++++++++++++ 1 files changed, 23 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index eb2e518..481d150 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -513,6 +513,27 @@ static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = { /*----------------------------------------------------------------------*/ +static const s16 dm646x_dma_rsv_chans[][2] = { + /* (offset, number) */ + { 0, 4}, + {13, 3}, + {24, 4}, + {30, 2}, + {54, 3}, + {-1, -1} +}; + +static const s16 dm646x_dma_rsv_slots[][2] = { + /* (offset, number) */ + { 0, 4}, + {13, 3}, + {24, 4}, + {30, 2}, + {54, 3}, + {128, 384}, + {-1, -1} +}; + /* Four Transfer Controllers on DM646x */ static const s8 dm646x_queue_tc_mapping[][2] = { @@ -541,6 +562,8 @@ static struct edma_soc_info dm646x_edma_info[] = { .n_slot = 512, .n_tc = 4, .n_cc = 1, + .rsv_chans = dm646x_dma_rsv_chans, + .rsv_slots = dm646x_dma_rsv_slots, .queue_tc_mapping = dm646x_queue_tc_mapping, .queue_priority_mapping = dm646x_queue_priority_mapping, }, -- 1.5.6 From chaithrika at ti.com Wed Dec 2 01:09:00 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Wed, 2 Dec 2009 12:39:00 +0530 Subject: [PATCH] ASoC: DaVinci: Update suspend/resume support for McASP driver Message-ID: <1259737740-27324-1-git-send-email-chaithrika@ti.com> Add clock enable and disable calls to resume and suspend respectively. Also add a member to the audio device data structure which tracks the clock status. Tested on DA850/OMAP-L138 EVM. For the purpose of testing, the patches[1] which add suspend-to-RAM support to DA850/OMAP-L138 SoC were applied. [1] http://linux.davincidsp.com/pipermail/davinci-linux-open-source/ 2009-November/016958.html Signed-off-by: Chaithrika U S --- Applies to ALSA GIT tree on branch topic/asoc at http://git.kernel.org/?p=linux/kernel/git/tiwai/sound-2.6.git;a=shortlog; h=topic/asoc sound/soc/davinci/davinci-mcasp.c | 18 ++++++++++++++++-- sound/soc/davinci/davinci-mcasp.h | 1 + sound/soc/davinci/davinci-pcm.c | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0a302e1..0d263f1 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -767,14 +767,27 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, int ret = 0; switch (cmd) { - case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: + if (!dev->clk_active) { + clk_enable(dev->clk); + dev->clk_active = 1; + } + + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: davinci_mcasp_start(dev, substream->stream); break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: + davinci_mcasp_stop(dev, substream->stream); + if (dev->clk_active) { + clk_disable(dev->clk); + dev->clk_active = 0; + } + + break; + + case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcasp_stop(dev, substream->stream); break; @@ -866,6 +879,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } clk_enable(dev->clk); + dev->clk_active = 1; dev->base = (void __iomem *)IO_ADDRESS(mem->start); dev->op_mode = pdata->op_mode; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 582c924..e755b51 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -44,6 +44,7 @@ struct davinci_audio_dev { int sample_rate; struct clk *clk; unsigned int codec_fmt; + u8 clk_active; /* McASP specific data */ int tdm_slots; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index ad4d7f4..80c7fdf 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name) static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | -- 1.5.6 From m-karicheri2 at ti.com Wed Dec 2 09:48:55 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Wed, 2 Dec 2009 09:48:55 -0600 Subject: [PATCH] V4L - Fix videobuf_dma_contig_user_get() getting page aligned physical address In-Reply-To: References: <1259681414-30246-1-git-send-email-m-karicheri2@ti.com> Message-ID: Magnus, >Thanks for the patch. For non-page aligned user space pointers I agree >that a fix is needed. Don't you think the while loop in >videobuf_dma_contig_user_get() also needs to be adjusted to include >the last page? I think the while loop checks one page too little in >the non-aligned case today. > >Cheers, > >/ magnus Thanks for reviewing my patch. It had worked for non-aligned address in my testing. If I understand this code correctly, the physical address of the user page start is determined in the first loop (pages_done == 0) and additional loops are run to make sure the memory is physically contiguous. Initially the mem->size is set to number of pages aligned to page size. Assume we pass 4097 bytes as size. mem->size = PAGE_ALIGN(vb->size); => 2 Inside the loop, iteration is done for 0 to pages-1. pages_done < (mem->size >> 12) => pages_done < 2 => iterate 2 times For size of 4096, we iterate once. For size of 4095, we iterate once. So IMO the loop is already iterate one more time when we pass non-aligned address since size is aligned to include the last page. So based on this could you ack my patch so that we could ask Mauro to merge it with priority? Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com From nsekhar at ti.com Wed Dec 2 10:54:37 2009 From: nsekhar at ti.com (Nori, Sekhar) Date: Wed, 2 Dec 2009 22:24:37 +0530 Subject: [PATCH 1/5 - v0] V4L-vpfe capture - adding CCDC driver for DM365 In-Reply-To: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> References: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> Message-ID: Hi Murali, Here is a (styling related) review from an non-video person. The review is neither complete nor exhaustive (the patch is huge!), but I thought will send across whatever I have for you to take a look. On Wed, Dec 02, 2009 at 03:08:49, Karicheri, Muralidharan wrote: > From: Muralidharan Karicheri > > This patch is for adding support for DM365 CCDC. This will allow to > capture YUV video frames from TVP5146 video decoder on DM365 EVM. The vpfe > capture driver will use this module to configure ISIF (a.k.a CCDC) > module to allow YUV data capture. This driver is written for ccdc_hw_device > interface used by vpfe capture driver to configure the ccdc module. > This patch is tested using NTSC & PAL video sources and verified for > both formats. > > NOTE: This is the initial version for review. Typically "RFC" is put instead of "PATCH" in subject line to convey this. > > Signed-off-by: Muralidharan Karicheri > --- > drivers/media/video/davinci/dm365_ccdc.c | 1529 +++++++++++++++++++++++++ > drivers/media/video/davinci/dm365_ccdc_regs.h | 293 +++++ > include/media/davinci/dm365_ccdc.h | 555 +++++++++ > 3 files changed, 2377 insertions(+), 0 deletions(-) > create mode 100644 drivers/media/video/davinci/dm365_ccdc.c > create mode 100644 drivers/media/video/davinci/dm365_ccdc_regs.h > create mode 100644 include/media/davinci/dm365_ccdc.h > > diff --git a/drivers/media/video/davinci/dm365_ccdc.c b/drivers/media/video/davinci/dm365_ccdc.c Hopefully it is possible to choose a "generic" name instead of tying it to an SoC. > new file mode 100644 > index 0000000..2f27696 > --- /dev/null > +++ b/drivers/media/video/davinci/dm365_ccdc.c > @@ -0,0 +1,1529 @@ [...] > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "dm365_ccdc_regs.h" > +#include "ccdc_hw_device.h" Typically the includes are grouped using empty lines based on the folder "linux", "media" "mach" etc. > + > +static struct device *dev; > + > +/* Defauts for module configuation paramaters */ > +static struct ccdc_config_params_raw ccdc_config_defaults = { > + .linearize = { > + .en = 0, > + .corr_shft = CCDC_NO_SHIFT, > + .scale_fact = {1, 0}, > + }, > + .df_csc = { > + .df_or_csc = 0, > + .csc = { > + .en = 0 Should use ',' at the end of line so adding new members leads to adding just one line. There are more of these in this static init below. > + }, > + }, > + .dfc = { > + .en = 0 > + }, > + .bclamp = { > + .en = 0 > + }, > + .gain_offset = { > + .gain = { > + .r_ye = {1, 0}, > + .gr_cy = {1, 0}, > + .gb_g = {1, 0}, > + .b_mg = {1, 0}, > + }, > + }, > + .culling = { > + .hcpat_odd = 0xff, > + .hcpat_even = 0xff, > + .vcpat = 0xff > + }, > + .compress = { > + .alg = CCDC_ALAW, > + }, > +}; > + > +/* ISIF operation configuration */ > +struct ccdc_oper_config { > + enum vpfe_hw_if_type if_type; > + struct ccdc_ycbcr_config ycbcr; > + struct ccdc_params_raw bayer; > + enum ccdc_data_pack data_pack; > + void *__iomem base_addr; > + void *__iomem linear_tbl0_addr; > + void *__iomem linear_tbl1_addr; Usually it is void __iomem *foo; > +}; > + > +static struct ccdc_oper_config ccdc_cfg = { > + .ycbcr = { > + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, > + .frm_fmt = CCDC_FRMFMT_INTERLACED, > + .win = CCDC_WIN_NTSC, > + .fid_pol = VPFE_PINPOL_POSITIVE, > + .vd_pol = VPFE_PINPOL_POSITIVE, > + .hd_pol = VPFE_PINPOL_POSITIVE, > + .pix_order = CCDC_PIXORDER_CBYCRY, > + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, > + }, > + .bayer = { > + .pix_fmt = CCDC_PIXFMT_RAW, > + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, > + .win = CCDC_WIN_VGA, > + .fid_pol = VPFE_PINPOL_POSITIVE, > + .vd_pol = VPFE_PINPOL_POSITIVE, > + .hd_pol = VPFE_PINPOL_POSITIVE, > + .gain = { > + .r_ye = {1, 0}, > + .gr_cy = {1, 0}, > + .gb_g = {1, 0}, > + .b_mg = {1, 0}, > + }, > + .cfa_pat = CCDC_CFA_PAT_MOSAIC, > + .data_msb = CCDC_BIT_MSB_11, > + .config_params = { > + .data_shift = CCDC_NO_SHIFT, > + .col_pat_field0 = { > + .olop = CCDC_GREEN_BLUE, > + .olep = CCDC_BLUE, > + .elop = CCDC_RED, > + .elep = CCDC_GREEN_RED, > + }, > + .col_pat_field1 = { > + .olop = CCDC_GREEN_BLUE, > + .olep = CCDC_BLUE, > + .elop = CCDC_RED, > + .elep = CCDC_GREEN_RED, > + }, > + .test_pat_gen = 0, > + }, > + }, > + .data_pack = CCDC_DATA_PACK8, > +}; > + > +/* Raw Bayer formats */ > +static u32 ccdc_raw_bayer_pix_formats[] = > + {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; > + > +/* Raw YUV formats */ > +static u32 ccdc_raw_yuv_pix_formats[] = > + {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; > + > +/* register access routines */ > +static inline u32 regr(u32 offset) > +{ > + return __raw_readl(ccdc_cfg.base_addr + offset); > +} > + > +static inline void regw(u32 val, u32 offset) > +{ > + __raw_writel(val, ccdc_cfg.base_addr + offset); > +} > + > +static inline u32 ccdc_merge(u32 mask, u32 val, u32 offset) "merge" was not intuitive until I read the implementation. How about "modify" (as used in arch/arm/mach-davinci/dma.c)? > +{ > + u32 new_val = (regr(offset) & ~mask) | (val & mask); > + > + regw(new_val, offset); > + return new_val; > +} > + > +static inline void regw_lin_tbl(u32 val, u32 offset, int i) > +{ > + if (!i) > + __raw_writel(val, ccdc_cfg.linear_tbl0_addr + offset); > + else > + __raw_writel(val, ccdc_cfg.linear_tbl1_addr + offset); > +} > + > +static void ccdc_disable_all_modules(void) > +{ > + /* disable BC */ > + regw(0, CLAMPCFG); > + /* disable vdfc */ > + regw(0, DFCCTL); > + /* disable CSC */ > + regw(0, CSCCTL); > + /* disable linearization */ > + regw(0, LINCFG0); > + /* disable other modules here as they are supported */ > +} > + > +static void ccdc_enable(int en) > +{ > + if (!en) { > + /* Before disable isif, disable all ISIF modules */ Could you use ccdc instead of isif in the comments too? > + ccdc_disable_all_modules(); > + /** > + * wait for next VD. Assume lowest scan rate is 12 Hz. So > + * 100 msec delay is good enough > + */ > + } The comment explaining the msleep seems mis-placed. > + msleep(100); > + ccdc_merge(CCDC_SYNCEN_VDHDEN_MASK, en, SYNCEN); > +} > + > +static void ccdc_enable_output_to_sdram(int en) > +{ > + ccdc_merge(CCDC_SYNCEN_WEN_MASK, en << CCDC_SYNCEN_WEN_SHIFT, SYNCEN); > +} > + > +static void ccdc_config_culling(struct ccdc_cul *cul) > +{ > + u32 val; > + > + /* Horizontal pattern */ > + val = (cul->hcpat_even) << CULL_PAT_EVEN_LINE_SHIFT; No need of parenthesis. > + val |= cul->hcpat_odd; > + regw(val, CULH); > + > + /* vertical pattern */ > + regw(cul->vcpat, CULV); > + > + /* LPF */ > + ccdc_merge((CCDC_LPF_MASK << CCDC_LPF_SHIFT), > + (cul->en_lpf << CCDC_LPF_SHIFT), MODESET); .. ditto .. > +} > + > +static void ccdc_config_gain_offset(void) > +{ > + struct ccdc_gain_offsets_adj *gain_off_ptr = > + &ccdc_cfg.bayer.config_params.gain_offset; > + u32 val; > + > + val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) | > + ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) | > + ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) | > + ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) | > + ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) | > + ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT); I think the intent here is to convert an arbitrary gain_off_ptr->foo to 0 or 1. In that case you can use !!gain_off_ptr->foo > + > + ccdc_merge(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); > + > + val = ((gain_off_ptr->gain.r_ye.integer & GAIN_INTEGER_MASK) > + << GAIN_INTEGER_SHIFT); > + val |= (ccdc_cfg.bayer. > + config_params.gain_offset.gain.r_ye.decimal & > + GAIN_DECIMAL_MASK); > + regw(val, CRGAIN); > + > + val = ((gain_off_ptr->gain.gr_cy > + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); > + val |= (gain_off_ptr->gain.gr_cy > + .decimal & GAIN_DECIMAL_MASK); > + regw(val, CGRGAIN); > + > + val = ((gain_off_ptr->gain.gb_g > + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); > + val |= (gain_off_ptr->gain.gb_g > + .decimal & GAIN_DECIMAL_MASK); > + regw(val, CGBGAIN); > + > + val = ((gain_off_ptr->gain.b_mg > + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); > + val |= (gain_off_ptr->gain.b_mg > + .decimal & GAIN_DECIMAL_MASK); Breaking the line at the . is making reading difficult. Can you break at '<<' instead? > + regw(val, CBGAIN); > + > + regw((gain_off_ptr->offset & > + OFFSET_MASK), COFSTA); Not sure if we really need to break here. Are you hitting the 80 char limit even here? > +} > + > +static void ccdc_restore_defaults(void) > +{ > + enum vpss_ccdc_source_sel source = VPSS_CCDCIN; > + int i; > + > + memcpy(&ccdc_cfg.bayer.config_params, &ccdc_config_defaults, > + sizeof(struct ccdc_config_params_raw)); > + > + dev_dbg(dev, "\nstarting ccdc_restore_defaults..."); > + /* Enable clock to ISIF, IPIPEIF and BL */ > + vpss_enable_clock(VPSS_CCDC_CLOCK, 1); > + vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); > + vpss_enable_clock(VPSS_BL_CLOCK, 1); > + > + /* set all registers to default value */ > + for (i = 0; i <= 0x1f8; i += 4) > + regw(0, i); Hmm, something like this is not usually expected. You would anyway be programming all the relevant registers again. So, why is this required? > + > + /* no culling support */ > + regw(0xffff, CULH); > + regw(0xff, CULV); > + > + /* Set default offset and gain */ > + ccdc_config_gain_offset(); > + > + vpss_select_ccdc_source(source); > + > + dev_dbg(dev, "\nEnd of ccdc_restore_defaults..."); > +} > + > +static int ccdc_open(struct device *device) > +{ > + dev = device; > + ccdc_restore_defaults(); > + return 0; > +} > + > +/* This function will configure the window size to be capture in CCDC reg */ > +static void ccdc_setwin(struct v4l2_rect *image_win, > + enum ccdc_frmfmt frm_fmt, int ppc) > +{ > + int horz_start, horz_nr_pixels; > + int vert_start, vert_nr_lines; > + int mid_img = 0; > + > + dev_dbg(dev, "\nStarting ccdc_setwin..."); > + /** > + * ppc - per pixel count. indicates how many pixels per cell Kernel doc style comments are only useful for API description, I guess. > + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. > + * raw capture this is 1 > + */ > + horz_start = image_win->left << (ppc - 1); > + horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; > + > + /* Writing the horizontal info into the registers */ > + regw(horz_start & START_PX_HOR_MASK, SPH); > + regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); > + vert_start = image_win->top; > + > + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { > + vert_nr_lines = (image_win->height >> 1) - 1; > + vert_start >>= 1; > + /* To account for VD since line 0 doesn't have any data */ > + vert_start += 1; > + } else { > + /* To account for VD since line 0 doesn't have any data */ > + vert_start += 1; > + vert_nr_lines = image_win->height - 1; > + /* configure VDINT0 and VDINT1 */ > + mid_img = vert_start + (image_win->height / 2); > + regw(mid_img, VDINT1); > + } > + > + regw(0, VDINT0); > + regw(vert_start & START_VER_ONE_MASK, SLV0); > + regw(vert_start & START_VER_TWO_MASK, SLV1); > + regw(vert_nr_lines & NUM_LINES_VER, LNV); > +} > + > +static void ccdc_config_bclamp(struct ccdc_black_clamp *bc) > +{ > + u32 val; > + > + /** > + * DC Offset is always added to image data irrespective of bc enable > + * status > + */ .. ditto .. > + val = bc->dc_offset & CCDC_BC_DCOFFSET_MASK; > + regw(val, CLDCOFST); > + > + if (bc->en) { > + val = (bc->bc_mode_color & CCDC_BC_MODE_COLOR_MASK) << > + CCDC_BC_MODE_COLOR_SHIFT; > + > + /* Enable BC and horizontal clamp caculation paramaters */ > + val = val | 1 | ((bc->horz.mode & CCDC_HORZ_BC_MODE_MASK) << > + CCDC_HORZ_BC_MODE_SHIFT); > + > + regw(val, CLAMPCFG); > + > + if (bc->horz.mode != CCDC_HORZ_BC_DISABLE) { > + /** > + * Window count for calculation > + * Base window selection > + * pixel limit > + * Horizontal size of window > + * vertical size of the window > + * Horizontal start position of the window > + * Vertical start position of the window > + */ > + val = (bc->horz.win_count_calc & > + CCDC_HORZ_BC_WIN_COUNT_MASK) | > + ((bc->horz.base_win_sel_calc & 1) > + << CCDC_HORZ_BC_WIN_SEL_SHIFT) | > + ((bc->horz.clamp_pix_limit & 1) > + << CCDC_HORZ_BC_PIX_LIMIT_SHIFT) | > + ((bc->horz.win_h_sz_calc & > + CCDC_HORZ_BC_WIN_H_SIZE_MASK) > + << CCDC_HORZ_BC_WIN_H_SIZE_SHIFT) | > + ((bc->horz.win_v_sz_calc & > + CCDC_HORZ_BC_WIN_V_SIZE_MASK) > + << CCDC_HORZ_BC_WIN_V_SIZE_SHIFT); > + > + regw(val, CLHWIN0); > + > + val = (bc->horz.win_start_h_calc & > + CCDC_HORZ_BC_WIN_START_H_MASK); > + regw(val, CLHWIN1); > + > + val = > + (bc->horz. > + win_start_v_calc & CCDC_HORZ_BC_WIN_START_V_MASK); Too much broken line. Suggest breaking at & instead. > + regw(val, CLHWIN2); > + } > + > + /* vertical clamp caculation paramaters */ > + > + /* OB H Valid */ > + val = (bc->vert.ob_h_sz_calc & CCDC_VERT_BC_OB_H_SZ_MASK); > + > + /* Reset clamp value sel for previous line */ > + val |= ((bc->vert.reset_val_sel & > + CCDC_VERT_BC_RST_VAL_SEL_MASK) > + << CCDC_VERT_BC_RST_VAL_SEL_SHIFT); > + > + /* Line average coefficient */ > + val |= (bc->vert.line_ave_coef << > + CCDC_VERT_BC_LINE_AVE_COEF_SHIFT); > + regw(val, CLVWIN0); > + > + /* Configured reset value */ > + if (bc->vert.reset_val_sel == > + CCDC_VERT_BC_USE_CONFIG_CLAMP_VAL) { > + val = > + (bc->vert. > + reset_clamp_val & CCDC_VERT_BC_RST_VAL_MASK); .. ditto .. There are other places in the patch where line breaks needs revisit. > + regw(val, CLVRV); > + } > + > + /* Optical Black horizontal start position */ > + val = (bc->vert.ob_start_h & CCDC_VERT_BC_OB_START_HORZ_MASK); > + regw(val, CLVWIN1); > + > + /* Optical Black vertical start position */ > + val = (bc->vert.ob_start_v & CCDC_VERT_BC_OB_START_VERT_MASK); > + regw(val, CLVWIN2); > + > + val = (bc->vert.ob_v_sz_calc & CCDC_VERT_BC_OB_VERT_SZ_MASK); > + regw(val, CLVWIN3); > + > + /* Vertical start position for BC subtraction */ > + val = (bc->vert_start_sub & CCDC_BC_VERT_START_SUB_V_MASK); > + regw(val, CLSV); > + } > +} > + > +static void ccdc_config_linearization(struct ccdc_linearize *linearize) > +{ > + u32 val, i; > + if (!linearize->en) { Typically an empty line is used after variable declarations. > + regw(0, LINCFG0); > + return; > + } > + > + /* shift value for correction */ > + val = (linearize->corr_shft & CCDC_LIN_CORRSFT_MASK) > + << CCDC_LIN_CORRSFT_SHIFT; > + /* enable */ > + val |= 1; > + regw(val, LINCFG0); > + > + /* Scale factor */ > + val = (linearize->scale_fact.integer & 1) > + << CCDC_LIN_SCALE_FACT_INTEG_SHIFT; > + val |= (linearize->scale_fact.decimal & > + CCDC_LIN_SCALE_FACT_DECIMAL_MASK); > + regw(val, LINCFG1); > + > + for (i = 0; i < CCDC_LINEAR_TAB_SIZE; i++) { > + val = linearize->table[i] & CCDC_LIN_ENTRY_MASK; > + if (i%2) > + regw_lin_tbl(val, ((i >> 1) << 2), 1); > + else > + regw_lin_tbl(val, ((i >> 1) << 2), 0); > + } > +} > + > +static void ccdc_config_dfc(struct ccdc_dfc *vdfc) > +{ > +#define DFC_WRITE_WAIT_COUNT 1000 > + u32 val, count = DFC_WRITE_WAIT_COUNT; > + int i; > + > + if (!vdfc->en) > + return; > + > + /* Correction mode */ > + val = ((vdfc->corr_mode & CCDC_VDFC_CORR_MOD_MASK) > + << CCDC_VDFC_CORR_MOD_SHIFT); > + > + /* Correct whole line or partial */ > + if (vdfc->corr_whole_line) > + val |= 1 << CCDC_VDFC_CORR_WHOLE_LN_SHIFT; > + > + /* level shift value */ > + val |= (vdfc->def_level_shift & CCDC_VDFC_LEVEL_SHFT_MASK) << > + CCDC_VDFC_LEVEL_SHFT_SHIFT; > + > + regw(val, DFCCTL); > + > + /* Defect saturation level */ > + val = vdfc->def_sat_level & CCDC_VDFC_SAT_LEVEL_MASK; > + regw(val, VDFSATLV); > + > + regw(vdfc->table[0].pos_vert & CCDC_VDFC_POS_MASK, DFCMEM0); > + regw(vdfc->table[0].pos_horz & CCDC_VDFC_POS_MASK, DFCMEM1); > + if (vdfc->corr_mode == CCDC_VDFC_NORMAL || > + vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) { > + regw(vdfc->table[0].level_at_pos, DFCMEM2); > + regw(vdfc->table[0].level_up_pixels, DFCMEM3); > + regw(vdfc->table[0].level_low_pixels, DFCMEM4); > + } > + > + val = regr(DFCMEMCTL); > + /* set DFCMARST and set DFCMWR */ > + val |= 1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT; > + val |= 1; > + regw(val, DFCMEMCTL); > + > + while (count && (regr(DFCMEMCTL) & 0x01)) > + count--; This is CPU speed dependent. Suggest using udelay() or loops_per_jiffy instead. > + > + val = regr(DFCMEMCTL); > + if (!count) { > + dev_dbg(dev, "defect table write timeout !!!\n"); > + return; > + } > + > + for (i = 1; i < vdfc->num_vdefects; i++) { > + regw(vdfc->table[i].pos_vert & CCDC_VDFC_POS_MASK, > + DFCMEM0); > + regw(vdfc->table[i].pos_horz & CCDC_VDFC_POS_MASK, > + DFCMEM1); > + if (vdfc->corr_mode == CCDC_VDFC_NORMAL || > + vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) { > + regw(vdfc->table[i].level_at_pos, DFCMEM2); > + regw(vdfc->table[i].level_up_pixels, DFCMEM3); > + regw(vdfc->table[i].level_low_pixels, DFCMEM4); > + } > + val = regr(DFCMEMCTL); > + /* clear DFCMARST and set DFCMWR */ > + val &= ~(1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT); Could use BIT(x) here. > + val |= 1; > + regw(val, DFCMEMCTL); > + > + count = DFC_WRITE_WAIT_COUNT; > + while (count && (regr(DFCMEMCTL) & 0x01)) > + count--; > + > + val = regr(DFCMEMCTL); > + if (!count) { > + dev_err(dev, "defect table write timeout !!!\n"); > + return; > + } > + } > + if (vdfc->num_vdefects < CCDC_VDFC_TABLE_SIZE) { > + /* Extra cycle needed */ > + regw(0, DFCMEM0); > + regw(0x1FFF, DFCMEM1); > + val = 1; > + regw(val, DFCMEMCTL); > + } > + > + /* enable VDFC */ > + ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (1 << CCDC_VDFC_EN_SHIFT), > + DFCCTL); > + > + ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (0 << CCDC_VDFC_EN_SHIFT), > + DFCCTL); > + > + regw(0x6, DFCMEMCTL); > + for (i = 0 ; i < vdfc->num_vdefects; i++) { > + count = DFC_WRITE_WAIT_COUNT; > + while (count && (regr(DFCMEMCTL) & 0x2)) > + count--; > + > + val = regr(DFCMEMCTL); > + if (!count) { > + dev_err(dev, "defect table write timeout !!!\n"); > + return; > + } > + > + val = regr(DFCMEM0) | regr(DFCMEM1) | regr(DFCMEM2) | > + regr(DFCMEM3) | regr(DFCMEM4); > + regw(0x2, DFCMEMCTL); > + } > +} > + [...] > + > +static int ccdc_config_raw(void) > +{ > + struct ccdc_params_raw *params = &ccdc_cfg.bayer; > + struct ccdc_config_params_raw *module_params = > + &ccdc_cfg.bayer.config_params; > + struct vpss_pg_frame_size frame_size; > + struct vpss_sync_pol sync; > + u32 val; > + > + dev_dbg(dev, "\nStarting ccdc_config_raw..\n"); > + > + /* Configure CCDCFG register */ > + > + /** > + * Set CCD Not to swap input since input is RAW data > + * Set FID detection function to Latch at V-Sync > + * Set WENLOG - ccdc valid area > + * Set TRGSEL > + * Set EXTRG > + * Packed to 8 or 16 bits > + */ > + > + val = CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | > + CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | > + CCDC_CCDCFG_EXTRG_DISABLE | (ccdc_cfg.data_pack & > + CCDC_DATA_PACK_MASK); > + > + dev_dbg(dev, "Writing 0x%x to ...CCDCFG \n", val); > + regw(val, CCDCFG); > + > + /** > + * Configure the vertical sync polarity(MODESET.VDPOL) > + * Configure the horizontal sync polarity (MODESET.HDPOL) > + * Configure frame id polarity (MODESET.FLDPOL) > + * Configure data polarity > + * Configure External WEN Selection > + * Configure frame format(progressive or interlace) > + * Configure pixel format (Input mode) > + * Configure the data shift > + */ > + > + val = CCDC_VDHDOUT_INPUT | > + ((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | > + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | > + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | > + ((CCDC_DATAPOL_NORMAL & CCDC_DATAPOL_MASK) > + << CCDC_DATAPOL_SHIFT) | > + ((CCDC_EXWEN_DISABLE & CCDC_EXWEN_MASK) << CCDC_EXWEN_SHIFT) | > + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | > + ((params->pix_fmt & CCDC_INPUT_MASK) << CCDC_INPUT_SHIFT) | > + ((params->config_params.data_shift & CCDC_DATASFT_MASK) > + << CCDC_DATASFT_SHIFT); > + > + regw(val, MODESET); > + dev_dbg(dev, "Writing 0x%x to MODESET...\n", val); > + > + /** > + * Configure GAMMAWD register > + * CFA pattern setting > + */ > + val = (params->cfa_pat & CCDC_GAMMAWD_CFA_MASK) << > + CCDC_GAMMAWD_CFA_SHIFT; > + > + /* Gamma msb */ > + if (module_params->compress.alg == CCDC_ALAW) > + val = val | CCDC_ALAW_ENABLE; val |= CCDC_ALAW_ENABLE; > + > + val = val | ((params->data_msb & CCDC_ALAW_GAMA_WD_MASK) << > + CCDC_ALAW_GAMA_WD_SHIFT); .. ditto .. > +static int ccdc_set_pixel_format(unsigned int pixfmt) > +{ > + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { > + if (pixfmt == V4L2_PIX_FMT_SBGGR8) { > + if ((ccdc_cfg.bayer.config_params.compress.alg != > + CCDC_ALAW) && > + (ccdc_cfg.bayer.config_params.compress.alg != > + CCDC_DPCM)) { > + dev_dbg(dev, "Either configure A-Law or" > + "DPCM\n"); Space required before DPCM Thanks, Sekhar From m-karicheri2 at ti.com Wed Dec 2 16:55:41 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Wed, 2 Dec 2009 17:55:41 -0500 Subject: [PATCH - v1] V4L - Digital Video Timings API documentation Message-ID: <1259794541-19250-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This patch updates the v4l2-dvb documentation for the new video timings API added. Also updated the document based on comments from Hans Verkuil Reviewed-by: Hans Verkuil Signed-off-by: Muralidharan Karicheri --- diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/common.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/common.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/common.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/common.xml 2009-12-02 17:16:24.000000000 -0500 @@ -716,6 +716,41 @@ } +
+ Digital Video (DV) Timings + + The video standards discussed so far has been dealing with Analog TV and the +corresponding video timings. Today there are many more different hardware interfaces +such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry +video signals and there is a need to extend the API to select the video timings + for these interfaces. Since it is not possible to extend the v4l2-std-id due to +the limited bits available, a new set of IOCTLs are added to set/get video timings at +the input and output: + + DV Presets: Digital Video (DV) presets. These are IDs representing a +video timing at the input/output. Presets are pre-defined timings implemented +by the hardware according to video standards. A __u32 data type is used to represent + a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions + to support many different presets as needed. + + + Custom DV Timings: This will allow applications to define more detailed +custom video timings at the interface. This includes parameters such as width, height, + polarities, frontporch, backporch etc. + + + + To enumerate and query the attributes of DV presets supported by a device, + applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset, + application use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset it uses the + &VIDIOC-S-DV-PRESET; ioctl. + To set a Custom DV timings at the device, applications use the + &VIDIOC-S-DV-TIMINGS; ioctl and to get current Custom DV timings, it uses the + &VIDIOC-G-DV-TIMINGS; ioctl. + Applications can make use of the and + flags to decide what ioctls are available to set the +video timings for the device. +
&sub-controls; diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/v4l2.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/v4l2.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/v4l2.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/v4l2.xml 2009-12-02 17:16:50.000000000 -0500 @@ -416,6 +416,10 @@ &sub-enum-frameintervals; &sub-enuminput; &sub-enumoutput; + &sub-enum-dv-presets; + &sub-g-dv-preset; + &sub-query-dv-preset; + &sub-g-dv-timings; &sub-enumstd; &sub-g-audio; &sub-g-audioout; diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/videodev2.h.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/videodev2.h.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/videodev2.h.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/videodev2.h.xml 2009-12-02 17:44:24.000000000 -0500 @@ -734,6 +734,99 @@ }; /* + * V I D E O T I M I N G S D V P R E S E T + */ +struct v4l2_dv_preset { + __u32 preset; + __u32 reserved[4]; +}; + +/* + * D V P R E S E T S E N U M E R A T I O N + */ +struct v4l2_dv_enum_preset { + __u32 index; + __u32 preset; + __u8 name[32]; /* Name of the preset timing */ + __u32 width; + __u32 height; + __u32 reserved[4]; +}; + +/* + * D V P R E S E T V A L U E S + */ +#define V4L2_DV_INVALID 0 +#define V4L2_DV_480P59_94 1 /* BT.1362 */ +#define V4L2_DV_576P50 2 /* BT.1362 */ +#define V4L2_DV_720P24 3 /* SMPTE 296M */ +#define V4L2_DV_720P25 4 /* SMPTE 296M */ +#define V4L2_DV_720P30 5 /* SMPTE 296M */ +#define V4L2_DV_720P50 6 /* SMPTE 296M */ +#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ +#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ +#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ +#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ +#define V4L2_DV_1080I25 11 /* BT.1120 */ +#define V4L2_DV_1080I50 12 /* SMPTE 296M */ +#define V4L2_DV_1080I60 13 /* SMPTE 296M */ +#define V4L2_DV_1080P24 14 /* SMPTE 296M */ +#define V4L2_DV_1080P25 15 /* SMPTE 296M */ +#define V4L2_DV_1080P30 16 /* SMPTE 296M */ +#define V4L2_DV_1080P50 17 /* BT.1120 */ +#define V4L2_DV_1080P60 18 /* BT.1120 */ + +/* + * D V B T T I M I N G S + */ + +/* BT.656/BT.1120 timing data */ +struct v4l2_bt_timings { + __u32 width; /* width in pixels */ + __u32 height; /* height in lines */ + __u32 interlaced; /* Interlaced or progressive */ + __u32 polarities; /* Positive or negative polarity */ + __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */ + __u32 hfrontporch; /* Horizpontal front porch in pixels */ + __u32 hsync; /* Horizontal Sync length in pixels */ + __u32 hbackporch; /* Horizontal back porch in pixels */ + __u32 vfrontporch; /* Vertical front porch in pixels */ + __u32 vsync; /* Vertical Sync length in lines */ + __u32 vbackporch; /* Vertical back porch in lines */ + __u32 il_vfrontporch; /* Vertical front porch for bottom field of + * interlaced field formats + */ + __u32 il_vsync; /* Vertical sync length for bottom field of + * interlaced field formats + */ + __u32 il_vbackporch; /* Vertical back porch for bottom field of + * interlaced field formats + */ + __u32 reserved[16]; +} __attribute__ ((packed)); + +/* Interlaced or progressive format */ +#define V4L2_DV_PROGRESSIVE 0 +#define V4L2_DV_INTERLACED 1 + +/* Polarities. If bit is not set, it is assumed to be negative polarity */ +#define V4L2_DV_VSYNC_POS_POL 0x00000001 +#define V4L2_DV_HSYNC_POS_POL 0x00000002 + + +/* DV timings */ +struct v4l2_dv_timings { + __u32 type; + union { + struct v4l2_bt_timings bt; + __u32 reserved[32]; + }; +} __attribute__ ((packed)); + +/* Values for the type field */ +#define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ + +/* * V I D E O I N P U T S */ struct v4l2_input { @@ -744,7 +837,8 @@ __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; - __u32 reserved[4]; + __u32 capabilities; + __u32 reserved[3]; }; /* Values for the 'type' field */ @@ -775,6 +869,11 @@ #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ +/* capabilities flags */ +#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ +#define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ +#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ + /* * V I D E O O U T P U T S */ @@ -785,13 +884,19 @@ __u32 audioset; /* Associated audios (bitfield) */ __u32 modulator; /* Associated modulator */ v4l2_std_id std; - __u32 reserved[4]; + __u32 capabilities; + __u32 reserved[3]; }; /* Values for the 'type' field */ #define V4L2_OUTPUT_TYPE_MODULATOR 1 #define V4L2_OUTPUT_TYPE_ANALOG 2 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 +/* capabilities flags */ +#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ +#define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ +#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ + /* * C O N T R O L S */ @@ -1626,6 +1731,13 @@ #endif #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) +#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) +#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) +#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) +#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) +#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) +#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) + /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml 1969-12-31 19:00:00.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml 2009-12-02 17:17:45.000000000 -0500 @@ -0,0 +1,238 @@ + + + ioctl VIDIOC_ENUM_DV_PRESETS + &manvol; + + + + VIDIOC_ENUM_DV_PRESETS + Enumerate supported Digital Video Presets + + + + + + int ioctl + int fd + int request + struct v4l2_dv_enum_preset *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_ENUM_DV_PRESETS + + + + argp + + + + + + + + + Description + + To query the attributes of a DV preset, applications initialize the +index field and zero the reserved array of &v4l2-dv-enum-preset; + and call the VIDIOC_ENUM_DV_PRESETS ioctl with a pointer to this +structure. Drivers fill the rest of the structure or return an +&EINVAL; when the index is out of bounds. To enumerate all DV Presets supported, +applications shall begin at index zero, incrementing by one until the +driver returns EINVAL. Drivers may enumerate a +different set of DV Presets after switching the video input or +output. + + + struct <structname>v4l2_dv_enum_presets</structname> + + &cs-str; + + + __u32 + index + Number of the DV preset, set by the +application. + + + __u32 + preset + This field identify one of the DV Preset value listed in . + + + __u8 + name[24] + Name of the preset, a NULL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is +intended for the user. + + + __u32 + width + Width of active video in pixels for the DV preset. + + + __u32 + height + Height of active video in lines for the DV preset. + + + __u32 + reserved[4] + Reserved for future extensions. Drivers must set the array to zero. + + + +
+ + + struct <structname>DV Presets</structname> + + &cs-str; + + + Preset + Preset value + Description + + + + + + + + V4L2_DV_INVALID + 0 + Invalid Preset value. + + + V4L2_DV_480P59_94 + 1 + 720x480 progressive video at 59.94 fps as per BT.1362. + + + V4L2_DV_576P50 + 2 + 720x576 progressive video at 50 fps as per BT.1362. + + + V4L2_DV_720P24 + 3 + 1280x720 progressive video at 24 fps as per SMPTE 296M. + + + V4L2_DV_720P25 + 4 + 1280x720 progressive video at 25 fps as per SMPTE 296M. + + + V4L2_DV_720P30 + 5 + 1280x720 progressive video at 30 fps as per SMPTE 296M. + + + V4L2_DV_720P50 + 6 + 1280x720 progressive video at 50 fps as per SMPTE 296M. + + + V4L2_DV_720P59_94 + 7 + 1280x720 progressive video at 59.94 fps as per SMPTE 274M. + + + V4L2_DV_720P60 + 8 + 1280x720 progressive video at 60 fps as per SMPTE 274M/296M. + + + V4L2_DV_1080I29_97 + 9 + 1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M. + + + V4L2_DV_1080I30 + 10 + 1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M. + + + V4L2_DV_1080I25 + 11 + 1920x1080 interlaced video at 25 fps as per BT.1120. + + + V4L2_DV_1080I50 + 12 + 1920x1080 interlaced video at 50 fps as per SMPTE 296M. + + + V4L2_DV_1080I60 + 13 + 1920x1080 interlaced video at 60 fps as per SMPTE 296M. + + + V4L2_DV_1080P24 + 14 + 1920x1080 progressive video at 24 fps as per SMPTE 296M. + + + V4L2_DV_1080P25 + 15 + 1920x1080 progressive video at 25 fps as per SMPTE 296M. + + + V4L2_DV_1080P30 + 16 + 1920x1080 progressive video at 30 fps as per SMPTE 296M. + + + V4L2_DV_1080P50 + 17 + 1920x1080 progressive video at 50 fps as per BT.1120. + + + V4L2_DV_1080P60 + 18 + 1920x1080 progressive video at 60 fps as per BT.1120. + + + +
+
+ + + &return-value; + + + + EINVAL + + The &v4l2-dv-enum-preset; index +is out of bounds. + + + + +
+ + diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-enuminput.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-enuminput.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-enuminput.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-enuminput.xml 2009-12-02 17:18:11.000000000 -0500 @@ -124,7 +124,13 @@ __u32 - reserved[4] + capabilities + This field provides capabilities that exists at the +input. See for flags. + + + __u32 + reserved[3] Reserved for future extensions. Drivers must set the array to zero. @@ -261,6 +267,34 @@ + + + + Input capabilities + + &cs-def; + + + V4L2_IN_CAP_PRESETS + 0x00000001 + This input supports setting DV PRESET using VIDIOC_S_DV_PRESET + + + V4L2_OUT_CAP_CUSTOM_TIMINGS + 0x00000002 + This input supports setting Custom timings using VIDIOC_S_DV_TIMINGS + + + V4L2_IN_CAP_STD + 0x00000004 + This input supports setting standard using VIDIOC_S_STD + + + +
diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-enumoutput.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-enumoutput.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-enumoutput.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-enumoutput.xml 2009-12-02 17:18:18.000000000 -0500 @@ -114,7 +114,13 @@ __u32 - reserved[4] + capabilities + This field provides capabilities that exists at the +output. See for flags. + + + __u32 + reserved[3] Reserved for future extensions. Drivers must set the array to zero. @@ -147,6 +153,34 @@ + + + Output capabilities + + &cs-def; + + + V4L2_OUT_CAP_PRESETS + 0x00000001 + This output supports setting DV PRESET using VIDIOC_S_DV_PRESET + + + V4L2_OUT_CAP_CUSTOM_TIMINGS + 0x00000002 + This output supports setting Custom timings using VIDIOC_S_DV_TIMINGS + + + V4L2_OUT_CAP_STD + 0x00000004 + This output supports setting standard using VIDIOC_S_STD + + + +
+
&return-value; diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml 1969-12-31 19:00:00.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml 2009-12-02 17:18:57.000000000 -0500 @@ -0,0 +1,111 @@ + + + ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET + &manvol; + + + + VIDIOC_G_DV_PRESET + VIDIOC_S_DV_PRESET + Query or select the DV preset of the current input or output + + + + + + int ioctl + int fd + int request + &v4l2-dv-preset; +*argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET + + + + argp + + + + + + + + + Description + To query and select the current DV preset, applications +use the VIDIOC_G_DV_PRESET and VIDIOC_S_DV_PRESET +ioctls which take a pointer to a &v4l2-dv-preset; type as argument. + Application must zero the reserved array in &v4l2-dv-preset;. +VIDIOC_G_DV_PRESET returns a dv preset in the field + preset of &v4l2-dv-preset;. + + VIDIOC_S_DV_PRESET accepts a pointer to a &v4l2-dv-preset; +that has the preset value to be set. Application must zero the reserved array in &v4l2-dv-preset;. +If the preset is not supported, it returns an &EINVAL; + + + + &return-value; + + + + EINVAL + + This ioctl is not supported, or the +VIDIOC_S_DV_PRESET,VIDIOC_S_DV_PRESET parameter was unsuitable. + + + + EBUSY + + The device is busy and therefore can not change the preset + + + + + + struct <structname>v4l2_dv_preset</structname> + + &cs-str; + + + __u32 + preset + preset value to represent the digital video timings + + + __u32 + reserved[4] + Reserved fields for future use + + + +
+ +
+
+ + diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml 1969-12-31 19:00:00.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml 2009-12-02 17:24:11.000000000 -0500 @@ -0,0 +1,224 @@ + + + ioctl VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS + &manvol; + + + + VIDIOC_G_DV_TIMINGS + VIDIOC_S_DV_TIMINGS + Get or Set Custom DV Timings at input or output + + + + + + int ioctl + int fd + int request + &v4l2-dv-timings; +*argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS + + + + argp + + + + + + + + + Description + To Set Custom DV timings at the input or output, applications use the +VIDIOC_S_DV_TIMINGS ioctl and to Get the current custom timings, +applications use VIDIOC_G_DV_TIMINGS ioctl. The detailed timing +informations are filled in using the structure &v4l2-dv-timings;. These ioctls take + a pointer to &v4l2-dv-timings; structure as argument. If the ioctl is not supported +or the timing values are not correct, driver returns an &EINVAL; + + + + &return-value; + + + + EINVAL + + This ioctl is not supported, or the +VIDIOC_S_DV_TIMINGS parameter was unsuitable. + + + + EBUSY + + The device is busy and therefore can not change the timings. + + + + + + struct <structname>v4l2_bt_timings</structname> + + &cs-str; + + + __u32 + width + Width of active video in pixels + + + __u32 + height + Height of active video in lines + + + __u32 + interlaced + Progressive (0) or interlaced (1) + + + __u32 + polarities + This is a bit mask that defines polarities of sync signals. +bit 0 is for vertical sync polarity and bit 1 for horizontal sync polarity. If the bit is set +it is positive polarity and if is reset, it is negative polarity. + + + __u32 + pixelclock + Pixel clock in Hz. Ex. 74.25MHz->74250000 + + + __u32 + hfrontporch + Horizontal front porch in pixels + + + __u32 + hsync + Horizontal Sync length in pixels + + + __u32 + hbackporch + Horizontal back porch in pixels + + + __u32 + vfrontporch + Vertical front porch in pixels + + + __u32 + vsync + Vertical Sync length in lines + + + __u32 + vbackporch + Vertical back porch in lines + + + __u32 + il_vfrontporch + Vertical front porch for bottom field of interlaced field formats + + + __u32 + il_vsync + Vertical sync length for bottom field of interlaced field formats + + + __u32 + il_vbackporch + Vertical back porch for bottom field of interlaced field formats + + + +
+ + + struct <structname>v4l2_dv_timings</structname> + + &cs-str; + + + __u32 + type + + Type of DV timings as listed in . + + + union + + + + + + &v4l2-bt-timings; + bt + Timings defined by BT.656/1120 specifications + + + + __u32 + reserved[32] + + + + +
+ + + DV Timing types + + &cs-str; + + + Timing type + value + Description + + + + + + + + V4L2_DV_BT_656_1120 + 0 + BT.656/1120 timings + + + +
+
+
+ + diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml 1969-12-31 19:00:00.000000000 -0500 +++ v4l-dvb-patch/linux/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml 2009-12-02 17:19:41.000000000 -0500 @@ -0,0 +1,85 @@ + + + ioctl VIDIOC_QUERY_DV_PRESET + &manvol; + + + + VIDIOC_QUERY_DV_PRESET + Sense the DV preset received by the current +input + + + + + + int ioctl + int fd + int request + &v4l2-dv-preset; *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_QUERY_DV_PRESET + + + + argp + + + + + + + + + Description + + The hardware may be able to detect the current DV preset +automatically similar to sensing the video standard. To do so, applications +call VIDIOC_QUERY_DV_PRESET with a pointer to a + &v4l2-dv-preset; type. Once hardware detects a preset, that preset is +returned in the preset field of &v4l2-dv-preset; When detection is not +possible or fails, the value V4L2_DV_INVALID is returned. + + + + &return-value; + + + EINVAL + + This ioctl is not supported. + + + + EBUSY + + The device is busy and therefore can not sense the preset + + + + + + + diff -uNr v4l-dvb-e0cd9a337600_master/linux/include/linux/videodev2.h v4l-dvb-patch/linux/include/linux/videodev2.h --- v4l-dvb-e0cd9a337600_master/linux/include/linux/videodev2.h 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/linux/include/linux/videodev2.h 2009-12-02 17:21:48.000000000 -0500 @@ -733,6 +733,99 @@ }; /* + * V I D E O T I M I N G S D V P R E S E T + */ +struct v4l2_dv_preset { + __u32 preset; + __u32 reserved[4]; +}; + +/* + * D V P R E S E T S E N U M E R A T I O N + */ +struct v4l2_dv_enum_preset { + __u32 index; + __u32 preset; + __u8 name[32]; /* Name of the preset timing */ + __u32 width; + __u32 height; + __u32 reserved[4]; +}; + +/* + * D V P R E S E T V A L U E S + */ +#define V4L2_DV_INVALID 0 +#define V4L2_DV_480P59_94 1 /* BT.1362 */ +#define V4L2_DV_576P50 2 /* BT.1362 */ +#define V4L2_DV_720P24 3 /* SMPTE 296M */ +#define V4L2_DV_720P25 4 /* SMPTE 296M */ +#define V4L2_DV_720P30 5 /* SMPTE 296M */ +#define V4L2_DV_720P50 6 /* SMPTE 296M */ +#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ +#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ +#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ +#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ +#define V4L2_DV_1080I25 11 /* BT.1120 */ +#define V4L2_DV_1080I50 12 /* SMPTE 296M */ +#define V4L2_DV_1080I60 13 /* SMPTE 296M */ +#define V4L2_DV_1080P24 14 /* SMPTE 296M */ +#define V4L2_DV_1080P25 15 /* SMPTE 296M */ +#define V4L2_DV_1080P30 16 /* SMPTE 296M */ +#define V4L2_DV_1080P50 17 /* BT.1120 */ +#define V4L2_DV_1080P60 18 /* BT.1120 */ + +/* + * D V B T T I M I N G S + */ + +/* BT.656/BT.1120 timing data */ +struct v4l2_bt_timings { + __u32 width; /* width in pixels */ + __u32 height; /* height in lines */ + __u32 interlaced; /* Interlaced or progressive */ + __u32 polarities; /* Positive or negative polarity */ + __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */ + __u32 hfrontporch; /* Horizpontal front porch in pixels */ + __u32 hsync; /* Horizontal Sync length in pixels */ + __u32 hbackporch; /* Horizontal back porch in pixels */ + __u32 vfrontporch; /* Vertical front porch in pixels */ + __u32 vsync; /* Vertical Sync length in lines */ + __u32 vbackporch; /* Vertical back porch in lines */ + __u32 il_vfrontporch; /* Vertical front porch for bottom field of + * interlaced field formats + */ + __u32 il_vsync; /* Vertical sync length for bottom field of + * interlaced field formats + */ + __u32 il_vbackporch; /* Vertical back porch for bottom field of + * interlaced field formats + */ + __u32 reserved[16]; +} __attribute__ ((packed)); + +/* Interlaced or progressive format */ +#define V4L2_DV_PROGRESSIVE 0 +#define V4L2_DV_INTERLACED 1 + +/* Polarities. If bit is not set, it is assumed to be negative polarity */ +#define V4L2_DV_VSYNC_POS_POL 0x00000001 +#define V4L2_DV_HSYNC_POS_POL 0x00000002 + + +/* DV timings */ +struct v4l2_dv_timings { + __u32 type; + union { + struct v4l2_bt_timings bt; + __u32 reserved[32]; + }; +} __attribute__ ((packed)); + +/* Values for the type field */ +#define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ + +/* * V I D E O I N P U T S */ struct v4l2_input { @@ -743,7 +836,8 @@ __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; - __u32 reserved[4]; + __u32 capabilities; + __u32 reserved[3]; }; /* Values for the 'type' field */ @@ -774,6 +868,11 @@ #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ +/* capabilities flags */ +#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ +#define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ +#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ + /* * V I D E O O U T P U T S */ @@ -784,13 +883,19 @@ __u32 audioset; /* Associated audios (bitfield) */ __u32 modulator; /* Associated modulator */ v4l2_std_id std; - __u32 reserved[4]; + __u32 capabilities; + __u32 reserved[3]; }; /* Values for the 'type' field */ #define V4L2_OUTPUT_TYPE_MODULATOR 1 #define V4L2_OUTPUT_TYPE_ANALOG 2 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 +/* capabilities flags */ +#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ +#define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ +#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ + /* * C O N T R O L S */ @@ -1625,6 +1730,13 @@ #endif #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) +#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) +#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) +#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) +#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) +#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) +#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) + /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ diff -uNr v4l-dvb-e0cd9a337600_master/media-specs/Makefile v4l-dvb-patch/media-specs/Makefile --- v4l-dvb-e0cd9a337600_master/media-specs/Makefile 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb-patch/media-specs/Makefile 2009-12-02 17:49:08.000000000 -0500 @@ -60,6 +60,10 @@ v4l/vidioc-enumaudioout.xml \ v4l/vidioc-enuminput.xml \ v4l/vidioc-enumoutput.xml \ + v4l/vidioc-enum-dv-presets.xml \ + v4l/vidioc-g-dv-preset.xml \ + v4l/vidioc-query-dv-preset.xml \ + v4l/vidioc-g-dv-timings.xml \ v4l/vidioc-enumstd.xml \ v4l/vidioc-g-audio.xml \ v4l/vidioc-g-audioout.xml \ @@ -191,6 +195,12 @@ VIDIOC_ENUMAUDOUT \ VIDIOC_ENUMINPUT \ VIDIOC_ENUMOUTPUT \ + VIDIOC_ENUM_DV_PRESETS \ + VIDIOC_QUERY_DV_PRESET \ + VIDIOC_G_DV_PRESET \ + VIDIOC_S_DV_PRESET \ + VIDIOC_G_DV_TIMINGS \ + VIDIOC_S_DV_TIMINGS \ VIDIOC_ENUMSTD \ VIDIOC_ENUM_FMT \ VIDIOC_ENUM_FRAMEINTERVALS \ @@ -333,6 +343,10 @@ v4l2_tuner \ v4l2_vbi_format \ v4l2_window \ + v4l2_dv_enum_preset \ + v4l2_dv_preset \ + v4l2_dv_timings \ + v4l2_bt_timings \ ERRORS = \ EACCES \ From hvaibhav at ti.com Thu Dec 3 00:40:02 2009 From: hvaibhav at ti.com (Hiremath, Vaibhav) Date: Thu, 3 Dec 2009 12:10:02 +0530 Subject: [PATCH - v0 2/2] DaVinci - vpfe capture - Make clocks configurable In-Reply-To: <1259687940-31435-2-git-send-email-m-karicheri2@ti.com> References: <1259687940-31435-1-git-send-email-m-karicheri2@ti.com> <1259687940-31435-2-git-send-email-m-karicheri2@ti.com> Message-ID: <19F8576C6E063C45BE387C64729E7394043716B186@dbde02.ent.ti.com> > -----Original Message----- > From: Karicheri, Muralidharan > Sent: Tuesday, December 01, 2009 10:49 PM > To: linux-media at vger.kernel.org; hverkuil at xs4all.nl; > khilman at deeprootsystems.com > Cc: davinci-linux-open-source at linux.davincidsp.com; Hiremath, > Vaibhav; Karicheri, Muralidharan > Subject: [PATCH - v0 2/2] DaVinci - vpfe capture - Make clocks > configurable > > From: Muralidharan Karicheri > > Adding the clocks in vpfe capture configuration > > Signed-off-by: Muralidharan Karicheri > --- > arch/arm/mach-davinci/board-dm355-evm.c | 2 ++ > arch/arm/mach-davinci/board-dm644x-evm.c | 2 ++ > 2 files changed, 4 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-dm355-evm.c > b/arch/arm/mach-davinci/board-dm355-evm.c > index a9b650d..a28985c 100644 > --- a/arch/arm/mach-davinci/board-dm355-evm.c > +++ b/arch/arm/mach-davinci/board-dm355-evm.c > @@ -239,6 +239,8 @@ static struct vpfe_config vpfe_cfg = { > .sub_devs = vpfe_sub_devs, > .card_name = "DM355 EVM", > .ccdc = "DM355 CCDC", > + .num_clocks = 2, > + .clocks = {"vpss_master", "vpss_slave"}, [Hiremath, Vaibhav] Hi Murali, I was talking to Sekhar about this and actually he made some good points about this implementation. If we consider specific IP, then the required clocks would remain always be the same. There might be some devices which may not be using some clocks (so as that specific feature). Actually we are trying to create one more wrapper for clock configuration. Just to illustrate I am putting some other generic drivers examples - Omap-hsmmc.c - This driver requires 2 clocks, interface and functional. The devices which would be using this driver have to define clock with names "ick" and "fck". VPFE-Capture (Considering only current implementation) - Currently we have vpfe_capture.c file (master/bridge driver) which is handling clk_get/put, and platform data is providing the details about it. Ideally we should handle it in respective ccdc driver file, since he has all the knowledge about required number of clocks and its name. This way we don't have to maintain/pass clock information in platform data. I would appreciate any comments/thoughts/pointers here. Thanks, Vaibhav > }; > > static struct platform_device *davinci_evm_devices[] __initdata = { > diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c > b/arch/arm/mach-davinci/board-dm644x-evm.c > index fd0398b..45beb99 100644 > --- a/arch/arm/mach-davinci/board-dm644x-evm.c > +++ b/arch/arm/mach-davinci/board-dm644x-evm.c > @@ -250,6 +250,8 @@ static struct vpfe_config vpfe_cfg = { > .sub_devs = vpfe_sub_devs, > .card_name = "DM6446 EVM", > .ccdc = "DM6446 CCDC", > + .num_clocks = 2, > + .clocks = {"vpss_master", "vpss_slave"}, > }; > > static struct platform_device rtc_dev = { > -- > 1.6.0.4 From nsekhar at ti.com Thu Dec 3 04:06:51 2009 From: nsekhar at ti.com (Sekhar Nori) Date: Thu, 3 Dec 2009 15:36:51 +0530 Subject: [PATCH 2/5] davinci: make /proc/davinci_clocks display multi-rooted clock tree In-Reply-To: <1259834814-4817-2-git-send-email-nsekhar@ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> Message-ID: <1259834814-4817-3-git-send-email-nsekhar@ti.com> This patch modifies clock dump to take care of clock tress rooted at multiple oscillators. Current code assumes the entire tree is rooted on a single oscillator. When using off-chip clock synthesizers, some of the clocks can be obtained from a different on-board oscillator. Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/clock.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index df884c8..ba0b68f 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -513,12 +513,15 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) static int davinci_ck_show(struct seq_file *m, void *v) { - /* Show clock tree; we know the main oscillator is first. - * We trust nonzero usecounts equate to PSC enables... + struct clk *clk; + + /* + * Show clock tree; We trust nonzero usecounts equate to PSC enables... */ mutex_lock(&clocks_mutex); - if (!list_empty(&clocks)) - dump_clock(m, 0, list_first_entry(&clocks, struct clk, node)); + list_for_each_entry(clk, &clocks, node) + if (!clk->parent) + dump_clock(m, 0, clk); mutex_unlock(&clocks_mutex); return 0; -- 1.6.2.4 From nsekhar at ti.com Thu Dec 3 04:06:52 2009 From: nsekhar at ti.com (Sekhar Nori) Date: Thu, 3 Dec 2009 15:36:52 +0530 Subject: [PATCH 3/5] davinci: move /proc/davinci_clocks to debugfs In-Reply-To: <1259834814-4817-3-git-send-email-nsekhar@ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> <1259834814-4817-3-git-send-email-nsekhar@ti.com> Message-ID: <1259834814-4817-4-git-send-email-nsekhar@ti.com> Move /proc/davinci_clocks to /sys/kernel/debug/davinci_clocks (debugfs). debugfs is more suited for this since the clock dump is debug information. Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/clock.c | 42 ++++++++++------------------------------ 1 files changed, 11 insertions(+), 31 deletions(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index ba0b68f..c9ea503 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -455,24 +455,10 @@ int __init davinci_clk_init(struct davinci_clk *clocks) return 0; } -#ifdef CONFIG_PROC_FS -#include -#include - -static void *davinci_ck_start(struct seq_file *m, loff_t *pos) -{ - return *pos < 1 ? (void *)1 : NULL; -} - -static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return NULL; -} +#ifdef CONFIG_DEBUG_FS -static void davinci_ck_stop(struct seq_file *m, void *v) -{ -} +#include +#include #define CLKNAME_MAX 10 /* longest clock name */ #define NEST_DELTA 2 @@ -527,30 +513,24 @@ static int davinci_ck_show(struct seq_file *m, void *v) return 0; } -static const struct seq_operations davinci_ck_op = { - .start = davinci_ck_start, - .next = davinci_ck_next, - .stop = davinci_ck_stop, - .show = davinci_ck_show -}; - static int davinci_ck_open(struct inode *inode, struct file *file) { - return seq_open(file, &davinci_ck_op); + return single_open(file, davinci_ck_show, NULL); } -static const struct file_operations proc_davinci_ck_operations = { +static const struct file_operations davinci_ck_operations = { .open = davinci_ck_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; -static int __init davinci_ck_proc_init(void) +static int __init davinci_clk_debugfs_init(void) { - proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations); + debugfs_create_file("davinci_clocks", S_IFREG | S_IRUGO, NULL, NULL, + &davinci_ck_operations); return 0; } -__initcall(davinci_ck_proc_init); -#endif /* CONFIG_DEBUG_PROC_FS */ +device_initcall(davinci_clk_debugfs_init); +#endif /* CONFIG_DEBUG_FS */ -- 1.6.2.4 From nsekhar at ti.com Thu Dec 3 04:06:54 2009 From: nsekhar at ti.com (Sekhar Nori) Date: Thu, 3 Dec 2009 15:36:54 +0530 Subject: [PATCH 5/5] davinci: add CDCE949 support on DM6467 EVM In-Reply-To: <1259834814-4817-5-git-send-email-nsekhar@ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> <1259834814-4817-3-git-send-email-nsekhar@ti.com> <1259834814-4817-4-git-send-email-nsekhar@ti.com> <1259834814-4817-5-git-send-email-nsekhar@ti.com> Message-ID: <1259834814-4817-6-git-send-email-nsekhar@ti.com> From: Nageswari Srinivasan This patch adds the CDCE949 reference oscillator to the davinci clock list. On the DM6467T EVM, the CDCE949 is responsible for generating the pixel clock for display. On the DM6467 EVM, this pixel clock was being obtained from an internal source. This is not possible on the DM6467T EVM because of the presence of a 33MHz oscillator. The TSIF module also requires the CDCE949 to generate the data clocks. The actual clock definitions will be added by patches adding support for DM6467T VPIF and TSIF. This patch mearly lays the foundation for that work. Signed-off-by: Nageswari Srinivasan Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/Makefile | 2 +- arch/arm/mach-davinci/board-dm646x-evm.c | 32 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index eeb9230..7e806b0 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_MACH_SFFSDR) += board-sffsdr.o obj-$(CONFIG_MACH_NEUROS_OSD2) += board-neuros-osd2.o obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o obj-$(CONFIG_MACH_DM355_LEOPARD) += board-dm355-leopard.o -obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o +obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o cdce949.o obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 6ff3411..5d9283f 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include "clock.h" @@ -389,6 +391,9 @@ static struct i2c_board_info __initdata i2c_info[] = { { I2C_BOARD_INFO("cpld_video", 0x3b), }, + { + I2C_BOARD_INFO("cdce949", 0x6c), + }, }; static struct davinci_i2c_platform_data i2c_pdata = { @@ -681,9 +686,36 @@ static void __init evm_init_i2c(void) evm_init_video(); } +#define CDCE949_XIN_RATE 27000000 + +/* CDCE949 support - "lpsc" field is overridden to work as clock number */ +static struct clk cdce_clk_in = { + .name = "cdce_xin", + .flags = ALWAYS_ENABLED, + .rate = ATOMIC_INIT(CDCE949_XIN_RATE), +}; + +static struct davinci_clk cdce_clks[] = { + CLK(NULL, "xin", &cdce_clk_in), + CLK(NULL, NULL, NULL), +}; + +static void __init cdce_clk_init(void) +{ + struct davinci_clk *c; + struct clk *clk; + + for (c = cdce_clks; c->lk.clk; c++) { + clk = c->lk.clk; + clkdev_add(&c->lk); + clk_register(clk); + } +} + static void __init davinci_map_io(void) { dm646x_init(); + cdce_clk_init(); } static struct davinci_uart_config uart_config __initdata = { -- 1.6.2.4 From nsekhar at ti.com Thu Dec 3 04:06:49 2009 From: nsekhar at ti.com (Sekhar Nori) Date: Thu, 3 Dec 2009 15:36:49 +0530 Subject: [PATCH 0/5] davinci: add support for CDCE949 clock synthesizer Message-ID: <1259834814-4817-1-git-send-email-nsekhar@ti.com> This series is meant to add CDCE949 support and does some modfications/improvements to clock framework as well. Applies on top of my earlier patch series the first of which was "davinci: board-dm646x-evm.c: arrange related code together" The series is boot tested on the EVMs of all supported SoCs: DM6446, DM355, DM6467, DM365, OMAP-L137 and OMAP-L138 to make sure the clock tree looks sane. Tested cpufreq on OMAP-L138 EVM with ondemand governer. Actual CDCE949 testing done on DM6467T EVM. Nageswari Srinivasan (2): davinci: add support for CDCE949 clock synthesizer davinci: add CDCE949 support on DM6467 EVM Sekhar Nori (3): davinci: clock framework: remove spinlock usage davinci: make /proc/davinci_clocks display multi-rooted clock tree davinci: move /proc/davinci_clocks to debugfs arch/arm/mach-davinci/Makefile | 2 +- arch/arm/mach-davinci/board-dm646x-evm.c | 36 +++- arch/arm/mach-davinci/cdce949.c | 289 ++++++++++++++++++++++++++ arch/arm/mach-davinci/clock.c | 127 +++++------- arch/arm/mach-davinci/clock.h | 4 +- arch/arm/mach-davinci/da830.c | 2 +- arch/arm/mach-davinci/da850.c | 4 +- arch/arm/mach-davinci/dm355.c | 4 +- arch/arm/mach-davinci/dm365.c | 4 +- arch/arm/mach-davinci/dm644x.c | 8 +- arch/arm/mach-davinci/dm646x.c | 8 +- arch/arm/mach-davinci/include/mach/cdce949.h | 19 ++ arch/arm/mach-davinci/psc.c | 6 + 13 files changed, 415 insertions(+), 98 deletions(-) create mode 100644 arch/arm/mach-davinci/cdce949.c create mode 100644 arch/arm/mach-davinci/include/mach/cdce949.h From nsekhar at ti.com Thu Dec 3 04:06:53 2009 From: nsekhar at ti.com (Sekhar Nori) Date: Thu, 3 Dec 2009 15:36:53 +0530 Subject: [PATCH 4/5] davinci: add support for CDCE949 clock synthesizer In-Reply-To: <1259834814-4817-4-git-send-email-nsekhar@ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> <1259834814-4817-3-git-send-email-nsekhar@ti.com> <1259834814-4817-4-git-send-email-nsekhar@ti.com> Message-ID: <1259834814-4817-5-git-send-email-nsekhar@ti.com> From: Nageswari Srinivasan This patch adds support for TI's CDCE949 - a clock synthesizer with 4 PLLs and 9 outputs. It is used on DM6467 EVM. On the EVM, it generates clocks required for VPIF, TSIF and Audio modules. This patch adds it as part of the DaVinci clock framework. Testing: The various frequency outputs on Y1 have been tested using a out-of-tree VPIF video driver supporting HD video. The register values for Y5 frequency outputs have been derived from TSIF driver sources in MontaVista LSP kernel, but actual output has not been tested for lack of TSIF driver which actually works on the latest kernel. Signed-off-by: Nageswari Srinivasan Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/cdce949.c | 289 ++++++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/cdce949.h | 19 ++ 2 files changed, 308 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-davinci/cdce949.c create mode 100644 arch/arm/mach-davinci/include/mach/cdce949.h diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c new file mode 100644 index 0000000..5a08283 --- /dev/null +++ b/arch/arm/mach-davinci/cdce949.c @@ -0,0 +1,289 @@ +/* + * TI CDCE949 clock synthesizer driver + * + * Note: This implementation assumes an input of 27MHz to the CDCE. + * This is by no means constrained by CDCE hardware although the datasheet + * does use this as an example for all illustrations and more importantly: + * that is the crystal input on boards it is currently used on. + * + * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include + +#include + +#include "clock.h" + +static struct i2c_client *cdce_i2c_client; + +/* CDCE register descriptor */ +struct cdce_reg { + u8 addr; + u8 val; +}; + +/* Per-Output (Y1, Y2 etc.) frequency descriptor */ +struct cdce_freq { + /* Frequency in KHz */ + unsigned long frequency; + /* + * List of registers to program to obtain a particular frequency. + * 0x0 in register address and value is the end of list marker. + */ + struct cdce_reg *reglist; +}; + +#define CDCE_FREQ_TABLE_ENTRY(line, out) \ +{ \ + .reglist = cdce_y ##line## _ ##out, \ + .frequency = out, \ +} + +/* List of CDCE outputs */ +struct cdce_output { + /* List of frequencies on this output */ + struct cdce_freq *freq_table; + /* Number of possible frequencies */ + int size; +}; + +/* + * Finding out the values to program into CDCE949 registers for a particular + * frequency output is not a simple calculation. Have a look at the datasheet + * for the details. There is desktop software available to help users with + * the calculations. Here, we just depend on the output of that software + * (or hand calculations) instead trying to runtime calculate the register + * values and inflicting misery on ourselves. + */ +static struct cdce_reg cdce_y1_148500[] = { + { 0x13, 0x00 }, + /* program PLL1_0 multiplier */ + { 0x18, 0xaf }, + { 0x19, 0x50 }, + { 0x1a, 0x02 }, + { 0x1b, 0xc9 }, + /* program PLL1_11 multiplier */ + { 0x1c, 0x00 }, + { 0x1d, 0x40 }, + { 0x1e, 0x02 }, + { 0x1f, 0xc9 }, + /* output state selection */ + { 0x15, 0x00 }, + { 0x14, 0xef }, + /* switch MUX to PLL1 output */ + { 0x14, 0x6f }, + { 0x16, 0x06 }, + /* set P2DIV divider, P3DIV and input crystal */ + { 0x17, 0x06 }, + { 0x01, 0x00 }, + { 0x05, 0x48 }, + { 0x02, 0x80 }, + /* enable and disable PLL */ + { 0x02, 0xbc }, + { 0x03, 0x01 }, + { }, +}; + +static struct cdce_reg cdce_y1_74250[] = { + { 0x13, 0x00 }, + { 0x18, 0xaf }, + { 0x19, 0x50 }, + { 0x1a, 0x02 }, + { 0x1b, 0xc9 }, + { 0x1c, 0x00 }, + { 0x1d, 0x40 }, + { 0x1e, 0x02 }, + { 0x1f, 0xc9 }, + /* output state selection */ + { 0x15, 0x00 }, + { 0x14, 0xef }, + /* switch MUX to PLL1 output */ + { 0x14, 0x6f }, + { 0x16, 0x06 }, + /* set P2DIV divider, P3DIV and input crystal */ + { 0x17, 0x06 }, + { 0x01, 0x00 }, + { 0x05, 0x48 }, + { 0x02, 0x80 }, + /* enable and disable PLL */ + { 0x02, 0xbc }, + { 0x03, 0x02 }, + { }, +}; + +static struct cdce_reg cdce_y1_27000[] = { + { 0x13, 0x00 }, + { 0x18, 0x00 }, + { 0x19, 0x40 }, + { 0x1a, 0x02 }, + { 0x1b, 0x08 }, + { 0x1c, 0x00 }, + { 0x1d, 0x40 }, + { 0x1e, 0x02 }, + { 0x1f, 0x08 }, + { 0x15, 0x02 }, + { 0x14, 0xed }, + { 0x16, 0x01 }, + { 0x17, 0x01 }, + { 0x01, 0x00 }, + { 0x05, 0x50 }, + { 0x02, 0xb4 }, + { 0x03, 0x01 }, + { }, +}; + +static struct cdce_freq cdce_y1_freqs[] = { + CDCE_FREQ_TABLE_ENTRY(1, 148500), + CDCE_FREQ_TABLE_ENTRY(1, 74250), + CDCE_FREQ_TABLE_ENTRY(1, 27000), +}; + +static struct cdce_reg cdce_y5_13500[] = { + { 0x27, 0x08 }, + { 0x28, 0x00 }, + { 0x29, 0x40 }, + { 0x2a, 0x02 }, + { 0x2b, 0x08 }, + { 0x24, 0x6f }, + { }, +}; + +static struct cdce_reg cdce_y5_16875[] = { + { 0x27, 0x08 }, + { 0x28, 0x9f }, + { 0x29, 0xb0 }, + { 0x2a, 0x02 }, + { 0x2b, 0x89 }, + { 0x24, 0x6f }, + { }, +}; + +static struct cdce_reg cdce_y5_27000[] = { + { 0x27, 0x04 }, + { 0x28, 0x00 }, + { 0x29, 0x40 }, + { 0x2a, 0x02 }, + { 0x2b, 0x08 }, + { 0x24, 0x6f }, + { }, +}; +static struct cdce_reg cdce_y5_54000[] = { + { 0x27, 0x04 }, + { 0x28, 0xff }, + { 0x29, 0x80 }, + { 0x2a, 0x02 }, + { 0x2b, 0x07 }, + { 0x24, 0x6f }, + { }, +}; + +static struct cdce_reg cdce_y5_81000[] = { + { 0x27, 0x02 }, + { 0x28, 0xbf }, + { 0x29, 0xa0 }, + { 0x2a, 0x03 }, + { 0x2b, 0x0a }, + { 0x24, 0x6f }, + { }, +}; + +static struct cdce_freq cdce_y5_freqs[] = { + CDCE_FREQ_TABLE_ENTRY(5, 13500), + CDCE_FREQ_TABLE_ENTRY(5, 16875), + CDCE_FREQ_TABLE_ENTRY(5, 27000), + CDCE_FREQ_TABLE_ENTRY(5, 54000), + CDCE_FREQ_TABLE_ENTRY(5, 81000), +}; + + +static struct cdce_output output_list[] = { + [1] = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) }, + [5] = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) }, +}; + +int cdce_set_rate(struct clk *clk, unsigned long rate) +{ + int i, ret = 0; + struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table; + struct cdce_reg *regs = NULL; + + if (!cdce_i2c_client) + return -ENODEV; + + if (!freq_table) + return -EINVAL; + + for (i = 0; i < output_list[clk->lpsc].size; i++) { + if (freq_table[i].frequency == rate / 1000) { + regs = freq_table[i].reglist; + break; + } + } + + if (!regs) + return -EINVAL; + + for (i = 0; regs[i].addr; i++) { + ret = i2c_smbus_write_byte_data(cdce_i2c_client, + regs[i].addr | 0x80, regs[i].val); + if (ret) + return ret; + } + + atomic_set(&clk->rate, rate); + + return 0; +} + +static int cdce_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + cdce_i2c_client = client; + return 0; +} + +static int __devexit cdce_remove(struct i2c_client *client) +{ + cdce_i2c_client = NULL; + return 0; +} + +static const struct i2c_device_id cdce_id[] = { + {"cdce949", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, cdce_id); + +static struct i2c_driver cdce_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cdce949", + }, + .probe = cdce_probe, + .remove = __devexit_p(cdce_remove), + .id_table = cdce_id, +}; + +static int __init cdce_init(void) +{ + return i2c_add_driver(&cdce_driver); +} +subsys_initcall(cdce_init); + +static void __exit cdce_exit(void) +{ + i2c_del_driver(&cdce_driver); +} +module_exit(cdce_exit); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("CDCE949 clock synthesizer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach-davinci/include/mach/cdce949.h new file mode 100644 index 0000000..c73331f --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/cdce949.h @@ -0,0 +1,19 @@ +/* + * TI CDCE949 off-chip clock synthesizer support + * + * 2009 (C) Texas Instruments, Inc. http://www.ti.com/ + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#ifndef _MACH_DAVINCI_CDCE949_H +#define _MACH_DAVINCI_CDCE949_H + +#include + +#include + +int cdce_set_rate(struct clk *clk, unsigned long rate); + +#endif -- 1.6.2.4 From nsekhar at ti.com Thu Dec 3 04:06:50 2009 From: nsekhar at ti.com (Sekhar Nori) Date: Thu, 3 Dec 2009 15:36:50 +0530 Subject: [PATCH 1/5] davinci: clock framework: remove spinlock usage In-Reply-To: <1259834814-4817-1-git-send-email-nsekhar@ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> Message-ID: <1259834814-4817-2-git-send-email-nsekhar@ti.com> Currently, the spinlock in DaVinci clock framework is being used to: 1) Protect clock structure variables usecount and rate against concurrent modification. 2) Protect against simultaneous PSC enables/disables ie. serialize davinci_psc_config(). 3) Serialize clk_set_rate(): i. Prevent simultaneous setting of clock rates ii. Ensure clock list remains sane during rate propagation (also in clk_set_parent). Remove the spinlock usage in clock framework by: 1) Making clock rate and usecount as atomic variables. 2) Making davinci_psc_config() protect itself instead of relying on serialization by caller. 3) (i) Allowing the clk->set_rate to serialize itself. There should be no need to serialize all clock rate settings. Currently the only user of rate setting is cpufreq driver on DA850. cpufreq naturally serializes the calls to set CPU rate. Also, there appears no need to lock IRQs during CPU rate transtitions. If required, IRQs can be locked in the actual set_rate function. 3) (ii) Use the mutex already in place for serialzing clock list manipulation for serializing clock rate propagation as well. Apart from the general benefit of reducing locking granurlarity, the main motivation behind this change is to enable usage of clock framework for off-chip clock synthesizers. One such synthesizer, CDCE949, is present on DM6467 EVM. Access to the synthesizer happens through I2C bus - accessing which can lead to CPU sleep. Having IRQs locked in clk_set_rate prevents the clk->set_rate function from sleeping. Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-dm646x-evm.c | 4 +- arch/arm/mach-davinci/clock.c | 74 ++++++++++++----------------- arch/arm/mach-davinci/clock.h | 4 +- arch/arm/mach-davinci/da830.c | 2 +- arch/arm/mach-davinci/da850.c | 4 +- arch/arm/mach-davinci/dm355.c | 4 +- arch/arm/mach-davinci/dm365.c | 4 +- arch/arm/mach-davinci/dm644x.c | 8 ++-- arch/arm/mach-davinci/dm646x.c | 8 ++-- arch/arm/mach-davinci/psc.c | 6 ++ 10 files changed, 56 insertions(+), 62 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 542bfdb..6ff3411 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -722,9 +722,9 @@ static __init void davinci_dm646x_evm_irq_init(void) void __init dm646x_board_setup_refclk(struct clk *clk) { if (machine_is_davinci_dm6467tevm()) - clk->rate = DM6467T_EVM_REF_FREQ; + atomic_set(&clk->rate, DM6467T_EVM_REF_FREQ); else - clk->rate = DM646X_EVM_REF_FREQ; + atomic_set(&clk->rate, DM646X_EVM_REF_FREQ); } MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index baece65..df884c8 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -28,7 +28,6 @@ static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); -static DEFINE_SPINLOCK(clockfw_lock); static unsigned psc_domain(struct clk *clk) { @@ -41,15 +40,16 @@ static void __clk_enable(struct clk *clk) { if (clk->parent) __clk_enable(clk->parent); - if (clk->usecount++ == 0 && (clk->flags & CLK_PSC)) + if (atomic_read(&clk->usecount) == 0 && (clk->flags & CLK_PSC)) davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 1); + atomic_inc(&clk->usecount); } static void __clk_disable(struct clk *clk) { - if (WARN_ON(clk->usecount == 0)) + if (WARN_ON(atomic_read(&clk->usecount) == 0)) return; - if (--clk->usecount == 0 && !(clk->flags & CLK_PLL)) + if (atomic_dec_and_test(&clk->usecount) && !(clk->flags & CLK_PLL)) davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0); if (clk->parent) __clk_disable(clk->parent); @@ -57,14 +57,10 @@ static void __clk_disable(struct clk *clk) int clk_enable(struct clk *clk) { - unsigned long flags; - if (clk == NULL || IS_ERR(clk)) return -EINVAL; - spin_lock_irqsave(&clockfw_lock, flags); __clk_enable(clk); - spin_unlock_irqrestore(&clockfw_lock, flags); return 0; } @@ -72,14 +68,10 @@ EXPORT_SYMBOL(clk_enable); void clk_disable(struct clk *clk) { - unsigned long flags; - if (clk == NULL || IS_ERR(clk)) return; - spin_lock_irqsave(&clockfw_lock, flags); __clk_disable(clk); - spin_unlock_irqrestore(&clockfw_lock, flags); } EXPORT_SYMBOL(clk_disable); @@ -88,7 +80,7 @@ unsigned long clk_get_rate(struct clk *clk) if (clk == NULL || IS_ERR(clk)) return -EINVAL; - return clk->rate; + return atomic_read(&clk->rate); } EXPORT_SYMBOL(clk_get_rate); @@ -100,7 +92,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate) if (clk->round_rate) return clk->round_rate(clk, rate); - return clk->rate; + return atomic_read(&clk->rate); } EXPORT_SYMBOL(clk_round_rate); @@ -111,28 +103,27 @@ static void propagate_rate(struct clk *root) list_for_each_entry(clk, &root->children, childnode) { if (clk->recalc) - clk->rate = clk->recalc(clk); + atomic_set(&clk->rate, clk->recalc(clk)); propagate_rate(clk); } } int clk_set_rate(struct clk *clk, unsigned long rate) { - unsigned long flags; int ret = -EINVAL; if (clk == NULL || IS_ERR(clk)) return ret; - spin_lock_irqsave(&clockfw_lock, flags); if (clk->set_rate) ret = clk->set_rate(clk, rate); if (ret == 0) { if (clk->recalc) - clk->rate = clk->recalc(clk); + atomic_set(&clk->rate, clk->recalc(clk)); + mutex_lock(&clocks_mutex); propagate_rate(clk); + mutex_unlock(&clocks_mutex); } - spin_unlock_irqrestore(&clockfw_lock, flags); return ret; } @@ -140,26 +131,22 @@ EXPORT_SYMBOL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { - unsigned long flags; - if (clk == NULL || IS_ERR(clk)) return -EINVAL; /* Cannot change parent on enabled clock */ - if (WARN_ON(clk->usecount)) + if (WARN_ON(atomic_read(&clk->usecount))) return -EINVAL; mutex_lock(&clocks_mutex); clk->parent = parent; list_del_init(&clk->childnode); list_add(&clk->childnode, &clk->parent->children); - mutex_unlock(&clocks_mutex); - spin_lock_irqsave(&clockfw_lock, flags); if (clk->recalc) - clk->rate = clk->recalc(clk); + atomic_set(&clk->rate, clk->recalc(clk)); propagate_rate(clk); - spin_unlock_irqrestore(&clockfw_lock, flags); + mutex_unlock(&clocks_mutex); return 0; } @@ -170,7 +157,7 @@ int clk_register(struct clk *clk) if (clk == NULL || IS_ERR(clk)) return -EINVAL; - if (WARN(clk->parent && !clk->parent->rate, + if (WARN(clk->parent && !atomic_read(&clk->parent->rate), "CLK: %s parent %s has no rate!\n", clk->name, clk->parent->name)) return -EINVAL; @@ -184,16 +171,16 @@ int clk_register(struct clk *clk) mutex_unlock(&clocks_mutex); /* If rate is already set, use it */ - if (clk->rate) + if (atomic_read(&clk->rate)) return 0; /* Else, see if there is a way to calculate it */ if (clk->recalc) - clk->rate = clk->recalc(clk); + atomic_set(&clk->rate, clk->recalc(clk)); /* Otherwise, default to parent rate */ else if (clk->parent) - clk->rate = clk->parent->rate; + atomic_set(&clk->rate, atomic_read(&clk->parent->rate)); return 0; } @@ -219,9 +206,9 @@ static int __init clk_disable_unused(void) { struct clk *ck; - spin_lock_irq(&clockfw_lock); + mutex_lock(&clocks_mutex); list_for_each_entry(ck, &clocks, node) { - if (ck->usecount > 0) + if (atomic_read(&ck->usecount) > 0) continue; if (!(ck->flags & CLK_PSC)) continue; @@ -233,7 +220,7 @@ static int __init clk_disable_unused(void) pr_info("Clocks: disable unused %s\n", ck->name); davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, 0); } - spin_unlock_irq(&clockfw_lock); + mutex_unlock(&clocks_mutex); return 0; } @@ -244,7 +231,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) { u32 v, plldiv; struct pll_data *pll; - unsigned long rate = clk->rate; + unsigned long rate = atomic_read(&clk->rate); /* If this is the PLL base clock, no more calculations needed */ if (clk->pll_data) @@ -253,7 +240,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) if (WARN_ON(!clk->parent)) return rate; - rate = clk->parent->rate; + rate = atomic_read(&clk->parent->rate); /* Otherwise, the parent must be a PLL */ if (WARN_ON(!clk->parent->pll_data)) @@ -281,9 +268,9 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) static unsigned long clk_leafclk_recalc(struct clk *clk) { if (WARN_ON(!clk->parent)) - return clk->rate; + return atomic_read(&clk->rate); - return clk->parent->rate; + return atomic_read(&clk->parent->rate); } static unsigned long clk_pllclk_recalc(struct clk *clk) @@ -291,11 +278,11 @@ static unsigned long clk_pllclk_recalc(struct clk *clk) u32 ctrl, mult = 1, prediv = 1, postdiv = 1; u8 bypass; struct pll_data *pll = clk->pll_data; - unsigned long rate = clk->rate; + unsigned long rate = atomic_read(&clk->rate); pll->base = IO_ADDRESS(pll->phys_base); ctrl = __raw_readl(pll->base + PLLCTL); - rate = pll->input_rate = clk->parent->rate; + rate = pll->input_rate = atomic_read(&clk->parent->rate); if (ctrl & PLLCTL_PLLEN) { bypass = 0; @@ -333,8 +320,8 @@ static unsigned long clk_pllclk_recalc(struct clk *clk) rate /= postdiv; } - pr_debug("PLL%d: input = %lu MHz [ ", - pll->num, clk->parent->rate / 1000000); + pr_debug("PLL%d: input = %u MHz [ ", + pll->num, atomic_read(&clk->parent->rate) / 1000000); if (bypass) pr_debug("bypass "); if (prediv > 1) @@ -452,7 +439,7 @@ int __init davinci_clk_init(struct davinci_clk *clocks) } if (clk->recalc) - clk->rate = clk->recalc(clk); + atomic_set(&clk->rate, clk->recalc(clk)); if (clk->lpsc) clk->flags |= CLK_PSC; @@ -514,7 +501,8 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) min(i, (unsigned)(sizeof(buf) - 1 - nest))); seq_printf(s, "%s users=%2d %-3s %9ld Hz\n", - buf, parent->usecount, state, clk_get_rate(parent)); + buf, atomic_read(&parent->usecount), state, + clk_get_rate(parent)); /* REVISIT show device associations too */ /* cost is now small, but not linear... */ diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index c92d77a..796a568 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -67,8 +67,8 @@ struct clk { struct list_head node; struct module *owner; const char *name; - unsigned long rate; - u8 usecount; + atomic_t rate; + atomic_t usecount; u8 lpsc; u8 gpsc; u32 flags; diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index b22b5cf..d1961d2 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -43,7 +43,7 @@ static struct pll_data pll0_data = { static struct clk ref_clk = { .name = "ref_clk", - .rate = DA830_REF_FREQ, + .rate = ATOMIC_INIT(DA830_REF_FREQ), }; static struct clk pll0_clk = { diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 717806c..62f8c22 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -54,7 +54,7 @@ static struct pll_data pll0_data = { static struct clk ref_clk = { .name = "ref_clk", - .rate = DA850_REF_FREQ, + .rate = ATOMIC_INIT(DA850_REF_FREQ), }; static struct clk pll0_clk = { @@ -1024,7 +1024,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long armrate) static int da850_round_armrate(struct clk *clk, unsigned long rate) { - return clk->rate; + return atomic_read(&clk->rate); } #endif diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index dedf4d4..2244e8c 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -55,7 +55,7 @@ static struct pll_data pll2_data = { static struct clk ref_clk = { .name = "ref_clk", /* FIXME -- crystal rate is board-specific */ - .rate = DM355_REF_FREQ, + .rate = ATOMIC_INIT(DM355_REF_FREQ), }; static struct clk pll1_clk = { @@ -314,7 +314,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, /* REVISIT: why cant' this be disabled? */ + .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */ }; static struct clk timer3_clk = { diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 2ec619e..cc3bae4 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -52,7 +52,7 @@ static struct pll_data pll2_data = { static struct clk ref_clk = { .name = "ref_clk", - .rate = DM365_REF_FREQ, + .rate = ATOMIC_INIT(DM365_REF_FREQ), }; static struct clk pll1_clk = { @@ -358,7 +358,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, + .usecount = ATOMIC_INIT(1), }; static struct clk timer3_clk = { diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 2cd0081..e65e29e 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -47,7 +47,7 @@ static struct pll_data pll2_data = { static struct clk ref_clk = { .name = "ref_clk", - .rate = DM644X_REF_FREQ, + .rate = ATOMIC_INIT(DM644X_REF_FREQ), }; static struct clk pll1_clk = { @@ -131,7 +131,7 @@ static struct clk dsp_clk = { .parent = &pll1_sysclk1, .lpsc = DAVINCI_LPSC_GEM, .flags = PSC_DSP, - .usecount = 1, /* REVISIT how to disable? */ + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ }; static struct clk arm_clk = { @@ -146,7 +146,7 @@ static struct clk vicp_clk = { .parent = &pll1_sysclk2, .lpsc = DAVINCI_LPSC_IMCOP, .flags = PSC_DSP, - .usecount = 1, /* REVISIT how to disable? */ + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ }; static struct clk vpss_master_clk = { @@ -274,7 +274,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, /* REVISIT: why cant' this be disabled? */ + .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */ }; struct davinci_clk dm644x_clks[] = { diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 515d3ed..6f80616 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -60,7 +60,7 @@ static struct clk ref_clk = { static struct clk aux_clkin = { .name = "aux_clkin", - .rate = DM646X_AUX_FREQ, + .rate = ATOMIC_INIT(DM646X_AUX_FREQ), }; static struct clk pll1_clk = { @@ -158,7 +158,7 @@ static struct clk dsp_clk = { .parent = &pll1_sysclk1, .lpsc = DM646X_LPSC_C64X_CPU, .flags = PSC_DSP, - .usecount = 1, /* REVISIT how to disable? */ + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ }; static struct clk arm_clk = { @@ -262,14 +262,14 @@ static struct clk pwm0_clk = { .name = "pwm0", .parent = &pll1_sysclk3, .lpsc = DM646X_LPSC_PWM0, - .usecount = 1, /* REVIST: disabling hangs system */ + .usecount = ATOMIC_INIT(1), /* REVIST: disabling hangs system */ }; static struct clk pwm1_clk = { .name = "pwm1", .parent = &pll1_sysclk3, .lpsc = DM646X_LPSC_PWM1, - .usecount = 1, /* REVIST: disabling hangs system */ + .usecount = ATOMIC_INIT(1), /* REVIST: disabling hangs system */ }; static struct clk timer0_clk = { diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index 04a3cb7..a9a4d08 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,9 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, void __iomem *psc_base; struct davinci_soc_info *soc_info = &davinci_soc_info; u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */ + /* Protect against simultaneous enable/disable of PSCs */ + DEFINE_SPINLOCK(lock); + unsigned long flags; if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { pr_warning("PSC: Bad psc data: 0x%x[%d]\n", @@ -73,6 +77,7 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, psc_base = soc_info->psc_bases[ctlr]; + spin_lock_irqsave(&lock, flags); mdctl = __raw_readl(psc_base + MDCTL + 4 * id); mdctl &= ~MDSTAT_STATE_MASK; mdctl |= next_state; @@ -111,4 +116,5 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, do { mdstat = __raw_readl(psc_base + MDSTAT + 4 * id); } while (!((mdstat & MDSTAT_STATE_MASK) == next_state)); + spin_unlock_irqrestore(&lock, flags); } -- 1.6.2.4 From chaithrika at ti.com Thu Dec 3 06:28:08 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Thu, 3 Dec 2009 17:58:08 +0530 Subject: [alsa-devel] [PATCH] ASoC: DaVinci: Update suspend/resume support for McASP driver In-Reply-To: References: <1259737740-27324-1-git-send-email-chaithrika@ti.com> Message-ID: <000301ca7414$12280120$36780360$@com> On Wed, Dec 02, 2009 at 14:56:31, Takashi Iwai wrote: > At Wed, 2 Dec 2009 12:39:00 +0530, > Chaithrika U S wrote: > > > > diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c > > index ad4d7f4..80c7fdf 100644 > > --- a/sound/soc/davinci/davinci-pcm.c > > +++ b/sound/soc/davinci/davinci-pcm.c > > @@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name) > > static struct snd_pcm_hardware pcm_hardware_playback = { > > .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | > > SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | > > - SNDRV_PCM_INFO_PAUSE), > > + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), > > Note that unless your driver supports the "full" resume, > SNDRV_PCM_INFO_RESUME shouldn't be set. Here, the "full" resume means > that the hardware gets back to a completely sane state and the PCM > streams are resumed without extra PCM prepare call at PM resume. > If the PCM (or whatever) needs another re-initialization (like in many > cases), don't set this flag. > > Just to be sure... > > > Takashi > PCM prepare call is not needed in this case. Testing was done with audio loopback and after a suspend/resume cycle the audio output was proper. Hope my understanding is correct. Is this test sufficient to prove that driver supports full resume? Regards, Chaithrika From chaithrika at ti.com Thu Dec 3 07:34:54 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Thu, 3 Dec 2009 19:04:54 +0530 Subject: [alsa-devel] [PATCH] ASoC: DaVinci: Update suspend/resume support for McASP driver In-Reply-To: <20091203132717.GA412@sirena.org.uk> References: <1259737740-27324-1-git-send-email-chaithrika@ti.com> <000301ca7414$12280120$36780360$@com> <20091203132717.GA412@sirena.org.uk> Message-ID: <000901ca741d$65cedd90$316c98b0$@com> On Thu, Dec 03, 2009 at 18:57:17, Mark Brown wrote: > On Thu, Dec 03, 2009 at 02:13:19PM +0100, Takashi Iwai wrote: > > > Yeah, if it worked with an actual app, it's fine :) > > That was just a slight concern. > > Chaithrika, could you please fix the issue with the comment for > fallthrough and resubmit? > Mark, I will resubmit this patch soon. Regards, Chaithrika From chaithrika at ti.com Thu Dec 3 07:26:56 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Thu, 3 Dec 2009 18:56:56 +0530 Subject: [PATCH v2] ASoC: DaVinci: Update suspend/resume support for McASP driver Message-ID: <1259846816-24730-1-git-send-email-chaithrika@ti.com> Add clock enable and disable calls to resume and suspend respectively. Also add a member to the audio device data structure which tracks the clock status. Tested on DA850/OMAP-L138 EVM. For the purpose of testing, the patches[1] which add suspend-to-RAM support to DA850/OMAP-L138 SoC were applied. [1] http://linux.davincidsp.com/pipermail/davinci-linux-open-source/ 2009-November/016958.html Signed-off-by: Chaithrika U S --- Applies to ALSA GIT tree on branch topic/asoc at http://git.kernel.org/?p=linux/kernel/git/tiwai/sound-2.6.git;a=shortlog; h=topic/asoc sound/soc/davinci/davinci-mcasp.c | 18 ++++++++++++++++-- sound/soc/davinci/davinci-mcasp.h | 1 + sound/soc/davinci/davinci-pcm.c | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0a302e1..a613bbb 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -767,14 +767,27 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, int ret = 0; switch (cmd) { - case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: + if (!dev->clk_active) { + clk_enable(dev->clk); + dev->clk_active = 1; + } + /* Fall through */ + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: davinci_mcasp_start(dev, substream->stream); break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: + davinci_mcasp_stop(dev, substream->stream); + if (dev->clk_active) { + clk_disable(dev->clk); + dev->clk_active = 0; + } + + break; + + case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcasp_stop(dev, substream->stream); break; @@ -866,6 +879,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } clk_enable(dev->clk); + dev->clk_active = 1; dev->base = (void __iomem *)IO_ADDRESS(mem->start); dev->op_mode = pdata->op_mode; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 582c924..e755b51 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -44,6 +44,7 @@ struct davinci_audio_dev { int sample_rate; struct clk *clk; unsigned int codec_fmt; + u8 clk_active; /* McASP specific data */ int tdm_slots; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index ad4d7f4..80c7fdf 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name) static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S16_LE), .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | -- 1.5.6 From m-karicheri2 at ti.com Thu Dec 3 09:45:06 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 09:45:06 -0600 Subject: [PATCH 0/2] davinci i2c fixes for 2.6.31 In-Reply-To: <1258989866.20007.237.camel@localhost.localdomain> References: <1246920516-31462-1-git-send-email-khilman@deeprootsystems.com> <20090707231938.GA9907@fluff.org.uk> <87skh79uai.fsf@deeprootsystems.com> <1247642943.5981.76.camel@localhost.localdomain> <1258989866.20007.237.camel@localhost.localdomain> Message-ID: Philby, Is this a generic solution which works on DM365 as well? Why did you do the following command? #./i2cset -y 0 0x50 0x00 Using the Arago tree kernel I was able to reproduce the issue by doing ./fbdev_loopback -i2 -d0 and then press Control C. I am not sure why you run the command ./i2cset -y 0 0x50 0x00 Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com >-----Original Message----- >From: Philby John [mailto:pjohn at in.mvista.com] >Sent: Monday, November 23, 2009 10:24 AM >To: Karicheri, Muralidharan >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 > >Hello Murali, > >On Thu, 2009-07-16 at 16:22 -0500, Karicheri, Muralidharan wrote: >> Philby, >> >> I tried running this patch against 2.6.31.rc2 (davinci kernel tree). But >I got a crash as I run the application which is given below.... >> >> In my case, time out happens when I kill the capture application using >Cntrl-C. After Cnrtl-C, the mt9t031 i2c device couldn't be contacted by the >host (during cleanup, i2c commands fails). When the application is run >again, I get following outputs.. >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> Here are the complete log.... >> >> application running and pressed Cntrl-C ====> >> >> time:105 frame:33 >> time:105 frame:34vpfe-capture vpfe-capture: stream off failed in >subdev >> >> Running it again ..... >> >> root at 158.218.100.186:/opt/git# ./fbdev_loopback -i2 -d0 > > >I have now verified the code on a DM6446 and DM355, with >the ./fbdev_loopback test. I had to first do a #./i2cset -y 0 0x50 0x00 >0x0000 w to kill the bus and then run the ./fbdev_loopback test to >recreate the issue. Recovery seems to happen with the new patch. Could >you try this out at your end, with the new patch? > >Thanks and regards, >Philby > From m-karicheri2 at ti.com Thu Dec 3 09:55:27 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 09:55:27 -0600 Subject: [PATCH - v0 2/2] DaVinci - vpfe capture - Make clocks configurable In-Reply-To: <19F8576C6E063C45BE387C64729E7394043716B186@dbde02.ent.ti.com> References: <1259687940-31435-1-git-send-email-m-karicheri2@ti.com> <1259687940-31435-2-git-send-email-m-karicheri2@ti.com> <19F8576C6E063C45BE387C64729E7394043716B186@dbde02.ent.ti.com> Message-ID: >I was talking to Sekhar about this and actually he made some good points >about this implementation. > >If we consider specific IP, then the required clocks would remain always be >the same. There might be some devices which may not be using some clocks >(so as that specific feature). > >Actually we are trying to create one more wrapper for clock configuration. >Just to illustrate I am putting some other generic drivers examples - > >Omap-hsmmc.c - > >This driver requires 2 clocks, interface and functional. The devices which >would be using this driver have to define clock with names "ick" and "fck". > >VPFE-Capture (Considering only current implementation) - > >Currently we have vpfe_capture.c file (master/bridge driver) which is >handling clk_get/put, and platform data is providing the details about it. >Ideally we should handle it in respective ccdc driver file, since he has >all the knowledge about required number of clocks and its name. This way we >don't have to maintain/pass clock information in platform data. > >I would appreciate any comments/thoughts/pointers here. > Though I agree that this clock could be set by the ccdc driver, I am not sure if the same clock is used by an IP on different SOCs. For example take the case of ccdc on DM6446 which is also used on OMAP 35xx SOC. Do they use vpss master and slave clocks as is done on DM6446? If this is true, then we could set the clock inside ccdc driver. Let me know so that I can re-work the patch and send it to the list. Murali >Thanks, >Vaibhav > >> }; >> >> static struct platform_device *davinci_evm_devices[] __initdata = { >> diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c >> b/arch/arm/mach-davinci/board-dm644x-evm.c >> index fd0398b..45beb99 100644 >> --- a/arch/arm/mach-davinci/board-dm644x-evm.c >> +++ b/arch/arm/mach-davinci/board-dm644x-evm.c >> @@ -250,6 +250,8 @@ static struct vpfe_config vpfe_cfg = { >> .sub_devs = vpfe_sub_devs, >> .card_name = "DM6446 EVM", >> .ccdc = "DM6446 CCDC", >> + .num_clocks = 2, >> + .clocks = {"vpss_master", "vpss_slave"}, >> }; >> >> static struct platform_device rtc_dev = { >> -- >> 1.6.0.4 From m-karicheri2 at ti.com Thu Dec 3 10:31:30 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Thu, 3 Dec 2009 11:31:30 -0500 Subject: [PATCH - v1] V4L - Documentation:Adds EBUSY error code for S_STD and QUERYSTD ioctls Message-ID: <1259857890-570-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri During review of Video Timing API documentation, Hans Verkuil had a comment on adding EBUSY error code for VIDIOC_S_STD and VIDIOC_QUERYSTD ioctls. This patch updates the document for this. Signed-off-by: Muralidharan Karicheri --- diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-g-std.xml v4l-dvb_patch1/linux/Documentation/DocBook/v4l/vidioc-g-std.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-g-std.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb_patch1/linux/Documentation/DocBook/v4l/vidioc-g-std.xml 2009-12-03 11:18:34.000000000 -0500 @@ -86,6 +86,12 @@ VIDIOC_S_STD parameter was unsuitable. + + EBUSY + + The device is busy and therefore can not change the standard + +
diff -uNr v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-querystd.xml v4l-dvb_patch1/linux/Documentation/DocBook/v4l/vidioc-querystd.xml --- v4l-dvb-e0cd9a337600_master/linux/Documentation/DocBook/v4l/vidioc-querystd.xml 2009-12-01 17:02:04.000000000 -0500 +++ v4l-dvb_patch1/linux/Documentation/DocBook/v4l/vidioc-querystd.xml 2009-12-03 11:18:44.000000000 -0500 @@ -70,6 +70,12 @@ This ioctl is not supported. + + EBUSY + + The device is busy and therefore can not detect the standard + + From m-karicheri2 at ti.com Thu Dec 3 10:33:45 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 10:33:45 -0600 Subject: [PATCH 0/2] davinci i2c fixes for 2.6.31 In-Reply-To: <1259856743.24844.13.camel@localhost.localdomain> References: <1246920516-31462-1-git-send-email-khilman@deeprootsystems.com> <20090707231938.GA9907@fluff.org.uk> <87skh79uai.fsf@deeprootsystems.com> <1247642943.5981.76.camel@localhost.localdomain> <1258989866.20007.237.camel@localhost.localdomain> <1259856743.24844.13.camel@localhost.localdomain> Message-ID: Philby, So where is the patch for adding davinci_i2c_platform_data in the platform file? Could you send it please? Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com >-----Original Message----- >From: Philby John [mailto:pjohn at in.mvista.com] >Sent: Thursday, December 03, 2009 11:12 AM >To: Karicheri, Muralidharan >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 > >Murali, > > The patch works for DM6446 and DM355 only. To get it to work for >DM365 >one must update the gpio pin number variables (sda_pin and scl_pin) in >struct davinci_i2c_platform_data for each platform. > >I do not have the pin number information for other Davinci platforms. >This was mentioned in the comment section of the patch v2... > >"TODO: Need to add SDA and SCL pin numbers to the respective >platforms such as dm355-leopard, dm365, dm646x, da8xx etc. >What I have info on is limited to just dm355 and dm6446." > >If someone can provide me with the relevant information, I could update >for all. > >I used "./i2cset -y 0 0x50 0x00" cause its the only way to kill the i2c >bus on a 2.6.18 kernel with DVSDK 2.0. FYI, I do not know how to >generate cmem.ko for the Arago tree kernel that would get >"fbdev_loopback" running. > >Regards, >Philby > > >On Thu, 2009-12-03 at 09:45 -0600, Karicheri, Muralidharan wrote: >> Philby, >> >> Is this a generic solution which works on DM365 as well? >> >> Why did you do the following command? >> >> #./i2cset -y 0 0x50 0x00 >> >> Using the Arago tree kernel I was able to reproduce the issue >> by doing >> >> ./fbdev_loopback -i2 -d0 >> >> and then press Control C. I am not sure why you run the command >> ./i2cset -y 0 0x50 0x00 >> >> >> Murali Karicheri >> Software Design Engineer >> Texas Instruments Inc. >> Germantown, MD 20874 >> phone: 301-407-9583 >> email: m-karicheri2 at ti.com >> >> >-----Original Message----- >> >From: Philby John [mailto:pjohn at in.mvista.com] >> >Sent: Monday, November 23, 2009 10:24 AM >> >To: Karicheri, Muralidharan >> >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >> >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >> >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 >> > >> >Hello Murali, >> > >> >On Thu, 2009-07-16 at 16:22 -0500, Karicheri, Muralidharan wrote: >> >> Philby, >> >> >> >> I tried running this patch against 2.6.31.rc2 (davinci kernel tree). >But >> >I got a crash as I run the application which is given below.... >> >> >> >> In my case, time out happens when I kill the capture application using >> >Cntrl-C. After Cnrtl-C, the mt9t031 i2c device couldn't be contacted by >the >> >host (during cleanup, i2c commands fails). When the application is run >> >again, I get following outputs.. >> >> >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> >> >> Here are the complete log.... >> >> >> >> application running and pressed Cntrl-C ====> >> >> >> >> time:105 frame:33 >> >> time:105 frame:34vpfe-capture vpfe-capture: stream off failed in >> >subdev >> >> >> >> Running it again ..... >> >> >> >> root at 158.218.100.186:/opt/git# ./fbdev_loopback -i2 -d0 >> > >> > >> >I have now verified the code on a DM6446 and DM355, with >> >the ./fbdev_loopback test. I had to first do a #./i2cset -y 0 0x50 0x00 >> >0x0000 w to kill the bus and then run the ./fbdev_loopback test to >> >recreate the issue. Recovery seems to happen with the new patch. Could >> >you try this out at your end, with the new patch? >> > >> >Thanks and regards, >> >Philby >> > >> From m-karicheri2 at ti.com Thu Dec 3 12:01:20 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 12:01:20 -0600 Subject: [PATCH 0/2] davinci i2c fixes for 2.6.31 In-Reply-To: <1259859011.24844.19.camel@localhost.localdomain> References: <1246920516-31462-1-git-send-email-khilman@deeprootsystems.com> <20090707231938.GA9907@fluff.org.uk> <87skh79uai.fsf@deeprootsystems.com> <1247642943.5981.76.camel@localhost.localdomain> <1258989866.20007.237.camel@localhost.localdomain> <1259856743.24844.13.camel@localhost.localdomain> <1259859011.24844.19.camel@localhost.localdomain> Message-ID: I can verify on DM355. But I will be running latest kernel on Arago. I have manually merged your patch. Did it worked on DM355? Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com >-----Original Message----- >From: Philby John [mailto:pjohn at in.mvista.com] >Sent: Thursday, December 03, 2009 11:50 AM >To: Karicheri, Muralidharan >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 > >Murali, > > It would be excellent if you could verify the patch on a DM6446 first >and perhaps then make changes for DM365. > >Regards, >Philby > > > >On Thu, 2009-12-03 at 10:33 -0600, Karicheri, Muralidharan wrote: >> Philby, >> >> So where is the patch for adding davinci_i2c_platform_data in the >platform >> file? Could you send it please? >> >> Murali Karicheri >> Software Design Engineer >> Texas Instruments Inc. >> Germantown, MD 20874 >> phone: 301-407-9583 >> email: m-karicheri2 at ti.com >> >> >-----Original Message----- >> >From: Philby John [mailto:pjohn at in.mvista.com] >> >Sent: Thursday, December 03, 2009 11:12 AM >> >To: Karicheri, Muralidharan >> >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >> >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >> >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 >> > >> >Murali, >> > >> > The patch works for DM6446 and DM355 only. To get it to work for >> >DM365 >> >one must update the gpio pin number variables (sda_pin and scl_pin) in >> >struct davinci_i2c_platform_data for each platform. >> > >> >I do not have the pin number information for other Davinci platforms. >> >This was mentioned in the comment section of the patch v2... >> > >> >"TODO: Need to add SDA and SCL pin numbers to the respective >> >platforms such as dm355-leopard, dm365, dm646x, da8xx etc. >> >What I have info on is limited to just dm355 and dm6446." >> > >> >If someone can provide me with the relevant information, I could update >> >for all. >> > >> >I used "./i2cset -y 0 0x50 0x00" cause its the only way to kill the i2c >> >bus on a 2.6.18 kernel with DVSDK 2.0. FYI, I do not know how to >> >generate cmem.ko for the Arago tree kernel that would get >> >"fbdev_loopback" running. >> > >> >Regards, >> >Philby >> > >> > >> >On Thu, 2009-12-03 at 09:45 -0600, Karicheri, Muralidharan wrote: >> >> Philby, >> >> >> >> Is this a generic solution which works on DM365 as well? >> >> >> >> Why did you do the following command? >> >> >> >> #./i2cset -y 0 0x50 0x00 >> >> >> >> Using the Arago tree kernel I was able to reproduce the issue >> >> by doing >> >> >> >> ./fbdev_loopback -i2 -d0 >> >> >> >> and then press Control C. I am not sure why you run the command >> >> ./i2cset -y 0 0x50 0x00 >> >> >> >> >> >> Murali Karicheri >> >> Software Design Engineer >> >> Texas Instruments Inc. >> >> Germantown, MD 20874 >> >> phone: 301-407-9583 >> >> email: m-karicheri2 at ti.com >> >> >> >> >-----Original Message----- >> >> >From: Philby John [mailto:pjohn at in.mvista.com] >> >> >Sent: Monday, November 23, 2009 10:24 AM >> >> >To: Karicheri, Muralidharan >> >> >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >> >> >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >> >> >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 >> >> > >> >> >Hello Murali, >> >> > >> >> >On Thu, 2009-07-16 at 16:22 -0500, Karicheri, Muralidharan wrote: >> >> >> Philby, >> >> >> >> >> >> I tried running this patch against 2.6.31.rc2 (davinci kernel tree). >> >But >> >> >I got a crash as I run the application which is given below.... >> >> >> >> >> >> In my case, time out happens when I kill the capture application >using >> >> >Cntrl-C. After Cnrtl-C, the mt9t031 i2c device couldn't be contacted >by >> >the >> >> >host (during cleanup, i2c commands fails). When the application is >run >> >> >again, I get following outputs.. >> >> >> >> >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> >> >> >> >> Here are the complete log.... >> >> >> >> >> >> application running and pressed Cntrl-C ====> >> >> >> >> >> >> time:105 frame:33 >> >> >> time:105 frame:34vpfe-capture vpfe-capture: stream off failed in >> >> >subdev >> >> >> >> >> >> Running it again ..... >> >> >> >> >> >> root at 158.218.100.186:/opt/git# ./fbdev_loopback -i2 -d0 >> >> > >> >> > >> >> >I have now verified the code on a DM6446 and DM355, with >> >> >the ./fbdev_loopback test. I had to first do a #./i2cset -y 0 0x50 >0x00 >> >> >0x0000 w to kill the bus and then run the ./fbdev_loopback test to >> >> >recreate the issue. Recovery seems to happen with the new patch. >Could >> >> >you try this out at your end, with the new patch? >> >> > >> >> >Thanks and regards, >> >> >Philby >> >> > >> >> >> From m-karicheri2 at ti.com Thu Dec 3 13:20:46 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 13:20:46 -0600 Subject: [PATCH 0/2] davinci i2c fixes for 2.6.31 In-Reply-To: <1259863857.24844.27.camel@localhost.localdomain> References: <1246920516-31462-1-git-send-email-khilman@deeprootsystems.com> <20090707231938.GA9907@fluff.org.uk> <87skh79uai.fsf@deeprootsystems.com> <1247642943.5981.76.camel@localhost.localdomain> <1258989866.20007.237.camel@localhost.localdomain> <1259856743.24844.13.camel@localhost.localdomain> <1259859011.24844.19.camel@localhost.localdomain> <1259863857.24844.27.camel@localhost.localdomain> Message-ID: Philby, My MT9T031 sensor has some problem (i2c stopped responding). So I need to get a sensor to test your fix. Let you know if I could test it. Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com >-----Original Message----- >From: Philby John [mailto:pjohn at in.mvista.com] >Sent: Thursday, December 03, 2009 1:11 PM >To: Karicheri, Muralidharan >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 > >Yes, it did (on DM355). >Let me know the result and I could also use the log in case of a kernel >dump. > >Thanks. >Philby > >On Thu, 2009-12-03 at 12:01 -0600, Karicheri, Muralidharan wrote: >> I can verify on DM355. But I will be running latest kernel on Arago. I >have manually merged your patch. Did it worked on DM355? >> >> Murali Karicheri >> Software Design Engineer >> Texas Instruments Inc. >> Germantown, MD 20874 >> phone: 301-407-9583 >> email: m-karicheri2 at ti.com >> >> >-----Original Message----- >> >From: Philby John [mailto:pjohn at in.mvista.com] >> >Sent: Thursday, December 03, 2009 11:50 AM >> >To: Karicheri, Muralidharan >> >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >> >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >> >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 >> > >> >Murali, >> > >> > It would be excellent if you could verify the patch on a DM6446 first >> >and perhaps then make changes for DM365. >> > >> >Regards, >> >Philby >> > >> > >> > >> >On Thu, 2009-12-03 at 10:33 -0600, Karicheri, Muralidharan wrote: >> >> Philby, >> >> >> >> So where is the patch for adding davinci_i2c_platform_data in the >> >platform >> >> file? Could you send it please? >> >> >> >> Murali Karicheri >> >> Software Design Engineer >> >> Texas Instruments Inc. >> >> Germantown, MD 20874 >> >> phone: 301-407-9583 >> >> email: m-karicheri2 at ti.com >> >> >> >> >-----Original Message----- >> >> >From: Philby John [mailto:pjohn at in.mvista.com] >> >> >Sent: Thursday, December 03, 2009 11:12 AM >> >> >To: Karicheri, Muralidharan >> >> >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >> >> >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >> >> >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 >> >> > >> >> >Murali, >> >> > >> >> > The patch works for DM6446 and DM355 only. To get it to work >for >> >> >DM365 >> >> >one must update the gpio pin number variables (sda_pin and scl_pin) >in >> >> >struct davinci_i2c_platform_data for each platform. >> >> > >> >> >I do not have the pin number information for other Davinci platforms. >> >> >This was mentioned in the comment section of the patch v2... >> >> > >> >> >"TODO: Need to add SDA and SCL pin numbers to the respective >> >> >platforms such as dm355-leopard, dm365, dm646x, da8xx etc. >> >> >What I have info on is limited to just dm355 and dm6446." >> >> > >> >> >If someone can provide me with the relevant information, I could >update >> >> >for all. >> >> > >> >> >I used "./i2cset -y 0 0x50 0x00" cause its the only way to kill the >i2c >> >> >bus on a 2.6.18 kernel with DVSDK 2.0. FYI, I do not know how to >> >> >generate cmem.ko for the Arago tree kernel that would get >> >> >"fbdev_loopback" running. >> >> > >> >> >Regards, >> >> >Philby >> >> > >> >> > >> >> >On Thu, 2009-12-03 at 09:45 -0600, Karicheri, Muralidharan wrote: >> >> >> Philby, >> >> >> >> >> >> Is this a generic solution which works on DM365 as well? >> >> >> >> >> >> Why did you do the following command? >> >> >> >> >> >> #./i2cset -y 0 0x50 0x00 >> >> >> >> >> >> Using the Arago tree kernel I was able to reproduce the issue >> >> >> by doing >> >> >> >> >> >> ./fbdev_loopback -i2 -d0 >> >> >> >> >> >> and then press Control C. I am not sure why you run the command >> >> >> ./i2cset -y 0 0x50 0x00 >> >> >> >> >> >> >> >> >> Murali Karicheri >> >> >> Software Design Engineer >> >> >> Texas Instruments Inc. >> >> >> Germantown, MD 20874 >> >> >> phone: 301-407-9583 >> >> >> email: m-karicheri2 at ti.com >> >> >> >> >> >> >-----Original Message----- >> >> >> >From: Philby John [mailto:pjohn at in.mvista.com] >> >> >> >Sent: Monday, November 23, 2009 10:24 AM >> >> >> >To: Karicheri, Muralidharan >> >> >> >Cc: Kevin Hilman; Ben Dooks; davinci-linux-open- >> >> >> >source at linux.davincidsp.com; linux-i2c at vger.kernel.org >> >> >> >Subject: RE: [PATCH 0/2] davinci i2c fixes for 2.6.31 >> >> >> > >> >> >> >Hello Murali, >> >> >> > >> >> >> >On Thu, 2009-07-16 at 16:22 -0500, Karicheri, Muralidharan wrote: >> >> >> >> Philby, >> >> >> >> >> >> >> >> I tried running this patch against 2.6.31.rc2 (davinci kernel >tree). >> >> >But >> >> >> >I got a crash as I run the application which is given below.... >> >> >> >> >> >> >> >> In my case, time out happens when I kill the capture application >> >using >> >> >> >Cntrl-C. After Cnrtl-C, the mt9t031 i2c device couldn't be >contacted >> >by >> >> >the >> >> >> >host (during cleanup, i2c commands fails). When the application is >> >run >> >> >> >again, I get following outputs.. >> >> >> >> >> >> >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> >> >> i2c_davinci i2c_davinci.1: timeout waiting for bus ready >> >> >> >> >> >> >> >> Here are the complete log.... >> >> >> >> >> >> >> >> application running and pressed Cntrl-C ====> >> >> >> >> >> >> >> >> time:105 frame:33 >> >> >> >> time:105 frame:34vpfe-capture vpfe-capture: stream off failed >in >> >> >> >subdev >> >> >> >> >> >> >> >> Running it again ..... >> >> >> >> >> >> >> >> root at 158.218.100.186:/opt/git# ./fbdev_loopback -i2 -d0 >> >> >> > >> >> >> > >> >> >> >I have now verified the code on a DM6446 and DM355, with >> >> >> >the ./fbdev_loopback test. I had to first do a #./i2cset -y 0 0x50 >> >0x00 >> >> >> >0x0000 w to kill the bus and then run the ./fbdev_loopback test to >> >> >> >recreate the issue. Recovery seems to happen with the new patch. >> >Could >> >> >> >you try this out at your end, with the new patch? >> >> >> > >> >> >> >Thanks and regards, >> >> >> >Philby >> >> >> > >> >> >> >> >> >> From m-karicheri2 at ti.com Thu Dec 3 13:31:31 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 13:31:31 -0600 Subject: [PATCH 2/2] DaVinci - vpfe capture - converting ccdc to platform driver In-Reply-To: <19F8576C6E063C45BE387C64729E7394043716AE12@dbde02.ent.ti.com> References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> <1259691333-32164-2-git-send-email-m-karicheri2@ti.com> <19F8576C6E063C45BE387C64729E7394043716AE12@dbde02.ent.ti.com> Message-ID: >> - /* >> - * setup Mux configuration for vpfe input and register >> - * vpfe capture platform device >> - */ >> - davinci_cfg_reg(DM355_VIN_PCLK); >> - davinci_cfg_reg(DM355_VIN_CAM_WEN); >> - davinci_cfg_reg(DM355_VIN_CAM_VD); >> - davinci_cfg_reg(DM355_VIN_CAM_HD); >> - davinci_cfg_reg(DM355_VIN_YIN_EN); >> - davinci_cfg_reg(DM355_VIN_CINL_EN); >> - davinci_cfg_reg(DM355_VIN_CINH_EN); >[Hiremath, Vaibhav] Why have you removed mux configuration from here and >moved to CCDC driver? Any specific reason? > Good catch. I wanted to do this clean up, but missed it. Actually platform data should have a function setup_pinmux() to set up the pin mux for the ccdc input. This function will be defined in the platform file and will be called during probe() Murali >> + platform_device_register(&dm355_ccdc_dev); >> platform_device_register(&vpfe_capture_dev); >> >> return 0; >> diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach- >> davinci/dm644x.c >> index 2cd0081..982be1f 100644 >> --- a/arch/arm/mach-davinci/dm644x.c >> +++ b/arch/arm/mach-davinci/dm644x.c >> @@ -612,6 +612,11 @@ static struct resource vpfe_resources[] = { >> .end = IRQ_VDINT1, >> .flags = IORESOURCE_IRQ, >> }, >> +}; >> + >> +static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); >> +static struct resource dm644x_ccdc_resource[] = { >> + /* CCDC Base address */ >> { >> .start = 0x01c70400, >> .end = 0x01c70400 + 0xff, >> @@ -619,7 +624,17 @@ static struct resource vpfe_resources[] = { >> }, >> }; >> >> -static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32); >> +static struct platform_device dm644x_ccdc_dev = { >> + .name = "dm644x_ccdc", >> + .id = -1, >> + .num_resources = ARRAY_SIZE(dm644x_ccdc_resource), >> + .resource = dm644x_ccdc_resource, >> + .dev = { >> + .dma_mask = &vpfe_capture_dma_mask, >> + .coherent_dma_mask = DMA_BIT_MASK(32), >> + }, >> +}; >> + >> static struct platform_device vpfe_capture_dev = { >> .name = CAPTURE_DRV_NAME, >> .id = -1, >> @@ -772,6 +787,7 @@ static int __init dm644x_init_devices(void) >> platform_device_register(&dm644x_edma_device); >> platform_device_register(&dm644x_emac_device); >> platform_device_register(&dm644x_vpss_device); >> + platform_device_register(&dm644x_ccdc_dev); >> platform_device_register(&vpfe_capture_dev); >> >> return 0; >> -- >> 1.6.0.4 From m-karicheri2 at ti.com Thu Dec 3 13:51:43 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Thu, 3 Dec 2009 13:51:43 -0600 Subject: [PATCH v0 1/2] V4L - vpfe capture - convert ccdc drivers to platform drivers In-Reply-To: <19F8576C6E063C45BE387C64729E7394043716AE11@dbde02.ent.ti.com> References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> <19F8576C6E063C45BE387C64729E7394043716AE11@dbde02.ent.ti.com> Message-ID: >> +#include >[Hiremath, Vaibhav] This should not be here, this should get handled in >board file. The driver should be generic. > See my comments against the platform part of this patch. >> #include >> #include >> #include "dm355_ccdc_regs.h" >> @@ -105,7 +106,6 @@ static struct ccdc_params_ycbcr >> ccdc_hw_params_ycbcr = { >> >> static enum vpfe_hw_if_type ccdc_if_type; >> static void *__iomem ccdc_base_addr; >> -static int ccdc_addr_size; >> >> /* Raw Bayer formats */ >> static u32 ccdc_raw_bayer_pix_formats[] = >> @@ -126,12 +126,6 @@ static inline void regw(u32 val, u32 offset) >> __raw_writel(val, ccdc_base_addr + offset); >> } >> >> -static void ccdc_set_ccdc_base(void *addr, int size) >> -{ >> - ccdc_base_addr = addr; >> - ccdc_addr_size = size; >> -} >> - >> static void ccdc_enable(int en) >> { >> unsigned int temp; >> @@ -938,7 +932,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { >> .hw_ops = { >> .open = ccdc_open, >> .close = ccdc_close, >> - .set_ccdc_base = ccdc_set_ccdc_base, >> .enable = ccdc_enable, >> .enable_out_to_sdram = ccdc_enable_output_to_sdram, >> .set_hw_if_params = ccdc_set_hw_if_params, >> @@ -959,19 +952,89 @@ static struct ccdc_hw_device ccdc_hw_dev = { >> }, >> }; >> >> -static int __init dm355_ccdc_init(void) >> +static int __init dm355_ccdc_probe(struct platform_device *pdev) >> { >> - printk(KERN_NOTICE "dm355_ccdc_init\n"); >> - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) >> - return -1; >> + static resource_size_t res_len; >> + struct resource *res; >> + int status = 0; >> + >> + /** >> + * first try to register with vpfe. If not correct platform, >> then we >> + * don't have to iomap >> + */ >> + status = vpfe_register_ccdc_device(&ccdc_hw_dev); >> + if (status < 0) >> + return status; >> + >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + if (!res) { >> + status = -ENOENT; >[Hiremath, Vaibhav] I think right return value is -ENODEV. > Right. I will change it. >> + goto fail_nores; >> + } >> + res_len = res->end - res->start + 1; >> + >> + res = request_mem_region(res->start, res_len, res->name); >[Hiremath, Vaibhav] You should use "resource_size" here for res_len here. Ok. I didn't know about such a function :( Will change res_len -> resource_size(res) > >> + if (!res) { >> + status = -EBUSY; >> + goto fail_nores; >> + } >> + >> + ccdc_base_addr = ioremap_nocache(res->start, res_len); >> + if (!ccdc_base_addr) { >> + status = -EBUSY; >[Hiremath, Vaibhav] Is -EBUSY right return value, I think it should be - >ENXIO or -ENOMEM. > I see -ENXIO & -ENOMEM being used by drivers. -ENXIO stands for "No such device or address". ENOMEM stands for "Out of memory" . Since we are trying to map the address here, -ENXIO looks reasonable to me. Same if request_mem_region() fails. >> + goto fail; >> + } >> + /** >> + * setup Mux configuration for vpfe input and register >> + * vpfe capture platform device >> + */ >> + davinci_cfg_reg(DM355_VIN_PCLK); >> + davinci_cfg_reg(DM355_VIN_CAM_WEN); >> + davinci_cfg_reg(DM355_VIN_CAM_VD); >> + davinci_cfg_reg(DM355_VIN_CAM_HD); >> + davinci_cfg_reg(DM355_VIN_YIN_EN); >> + davinci_cfg_reg(DM355_VIN_CINL_EN); >> + davinci_cfg_reg(DM355_VIN_CINH_EN); >> + >[Hiremath, Vaibhav] This should not be here, this code must be generic and >might get used in another SoC. yes. See my suggestion against the architecture part. will be replaced with a setup_pinmux() fuction from platform_data. > >> printk(KERN_NOTICE "%s is registered with vpfe.\n", >> ccdc_hw_dev.name); >> return 0; >> +fail: >> + release_mem_region(res->start, res_len); >> +fail_nores: >> + vpfe_unregister_ccdc_device(&ccdc_hw_dev); >> + return status; >> } >> >> -static void __exit dm355_ccdc_exit(void) >> +static int dm355_ccdc_remove(struct platform_device *pdev) >> { >> + struct resource *res; >> + >> + iounmap(ccdc_base_addr); >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + if (res) >> + release_mem_region(res->start, res->end - res->start + >> 1); >[Hiremath, Vaibhav] Please use "resource_size" here for size. Ok. > >> vpfe_unregister_ccdc_device(&ccdc_hw_dev); >> + return 0; >> +} >> + >> +static struct platform_driver dm355_ccdc_driver = { >> + .driver = { >> + .name = "dm355_ccdc", >> + .owner = THIS_MODULE, >> + }, >> + .remove = __devexit_p(dm355_ccdc_remove), >> + .probe = dm355_ccdc_probe, >> +}; >> + >> +static int __init dm355_ccdc_init(void) >> +{ >> + return platform_driver_register(&dm355_ccdc_driver); >> +} >> + >> +static void __exit dm355_ccdc_exit(void) >> +{ >> + platform_driver_unregister(&dm355_ccdc_driver); >> } >> >> module_init(dm355_ccdc_init); >> diff --git a/drivers/media/video/davinci/dm644x_ccdc.c >> b/drivers/media/video/davinci/dm644x_ccdc.c >> index d5fa193..89ea6ae 100644 >> --- a/drivers/media/video/davinci/dm644x_ccdc.c >> +++ b/drivers/media/video/davinci/dm644x_ccdc.c >> @@ -85,7 +85,6 @@ static u32 ccdc_raw_yuv_pix_formats[] = >> {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; >> >> static void *__iomem ccdc_base_addr; >> -static int ccdc_addr_size; >> static enum vpfe_hw_if_type ccdc_if_type; >> >> /* register access routines */ >> @@ -99,12 +98,6 @@ static inline void regw(u32 val, u32 offset) >> __raw_writel(val, ccdc_base_addr + offset); >> } >> >> -static void ccdc_set_ccdc_base(void *addr, int size) >> -{ >> - ccdc_base_addr = addr; >> - ccdc_addr_size = size; >> -} >> - >> static void ccdc_enable(int flag) >> { >> regw(flag, CCDC_PCR); >> @@ -838,7 +831,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { >> .hw_ops = { >> .open = ccdc_open, >> .close = ccdc_close, >> - .set_ccdc_base = ccdc_set_ccdc_base, >> .reset = ccdc_sbl_reset, >> .enable = ccdc_enable, >> .set_hw_if_params = ccdc_set_hw_if_params, >> @@ -859,19 +851,79 @@ static struct ccdc_hw_device ccdc_hw_dev = { >> }, >> }; >> >> -static int __init dm644x_ccdc_init(void) >> +static int __init dm644x_ccdc_probe(struct platform_device *pdev) >> { >> - printk(KERN_NOTICE "dm644x_ccdc_init\n"); >> - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) >> - return -1; >> + static resource_size_t res_len; >> + struct resource *res; >> + int status = 0; >> + >> + /** >> + * first try to register with vpfe. If not correct platform, >> then we >> + * don't have to iomap >> + */ >> + status = vpfe_register_ccdc_device(&ccdc_hw_dev); >> + if (status < 0) >> + return status; >> + >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + if (!res) { >> + status = -ENOENT; >> + goto fail_nores; >> + } >> + >> + res_len = res->end - res->start + 1; >> + >> + res = request_mem_region(res->start, res_len, res->name); >> + if (!res) { >> + status = -EBUSY; >> + goto fail_nores; >> + } >> + >> + ccdc_base_addr = ioremap_nocache(res->start, res_len); >> + if (!ccdc_base_addr) { >> + status = -EBUSY; >> + goto fail; >> + } >> + >> printk(KERN_NOTICE "%s is registered with vpfe.\n", >> ccdc_hw_dev.name); >> return 0; >> +fail: >> + release_mem_region(res->start, res_len); >> +fail_nores: >> + vpfe_unregister_ccdc_device(&ccdc_hw_dev); >> + return status; >> +} >> + >> +static int dm644x_ccdc_remove(struct platform_device *pdev) >> +{ >> + struct resource *res; >> + >> + iounmap(ccdc_base_addr); >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + if (res) >> + release_mem_region(res->start, res->end - res->start + >> 1); >> + vpfe_unregister_ccdc_device(&ccdc_hw_dev); >> + return 0; >> +} >> + >> +static struct platform_driver dm644x_ccdc_driver = { >> + .driver = { >> + .name = "dm644x_ccdc", >> + .owner = THIS_MODULE, >> + }, >> + .remove = __devexit_p(dm644x_ccdc_remove), >> + .probe = dm644x_ccdc_probe, >> +}; >> + >> +static int __init dm644x_ccdc_init(void) >> +{ >> + return platform_driver_register(&dm644x_ccdc_driver); >> } >> >> static void __exit dm644x_ccdc_exit(void) >> { >> - vpfe_unregister_ccdc_device(&ccdc_hw_dev); >> + platform_driver_unregister(&dm644x_ccdc_driver); >> } >[Hiremath, Vaibhav] All above comments mentioned for DM355 applicable here >too. Ok. > >Thanks, >Vaibhav > >> >> module_init(dm644x_ccdc_init); >> diff --git a/drivers/media/video/davinci/vpfe_capture.c >> b/drivers/media/video/davinci/vpfe_capture.c >> index c3468ee..35bbb08 100644 >> --- a/drivers/media/video/davinci/vpfe_capture.c >> +++ b/drivers/media/video/davinci/vpfe_capture.c >> @@ -108,9 +108,6 @@ struct ccdc_config { >> int vpfe_probed; >> /* name of ccdc device */ >> char name[32]; >> - /* for storing mem maps for CCDC */ >> - int ccdc_addr_size; >> - void *__iomem ccdc_addr; >> }; >> >> /* data structures */ >> @@ -230,7 +227,6 @@ int vpfe_register_ccdc_device(struct >> ccdc_hw_device *dev) >> BUG_ON(!dev->hw_ops.set_image_window); >> BUG_ON(!dev->hw_ops.get_image_window); >> BUG_ON(!dev->hw_ops.get_line_length); >> - BUG_ON(!dev->hw_ops.setfbaddr); >> BUG_ON(!dev->hw_ops.getfid); >> >> mutex_lock(&ccdc_lock); >> @@ -241,25 +237,23 @@ int vpfe_register_ccdc_device(struct >> ccdc_hw_device *dev) >> * walk through it during vpfe probe >> */ >> printk(KERN_ERR "vpfe capture not initialized\n"); >> - ret = -1; >> + ret = -EFAULT; >> goto unlock; >> } >> >> if (strcmp(dev->name, ccdc_cfg->name)) { >> /* ignore this ccdc */ >> - ret = -1; >> + ret = -EINVAL; >> goto unlock; >> } >> >> if (ccdc_dev) { >> printk(KERN_ERR "ccdc already registered\n"); >> - ret = -1; >> + ret = -EINVAL; >> goto unlock; >> } >> >> ccdc_dev = dev; >> - dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr, >> - ccdc_cfg->ccdc_addr_size); >> unlock: >> mutex_unlock(&ccdc_lock); >> return ret; >> @@ -1947,37 +1941,12 @@ static __init int vpfe_probe(struct >> platform_device *pdev) >> } >> vpfe_dev->ccdc_irq1 = res1->start; >> >> - /* Get address base of CCDC */ >> - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> - if (!res1) { >> - v4l2_err(pdev->dev.driver, >> - "Unable to get register address map\n"); >> - ret = -ENOENT; >> - goto probe_disable_clock; >> - } >> - >> - ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1; >> - if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size, >> - pdev->dev.driver->name)) { >> - v4l2_err(pdev->dev.driver, >> - "Failed request_mem_region for ccdc base\n"); >> - ret = -ENXIO; >> - goto probe_disable_clock; >> - } >> - ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start, >> - ccdc_cfg->ccdc_addr_size); >> - if (!ccdc_cfg->ccdc_addr) { >> - v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc >> addr\n"); >> - ret = -ENXIO; >> - goto probe_out_release_mem1; >> - } >> - >> ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, >> IRQF_DISABLED, >> "vpfe_capture0", vpfe_dev); >> >> if (0 != ret) { >> v4l2_err(pdev->dev.driver, "Unable to request >> interrupt\n"); >> - goto probe_out_unmap1; >> + goto probe_disable_clock; >> } >> >> /* Allocate memory for video device */ >> @@ -2101,10 +2070,6 @@ probe_out_video_release: >> video_device_release(vpfe_dev->video_dev); >> probe_out_release_irq: >> free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); >> -probe_out_unmap1: >> - iounmap(ccdc_cfg->ccdc_addr); >> -probe_out_release_mem1: >> - release_mem_region(res1->start, res1->end - res1->start + 1); >> probe_disable_clock: >> vpfe_disable_clock(vpfe_dev); >> mutex_unlock(&ccdc_lock); >> @@ -2120,7 +2085,6 @@ probe_free_dev_mem: >> static int vpfe_remove(struct platform_device *pdev) >> { >> struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); >> - struct resource *res; >> >> v4l2_info(pdev->dev.driver, "vpfe_remove\n"); >> >> @@ -2128,11 +2092,6 @@ static int vpfe_remove(struct platform_device >> *pdev) >> kfree(vpfe_dev->sd); >> v4l2_device_unregister(&vpfe_dev->v4l2_dev); >> video_unregister_device(vpfe_dev->video_dev); >> - mutex_lock(&ccdc_lock); >> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> - release_mem_region(res->start, res->end - res->start + 1); >> - iounmap(ccdc_cfg->ccdc_addr); >> - mutex_unlock(&ccdc_lock); >> vpfe_disable_clock(vpfe_dev); >> kfree(vpfe_dev); >> kfree(ccdc_cfg); >> -- >> 1.6.0.4 From m-karicheri2 at ti.com Thu Dec 3 14:18:24 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Thu, 3 Dec 2009 15:18:24 -0500 Subject: [PATCH -v2] Adding helper function to get dv preset description Message-ID: <1259871504-18156-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri Updated based on comments against v1 of the patch This patch adds a helper function to get description of a digital video preset added by the video timing API. This will be usefull for drivers implementing the above API. NOTE: depends on the patch that adds video timing API. Signed-off-by: Muralidharan Karicheri Reviewed-by: Hans Verkuil --- Applies to V4L-DVB linux-next branch drivers/media/video/v4l2-common.c | 47 +++++++++++++++++++++++++++++++++++++ include/media/v4l2-common.h | 2 +- 2 files changed, 48 insertions(+), 1 deletions(-) diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index e8e5aff..36b5cb8 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -1024,3 +1024,50 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } } EXPORT_SYMBOL_GPL(v4l_bound_align_image); + +/** + * v4l_fill_dv_preset_info - fill description of a digital video preset + * @preset - preset value + * @info - pointer to struct v4l2_dv_enum_preset + * + * drivers can use this helper function to fill description of dv preset + * in info. + */ +int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info) +{ + static const struct v4l2_dv_preset_info { + u16 width; + u16 height; + const char *name; + } dv_presets[] = { + { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ + { 720, 480, "480p at 59.94" }, /* V4L2_DV_480P59_94 */ + { 720, 576, "576p at 50" }, /* V4L2_DV_576P50 */ + { 1280, 720, "720p at 24" }, /* V4L2_DV_720P24 */ + { 1280, 720, "720p at 25" }, /* V4L2_DV_720P25 */ + { 1280, 720, "720p at 30" }, /* V4L2_DV_720P30 */ + { 1280, 720, "720p at 50" }, /* V4L2_DV_720P50 */ + { 1280, 720, "720p at 59.94" }, /* V4L2_DV_720P59_94 */ + { 1280, 720, "720p at 60" }, /* V4L2_DV_720P60 */ + { 1920, 1080, "1080i at 29.97" }, /* V4L2_DV_1080I29_97 */ + { 1920, 1080, "1080i at 30" }, /* V4L2_DV_1080I30 */ + { 1920, 1080, "1080i at 25" }, /* V4L2_DV_1080I25 */ + { 1920, 1080, "1080i at 50" }, /* V4L2_DV_1080I50 */ + { 1920, 1080, "1080i at 60" }, /* V4L2_DV_1080I60 */ + { 1920, 1080, "1080p at 24" }, /* V4L2_DV_1080P24 */ + { 1920, 1080, "1080p at 25" }, /* V4L2_DV_1080P25 */ + { 1920, 1080, "1080p at 30" }, /* V4L2_DV_1080P30 */ + { 1920, 1080, "1080p at 50" }, /* V4L2_DV_1080P50 */ + { 1920, 1080, "1080p at 60" }, /* V4L2_DV_1080P60 */ + }; + + if (info == NULL || preset >= ARRAY_SIZE(dv_presets)) + return -EINVAL; + + info->preset = preset; + info->width = dv_presets[preset].width; + info->height = dv_presets[preset].height; + strlcpy(info->name, dv_presets[preset].name, sizeof(info->name)); + return 0; +} +EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info); diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 1c25b10..1c7b259 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -212,5 +212,5 @@ void v4l_bound_align_image(unsigned int *w, unsigned int wmin, unsigned int *h, unsigned int hmin, unsigned int hmax, unsigned int halign, unsigned int salign); - +int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info); #endif /* V4L2_COMMON_H_ */ -- 1.6.0.4 From nsnehaprabha at ti.com Thu Dec 3 14:56:54 2009 From: nsnehaprabha at ti.com (Narnakaje, Snehaprabha) Date: Thu, 3 Dec 2009 14:56:54 -0600 Subject: [PATCH 4/5] davinci: add support for CDCE949 clock synthesizer In-Reply-To: <1259834814-4817-5-git-send-email-nsekhar@ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> <1259834814-4817-3-git-send-email-nsekhar@ti.com> <1259834814-4817-4-git-send-email-nsekhar@ti.com> <1259834814-4817-5-git-send-email-nsekhar@ti.com> Message-ID: <7A436F7769CA33409C6B44B358BFFF0C012B7A2645@dlee02.ent.ti.com> Sekhar, Not sure if you have looked at the clock requirements for VPIF on DA850/OMAP-L138, it seems like we also need similar support - CDCE913. I believe, it supports only one clock - 27MHz for VPIF display. May be we could re-use the same driver? The values and registers do match with cdce_y1_27000[]. On DA850/OMAP-L138: { 0x14, 0xED }, { 0x18, 0x00 }, { 0x19, 0x40 }, { 0x1a, 0x02 }, { 0x1b, 0x08 }, Thanks Sneha > -----Original Message----- > From: davinci-linux-open-source-bounces at linux.davincidsp.com > [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf > Of Nori, Sekhar > Sent: Thursday, December 03, 2009 5:07 AM > To: davinci-linux-open-source at linux.davincidsp.com > Subject: [PATCH 4/5] davinci: add support for CDCE949 clock synthesizer > > From: Nageswari Srinivasan > > This patch adds support for TI's CDCE949 - a clock > synthesizer with 4 PLLs and 9 outputs. > > It is used on DM6467 EVM. On the EVM, it generates > clocks required for VPIF, TSIF and Audio modules. > > This patch adds it as part of the DaVinci clock framework. > > Testing: > The various frequency outputs on Y1 have been tested using > a out-of-tree VPIF video driver supporting HD video. > The register values for Y5 frequency outputs have been > derived from TSIF driver sources in MontaVista LSP kernel, > but actual output has not been tested for lack of TSIF > driver which actually works on the latest kernel. > > Signed-off-by: Nageswari Srinivasan > Signed-off-by: Sekhar Nori > --- > arch/arm/mach-davinci/cdce949.c | 289 > ++++++++++++++++++++++++++ > arch/arm/mach-davinci/include/mach/cdce949.h | 19 ++ > 2 files changed, 308 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/mach-davinci/cdce949.c > create mode 100644 arch/arm/mach-davinci/include/mach/cdce949.h > > diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach- > davinci/cdce949.c > new file mode 100644 > index 0000000..5a08283 > --- /dev/null > +++ b/arch/arm/mach-davinci/cdce949.c > @@ -0,0 +1,289 @@ > +/* > + * TI CDCE949 clock synthesizer driver > + * > + * Note: This implementation assumes an input of 27MHz to the CDCE. > + * This is by no means constrained by CDCE hardware although the > datasheet > + * does use this as an example for all illustrations and more > importantly: > + * that is the crystal input on boards it is currently used on. > + * > + * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/ > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > +#include > +#include > +#include > +#include > + > +#include > + > +#include "clock.h" > + > +static struct i2c_client *cdce_i2c_client; > + > +/* CDCE register descriptor */ > +struct cdce_reg { > + u8 addr; > + u8 val; > +}; > + > +/* Per-Output (Y1, Y2 etc.) frequency descriptor */ > +struct cdce_freq { > + /* Frequency in KHz */ > + unsigned long frequency; > + /* > + * List of registers to program to obtain a particular frequency. > + * 0x0 in register address and value is the end of list marker. > + */ > + struct cdce_reg *reglist; > +}; > + > +#define CDCE_FREQ_TABLE_ENTRY(line, out) \ > +{ \ > + .reglist = cdce_y ##line## _ ##out, \ > + .frequency = out, \ > +} > + > +/* List of CDCE outputs */ > +struct cdce_output { > + /* List of frequencies on this output */ > + struct cdce_freq *freq_table; > + /* Number of possible frequencies */ > + int size; > +}; > + > +/* > + * Finding out the values to program into CDCE949 registers for a > particular > + * frequency output is not a simple calculation. Have a look at the > datasheet > + * for the details. There is desktop software available to help users > with > + * the calculations. Here, we just depend on the output of that software > + * (or hand calculations) instead trying to runtime calculate the > register > + * values and inflicting misery on ourselves. > + */ > +static struct cdce_reg cdce_y1_148500[] = { > + { 0x13, 0x00 }, > + /* program PLL1_0 multiplier */ > + { 0x18, 0xaf }, > + { 0x19, 0x50 }, > + { 0x1a, 0x02 }, > + { 0x1b, 0xc9 }, > + /* program PLL1_11 multiplier */ > + { 0x1c, 0x00 }, > + { 0x1d, 0x40 }, > + { 0x1e, 0x02 }, > + { 0x1f, 0xc9 }, > + /* output state selection */ > + { 0x15, 0x00 }, > + { 0x14, 0xef }, > + /* switch MUX to PLL1 output */ > + { 0x14, 0x6f }, > + { 0x16, 0x06 }, > + /* set P2DIV divider, P3DIV and input crystal */ > + { 0x17, 0x06 }, > + { 0x01, 0x00 }, > + { 0x05, 0x48 }, > + { 0x02, 0x80 }, > + /* enable and disable PLL */ > + { 0x02, 0xbc }, > + { 0x03, 0x01 }, > + { }, > +}; > + > +static struct cdce_reg cdce_y1_74250[] = { > + { 0x13, 0x00 }, > + { 0x18, 0xaf }, > + { 0x19, 0x50 }, > + { 0x1a, 0x02 }, > + { 0x1b, 0xc9 }, > + { 0x1c, 0x00 }, > + { 0x1d, 0x40 }, > + { 0x1e, 0x02 }, > + { 0x1f, 0xc9 }, > + /* output state selection */ > + { 0x15, 0x00 }, > + { 0x14, 0xef }, > + /* switch MUX to PLL1 output */ > + { 0x14, 0x6f }, > + { 0x16, 0x06 }, > + /* set P2DIV divider, P3DIV and input crystal */ > + { 0x17, 0x06 }, > + { 0x01, 0x00 }, > + { 0x05, 0x48 }, > + { 0x02, 0x80 }, > + /* enable and disable PLL */ > + { 0x02, 0xbc }, > + { 0x03, 0x02 }, > + { }, > +}; > + > +static struct cdce_reg cdce_y1_27000[] = { > + { 0x13, 0x00 }, > + { 0x18, 0x00 }, > + { 0x19, 0x40 }, > + { 0x1a, 0x02 }, > + { 0x1b, 0x08 }, > + { 0x1c, 0x00 }, > + { 0x1d, 0x40 }, > + { 0x1e, 0x02 }, > + { 0x1f, 0x08 }, > + { 0x15, 0x02 }, > + { 0x14, 0xed }, > + { 0x16, 0x01 }, > + { 0x17, 0x01 }, > + { 0x01, 0x00 }, > + { 0x05, 0x50 }, > + { 0x02, 0xb4 }, > + { 0x03, 0x01 }, > + { }, > +}; > + > +static struct cdce_freq cdce_y1_freqs[] = { > + CDCE_FREQ_TABLE_ENTRY(1, 148500), > + CDCE_FREQ_TABLE_ENTRY(1, 74250), > + CDCE_FREQ_TABLE_ENTRY(1, 27000), > +}; > + > +static struct cdce_reg cdce_y5_13500[] = { > + { 0x27, 0x08 }, > + { 0x28, 0x00 }, > + { 0x29, 0x40 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x08 }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_reg cdce_y5_16875[] = { > + { 0x27, 0x08 }, > + { 0x28, 0x9f }, > + { 0x29, 0xb0 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x89 }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_reg cdce_y5_27000[] = { > + { 0x27, 0x04 }, > + { 0x28, 0x00 }, > + { 0x29, 0x40 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x08 }, > + { 0x24, 0x6f }, > + { }, > +}; > +static struct cdce_reg cdce_y5_54000[] = { > + { 0x27, 0x04 }, > + { 0x28, 0xff }, > + { 0x29, 0x80 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x07 }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_reg cdce_y5_81000[] = { > + { 0x27, 0x02 }, > + { 0x28, 0xbf }, > + { 0x29, 0xa0 }, > + { 0x2a, 0x03 }, > + { 0x2b, 0x0a }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_freq cdce_y5_freqs[] = { > + CDCE_FREQ_TABLE_ENTRY(5, 13500), > + CDCE_FREQ_TABLE_ENTRY(5, 16875), > + CDCE_FREQ_TABLE_ENTRY(5, 27000), > + CDCE_FREQ_TABLE_ENTRY(5, 54000), > + CDCE_FREQ_TABLE_ENTRY(5, 81000), > +}; > + > + > +static struct cdce_output output_list[] = { > + [1] = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) }, > + [5] = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) }, > +}; > + > +int cdce_set_rate(struct clk *clk, unsigned long rate) > +{ > + int i, ret = 0; > + struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table; > + struct cdce_reg *regs = NULL; > + > + if (!cdce_i2c_client) > + return -ENODEV; > + > + if (!freq_table) > + return -EINVAL; > + > + for (i = 0; i < output_list[clk->lpsc].size; i++) { > + if (freq_table[i].frequency == rate / 1000) { > + regs = freq_table[i].reglist; > + break; > + } > + } > + > + if (!regs) > + return -EINVAL; > + > + for (i = 0; regs[i].addr; i++) { > + ret = i2c_smbus_write_byte_data(cdce_i2c_client, > + regs[i].addr | 0x80, regs[i].val); > + if (ret) > + return ret; > + } > + > + atomic_set(&clk->rate, rate); > + > + return 0; > +} > + > +static int cdce_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + cdce_i2c_client = client; > + return 0; > +} > + > +static int __devexit cdce_remove(struct i2c_client *client) > +{ > + cdce_i2c_client = NULL; > + return 0; > +} > + > +static const struct i2c_device_id cdce_id[] = { > + {"cdce949", 0}, > + {}, > +}; > +MODULE_DEVICE_TABLE(i2c, cdce_id); > + > +static struct i2c_driver cdce_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = "cdce949", > + }, > + .probe = cdce_probe, > + .remove = __devexit_p(cdce_remove), > + .id_table = cdce_id, > +}; > + > +static int __init cdce_init(void) > +{ > + return i2c_add_driver(&cdce_driver); > +} > +subsys_initcall(cdce_init); > + > +static void __exit cdce_exit(void) > +{ > + i2c_del_driver(&cdce_driver); > +} > +module_exit(cdce_exit); > + > +MODULE_AUTHOR("Texas Instruments"); > +MODULE_DESCRIPTION("CDCE949 clock synthesizer driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach- > davinci/include/mach/cdce949.h > new file mode 100644 > index 0000000..c73331f > --- /dev/null > +++ b/arch/arm/mach-davinci/include/mach/cdce949.h > @@ -0,0 +1,19 @@ > +/* > + * TI CDCE949 off-chip clock synthesizer support > + * > + * 2009 (C) Texas Instruments, Inc. http://www.ti.com/ > + * > + * This file is licensed under the terms of the GNU General Public > License > + * version 2. This program is licensed "as is" without any warranty of > any > + * kind, whether express or implied. > + */ > +#ifndef _MACH_DAVINCI_CDCE949_H > +#define _MACH_DAVINCI_CDCE949_H > + > +#include > + > +#include > + > +int cdce_set_rate(struct clk *clk, unsigned long rate); > + > +#endif > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From nsekhar at ti.com Thu Dec 3 23:55:14 2009 From: nsekhar at ti.com (Nori, Sekhar) Date: Fri, 4 Dec 2009 11:25:14 +0530 Subject: [PATCH 4/5] davinci: add support for CDCE949 clock synthesizer In-Reply-To: <7A436F7769CA33409C6B44B358BFFF0C012B7A2645@dlee02.ent.ti.com> References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> <1259834814-4817-3-git-send-email-nsekhar@ti.com> <1259834814-4817-4-git-send-email-nsekhar@ti.com> <1259834814-4817-5-git-send-email-nsekhar@ti.com> <7A436F7769CA33409C6B44B358BFFF0C012B7A2645@dlee02.ent.ti.com> Message-ID: Hi Sneha, On Fri, Dec 04, 2009 at 02:26:54, Narnakaje, Snehaprabha wrote: > Sekhar, > > Not sure if you have looked at the clock requirements for VPIF on DA850/OMAP-L138, it > seems like we also need similar support - CDCE913. No, honestly didn't realize there was a CDCE in there so far :) > > I believe, it supports only one clock - 27MHz for VPIF display. > Okay. On reset the CDCE should give the this clock out by default without a need to re-program. We only support SD resolutions on DA850, so I assume there is no need to reprogram the CDCE for higher/different clocks. > May be we could re-use the same driver? The values and registers do match with > cdce_y1_27000[]. Unless there is a need to reprogram the CDCE, there should be no need for the driver. The VPIF driver should simply refer the 27MHz clock as "pixel_clk" or "data_clk" and the platform code should provide the definition for that clock. In the case of DA850 the board code can register a clock with this name and having a fixed rate of 27MHz. Thanks, Sekhar > > On DA850/OMAP-L138: > { 0x14, 0xED }, > { 0x18, 0x00 }, > { 0x19, 0x40 }, > { 0x1a, 0x02 }, > { 0x1b, 0x08 }, > > Thanks > Sneha > > > -----Original Message----- > > From: davinci-linux-open-source-bounces at linux.davincidsp.com > > [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf > > Of Nori, Sekhar > > Sent: Thursday, December 03, 2009 5:07 AM > > To: davinci-linux-open-source at linux.davincidsp.com > > Subject: [PATCH 4/5] davinci: add support for CDCE949 clock synthesizer > > > > From: Nageswari Srinivasan > > > > This patch adds support for TI's CDCE949 - a clock > > synthesizer with 4 PLLs and 9 outputs. > > > > It is used on DM6467 EVM. On the EVM, it generates > > clocks required for VPIF, TSIF and Audio modules. > > > > This patch adds it as part of the DaVinci clock framework. > > > > Testing: > > The various frequency outputs on Y1 have been tested using > > a out-of-tree VPIF video driver supporting HD video. > > The register values for Y5 frequency outputs have been > > derived from TSIF driver sources in MontaVista LSP kernel, > > but actual output has not been tested for lack of TSIF > > driver which actually works on the latest kernel. > > > > Signed-off-by: Nageswari Srinivasan > > Signed-off-by: Sekhar Nori > > --- > > arch/arm/mach-davinci/cdce949.c | 289 > > ++++++++++++++++++++++++++ > > arch/arm/mach-davinci/include/mach/cdce949.h | 19 ++ > > 2 files changed, 308 insertions(+), 0 deletions(-) > > create mode 100644 arch/arm/mach-davinci/cdce949.c > > create mode 100644 arch/arm/mach-davinci/include/mach/cdce949.h > > > > diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach- > > davinci/cdce949.c > > new file mode 100644 > > index 0000000..5a08283 > > --- /dev/null > > +++ b/arch/arm/mach-davinci/cdce949.c > > @@ -0,0 +1,289 @@ > > +/* > > + * TI CDCE949 clock synthesizer driver > > + * > > + * Note: This implementation assumes an input of 27MHz to the CDCE. > > + * This is by no means constrained by CDCE hardware although the > > datasheet > > + * does use this as an example for all illustrations and more > > importantly: > > + * that is the crystal input on boards it is currently used on. > > + * > > + * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/ > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License version 2 as > > + * published by the Free Software Foundation. > > + * > > + */ > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > + > > +#include "clock.h" > > + > > +static struct i2c_client *cdce_i2c_client; > > + > > +/* CDCE register descriptor */ > > +struct cdce_reg { > > + u8 addr; > > + u8 val; > > +}; > > + > > +/* Per-Output (Y1, Y2 etc.) frequency descriptor */ > > +struct cdce_freq { > > + /* Frequency in KHz */ > > + unsigned long frequency; > > + /* > > + * List of registers to program to obtain a particular frequency. > > + * 0x0 in register address and value is the end of list marker. > > + */ > > + struct cdce_reg *reglist; > > +}; > > + > > +#define CDCE_FREQ_TABLE_ENTRY(line, out) \ > > +{ \ > > + .reglist = cdce_y ##line## _ ##out, \ > > + .frequency = out, \ > > +} > > + > > +/* List of CDCE outputs */ > > +struct cdce_output { > > + /* List of frequencies on this output */ > > + struct cdce_freq *freq_table; > > + /* Number of possible frequencies */ > > + int size; > > +}; > > + > > +/* > > + * Finding out the values to program into CDCE949 registers for a > > particular > > + * frequency output is not a simple calculation. Have a look at the > > datasheet > > + * for the details. There is desktop software available to help users > > with > > + * the calculations. Here, we just depend on the output of that software > > + * (or hand calculations) instead trying to runtime calculate the > > register > > + * values and inflicting misery on ourselves. > > + */ > > +static struct cdce_reg cdce_y1_148500[] = { > > + { 0x13, 0x00 }, > > + /* program PLL1_0 multiplier */ > > + { 0x18, 0xaf }, > > + { 0x19, 0x50 }, > > + { 0x1a, 0x02 }, > > + { 0x1b, 0xc9 }, > > + /* program PLL1_11 multiplier */ > > + { 0x1c, 0x00 }, > > + { 0x1d, 0x40 }, > > + { 0x1e, 0x02 }, > > + { 0x1f, 0xc9 }, > > + /* output state selection */ > > + { 0x15, 0x00 }, > > + { 0x14, 0xef }, > > + /* switch MUX to PLL1 output */ > > + { 0x14, 0x6f }, > > + { 0x16, 0x06 }, > > + /* set P2DIV divider, P3DIV and input crystal */ > > + { 0x17, 0x06 }, > > + { 0x01, 0x00 }, > > + { 0x05, 0x48 }, > > + { 0x02, 0x80 }, > > + /* enable and disable PLL */ > > + { 0x02, 0xbc }, > > + { 0x03, 0x01 }, > > + { }, > > +}; > > + > > +static struct cdce_reg cdce_y1_74250[] = { > > + { 0x13, 0x00 }, > > + { 0x18, 0xaf }, > > + { 0x19, 0x50 }, > > + { 0x1a, 0x02 }, > > + { 0x1b, 0xc9 }, > > + { 0x1c, 0x00 }, > > + { 0x1d, 0x40 }, > > + { 0x1e, 0x02 }, > > + { 0x1f, 0xc9 }, > > + /* output state selection */ > > + { 0x15, 0x00 }, > > + { 0x14, 0xef }, > > + /* switch MUX to PLL1 output */ > > + { 0x14, 0x6f }, > > + { 0x16, 0x06 }, > > + /* set P2DIV divider, P3DIV and input crystal */ > > + { 0x17, 0x06 }, > > + { 0x01, 0x00 }, > > + { 0x05, 0x48 }, > > + { 0x02, 0x80 }, > > + /* enable and disable PLL */ > > + { 0x02, 0xbc }, > > + { 0x03, 0x02 }, > > + { }, > > +}; > > + > > +static struct cdce_reg cdce_y1_27000[] = { > > + { 0x13, 0x00 }, > > + { 0x18, 0x00 }, > > + { 0x19, 0x40 }, > > + { 0x1a, 0x02 }, > > + { 0x1b, 0x08 }, > > + { 0x1c, 0x00 }, > > + { 0x1d, 0x40 }, > > + { 0x1e, 0x02 }, > > + { 0x1f, 0x08 }, > > + { 0x15, 0x02 }, > > + { 0x14, 0xed }, > > + { 0x16, 0x01 }, > > + { 0x17, 0x01 }, > > + { 0x01, 0x00 }, > > + { 0x05, 0x50 }, > > + { 0x02, 0xb4 }, > > + { 0x03, 0x01 }, > > + { }, > > +}; > > + > > +static struct cdce_freq cdce_y1_freqs[] = { > > + CDCE_FREQ_TABLE_ENTRY(1, 148500), > > + CDCE_FREQ_TABLE_ENTRY(1, 74250), > > + CDCE_FREQ_TABLE_ENTRY(1, 27000), > > +}; > > + > > +static struct cdce_reg cdce_y5_13500[] = { > > + { 0x27, 0x08 }, > > + { 0x28, 0x00 }, > > + { 0x29, 0x40 }, > > + { 0x2a, 0x02 }, > > + { 0x2b, 0x08 }, > > + { 0x24, 0x6f }, > > + { }, > > +}; > > + > > +static struct cdce_reg cdce_y5_16875[] = { > > + { 0x27, 0x08 }, > > + { 0x28, 0x9f }, > > + { 0x29, 0xb0 }, > > + { 0x2a, 0x02 }, > > + { 0x2b, 0x89 }, > > + { 0x24, 0x6f }, > > + { }, > > +}; > > + > > +static struct cdce_reg cdce_y5_27000[] = { > > + { 0x27, 0x04 }, > > + { 0x28, 0x00 }, > > + { 0x29, 0x40 }, > > + { 0x2a, 0x02 }, > > + { 0x2b, 0x08 }, > > + { 0x24, 0x6f }, > > + { }, > > +}; > > +static struct cdce_reg cdce_y5_54000[] = { > > + { 0x27, 0x04 }, > > + { 0x28, 0xff }, > > + { 0x29, 0x80 }, > > + { 0x2a, 0x02 }, > > + { 0x2b, 0x07 }, > > + { 0x24, 0x6f }, > > + { }, > > +}; > > + > > +static struct cdce_reg cdce_y5_81000[] = { > > + { 0x27, 0x02 }, > > + { 0x28, 0xbf }, > > + { 0x29, 0xa0 }, > > + { 0x2a, 0x03 }, > > + { 0x2b, 0x0a }, > > + { 0x24, 0x6f }, > > + { }, > > +}; > > + > > +static struct cdce_freq cdce_y5_freqs[] = { > > + CDCE_FREQ_TABLE_ENTRY(5, 13500), > > + CDCE_FREQ_TABLE_ENTRY(5, 16875), > > + CDCE_FREQ_TABLE_ENTRY(5, 27000), > > + CDCE_FREQ_TABLE_ENTRY(5, 54000), > > + CDCE_FREQ_TABLE_ENTRY(5, 81000), > > +}; > > + > > + > > +static struct cdce_output output_list[] = { > > + [1] = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) }, > > + [5] = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) }, > > +}; > > + > > +int cdce_set_rate(struct clk *clk, unsigned long rate) > > +{ > > + int i, ret = 0; > > + struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table; > > + struct cdce_reg *regs = NULL; > > + > > + if (!cdce_i2c_client) > > + return -ENODEV; > > + > > + if (!freq_table) > > + return -EINVAL; > > + > > + for (i = 0; i < output_list[clk->lpsc].size; i++) { > > + if (freq_table[i].frequency == rate / 1000) { > > + regs = freq_table[i].reglist; > > + break; > > + } > > + } > > + > > + if (!regs) > > + return -EINVAL; > > + > > + for (i = 0; regs[i].addr; i++) { > > + ret = i2c_smbus_write_byte_data(cdce_i2c_client, > > + regs[i].addr | 0x80, regs[i].val); > > + if (ret) > > + return ret; > > + } > > + > > + atomic_set(&clk->rate, rate); > > + > > + return 0; > > +} > > + > > +static int cdce_probe(struct i2c_client *client, > > + const struct i2c_device_id *id) > > +{ > > + cdce_i2c_client = client; > > + return 0; > > +} > > + > > +static int __devexit cdce_remove(struct i2c_client *client) > > +{ > > + cdce_i2c_client = NULL; > > + return 0; > > +} > > + > > +static const struct i2c_device_id cdce_id[] = { > > + {"cdce949", 0}, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(i2c, cdce_id); > > + > > +static struct i2c_driver cdce_driver = { > > + .driver = { > > + .owner = THIS_MODULE, > > + .name = "cdce949", > > + }, > > + .probe = cdce_probe, > > + .remove = __devexit_p(cdce_remove), > > + .id_table = cdce_id, > > +}; > > + > > +static int __init cdce_init(void) > > +{ > > + return i2c_add_driver(&cdce_driver); > > +} > > +subsys_initcall(cdce_init); > > + > > +static void __exit cdce_exit(void) > > +{ > > + i2c_del_driver(&cdce_driver); > > +} > > +module_exit(cdce_exit); > > + > > +MODULE_AUTHOR("Texas Instruments"); > > +MODULE_DESCRIPTION("CDCE949 clock synthesizer driver"); > > +MODULE_LICENSE("GPL v2"); > > diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach- > > davinci/include/mach/cdce949.h > > new file mode 100644 > > index 0000000..c73331f > > --- /dev/null > > +++ b/arch/arm/mach-davinci/include/mach/cdce949.h > > @@ -0,0 +1,19 @@ > > +/* > > + * TI CDCE949 off-chip clock synthesizer support > > + * > > + * 2009 (C) Texas Instruments, Inc. http://www.ti.com/ > > + * > > + * This file is licensed under the terms of the GNU General Public > > License > > + * version 2. This program is licensed "as is" without any warranty of > > any > > + * kind, whether express or implied. > > + */ > > +#ifndef _MACH_DAVINCI_CDCE949_H > > +#define _MACH_DAVINCI_CDCE949_H > > + > > +#include > > + > > +#include > > + > > +int cdce_set_rate(struct clk *clk, unsigned long rate); > > + > > +#endif > > -- > > 1.6.2.4 > > > > _______________________________________________ > > Davinci-linux-open-source mailing list > > Davinci-linux-open-source at linux.davincidsp.com > > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > From nsekhar at ti.com Fri Dec 4 00:44:35 2009 From: nsekhar at ti.com (Nori, Sekhar) Date: Fri, 4 Dec 2009 12:14:35 +0530 Subject: [PATCH v0 1/2] V4L - vpfe capture - convert ccdc drivers to platform drivers In-Reply-To: References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> <19F8576C6E063C45BE387C64729E7394043716AE11@dbde02.ent.ti.com> Message-ID: On Fri, Dec 04, 2009 at 01:21:43, Karicheri, Muralidharan wrote: > [...] > > > >> + if (!res) { > >> + status = -EBUSY; > >> + goto fail_nores; > >> + } > >> + > >> + ccdc_base_addr = ioremap_nocache(res->start, res_len); > >> + if (!ccdc_base_addr) { > >> + status = -EBUSY; > >[Hiremath, Vaibhav] Is -EBUSY right return value, I think it should be - > >ENXIO or -ENOMEM. > > > I see -ENXIO & -ENOMEM being used by drivers. -ENXIO stands for "No such device or address". ENOMEM stands for "Out of memory" . Since we are trying to map the address here, -ENXIO looks reasonable to me. Same if request_mem_region() fails. > Sergei had posted on this earlier[1]. Quoting him here: " > What are the proper error codes when platform_get_resource, -ENODEV. > request_mem_region -EBUSY. > and ioremap functions fail?. -ENOMEM. " Not sure if ioremap failure can relate to absence of a device. Thanks, Sekhar [1] http://www.mail-archive.com/davinci-linux-open-source at linux.davincidsp.com/msg14973.html From m-karicheri2 at ti.com Fri Dec 4 09:31:25 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Fri, 4 Dec 2009 09:31:25 -0600 Subject: [PATCH] V4L - Fix videobuf_dma_contig_user_get() getting page aligned physical address In-Reply-To: References: <1259681414-30246-1-git-send-email-m-karicheri2@ti.com> Message-ID: Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 phone: 301-407-9583 email: m-karicheri2 at ti.com >-----Original Message----- >From: Magnus Damm [mailto:magnus.damm at gmail.com] >Sent: Friday, December 04, 2009 6:06 AM >To: Karicheri, Muralidharan >Cc: linux-media at vger.kernel.org; mchehab at infradead.org; davinci-linux-open- >source at linux.davincidsp.com >Subject: Re: [PATCH] V4L - Fix videobuf_dma_contig_user_get() getting page >aligned physical address > >Hi again Murali, > >Thanks for your work on this. > >On Thu, Dec 3, 2009 at 12:48 AM, Karicheri, Muralidharan > wrote: >> Magnus, >> >>>Thanks for the patch. For non-page aligned user space pointers I agree >>>that a fix is needed. Don't you think the while loop in >>>videobuf_dma_contig_user_get() also needs to be adjusted to include >>>the last page? I think the while loop checks one page too little in >>>the non-aligned case today. >> >> Thanks for reviewing my patch. It had worked for non-aligned address in >> my testing. If I understand this code correctly, the physical address of >> the user page start is determined in the first loop (pages_done == 0) >> and additional loops are run to make sure the memory is physically >> contiguous. Initially the mem->size is set to number of pages aligned to >> page size. >> >> Assume we pass 4097 bytes as size. >> >> mem->size = PAGE_ALIGN(vb->size); => 2 >> >> Inside the loop, iteration is done for 0 to pages-1. >> >> pages_done < (mem->size >> 12) => pages_done < 2 => iterate 2 times >> >> For size of 4096, we iterate once. >> For size of 4095, we iterate once. >> >> So IMO the loop is already iterate one more time when we pass non-aligned >address since size is aligned to include the last page. So based on this >> could you ack my patch so that we could ask Mauro to merge it with >priority? > >I think your observations are correct, but I also think there is one >more hidden issue. In the case where the offset within the page is >other than 0 then we should loop once more to also check the final >page. Right now no one is checking if the last page is contiguous or >not in the case on non-page-aligned offset.. > >So in your case with a 4096 or 4095 size, but if the offset withing >the page is non-zero then we should loop twice to make sure the pages >really are physically contiguous. Today we only loop once based on the >size. We should also include the offset in the calculation of number >of pages to check. Yes. You are right. For offsets that are non-aligned we need to check for the last one. Probably unsigned int offset = vb->baddr & ~PAGE_MASK; mem->size = PAGE_ALIGN(vb->size + offset); ...... if (pages_done == 0) mem->handle = (this_pfn << PAGE_SHIFT) + offset; If this is fine, I can send you a updated patch. If you can fix it that is fine too. regards, Murali > >If you can include that fix in your patch that would be great. If not >then i'll fix it up myself. > If you could do this it will be great! >Thanks! > >/ magnus From m-karicheri2 at ti.com Fri Dec 4 17:05:28 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Fri, 4 Dec 2009 17:05:28 -0600 Subject: [PATCH v0 1/2] V4L - vpfe capture - convert ccdc drivers to platform drivers In-Reply-To: References: <1259691333-32164-1-git-send-email-m-karicheri2@ti.com> <19F8576C6E063C45BE387C64729E7394043716AE11@dbde02.ent.ti.com> Message-ID: Sekhar, >> >> + status = -EBUSY; >> >[Hiremath, Vaibhav] Is -EBUSY right return value, I think it should be - >> >ENXIO or -ENOMEM. >> > >> I see -ENXIO & -ENOMEM being used by drivers. -ENXIO stands for "No such >device or address". ENOMEM stands for "Out of memory" . Since we are trying >to map the address here, -ENXIO looks reasonable to me. Same if >request_mem_region() fails. >> > >Sergei had posted on this earlier[1]. Quoting him here: Was this his personal opinion or has he given any reference to support it? I did a grep for this in the driver directory and the result I got is in inline with Sergie's suggestion. So I am going to update the patch with these and send it again. -Murali > >" >> What are the proper error codes when platform_get_resource, > > -ENODEV. > >> request_mem_region > > -EBUSY. > >> and ioremap functions fail?. > > -ENOMEM. >" > >Not sure if ioremap failure can relate to absence of a device. > >Thanks, >Sekhar > >[1] http://www.mail-archive.com/davinci-linux-open- >source at linux.davincidsp.com/msg14973.html From m-karicheri2 at ti.com Fri Dec 4 17:12:02 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Fri, 4 Dec 2009 17:12:02 -0600 Subject: [PATCH - v0 2/2] DaVinci - vpfe capture - Make clocks configurable References: <1259687940-31435-1-git-send-email-m-karicheri2@ti.com> <1259687940-31435-2-git-send-email-m-karicheri2@ti.com> <19F8576C6E063C45BE387C64729E7394043716B186@dbde02.ent.ti.com> Message-ID: Vaibhav, Could you confirm my question below? I need to submit a patch on Monday. >>Currently we have vpfe_capture.c file (master/bridge driver) which is >>handling clk_get/put, and platform data is providing the details about it. >>Ideally we should handle it in respective ccdc driver file, since he has >>all the knowledge about required number of clocks and its name. This way >we >>don't have to maintain/pass clock information in platform data. >> >>I would appreciate any comments/thoughts/pointers here. >> >Though I agree that this clock could be set by the ccdc driver, I am not >sure if the same clock is used by an IP on different SOCs. For example take >the case of ccdc on DM6446 which is also used on OMAP 35xx SOC. Do they use >vpss master and slave clocks as is done on DM6446? If this is true, then we >could set the clock inside ccdc driver. > >Let me know so that I can re-work the patch and send it to the list. > >Murali >>Thanks, >>Vaibhav >> >>> }; >>> >>> static struct platform_device *davinci_evm_devices[] __initdata = { >>> diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c >>> b/arch/arm/mach-davinci/board-dm644x-evm.c >>> index fd0398b..45beb99 100644 >>> --- a/arch/arm/mach-davinci/board-dm644x-evm.c >>> +++ b/arch/arm/mach-davinci/board-dm644x-evm.c >>> @@ -250,6 +250,8 @@ static struct vpfe_config vpfe_cfg = { >>> .sub_devs = vpfe_sub_devs, >>> .card_name = "DM6446 EVM", >>> .ccdc = "DM6446 CCDC", >>> + .num_clocks = 2, >>> + .clocks = {"vpss_master", "vpss_slave"}, >>> }; >>> >>> static struct platform_device rtc_dev = { >>> -- >>> 1.6.0.4 From sudhakar.raj at ti.com Sun Dec 6 22:33:14 2009 From: sudhakar.raj at ti.com (Sudhakar Rajashekhara) Date: Mon, 7 Dec 2009 10:03:14 +0530 Subject: [PATCH] mtd-nand: davinci: Correct 4-bit error correction In-Reply-To: <1257244270-2433-1-git-send-email-sudhakar.raj@ti.com> References: <1257244270-2433-1-git-send-email-sudhakar.raj@ti.com> Message-ID: <001f01ca76f6$63e86f10$2bb94d30$@raj@ti.com> On Tue, Nov 03, 2009 at 16:01:10, Sudhakar Rajashekhara wrote: > On TI's DA830/OMAP-L137, DA850/OMAP-L138 and DM365, after > setting the 4BITECC_ADD_CALC_START bit in the NAND Flash > control register to 1 and before waiting for the NAND Flash > status register to be equal to 1, 2 or 3, we have to wait > till the ECC HW goes to correction state. Without this wait, > ECC correction calculations will not be proper. > > This has been tested on DA830/OMAP-L137, DA850/OMAP-L138, > DM355 and DM365 EVMs. > > Signed-off-by: Sudhakar Rajashekhara > Acked-by: Sneha Narnakaje > --- > drivers/mtd/nand/davinci_nand.c | 16 ++++++++++++++++ > 1 files changed, 16 insertions(+), 0 deletions(-) > > diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c > index fe3eba8..8a32999 100644 > --- a/drivers/mtd/nand/davinci_nand.c > +++ b/drivers/mtd/nand/davinci_nand.c [...] > + > + /* > + * ECC_STATE field reads 0x3 (Error correction complete) immediately > + * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately > + * begin trying to poll for the state, you may fall right out of your > + * loop without any of the correction calculations having taken place. > + * The recommendation from the hardware team is to wait till ECC_STATE > + * reads less than 4, which means ECC HW has entered correction state. > + */ > + do { > + ecc_state = (davinci_nand_readl(info, > + NANDFSR_OFFSET) >> 8) & 0x0f; > + cpu_relax(); > + } while (ecc_state < 4); > + Kevin, David Woodhouse has suggested to add timeout in the above loop. I'll be re-submitting this patch soon. Regards, Sudhakar From chaithrika at ti.com Mon Dec 7 03:28:53 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Mon, 7 Dec 2009 14:58:53 +0530 Subject: [PATCH 0/3] i2c: davinci: Add power management features Message-ID: <1260178136-26416-1-git-send-email-chaithrika@ti.com> Add suspend/resume and cpufreq features to DaVinci I2C driver All patches apply to Linus' kernel tree. Testing of these features was done on DA850/OMAP-L138 EVM. Chaithrika U S (3): i2c: davinci: Add helper functions i2c: davinci: Add suspend/resume support i2c: davinci: Add cpufreq support drivers/i2c/busses/i2c-davinci.c | 147 ++++++++++++++++++++++++++++++++----- 1 files changed, 127 insertions(+), 20 deletions(-) From chaithrika at ti.com Mon Dec 7 03:28:55 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Mon, 7 Dec 2009 14:58:55 +0530 Subject: [PATCH 2/3] i2c: davinci: Add suspend/resume support In-Reply-To: <1260178136-26416-2-git-send-email-chaithrika@ti.com> References: <1260178136-26416-1-git-send-email-chaithrika@ti.com> <1260178136-26416-2-git-send-email-chaithrika@ti.com> Message-ID: <1260178136-26416-3-git-send-email-chaithrika@ti.com> Add suspend and resume callbacks to DaVinci I2C driver. This has been tested on DA850/OMAP-L138 EVM. The SoC specific suspend-to-RAM support patch series [1] is needed to test this feature. [1] http://linux.davincidsp.com/pipermail/davinci-linux-open-source/ 2009-November/016958.html Signed-off-by: Chaithrika U S --- drivers/i2c/busses/i2c-davinci.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 5f3838c..5f0888d 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -623,6 +623,36 @@ static int davinci_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int davinci_i2c_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + + /* put I2C into reset */ + davinci_i2c_reset_ctrl(dev, 0); + + clk_disable(dev->clk); + + return 0; +} + +static int davinci_i2c_resume(struct platform_device *pdev) +{ + struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + + clk_enable(dev->clk); + + /* take I2C out of reset */ + davinci_i2c_reset_ctrl(dev, 1); + + return 0; +} + +#else +#define davinci_i2c_suspend NULL +#define davinci_i2c_resume NULL +#endif + /* work with hotplug and coldplug */ MODULE_ALIAS("platform:i2c_davinci"); @@ -633,6 +663,8 @@ static struct platform_driver davinci_i2c_driver = { .name = "i2c_davinci", .owner = THIS_MODULE, }, + .suspend = davinci_i2c_suspend, + .resume = davinci_i2c_resume, }; /* I2C may be needed to bring up other drivers */ -- 1.5.6 From chaithrika at ti.com Mon Dec 7 03:28:56 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Mon, 7 Dec 2009 14:58:56 +0530 Subject: [PATCH 3/3] i2c: davinci: Add cpufreq support In-Reply-To: <1260178136-26416-3-git-send-email-chaithrika@ti.com> References: <1260178136-26416-1-git-send-email-chaithrika@ti.com> <1260178136-26416-2-git-send-email-chaithrika@ti.com> <1260178136-26416-3-git-send-email-chaithrika@ti.com> Message-ID: <1260178136-26416-4-git-send-email-chaithrika@ti.com> Add cpufreq support for DaVinci I2C driver. Tested on DA850/OMAP-L138 EVM. For the purpose of testing, the patches which add cpufreq support [1] for this SoC are needed. [1]http://linux.davincidsp.com/pipermail/davinci-linux-open-source/ 2009-September/016118.html Signed-off-by: Chaithrika U S --- drivers/i2c/busses/i2c-davinci.c | 59 +++++++++++++++++++++++++++++++++++++- 1 files changed, 58 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 5f0888d..0f41da4 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -35,9 +35,9 @@ #include #include #include +#include #include - #include /* ----- global defines ----------------------------------------------- */ @@ -114,6 +114,10 @@ struct davinci_i2c_dev { int irq; u8 terminate; struct i2c_adapter adapter; +#ifdef CONFIG_CPU_FREQ + struct completion xfr_complete; + struct notifier_block freq_transition; +#endif }; /* default platform data to use if not supplied in the platform_device */ @@ -384,6 +388,11 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (ret < 0) return ret; } + +#ifdef CONFIG_CPU_FREQ + complete(&dev->xfr_complete); +#endif + return num; } @@ -508,6 +517,39 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) return count ? IRQ_HANDLED : IRQ_NONE; } +#ifdef CONFIG_CPU_FREQ +static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct davinci_i2c_dev *dev; + + dev = container_of(nb, struct davinci_i2c_dev, freq_transition); + if (val == CPUFREQ_PRECHANGE) { + wait_for_completion(&dev->xfr_complete); + davinci_i2c_reset_ctrl(dev, 0); + } else if (val == CPUFREQ_POSTCHANGE) { + i2c_davinci_calc_clk_dividers(dev); + davinci_i2c_reset_ctrl(dev, 1); + } + + return 0; +} + +static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev) +{ + dev->freq_transition.notifier_call = i2c_davinci_cpufreq_transition; + + return cpufreq_register_notifier(&dev->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev) +{ + cpufreq_unregister_notifier(&dev->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} +#endif + static struct i2c_algorithm i2c_davinci_algo = { .master_xfer = i2c_davinci_xfer, .functionality = i2c_davinci_func, @@ -547,6 +589,9 @@ static int davinci_i2c_probe(struct platform_device *pdev) } init_completion(&dev->cmd_complete); +#ifdef CONFIG_CPU_FREQ + init_completion(&dev->xfr_complete); +#endif dev->dev = get_device(&pdev->dev); dev->irq = irq->start; platform_set_drvdata(pdev, dev); @@ -567,6 +612,14 @@ static int davinci_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } +#ifdef CONFIG_CPU_FREQ + r = i2c_davinci_cpufreq_register(dev); + if (r) { + dev_err(&pdev->dev, "failed to register cpufreq\n"); + goto err_free_irq; + } +#endif + adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; @@ -606,6 +659,10 @@ static int davinci_i2c_remove(struct platform_device *pdev) struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; +#ifdef CONFIG_CPU_FREQ + i2c_davinci_cpufreq_deregister(dev); +#endif + platform_set_drvdata(pdev, NULL); i2c_del_adapter(&dev->adapter); put_device(&pdev->dev); -- 1.5.6 From chaithrika at ti.com Mon Dec 7 03:28:54 2009 From: chaithrika at ti.com (Chaithrika U S) Date: Mon, 7 Dec 2009 14:58:54 +0530 Subject: [PATCH 1/3] i2c: davinci: Add helper functions In-Reply-To: <1260178136-26416-1-git-send-email-chaithrika@ti.com> References: <1260178136-26416-1-git-send-email-chaithrika@ti.com> Message-ID: <1260178136-26416-2-git-send-email-chaithrika@ti.com> Add i2c reset control and clock divider calculation functions which will be useful for power management features. Signed-off-by: Chaithrika U S --- drivers/i2c/busses/i2c-davinci.c | 56 +++++++++++++++++++++++++------------- 1 files changed, 37 insertions(+), 19 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index c89687a..5f3838c 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -133,12 +133,21 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg) return __raw_readw(i2c_dev->base + reg); } -/* - * This functions configures I2C and brings I2C out of reset. - * This function is called during I2C init function. This function - * also gets called if I2C encounters any errors. - */ -static int i2c_davinci_init(struct davinci_i2c_dev *dev) +static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, + int val) +{ + u16 w; + + w = davinci_i2c_read_reg(i2c_dev, DAVINCI_I2C_MDR_REG); + if (!val) /* put I2C into reset */ + MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0); + else /* take I2C out of reset */ + MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1); + + davinci_i2c_write_reg(i2c_dev, DAVINCI_I2C_MDR_REG, w); +} + +static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) { struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; u16 psc; @@ -147,15 +156,6 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) u32 clkh; u32 clkl; u32 input_clock = clk_get_rate(dev->clk); - u16 w; - - if (!pdata) - pdata = &davinci_i2c_platform_data_default; - - /* put I2C into reset */ - w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); - MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0); - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); /* NOTE: I2C Clock divider programming info * As per I2C specs the following formulas provide prescaler @@ -187,12 +187,32 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh); davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl); + dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk); +} + +/* + * This functions configures I2C and brings I2C out of reset. + * This function is called during I2C init function. This function + * also gets called if I2C encounters any errors. + */ +static int i2c_davinci_init(struct davinci_i2c_dev *dev) +{ + struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + + if (!pdata) + pdata = &davinci_i2c_platform_data_default; + + /* put I2C into reset */ + davinci_i2c_reset_ctrl(dev, 0); + + /* compute clock dividers */ + i2c_davinci_calc_clk_dividers(dev); + /* Respond at reserved "SMBus Host" slave address" (and zero); * we seem to have no option to not respond... */ davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08); - dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk); dev_dbg(dev->dev, "PSC = %d\n", davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG)); dev_dbg(dev->dev, "CLKL = %d\n", @@ -203,9 +223,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) pdata->bus_freq, pdata->bus_delay); /* Take the I2C module out of reset: */ - w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); - MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1); - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); + davinci_i2c_reset_ctrl(dev, 1); /* Enable interrupts */ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL); -- 1.5.6 From snunez at ridgerun.com Mon Dec 7 14:14:43 2009 From: snunez at ridgerun.com (Santiago Nunez-Corrales) Date: Mon, 07 Dec 2009 14:14:43 -0600 Subject: [PATCH 0/4 v11] Support for TVP7002 in DM365 In-Reply-To: <4B13E9EB.8020309@ridgerun.com> References: <4B13E9EB.8020309@ridgerun.com> Message-ID: <4B1D6233.1040704@ridgerun.com> Hans, Hi. Have you had a chance to look at this version of the driver? Regards, Santiago. Santiago Nunez-Corrales wrote: > This series of patches provide support for the TVP7002 decoder in DM365. > > Support includes: > > * Inclusion of the chip in v4l2 definitions > * Definition of TVP7002 specific data structures > * Kconfig and Makefile support > > This series corrects many issued pointed out by Snehaprabha Narnakaje, > Muralidharan Karicheri, Vaibhav Hiremath and Hans Verkuil and solves > testing problems. Tested on DM365 TI EVM with resolutions 720p, > 1080i at 60, 576P and 480P with video capture application and video > output in 480P, 576P, 720P and 1080I. This driver depends upon > board-dm365-evm.c and vpfe_capture.c to be ready for complete > integration. Uses the new V4L2 DV API sent by Muralidharan Karicheri. > Removed shadow register values. Removed unnecesary power down and up > of the device (tests work fine). Improved readability. > > -- Santiago Nunez-Corrales, Eng. RidgeRun Engineering, LLC Guayabos, Curridabat San Jose, Costa Rica +(506) 2271 1487 +(506) 8313 0536 http://www.ridgerun.com From s-paulraj at ti.com Mon Dec 7 14:23:30 2009 From: s-paulraj at ti.com (Paulraj, Sandeep) Date: Mon, 7 Dec 2009 14:23:30 -0600 Subject: [PATCH 1/2] DM6446 DMSoC SPI driver In-Reply-To: References: Message-ID: <0554BEF07D437848AF01B9C9B5F0BC5D94818773@dlee01.ent.ti.com> Will, Use this tree http://arago-project.org/git/people/?p=sneha/linux-davinci-staging.git;a=shortlog It has the SPI driver which has been tested on multiple SOC's. On the DM365 multiple slaves have also been tested. You will need to add support for SPI for DM6446. The reason we have not added it is because the DM6446 EVM does not have anything connected to SPI so even if we add, we cannot test. You can refer the DM355 and DM365 patches to add support. If you are trying to interface a SPI FLASH maybe this page can help as well. http://wiki.davincidsp.com/index.php/SPI_flash_boot_and_flashing_tool_for_DM365 Thanks, Sandeep ________________________________ From: Will Berry [mailto:Will.Berry at mediwatch.com] Sent: Monday, December 07, 2009 12:13 PM To: davinci-linux-open-source at linux.davincidsp.com; Paulraj, Sandeep Subject: [PATCH 1/2] DM6446 DMSoC SPI driver Hi Sandeep, I've been after a SPI driver for my DM6446 / DaVinci DVEVM board. I was hoping something would have been merged into the DaVinci Open Source Linux but v2.6.31 doesn't appear to have spidev support that works. Is there a SPI driver available somewhere? Am I just using the open source kernel incorrectly? Thanks for taking to time to read this. All help greatly appreciated. Will. -------------- next part -------------- An HTML attachment was scrubbed... URL: From m-karicheri2 at ti.com Mon Dec 7 14:58:48 2009 From: m-karicheri2 at ti.com (Karicheri, Muralidharan) Date: Mon, 7 Dec 2009 14:58:48 -0600 Subject: [PATCH 1/5 - v0] V4L-vpfe capture - adding CCDC driver for DM365 In-Reply-To: References: <1259703533-1789-1-git-send-email-m-karicheri2@ti.com> Message-ID: Sekhar, > >Hi Murali, > >Here is a (styling related) review from an non-video person. The [MK] The styling was mostly done by one of our intern who is new to open source coding. So I will fix it based on your comments. >review is neither complete nor exhaustive (the patch is huge!), >but I thought will send across whatever I have for you to take a look. > [MK] Yes Sure! >On Wed, Dec 02, 2009 at 03:08:49, Karicheri, Muralidharan wrote: >> From: Muralidharan Karicheri >> >> This patch is for adding support for DM365 CCDC. This will allow to >> capture YUV video frames from TVP5146 video decoder on DM365 EVM. The >vpfe >> capture driver will use this module to configure ISIF (a.k.a CCDC) >> module to allow YUV data capture. This driver is written for >ccdc_hw_device >> interface used by vpfe capture driver to configure the ccdc module. >> This patch is tested using NTSC & PAL video sources and verified for >> both formats. >> >> NOTE: This is the initial version for review. > >Typically "RFC" is put instead of "PATCH" in subject line >to convey this. [MK] IMO, RFC is for something that is a proposal to make some changes in the architecture/implementation to get feedback from the reviewers. But here it is a real code that is being reviewed. I just mentioned it to make sure no body complains that it doesn't apply to the latest tree :). This is based on what I see in the mailing list. > >> >> Signed-off-by: Muralidharan Karicheri >> --- >> drivers/media/video/davinci/dm365_ccdc.c | 1529 >+++++++++++++++++++++++++ >> drivers/media/video/davinci/dm365_ccdc_regs.h | 293 +++++ >> include/media/davinci/dm365_ccdc.h | 555 +++++++++ >> 3 files changed, 2377 insertions(+), 0 deletions(-) >> create mode 100644 drivers/media/video/davinci/dm365_ccdc.c >> create mode 100644 drivers/media/video/davinci/dm365_ccdc_regs.h >> create mode 100644 include/media/davinci/dm365_ccdc.h >> >> diff --git a/drivers/media/video/davinci/dm365_ccdc.c >b/drivers/media/video/davinci/dm365_ccdc.c > >Hopefully it is possible to choose a "generic" name >instead of tying it to an SoC. > [MK]I agree there is problem here. For example, we have same ccdc IP used across DM6446, OMAP34xx and Sitara (earlier Shiva). We have it named currently as dm644x_ccdc.c. I have checked the DM6446 and OMAP34xx PRG and finds that CCDC IP has a Peripheral identification (TID) and class identification (CID). For OMAP & DM6446, they have the same values. So We might be able to rename them as ccdc_.c. But for CCDC on DM355, we don't have a PID/CID for ccdc. So how do we name it? I don't see a uniform way we can name the driver for these IPs. Probably change dm365_ccdc.c to isif.c since that is the IP name on DM365. ISIF stands for Image Sensor Interface. >> new file mode 100644 >> index 0000000..2f27696 >> --- /dev/null >> +++ b/drivers/media/video/davinci/dm365_ccdc.c >> @@ -0,0 +1,1529 @@ > >[...] > >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include "dm365_ccdc_regs.h" >> +#include "ccdc_hw_device.h" > >Typically the includes are grouped using empty lines >based on the folder "linux", "media" "mach" etc. > [MK]This is not strictly followed in the community, But I think it is good to do this for better readability. >> + >> +static struct device *dev; >> + >> +/* Defauts for module configuation paramaters */ >> +static struct ccdc_config_params_raw ccdc_config_defaults = { >> + .linearize = { >> + .en = 0, >> + .corr_shft = CCDC_NO_SHIFT, >> + .scale_fact = {1, 0}, >> + }, >> + .df_csc = { >> + .df_or_csc = 0, >> + .csc = { >> + .en = 0 > >Should use ',' at the end of line so adding >new members leads to adding just one line. >There are more of these in this static init >below. > [MK] Ok. >> + }, >> + }, >> + .dfc = { >> + .en = 0 >> + }, >> + .bclamp = { >> + .en = 0 >> + }, >> + .gain_offset = { >> + .gain = { >> + .r_ye = {1, 0}, >> + .gr_cy = {1, 0}, >> + .gb_g = {1, 0}, >> + .b_mg = {1, 0}, >> + }, >> + }, >> + .culling = { >> + .hcpat_odd = 0xff, >> + .hcpat_even = 0xff, >> + .vcpat = 0xff >> + }, >> + .compress = { >> + .alg = CCDC_ALAW, >> + }, >> +}; >> + >> +/* ISIF operation configuration */ >> +struct ccdc_oper_config { >> + enum vpfe_hw_if_type if_type; >> + struct ccdc_ycbcr_config ycbcr; >> + struct ccdc_params_raw bayer; >> + enum ccdc_data_pack data_pack; >> + void *__iomem base_addr; >> + void *__iomem linear_tbl0_addr; >> + void *__iomem linear_tbl1_addr; > >Usually it is void __iomem *foo; [MK] Correct. > >> +}; >> + >> +static struct ccdc_oper_config ccdc_cfg = { >> + .ycbcr = { >> + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, >> + .frm_fmt = CCDC_FRMFMT_INTERLACED, >> + .win = CCDC_WIN_NTSC, >> + .fid_pol = VPFE_PINPOL_POSITIVE, >> + .vd_pol = VPFE_PINPOL_POSITIVE, >> + .hd_pol = VPFE_PINPOL_POSITIVE, >> + .pix_order = CCDC_PIXORDER_CBYCRY, >> + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, >> + }, >> + .bayer = { >> + .pix_fmt = CCDC_PIXFMT_RAW, >> + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, >> + .win = CCDC_WIN_VGA, >> + .fid_pol = VPFE_PINPOL_POSITIVE, >> + .vd_pol = VPFE_PINPOL_POSITIVE, >> + .hd_pol = VPFE_PINPOL_POSITIVE, >> + .gain = { >> + .r_ye = {1, 0}, >> + .gr_cy = {1, 0}, >> + .gb_g = {1, 0}, >> + .b_mg = {1, 0}, >> + }, >> + .cfa_pat = CCDC_CFA_PAT_MOSAIC, >> + .data_msb = CCDC_BIT_MSB_11, >> + .config_params = { >> + .data_shift = CCDC_NO_SHIFT, >> + .col_pat_field0 = { >> + .olop = CCDC_GREEN_BLUE, >> + .olep = CCDC_BLUE, >> + .elop = CCDC_RED, >> + .elep = CCDC_GREEN_RED, >> + }, >> + .col_pat_field1 = { >> + .olop = CCDC_GREEN_BLUE, >> + .olep = CCDC_BLUE, >> + .elop = CCDC_RED, >> + .elep = CCDC_GREEN_RED, >> + }, >> + .test_pat_gen = 0, >> + }, >> + }, >> + .data_pack = CCDC_DATA_PACK8, >> +}; >> + >> +/* Raw Bayer formats */ >> +static u32 ccdc_raw_bayer_pix_formats[] = >> + {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; >> + >> +/* Raw YUV formats */ >> +static u32 ccdc_raw_yuv_pix_formats[] = >> + {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; >> + >> +/* register access routines */ >> +static inline u32 regr(u32 offset) >> +{ >> + return __raw_readl(ccdc_cfg.base_addr + offset); >> +} >> + >> +static inline void regw(u32 val, u32 offset) >> +{ >> + __raw_writel(val, ccdc_cfg.base_addr + offset); >> +} >> + >> +static inline u32 ccdc_merge(u32 mask, u32 val, u32 offset) > >"merge" was not intuitive until I read the implementation. >How about "modify" (as used in arch/arm/mach-davinci/dma.c)? Merge sounds okay to me. Besides, it is within the same file. So not difficult to check what the function does. I will add a function header. > >> +{ >> + u32 new_val = (regr(offset) & ~mask) | (val & mask); >> + >> + regw(new_val, offset); >> + return new_val; >> +} >> + >> +static inline void regw_lin_tbl(u32 val, u32 offset, int i) >> +{ >> + if (!i) >> + __raw_writel(val, ccdc_cfg.linear_tbl0_addr + offset); >> + else >> + __raw_writel(val, ccdc_cfg.linear_tbl1_addr + offset); >> +} >> + >> +static void ccdc_disable_all_modules(void) >> +{ >> + /* disable BC */ >> + regw(0, CLAMPCFG); >> + /* disable vdfc */ >> + regw(0, DFCCTL); >> + /* disable CSC */ >> + regw(0, CSCCTL); >> + /* disable linearization */ >> + regw(0, LINCFG0); >> + /* disable other modules here as they are supported */ >> +} >> + >> +static void ccdc_enable(int en) >> +{ >> + if (!en) { >> + /* Before disable isif, disable all ISIF modules */ > >Could you use ccdc instead of isif in the comments too? If name of the file to be changed, then I will rename all functions to isif_ and comments will reflect the same. > >> + ccdc_disable_all_modules(); >> + /** >> + * wait for next VD. Assume lowest scan rate is 12 Hz. So >> + * 100 msec delay is good enough >> + */ >> + } > >The comment explaining the msleep seems mis-placed. > [MK] Ok. >> + msleep(100); >> + ccdc_merge(CCDC_SYNCEN_VDHDEN_MASK, en, SYNCEN); >> +} >> + >> +static void ccdc_enable_output_to_sdram(int en) >> +{ >> + ccdc_merge(CCDC_SYNCEN_WEN_MASK, en << CCDC_SYNCEN_WEN_SHIFT, >SYNCEN); >> +} >> + >> +static void ccdc_config_culling(struct ccdc_cul *cul) >> +{ >> + u32 val; >> + >> + /* Horizontal pattern */ >> + val = (cul->hcpat_even) << CULL_PAT_EVEN_LINE_SHIFT; > >No need of parenthesis. [MK] Correct. > >> + val |= cul->hcpat_odd; >> + regw(val, CULH); >> + >> + /* vertical pattern */ >> + regw(cul->vcpat, CULV); >> + >> + /* LPF */ >> + ccdc_merge((CCDC_LPF_MASK << CCDC_LPF_SHIFT), >> + (cul->en_lpf << CCDC_LPF_SHIFT), MODESET); > >.. ditto .. > [MK] Ok. >> +} >> + >> +static void ccdc_config_gain_offset(void) >> +{ >> + struct ccdc_gain_offsets_adj *gain_off_ptr = >> + &ccdc_cfg.bayer.config_params.gain_offset; >> + u32 val; >> + >> + val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) | >> + ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) | >> + ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) | >> + ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) | >> + ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) | >> + ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT); > >I think the intent here is to convert an arbitrary >gain_off_ptr->foo to 0 or 1. In that case you can >use !!gain_off_ptr->foo > [MK] That is a good idea ! >> + >> + ccdc_merge(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); >> + >> + val = ((gain_off_ptr->gain.r_ye.integer & GAIN_INTEGER_MASK) >> + << GAIN_INTEGER_SHIFT); >> + val |= (ccdc_cfg.bayer. >> + config_params.gain_offset.gain.r_ye.decimal & >> + GAIN_DECIMAL_MASK); >> + regw(val, CRGAIN); >> + >> + val = ((gain_off_ptr->gain.gr_cy >> + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); >> + val |= (gain_off_ptr->gain.gr_cy >> + .decimal & GAIN_DECIMAL_MASK); >> + regw(val, CGRGAIN); >> + >> + val = ((gain_off_ptr->gain.gb_g >> + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); >> + val |= (gain_off_ptr->gain.gb_g >> + .decimal & GAIN_DECIMAL_MASK); >> + regw(val, CGBGAIN); >> + >> + val = ((gain_off_ptr->gain.b_mg >> + .integer & GAIN_INTEGER_MASK) << GAIN_INTEGER_SHIFT); >> + val |= (gain_off_ptr->gain.b_mg >> + .decimal & GAIN_DECIMAL_MASK); > >Breaking the line at the . is making reading difficult. >Can you break at '<<' instead? > [MK] Correct. >> + regw(val, CBGAIN); >> + >> + regw((gain_off_ptr->offset & >> + OFFSET_MASK), COFSTA); > >Not sure if we really need to break here. Are you hitting >the 80 char limit even here? > [MK] Looks unnecessary >> +} >> + >> +static void ccdc_restore_defaults(void) >> +{ >> + enum vpss_ccdc_source_sel source = VPSS_CCDCIN; >> + int i; >> + >> + memcpy(&ccdc_cfg.bayer.config_params, &ccdc_config_defaults, >> + sizeof(struct ccdc_config_params_raw)); >> + >> + dev_dbg(dev, "\nstarting ccdc_restore_defaults..."); >> + /* Enable clock to ISIF, IPIPEIF and BL */ >> + vpss_enable_clock(VPSS_CCDC_CLOCK, 1); >> + vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); >> + vpss_enable_clock(VPSS_BL_CLOCK, 1); >> + >> + /* set all registers to default value */ >> + for (i = 0; i <= 0x1f8; i += 4) >> + regw(0, i); > >Hmm, something like this is not usually expected. >You would anyway be programming all the relevant >registers again. So, why is this required? > [MK] Will investigate if this can be removed. I think the implementation assumes that all register values are restored to default. >> + >> + /* no culling support */ >> + regw(0xffff, CULH); >> + regw(0xff, CULV); >> + >> + /* Set default offset and gain */ >> + ccdc_config_gain_offset(); >> + >> + vpss_select_ccdc_source(source); >> + >> + dev_dbg(dev, "\nEnd of ccdc_restore_defaults..."); >> +} >> + >> +static int ccdc_open(struct device *device) >> +{ >> + dev = device; >> + ccdc_restore_defaults(); >> + return 0; >> +} >> + >> +/* This function will configure the window size to be capture in CCDC >reg */ >> +static void ccdc_setwin(struct v4l2_rect *image_win, >> + enum ccdc_frmfmt frm_fmt, int ppc) >> +{ >> + int horz_start, horz_nr_pixels; >> + int vert_start, vert_nr_lines; >> + int mid_img = 0; >> + >> + dev_dbg(dev, "\nStarting ccdc_setwin..."); >> + /** >> + * ppc - per pixel count. indicates how many pixels per cell > >Kernel doc style comments are only useful for >API description, I guess. [MK] yes. Will change > >> + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. >> + * raw capture this is 1 >> + */ >> + horz_start = image_win->left << (ppc - 1); >> + horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; >> + >> + /* Writing the horizontal info into the registers */ >> + regw(horz_start & START_PX_HOR_MASK, SPH); >> + regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); >> + vert_start = image_win->top; >> + >> + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { >> + vert_nr_lines = (image_win->height >> 1) - 1; >> + vert_start >>= 1; >> + /* To account for VD since line 0 doesn't have any data */ >> + vert_start += 1; >> + } else { >> + /* To account for VD since line 0 doesn't have any data */ >> + vert_start += 1; >> + vert_nr_lines = image_win->height - 1; >> + /* configure VDINT0 and VDINT1 */ >> + mid_img = vert_start + (image_win->height / 2); >> + regw(mid_img, VDINT1); >> + } >> + >> + regw(0, VDINT0); >> + regw(vert_start & START_VER_ONE_MASK, SLV0); >> + regw(vert_start & START_VER_TWO_MASK, SLV1); >> + regw(vert_nr_lines & NUM_LINES_VER, LNV); >> +} >> + >> +static void ccdc_config_bclamp(struct ccdc_black_clamp *bc) >> +{ >> + u32 val; >> + >> + /** >> + * DC Offset is always added to image data irrespective of bc enable >> + * status >> + */ > >.. ditto .. [MK] Will change > >> + val = bc->dc_offset & CCDC_BC_DCOFFSET_MASK; >> + regw(val, CLDCOFST); >> + >> + if (bc->en) { >> + val = (bc->bc_mode_color & CCDC_BC_MODE_COLOR_MASK) << >> + CCDC_BC_MODE_COLOR_SHIFT; >> + >> + /* Enable BC and horizontal clamp caculation paramaters */ >> + val = val | 1 | ((bc->horz.mode & CCDC_HORZ_BC_MODE_MASK) << >> + CCDC_HORZ_BC_MODE_SHIFT); >> + >> + regw(val, CLAMPCFG); >> + >> + if (bc->horz.mode != CCDC_HORZ_BC_DISABLE) { >> + /** >> + * Window count for calculation >> + * Base window selection >> + * pixel limit >> + * Horizontal size of window >> + * vertical size of the window >> + * Horizontal start position of the window >> + * Vertical start position of the window >> + */ >> + val = (bc->horz.win_count_calc & >> + CCDC_HORZ_BC_WIN_COUNT_MASK) | >> + ((bc->horz.base_win_sel_calc & 1) >> + << CCDC_HORZ_BC_WIN_SEL_SHIFT) | >> + ((bc->horz.clamp_pix_limit & 1) >> + << CCDC_HORZ_BC_PIX_LIMIT_SHIFT) | >> + ((bc->horz.win_h_sz_calc & >> + CCDC_HORZ_BC_WIN_H_SIZE_MASK) >> + << CCDC_HORZ_BC_WIN_H_SIZE_SHIFT) | >> + ((bc->horz.win_v_sz_calc & >> + CCDC_HORZ_BC_WIN_V_SIZE_MASK) >> + << CCDC_HORZ_BC_WIN_V_SIZE_SHIFT); >> + >> + regw(val, CLHWIN0); >> + >> + val = (bc->horz.win_start_h_calc & >> + CCDC_HORZ_BC_WIN_START_H_MASK); >> + regw(val, CLHWIN1); >> + >> + val = >> + (bc->horz. >> + win_start_v_calc & CCDC_HORZ_BC_WIN_START_V_MASK); > >Too much broken line. Suggest breaking at & instead. > [MK] Ok. >> + regw(val, CLHWIN2); >> + } >> + >> + /* vertical clamp caculation paramaters */ >> + >> + /* OB H Valid */ >> + val = (bc->vert.ob_h_sz_calc & CCDC_VERT_BC_OB_H_SZ_MASK); >> + >> + /* Reset clamp value sel for previous line */ >> + val |= ((bc->vert.reset_val_sel & >> + CCDC_VERT_BC_RST_VAL_SEL_MASK) >> + << CCDC_VERT_BC_RST_VAL_SEL_SHIFT); >> + >> + /* Line average coefficient */ >> + val |= (bc->vert.line_ave_coef << >> + CCDC_VERT_BC_LINE_AVE_COEF_SHIFT); >> + regw(val, CLVWIN0); >> + >> + /* Configured reset value */ >> + if (bc->vert.reset_val_sel == >> + CCDC_VERT_BC_USE_CONFIG_CLAMP_VAL) { >> + val = >> + (bc->vert. >> + reset_clamp_val & CCDC_VERT_BC_RST_VAL_MASK); > >.. ditto .. There are other places in the patch >where line breaks needs revisit. [MK] Ok. > >> + regw(val, CLVRV); >> + } >> + >> + /* Optical Black horizontal start position */ >> + val = (bc->vert.ob_start_h & CCDC_VERT_BC_OB_START_HORZ_MASK); >> + regw(val, CLVWIN1); >> + >> + /* Optical Black vertical start position */ >> + val = (bc->vert.ob_start_v & CCDC_VERT_BC_OB_START_VERT_MASK); >> + regw(val, CLVWIN2); >> + >> + val = (bc->vert.ob_v_sz_calc & CCDC_VERT_BC_OB_VERT_SZ_MASK); >> + regw(val, CLVWIN3); >> + >> + /* Vertical start position for BC subtraction */ >> + val = (bc->vert_start_sub & CCDC_BC_VERT_START_SUB_V_MASK); >> + regw(val, CLSV); >> + } >> +} >> + >> +static void ccdc_config_linearization(struct ccdc_linearize *linearize) >> +{ >> + u32 val, i; >> + if (!linearize->en) { > >Typically an empty line is used after variable >declarations. > [MK] Ok. >> + regw(0, LINCFG0); >> + return; >> + } >> + >> + /* shift value for correction */ >> + val = (linearize->corr_shft & CCDC_LIN_CORRSFT_MASK) >> + << CCDC_LIN_CORRSFT_SHIFT; >> + /* enable */ >> + val |= 1; >> + regw(val, LINCFG0); >> + >> + /* Scale factor */ >> + val = (linearize->scale_fact.integer & 1) >> + << CCDC_LIN_SCALE_FACT_INTEG_SHIFT; >> + val |= (linearize->scale_fact.decimal & >> + CCDC_LIN_SCALE_FACT_DECIMAL_MASK); >> + regw(val, LINCFG1); >> + >> + for (i = 0; i < CCDC_LINEAR_TAB_SIZE; i++) { >> + val = linearize->table[i] & CCDC_LIN_ENTRY_MASK; >> + if (i%2) >> + regw_lin_tbl(val, ((i >> 1) << 2), 1); >> + else >> + regw_lin_tbl(val, ((i >> 1) << 2), 0); >> + } >> +} >> + >> +static void ccdc_config_dfc(struct ccdc_dfc *vdfc) >> +{ >> +#define DFC_WRITE_WAIT_COUNT 1000 >> + u32 val, count = DFC_WRITE_WAIT_COUNT; >> + int i; >> + >> + if (!vdfc->en) >> + return; >> + >> + /* Correction mode */ >> + val = ((vdfc->corr_mode & CCDC_VDFC_CORR_MOD_MASK) >> + << CCDC_VDFC_CORR_MOD_SHIFT); >> + >> + /* Correct whole line or partial */ >> + if (vdfc->corr_whole_line) >> + val |= 1 << CCDC_VDFC_CORR_WHOLE_LN_SHIFT; >> + >> + /* level shift value */ >> + val |= (vdfc->def_level_shift & CCDC_VDFC_LEVEL_SHFT_MASK) << >> + CCDC_VDFC_LEVEL_SHFT_SHIFT; >> + >> + regw(val, DFCCTL); >> + >> + /* Defect saturation level */ >> + val = vdfc->def_sat_level & CCDC_VDFC_SAT_LEVEL_MASK; >> + regw(val, VDFSATLV); >> + >> + regw(vdfc->table[0].pos_vert & CCDC_VDFC_POS_MASK, DFCMEM0); >> + regw(vdfc->table[0].pos_horz & CCDC_VDFC_POS_MASK, DFCMEM1); >> + if (vdfc->corr_mode == CCDC_VDFC_NORMAL || >> + vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) { >> + regw(vdfc->table[0].level_at_pos, DFCMEM2); >> + regw(vdfc->table[0].level_up_pixels, DFCMEM3); >> + regw(vdfc->table[0].level_low_pixels, DFCMEM4); >> + } >> + >> + val = regr(DFCMEMCTL); >> + /* set DFCMARST and set DFCMWR */ >> + val |= 1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT; >> + val |= 1; >> + regw(val, DFCMEMCTL); >> + >> + while (count && (regr(DFCMEMCTL) & 0x01)) >> + count--; > >This is CPU speed dependent. Suggest using udelay() >or loops_per_jiffy instead. > [MK] will investigate. >> + >> + val = regr(DFCMEMCTL); >> + if (!count) { >> + dev_dbg(dev, "defect table write timeout !!!\n"); >> + return; >> + } >> + >> + for (i = 1; i < vdfc->num_vdefects; i++) { >> + regw(vdfc->table[i].pos_vert & CCDC_VDFC_POS_MASK, >> + DFCMEM0); >> + regw(vdfc->table[i].pos_horz & CCDC_VDFC_POS_MASK, >> + DFCMEM1); >> + if (vdfc->corr_mode == CCDC_VDFC_NORMAL || >> + vdfc->corr_mode == CCDC_VDFC_HORZ_INTERPOL_IF_SAT) { >> + regw(vdfc->table[i].level_at_pos, DFCMEM2); >> + regw(vdfc->table[i].level_up_pixels, DFCMEM3); >> + regw(vdfc->table[i].level_low_pixels, DFCMEM4); >> + } >> + val = regr(DFCMEMCTL); >> + /* clear DFCMARST and set DFCMWR */ >> + val &= ~(1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT); > >Could use BIT(x) here. [MK] Will check > >> + val |= 1; >> + regw(val, DFCMEMCTL); >> + >> + count = DFC_WRITE_WAIT_COUNT; >> + while (count && (regr(DFCMEMCTL) & 0x01)) >> + count--; >> + >> + val = regr(DFCMEMCTL); >> + if (!count) { >> + dev_err(dev, "defect table write timeout !!!\n"); >> + return; >> + } >> + } >> + if (vdfc->num_vdefects < CCDC_VDFC_TABLE_SIZE) { >> + /* Extra cycle needed */ >> + regw(0, DFCMEM0); >> + regw(0x1FFF, DFCMEM1); >> + val = 1; >> + regw(val, DFCMEMCTL); >> + } >> + >> + /* enable VDFC */ >> + ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (1 << CCDC_VDFC_EN_SHIFT), >> + DFCCTL); >> + >> + ccdc_merge((1 << CCDC_VDFC_EN_SHIFT), (0 << CCDC_VDFC_EN_SHIFT), >> + DFCCTL); >> + >> + regw(0x6, DFCMEMCTL); >> + for (i = 0 ; i < vdfc->num_vdefects; i++) { >> + count = DFC_WRITE_WAIT_COUNT; >> + while (count && (regr(DFCMEMCTL) & 0x2)) >> + count--; >> + >> + val = regr(DFCMEMCTL); >> + if (!count) { >> + dev_err(dev, "defect table write timeout !!!\n"); >> + return; >> + } >> + >> + val = regr(DFCMEM0) | regr(DFCMEM1) | regr(DFCMEM2) | >> + regr(DFCMEM3) | regr(DFCMEM4); >> + regw(0x2, DFCMEMCTL); >> + } >> +} >> + > >[...] > >> + >> +static int ccdc_config_raw(void) >> +{ >> + struct ccdc_params_raw *params = &ccdc_cfg.bayer; >> + struct ccdc_config_params_raw *module_params = >> + &ccdc_cfg.bayer.config_params; >> + struct vpss_pg_frame_size frame_size; >> + struct vpss_sync_pol sync; >> + u32 val; >> + >> + dev_dbg(dev, "\nStarting ccdc_config_raw..\n"); >> + >> + /* Configure CCDCFG register */ >> + >> + /** >> + * Set CCD Not to swap input since input is RAW data >> + * Set FID detection function to Latch at V-Sync >> + * Set WENLOG - ccdc valid area >> + * Set TRGSEL >> + * Set EXTRG >> + * Packed to 8 or 16 bits >> + */ >> + >> + val = CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | >> + CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | >> + CCDC_CCDCFG_EXTRG_DISABLE | (ccdc_cfg.data_pack & >> + CCDC_DATA_PACK_MASK); >> + >> + dev_dbg(dev, "Writing 0x%x to ...CCDCFG \n", val); >> + regw(val, CCDCFG); >> + >> + /** >> + * Configure the vertical sync polarity(MODESET.VDPOL) >> + * Configure the horizontal sync polarity (MODESET.HDPOL) >> + * Configure frame id polarity (MODESET.FLDPOL) >> + * Configure data polarity >> + * Configure External WEN Selection >> + * Configure frame format(progressive or interlace) >> + * Configure pixel format (Input mode) >> + * Configure the data shift >> + */ >> + >> + val = CCDC_VDHDOUT_INPUT | >> + ((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | >> + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | >> + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | >> + ((CCDC_DATAPOL_NORMAL & CCDC_DATAPOL_MASK) >> + << CCDC_DATAPOL_SHIFT) | >> + ((CCDC_EXWEN_DISABLE & CCDC_EXWEN_MASK) << CCDC_EXWEN_SHIFT) | >> + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | >> + ((params->pix_fmt & CCDC_INPUT_MASK) << CCDC_INPUT_SHIFT) | >> + ((params->config_params.data_shift & CCDC_DATASFT_MASK) >> + << CCDC_DATASFT_SHIFT); >> + >> + regw(val, MODESET); >> + dev_dbg(dev, "Writing 0x%x to MODESET...\n", val); >> + >> + /** >> + * Configure GAMMAWD register >> + * CFA pattern setting >> + */ >> + val = (params->cfa_pat & CCDC_GAMMAWD_CFA_MASK) << >> + CCDC_GAMMAWD_CFA_SHIFT; >> + >> + /* Gamma msb */ >> + if (module_params->compress.alg == CCDC_ALAW) >> + val = val | CCDC_ALAW_ENABLE; > >val |= CCDC_ALAW_ENABLE; > >> + >> + val = val | ((params->data_msb & CCDC_ALAW_GAMA_WD_MASK) << >> + CCDC_ALAW_GAMA_WD_SHIFT); > >.. ditto .. > [MK] Will check. >> +static int ccdc_set_pixel_format(unsigned int pixfmt) >> +{ >> + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { >> + if (pixfmt == V4L2_PIX_FMT_SBGGR8) { >> + if ((ccdc_cfg.bayer.config_params.compress.alg != >> + CCDC_ALAW) && >> + (ccdc_cfg.bayer.config_params.compress.alg != >> + CCDC_DPCM)) { >> + dev_dbg(dev, "Either configure A-Law or" >> + "DPCM\n"); > >Space required before DPCM > >Thanks, >Sekhar [MK] Ok. From stsongas at yahoo.com Mon Dec 7 15:11:59 2009 From: stsongas at yahoo.com (Sotirios Tsongas) Date: Mon, 7 Dec 2009 13:11:59 -0800 (PST) Subject: test 1a Message-ID: <625429.70177.qm@web52908.mail.re2.yahoo.com> test 1a -------------- next part -------------- An HTML attachment was scrubbed... URL: From khilman at deeprootsystems.com Mon Dec 7 15:16:04 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 13:16:04 -0800 Subject: test Message-ID: <87bpiaa3jf.fsf@deeprootsystems.com> Testing if list is accepting emails from me yet. Updated TI spam filters were rejecting mails from me, probably due to reverse DNS lookup failures. I've fixed the reverse DNS problems and now testing if list will accept posts from me. Kevin From stsongas at yahoo.com Mon Dec 7 15:16:25 2009 From: stsongas at yahoo.com (Sotirios Tsongas) Date: Mon, 7 Dec 2009 13:16:25 -0800 (PST) Subject: test5a Message-ID: <755613.5978.qm@web52907.mail.re2.yahoo.com> test5a -------------- next part -------------- An HTML attachment was scrubbed... URL: From nkansara at irvine-sensors.com Mon Dec 7 16:04:23 2009 From: nkansara at irvine-sensors.com (Naresh Kansara) Date: Mon, 7 Dec 2009 14:04:23 -0800 Subject: NAND support of DaVinci Message-ID: Hello All, The Spectrum DVEVM board uses a NAND Flash device that is not easily available from supplier/distributor in US. Has someone on his/her custom Davinci board has used a new NAND Flash device that is >= 128Mbytes and easily available from local US supplier? Thank you for help. Naresh Kansara Irvine Sensors Corporation phone: (714)-435-8928 email: nkansara at irvine-sensors.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From s-paulraj at ti.com Mon Dec 7 16:09:08 2009 From: s-paulraj at ti.com (Paulraj, Sandeep) Date: Mon, 7 Dec 2009 16:09:08 -0600 Subject: NAND support of DaVinci In-Reply-To: References: Message-ID: <0554BEF07D437848AF01B9C9B5F0BC5D94818A05@dlee01.ent.ti.com> We have tried NANDs of large sizes in DM355 and DM365. Before opting for a NAND you should check if the NAND will get detected by the RBL. Also DM6446 supports only 1 bit HW ECC so you should also make sure that the NAND you choose does not require more than I bit ECC. If you satisfy these 2 conditions then you should be able to use NANDs of large sizes. ________________________________ From: davinci-linux-open-source-bounces at linux.davincidsp.com [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf Of Naresh Kansara Sent: Monday, December 07, 2009 5:04 PM To: davinci-linux-open-source at linux.davincidsp.com Subject: NAND support of DaVinci Hello All, The Spectrum DVEVM board uses a NAND Flash device that is not easily available from supplier/distributor in US. Has someone on his/her custom Davinci board has used a new NAND Flash device that is >= 128Mbytes and easily available from local US supplier? Thank you for help. Naresh Kansara Irvine Sensors Corporation phone: (714)-435-8928 email: nkansara at irvine-sensors.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From khilman at deeprootsystems.com Mon Dec 7 16:23:24 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 14:23:24 -0800 Subject: [PATCH 12/14] davinci: add power management support In-Reply-To: (Sekhar Nori's message of "Thu\, 26 Nov 2009 12\:01\:18 +0530") References: <1258372302-12678-1-git-send-email-nsekhar@ti.com> <1258372302-12678-2-git-send-email-nsekhar@ti.com> <1258372302-12678-3-git-send-email-nsekhar@ti.com> <1258372302-12678-4-git-send-email-nsekhar@ti.com> <1258372302-12678-5-git-send-email-nsekhar@ti.com> <1258372302-12678-6-git-send-email-nsekhar@ti.com> <1258372302-12678-7-git-send-email-nsekhar@ti.com> <1258372302-12678-8-git-send-email-nsekhar@ti.com> <1258372302-12678-9-git-send-email-nsekhar@ti.com> <1258372302-12678-10-git-send-email-nsekhar@ti.com> <1258372302-12678-11-git-send-email-nsekhar@ti.com> <1258372302-12678-12-git-send-email-nsekhar@ti.com> <1258372302-12678-13-git-send-email-nsekhar@ti.com> <87d436e7bd.fsf@deeprootsystems.com> Message-ID: <87k4wy8lur.fsf@deeprootsystems.com> "Nori, Sekhar" writes: > On Thu, Nov 26, 2009 at 00:54:38, Kevin Hilman wrote: >> Sekhar Nori writes: >> > > [...] > >> > + * Note on SLEEPCOUNT: >> > + * The SLEEPCOUNT feature is mainly intended for cases in which >> > + * the internal oscillator is used. The internal oscillator is >> > + * fully disabled in deep sleep mode. When you exist deep sleep >> > + * mode, the oscillator will be turned on and will generate very >> > + * small oscillations which will not be detected by the deep sleep >> > + * counter. Eventually those oscillations will grow to an amplitude >> > + * large enough to start incrementing the deep sleep counter. >> > + * In this case recommendation from hardware enginners is that the > > Oops "engineers" :) > >> > diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c >> > new file mode 100644 >> > index 0000000..de378dc >> > --- /dev/null >> > +++ b/arch/arm/mach-davinci/pm.c >> > @@ -0,0 +1,172 @@ >> > +/* > > [...] > >> > + >> > +#include "clock.h" >> > + >> > +#define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF >> > + >> > +static void (*suspend) (struct davinci_pm_config *); >> >> Maybe davinci_sram_suspend is a better name here. > > Okay. > >> >> > +static struct davinci_pm_config *pdata; >> > + >> > +static void davinci_sram_push(void *dest, void *src, unsigned int size) >> > +{ >> > + memcpy(dest, src, size); >> > + flush_icache_range((unsigned long)dest, (unsigned long)(dest + size)); >> > +} >> > + >> > +static inline void davinci_pm_and(void __iomem *base, int offset, unsigned and) >> > +{ >> > + unsigned val = __raw_readl(base + offset); >> > + val &= and; >> > + __raw_writel(val, base + offset); >> > +} >> > + >> > +static inline void davinci_pm_or(void __iomem *base, int offset, unsigned or) >> > +{ >> > + unsigned val = __raw_readl(base + offset); >> > + val |= or; >> > + __raw_writel(val, base + offset); >> > +} >> > + >> > +static inline void davinci_pm_modify(void __iomem *base, int offset, >> > + unsigned and, unsigned or) >> > +{ >> > + unsigned val = __raw_readl(base + offset); >> > + val &= and; >> > + val |= or; >> > + __raw_writel(val, base + offset); >> > +} >> >> I'm not sure these helper functions help in readability. >> >> I think the functions would be more readable using accessing the >> registers directly, and could also be more efficient. e.g. a single >> read up front followed by modify/write accesses. >> >> At least in the suspend func below, all the accesses are to the same >> register, so i don't see the value in these helper funcs. > > This comes from a desire to transliterate the user guide > step-by-step procedure into C code. Also, it is not always > possible to just read once and write once as there is a > requirement to wait after writing certain bits (reset wait, > lock wait). > > Let me know, I can always redo the way you suggest and we > can then choose the one that looks better. I think those helper functions do not help readability. Just do the raw read/modify/writes and I think it will greatly improve readability. If you want to track the docs, you could use comments for that including a reference to the doc and relevant sections. >> >> > +static void davinci_pm_suspend(void) >> > +{ >> > + DEFINE_SPINLOCK(lock); >> >> What is this local lock protecting? and why is an IRQ-save lock. I'm >> guessing what you is to be sure this is an IRQs off section, but I'm >> pretty sure the higher level suspend code has disabled IRQs by now. >> > > Honestly, I just saw that preempt_count() is still 0 in > davinci_pm_suspend() and went ahead with the locking. I > will check and remove the locking. If the upper layers of the suspend code don't disable interrupts, then I suggest you just use a local_irq_save/restore block here instad of a spinlock. Kevin From nkansara at irvine-sensors.com Mon Dec 7 16:31:50 2009 From: nkansara at irvine-sensors.com (Naresh Kansara) Date: Mon, 7 Dec 2009 14:31:50 -0800 Subject: NAND support of DaVinci In-Reply-To: <0554BEF07D437848AF01B9C9B5F0BC5D94818A05@dlee01.ent.ti.com> References: <0554BEF07D437848AF01B9C9B5F0BC5D94818A05@dlee01.ent.ti.com> Message-ID: Sandeep, Thank you for your response. We are using TMS320DM6441ZWT device. Can you suggest any NAND device that will be recognized by RBL and easily available from a supplier/distributor in US? Regards, Naresh Irvine Sensors Corporation phone: (714)-435-8928 email: nkansara at irvine-sensors.com ________________________________ From: Paulraj, Sandeep [mailto:s-paulraj at ti.com] Sent: Monday, December 07, 2009 2:09 PM To: Naresh Kansara Cc: davinci-linux-open-source at linux.davincidsp.com Subject: RE: NAND support of DaVinci We have tried NANDs of large sizes in DM355 and DM365. Before opting for a NAND you should check if the NAND will get detected by the RBL. Also DM6446 supports only 1 bit HW ECC so you should also make sure that the NAND you choose does not require more than I bit ECC. If you satisfy these 2 conditions then you should be able to use NANDs of large sizes. ________________________________ From: davinci-linux-open-source-bounces at linux.davincidsp.com [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf Of Naresh Kansara Sent: Monday, December 07, 2009 5:04 PM To: davinci-linux-open-source at linux.davincidsp.com Subject: NAND support of DaVinci Hello All, The Spectrum DVEVM board uses a NAND Flash device that is not easily available from supplier/distributor in US. Has someone on his/her custom Davinci board has used a new NAND Flash device that is >= 128Mbytes and easily available from local US supplier? Thank you for help. Naresh Kansara Irvine Sensors Corporation phone: (714)-435-8928 email: nkansara at irvine-sensors.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From khilman at deeprootsystems.com Mon Dec 7 16:35:29 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 14:35:29 -0800 Subject: [GIT PULL] davinci platform updates for v2.6.33 Message-ID: <87hbs28lam.fsf@deeprootsystems.com> Linus, Please pull the davinci platform updates for 2.6.33. Thanks, Kevin The following changes since commit 648f4e3e50c4793d9dbf9a09afa193631f76fa26: Linus Torvalds (1): Linux 2.6.32-rc8 are available in the git repository at: ssh://master.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git davinci-for-linus or git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git davinci-for-linus Andrey Porodko (1): davinci: Initial support for Neuros OSD2 platform. Chaithrika U S (4): davinci: DA850/OMAP-L138 EVM expander setup and UI card detection davinci: RMII support for DA850/OMAP-L138 EVM davinci: DA850/OMAP-L138: Set ASYNC3 domain flag for McASP DA8xx/OMAP-L1xx: Add high speed SD/MMC capabilities David A. Griego (2): davinci: Add MMC/SD support for DA830/OMAP-L137 EVM davinci: Add NAND support for DA830/OMAP-L137 EVM platform Hemant Pedanekar (2): davinci: dm646x: Add support for 3.x silicon revision davinci: dm646x-evm: Add platform data for NAND Kevin Hilman (4): davinci: da830 EVM: make machine name string consistent with da850 davinci: da830: add support for new silicon revisions davinci: da830 EVM: remove #include davinci: DMx and da8xx defconfig updates Mark A. Greer (5): davinci: Move DA8xx/OMAP-L13x emac register routine davinci: Change DA8xx/OMAP-L13x McASP registration routine name davinci: Add DA830/OMAP-L137 EVM specific pinmux setting for McASP1 davinci: Add support for Sharp LCD035Q3DG01 graphical LCD davinci: Add RTC support for DA8xx/OMAP-L13x SoC's Miguel Aguilar (3): Davinci: DM365: Add platform device for McBSP Davinci: DM365: Enable DaVinci Key Scan support for DM365 EVM DaVinci: DM365: Enable DaVinci RTC support for DM365 EVM Phaneendra Kumar (1): DaVinci: DM365: SDIO interrupt resource correction Sandeep Paulraj (5): DaVinci: DM365: Correct USB parent clock DaVinci: EDMA: Fix bug in edma_free_cont_slots API DaVinci: EDMA: Fix Bug in edma_alloc_cont_slots API DaVinci: EDMA: Fix Bug while obtaining contiguous params DaVinci: EDMA: Updating terminlogy in EDMA driver Sekhar Nori (28): davinci: DA8XX/OMAP-L1XX: It's SYSCFG not BOOT_CFG davinci: DA8XX/OMAP-L1XX: Avoid use of IO_ADDRESS for SYSCFG module davinci: DA8XX/OMAP-L1XX: JTAG ID register should offset from SYSCFG base davinci: enable easy top down traversal of clock tree davinci: make clock rate re-calculation easy davinci: support changing the clock rate in clock framework davinci: support re-parenting a clock in the clock framework davinci: DA850/OMAP-L138: allow async3 source to be changed davinci: add generic CPUFreq driver for DaVinci davinci: DA850/OMAP-L138: add frequency scaling support davinci: DA850/OMAP-L138: add voltage regulation support davinci: DA850/OMAP-L138 EVM: register for CPUFreq support davinci: DA850/OMAP-L138 EVM: add support for TPS65070 PMIC davinci: make it easier to identify SoC init failures davinci: DA830/OMAP-L137 EVM: fix warning with default config davinci: DA830/OMAP-L137 EVM: remove ifdefs inside da830_evm_init() davinci: DA830/OMAP-L137 EVM: use runtime detection for UI card davinci: DA830/OMAP-L137 EVM: do not configure NAND on UI card when MMC/SD is selected davinci: DA850/OMAP-L138 EVM: implement autodetect of RMII PHY davinci: DA850/OMAP-L138 EVM: get rid of DA850_UI_EXP config option davinci: DA850/OMAP-L138 EVM: simplify configuration of emac in MII/RMII mode davinci: add CPU idle driver davinci: DA8XX/OMAP-L1XX: add support for cpuidle driver register davinci: DA850/OMAP-L138 EVM: register for cpuidle support davinci: DA850/OMAP-L138: avoid using separate initcall for initializing regulator davinci: DA8XX/OMAP-L1XX: enable cpuidle and regulator in defconfig davinci: fix section mismatch warning in arch/arm/mach-davinci/board-dm646x-evm.c davinci: remove unused variable in arch/arm/mach-davinci/board-sffsdr.c Sergei Shtylyov (8): davinci: DA8xx: CFGCHIP2 register definitions davinci: DA8xx: OHCI platform device davinci: DA830 EVM: OHCI platform code davinci: DA8xx: rename 'psc_ctlr' field into 'gpsc' DaVinci: remove unneeded #include's DaVinci: rename setup_usb() to davinci_setup_usb() DA8xx: MUSB platform device registration DA830 EVM: MUSB platform code Sneha Narnakaje (2): davinci: DM355: Update NAND driver platform data davinci: DM365: Update NAND driver platform data Steve Chen (1): davinci: Add LCD Graphics support for DA830/OMAP-L137 EVM Sudhakar Rajashekhara (3): davinci: Correct the GPIO number for LCD panel power davinci: DA850/OMAP-L138: eliminate static function declaration davinci: DA8XX/OMAP-L1XX: fix compiler warning arch/arm/configs/da830_omapl137_defconfig | 1254 -------------------- ...50_omapl138_defconfig => da8xx_omapl_defconfig} | 257 +++-- arch/arm/configs/davinci_all_defconfig | 126 ++- arch/arm/mach-davinci/Kconfig | 59 + arch/arm/mach-davinci/Makefile | 5 + arch/arm/mach-davinci/board-da830-evm.c | 466 +++++++- arch/arm/mach-davinci/board-da850-evm.c | 437 ++++++- arch/arm/mach-davinci/board-dm355-evm.c | 16 +- arch/arm/mach-davinci/board-dm355-leopard.c | 13 +- arch/arm/mach-davinci/board-dm365-evm.c | 57 +- arch/arm/mach-davinci/board-dm644x-evm.c | 15 +- arch/arm/mach-davinci/board-dm646x-evm.c | 86 ++- arch/arm/mach-davinci/board-neuros-osd2.c | 323 +++++ arch/arm/mach-davinci/board-sffsdr.c | 20 +- arch/arm/mach-davinci/clock.c | 231 +++- arch/arm/mach-davinci/clock.h | 17 +- arch/arm/mach-davinci/common.c | 4 +- arch/arm/mach-davinci/cp_intc.c | 3 - arch/arm/mach-davinci/cpufreq.c | 226 ++++ arch/arm/mach-davinci/cpuidle.c | 197 +++ arch/arm/mach-davinci/da830.c | 75 +- arch/arm/mach-davinci/da850.c | 298 +++++- arch/arm/mach-davinci/devices-da8xx.c | 106 ++- arch/arm/mach-davinci/devices.c | 6 +- arch/arm/mach-davinci/dm355.c | 2 - arch/arm/mach-davinci/dm365.c | 107 ++- arch/arm/mach-davinci/dm644x.c | 7 +- arch/arm/mach-davinci/dm646x.c | 11 +- arch/arm/mach-davinci/dma.c | 105 +- arch/arm/mach-davinci/gpio.c | 9 - arch/arm/mach-davinci/include/mach/asp.h | 3 + arch/arm/mach-davinci/include/mach/common.h | 6 - arch/arm/mach-davinci/include/mach/cpufreq.h | 26 + arch/arm/mach-davinci/include/mach/cpuidle.h | 17 + arch/arm/mach-davinci/include/mach/da8xx.h | 26 +- arch/arm/mach-davinci/include/mach/dm365.h | 10 + arch/arm/mach-davinci/include/mach/dm644x.h | 1 - arch/arm/mach-davinci/include/mach/irqs.h | 1 + arch/arm/mach-davinci/include/mach/mux.h | 20 +- arch/arm/mach-davinci/include/mach/system.h | 3 - arch/arm/mach-davinci/include/mach/usb.h | 59 + arch/arm/mach-davinci/mux.c | 1 - arch/arm/mach-davinci/psc.c | 3 - arch/arm/mach-davinci/serial.c | 6 - arch/arm/mach-davinci/sram.c | 3 - arch/arm/mach-davinci/time.c | 6 - arch/arm/mach-davinci/usb.c | 84 ++- 47 files changed, 3051 insertions(+), 1762 deletions(-) delete mode 100644 arch/arm/configs/da830_omapl137_defconfig rename arch/arm/configs/{da850_omapl138_defconfig => da8xx_omapl_defconfig} (85%) create mode 100644 arch/arm/mach-davinci/board-neuros-osd2.c create mode 100644 arch/arm/mach-davinci/cpufreq.c create mode 100644 arch/arm/mach-davinci/cpuidle.c create mode 100644 arch/arm/mach-davinci/include/mach/cpufreq.h create mode 100644 arch/arm/mach-davinci/include/mach/cpuidle.h create mode 100644 arch/arm/mach-davinci/include/mach/usb.h From khilman at deeprootsystems.com Mon Dec 7 17:16:07 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 15:16:07 -0800 Subject: [PATCH 00/14] davinci: add suspend-to-RAM support In-Reply-To: <1258372302-12678-1-git-send-email-nsekhar@ti.com> (Sekhar Nori's message of "Mon\, 16 Nov 2009 17\:21\:28 +0530") References: <1258372302-12678-1-git-send-email-nsekhar@ti.com> Message-ID: <87d42q8jew.fsf@deeprootsystems.com> Sekhar Nori writes: > This set of patches adds suspend-to-RAM support for DaVinci. > The support is presented as generic for DaVinci but has been > tested only on OMAP-L138. Hopefully extending it for other > SoCs is only a matter of adding SoC and board code. > > Patch 12/14 adds the meat of the support; all previous patches > are prepratory in nature. > > The patch set has been boot tested on OMAP-L137, DM355 and DM644x > EVM boards. OK, I'm adding patches 1-11 to davinci git (patch 1 into davinci-upstream-accepted, patches 2-11 into my queue for 2.6.34) After making changes to patch 12, please repost 13 and 14 with it. Thanks, Kevin > Sekhar Nori (14): > rtc: make rtc-omap wakeup capable > davinci: cp_intc: provide set_wake function > davinci: da8xx/omap-l1: mark RTC as a wakeup source > davinci: da8xx/omapl1: add support for the second sysconfig module > davinci: move PLL wait time values to clock.h > davinci: move DDR2 controller defines to memory.h > davinci: move PSC register definitions from psc.c to psc.h > davinci: make it possible to include clock.h and psc.h in assembly > code > davinci: cpuidle: move mapping of DDR2 controller registers out of > driver > davinci: da850/omap-l138: unlock PLL registers during init > davinci: da850/omap-l138: create static map for SRAM > davinci: add power management support > davinci: da850/omap-l138: add support for SoC suspend > davinci: da850/omap-l138 EVM: register for suspend support > > arch/arm/mach-davinci/Makefile | 1 + > arch/arm/mach-davinci/board-da830-evm.c | 4 +- > arch/arm/mach-davinci/board-da850-evm.c | 19 ++- > arch/arm/mach-davinci/clock.c | 15 +-- > arch/arm/mach-davinci/clock.h | 25 +++- > arch/arm/mach-davinci/cp_intc.c | 11 ++ > arch/arm/mach-davinci/cpuidle.c | 38 +---- > arch/arm/mach-davinci/da830.c | 8 +- > arch/arm/mach-davinci/da850.c | 82 ++++++++-- > arch/arm/mach-davinci/devices-da8xx.c | 28 +++- > arch/arm/mach-davinci/include/mach/cpuidle.h | 1 + > arch/arm/mach-davinci/include/mach/da8xx.h | 16 ++- > arch/arm/mach-davinci/include/mach/memory.h | 5 + > arch/arm/mach-davinci/include/mach/mux.h | 1 + > arch/arm/mach-davinci/include/mach/pm.h | 54 ++++++ > arch/arm/mach-davinci/include/mach/psc.h | 15 ++ > arch/arm/mach-davinci/pm.c | 172 ++++++++++++++++++++ > arch/arm/mach-davinci/psc.c | 11 -- > arch/arm/mach-davinci/sleep.S | 224 ++++++++++++++++++++++++++ > drivers/rtc/rtc-omap.c | 5 - > 20 files changed, 646 insertions(+), 89 deletions(-) > create mode 100644 arch/arm/mach-davinci/include/mach/pm.h > create mode 100644 arch/arm/mach-davinci/pm.c > create mode 100644 arch/arm/mach-davinci/sleep.S > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From khilman at deeprootsystems.com Mon Dec 7 17:21:27 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 15:21:27 -0800 Subject: [PATCH] Neuros OSD2 platform support for sound. In-Reply-To: <1258966732-13261-1-git-send-email-panda@chelcom.ru> (Andrey Porodko's message of "Mon\, 23 Nov 2009 13\:58\:52 +0500") References: <1258966732-13261-1-git-send-email-panda@chelcom.ru> Message-ID: <877hsy8j60.fsf@deeprootsystems.com> Andrey Porodko writes: Please add a descriptive changelog. Kevin > Signed-off-by: Andrey Porodko > --- > arch/arm/mach-davinci/board-neuros-osd2.c | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c > index 0949fa9..8fbb838 100644 > --- a/arch/arm/mach-davinci/board-neuros-osd2.c > +++ b/arch/arm/mach-davinci/board-neuros-osd2.c > @@ -205,6 +205,9 @@ static struct i2c_board_info __initdata ntosd2_i2c_info[] = { > { /* MSP430 interface */ > I2C_BOARD_INFO("neuros_osd2_msp", NTOSD2_MSP430_I2C_ADDR), > }, > + { > + I2C_BOARD_INFO("tlv320aic3x", NTOSD2_AUDIOSOC_I2C_ADDR ), > + }, > }; > > static int ntosd2_init_i2c(void) > -- > 1.5.6.5 > > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From khilman at deeprootsystems.com Mon Dec 7 17:34:03 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 15:34:03 -0800 Subject: [PATCH 1/2] davinci: board-dm646x-evm.c: arrange related code together In-Reply-To: <1259067315-21761-1-git-send-email-nsekhar@ti.com> (Sekhar Nori's message of "Tue\, 24 Nov 2009 18\:25\:14 +0530") References: <1259067315-21761-1-git-send-email-nsekhar@ti.com> Message-ID: <87ws0y740k.fsf@deeprootsystems.com> Sekhar Nori writes: > Currently all the #defines and static variables in the > board-dm646x-evm.c file are located right at the start > of the file because of which the related code is not > together - making reading the code difficult. > > This patch moves around the code keeping related code > together. > > Signed-off-by: Sekhar Nori Thanks, adding to davinci git, queuing for 2.6.34. Kevin From khilman at deeprootsystems.com Mon Dec 7 17:39:37 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 15:39:37 -0800 Subject: [PATCH 2/2] davinci: add support for DM6467T EVM In-Reply-To: <1259067315-21761-2-git-send-email-nsekhar@ti.com> (Sekhar Nori's message of "Tue\, 24 Nov 2009 18\:25\:15 +0530") References: <1259067315-21761-1-git-send-email-nsekhar@ti.com> <1259067315-21761-2-git-send-email-nsekhar@ti.com> Message-ID: <87hbs273ra.fsf@deeprootsystems.com> Sekhar Nori writes: > DM6467T (T for Turbo) is a newer and faster DM6467 > part from TI. The new part supports 1080p video and > has the ARM running at 495MHz. More SoC information: > > http://focus.ti.com/docs/prod/folders/print/tms320dm6467t.html > > Spectrum Digital, Inc has a new EVM for this part. > It is _mostly_ same as the older DM6467 EVM except > for a 33MHz crystal input and THS8200 video encoder > for 1080p support. > > The meat of this patch is dedicated to initializing > the crystal frequency from EVM board file. > > Additional notes: > I did consider some alternative ways to make the crystal > input board specific including - (1) having board code > initialize the crystal frequency using the first member > of soc_info->cpu_clks array (2) introducing a new ref_clk_rate > member in soc_info structure. > > But, the current way seems to be the simplest and least > intruding considering that both the clock array and SoC > info structure are actually private to the SoC file. Also > the fact that davinci_common_init() initializes both the > soc_info and clocks in one go. > > Signed-off-by: Sekhar Nori This approach seems fine to me. Some minor comments below... > --- > This patch needs updated mach-types file for building. > Get it from here: http://www.arm.linux.org.uk/developer/machines/download.php You could also send a patch with just the new mach-type added. I will include it in davinci git and will drop it as soon as the new mach-types changes hit upstream. > arch/arm/mach-davinci/Kconfig | 4 ++++ > arch/arm/mach-davinci/board-dm646x-evm.c | 24 ++++++++++++++++++++++++ > arch/arm/mach-davinci/dm646x.c | 3 +-- > arch/arm/mach-davinci/include/mach/dm646x.h | 2 ++ > 4 files changed, 31 insertions(+), 2 deletions(-) > > diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig > index 033bfed..0ebe185 100644 > --- a/arch/arm/mach-davinci/Kconfig > +++ b/arch/arm/mach-davinci/Kconfig > @@ -91,10 +91,14 @@ config MACH_DAVINCI_DM6467_EVM > bool "TI DM6467 EVM" > default ARCH_DAVINCI_DM646x > depends on ARCH_DAVINCI_DM646x > + select MACH_DAVINCI_DM6467TEVM > help > Configure this option to specify the whether the board used > for development is a DM6467 EVM > > +config MACH_DAVINCI_DM6467TEVM > + bool > + I think you should add a comment here about the fact that this is always auto-selected when DM6467 EVM is selected and is required for the machine_is_* stuff to work. Kevin From khilman at deeprootsystems.com Mon Dec 7 17:41:28 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 15:41:28 -0800 Subject: [PATCH] davinci: enable ARCH_HAS_HOLES_MEMORYMODEL for DaVinci In-Reply-To: <1258625041-3212-1-git-send-email-nsekhar@ti.com> (Sekhar Nori's message of "Thu\, 19 Nov 2009 15\:34\:01 +0530") References: <1258625041-3212-1-git-send-email-nsekhar@ti.com> Message-ID: <87d42q73o7.fsf@deeprootsystems.com> Sekhar Nori writes: > All DaVinci platforms include a DSP or co-processor for > audio/video acceleration. > > While creating memory for the DSP/co-processor, system > integrator can end up creating a hole in the memory map > of the sort: > > > > This sort of configuration needs ARCH_HAS_HOLES_MEMORYMODEL > enabled. See further details see this discussion on ARM > linux mailing list: > http://www.mail-archive.com/linux-omap at vger.kernel.org/msg15262.html > > The patch is boot tested on OMAP-L138, DM6446 and DM355 EVMs > > Signed-off-by: Sekhar Nori > CC: Sriramakrishnan > CC: Khasim Syed Mohammed Thanks, applying to davinci git, queued for 2.6.34. Kevin From khilman at deeprootsystems.com Mon Dec 7 17:47:46 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 15:47:46 -0800 Subject: architecture part of video driver patch In-Reply-To: (Muralidharan Karicheri's message of "Tue\, 1 Dec 2009 09\:42\:12 -0600") References: Message-ID: <87638i73dp.fsf@deeprootsystems.com> "Karicheri, Muralidharan" writes: > Kevin, > > Following patch merged to v4l-dvb linux-next has an architectural > part as attached. If you have not merged it to your next branch > for linux-davinci tree, please do so at your earliest convenience > so that they are in sync. OK, applying to davinci git, and queuing for 2.6.34. > Patch merged to linux-next is available at > > http://git.kernel.org/?p=linux/kernel/git/mchehab/linux-next.git;a=commitdiff;h=600cc66f7f3ec93ab4f09cf6b63980f4c5e8f8db > > I will be pushing some more patches to upstream that are having > changes to arch part. I will notify once they are merged to linux-next. OK, thanks, Kevin > Murali Karicheri > Software Design Engineer > Texas Instruments Inc. > Germantown, MD 20874 > phone: 301-407-9583 > email: m-karicheri2 at ti.com > > From: "Hiremath, Vaibhav" > Subject: [PATCH 3/6] Davinci VPFE Capture: Take i2c adapter id through platform data > To: "linux-media at vger.kernel.org" > CC: "davinci-linux-open-source at linux.davincidsp.com" > Date: Tue, 13 Oct 2009 10:08:54 -0500 > > From: Vaibhav Hiremath > > The I2C adapter ID is actually depends on Board and may vary, Davinci > uses id=1, but in case of AM3517 id=3. > > So modified respective davinci board files. > > Signed-off-by: Vaibhav Hiremath > --- > arch/arm/mach-davinci/board-dm355-evm.c | 1 + > arch/arm/mach-davinci/board-dm644x-evm.c | 1 + > 2 files changed, 2 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c > index f683559..4a9252a 100644 > --- a/arch/arm/mach-davinci/board-dm355-evm.c > +++ b/arch/arm/mach-davinci/board-dm355-evm.c > @@ -372,6 +372,7 @@ static struct vpfe_subdev_info vpfe_sub_devs[] = { > > static struct vpfe_config vpfe_cfg = { > .num_subdevs = ARRAY_SIZE(vpfe_sub_devs), > + .i2c_adapter_id = 1, > .sub_devs = vpfe_sub_devs, > .card_name = "DM355 EVM", > .ccdc = "DM355 CCDC", > diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c > index cfd9afa..fed64e2 100644 > --- a/arch/arm/mach-davinci/board-dm644x-evm.c > +++ b/arch/arm/mach-davinci/board-dm644x-evm.c > @@ -257,6 +257,7 @@ static struct vpfe_subdev_info vpfe_sub_devs[] = { > > static struct vpfe_config vpfe_cfg = { > .num_subdevs = ARRAY_SIZE(vpfe_sub_devs), > + .i2c_adapter_id = 1, > .sub_devs = vpfe_sub_devs, > .card_name = "DM6446 EVM", > .ccdc = "DM6446 CCDC", > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > ---------- From khilman at deeprootsystems.com Mon Dec 7 18:04:41 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 16:04:41 -0800 Subject: [PATCH 1/5] davinci: clock framework: remove spinlock usage In-Reply-To: <1259834814-4817-2-git-send-email-nsekhar@ti.com> (Sekhar Nori's message of "Thu\, 3 Dec 2009 15\:36\:50 +0530") References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> Message-ID: <87vdgi5o12.fsf@deeprootsystems.com> Sekhar Nori writes: > Currently, the spinlock in DaVinci clock framework is being > used to: > > 1) Protect clock structure variables usecount and rate against > concurrent modification. > > 2) Protect against simultaneous PSC enables/disables ie. > serialize davinci_psc_config(). > > 3) Serialize clk_set_rate(): > i. Prevent simultaneous setting of clock rates > ii. Ensure clock list remains sane during rate > propagation (also in clk_set_parent). > > Remove the spinlock usage in clock framework by: > > 1) Making clock rate and usecount as atomic variables. > > 2) Making davinci_psc_config() protect itself instead of > relying on serialization by caller. > > 3) (i) Allowing the clk->set_rate to serialize itself. There > should be no need to serialize all clock rate settings. > Currently the only user of rate setting is cpufreq driver on > DA850. cpufreq naturally serializes the calls to set CPU rate. > Also, there appears no need to lock IRQs during CPU rate > transtitions. If required, IRQs can be locked in the actual > set_rate function. > > 3) (ii) Use the mutex already in place for serialzing clock list > manipulation for serializing clock rate propagation as well. > > Apart from the general benefit of reducing locking granurlarity, > the main motivation behind this change is to enable usage of > clock framework for off-chip clock synthesizers. One such > synthesizer, CDCE949, is present on DM6467 EVM. Access to the > synthesizer happens through I2C bus - accessing which can lead to > CPU sleep. Having IRQs locked in clk_set_rate prevents the > clk->set_rate function from sleeping. > > Signed-off-by: Sekhar Nori > --- > arch/arm/mach-davinci/board-dm646x-evm.c | 4 +- > arch/arm/mach-davinci/clock.c | 74 ++++++++++++----------------- > arch/arm/mach-davinci/clock.h | 4 +- > arch/arm/mach-davinci/da830.c | 2 +- > arch/arm/mach-davinci/da850.c | 4 +- > arch/arm/mach-davinci/dm355.c | 4 +- > arch/arm/mach-davinci/dm365.c | 4 +- > arch/arm/mach-davinci/dm644x.c | 8 ++-- > arch/arm/mach-davinci/dm646x.c | 8 ++-- > arch/arm/mach-davinci/psc.c | 6 ++ > 10 files changed, 56 insertions(+), 62 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c > index 542bfdb..6ff3411 100644 > --- a/arch/arm/mach-davinci/board-dm646x-evm.c > +++ b/arch/arm/mach-davinci/board-dm646x-evm.c > @@ -722,9 +722,9 @@ static __init void davinci_dm646x_evm_irq_init(void) > void __init dm646x_board_setup_refclk(struct clk *clk) > { > if (machine_is_davinci_dm6467tevm()) > - clk->rate = DM6467T_EVM_REF_FREQ; > + atomic_set(&clk->rate, DM6467T_EVM_REF_FREQ); > else > - clk->rate = DM646X_EVM_REF_FREQ; > + atomic_set(&clk->rate, DM646X_EVM_REF_FREQ); > } > > MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") > diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c > index baece65..df884c8 100644 > --- a/arch/arm/mach-davinci/clock.c > +++ b/arch/arm/mach-davinci/clock.c > @@ -28,7 +28,6 @@ > > static LIST_HEAD(clocks); > static DEFINE_MUTEX(clocks_mutex); > -static DEFINE_SPINLOCK(clockfw_lock); > > static unsigned psc_domain(struct clk *clk) > { > @@ -41,15 +40,16 @@ static void __clk_enable(struct clk *clk) > { > if (clk->parent) > __clk_enable(clk->parent); > - if (clk->usecount++ == 0 && (clk->flags & CLK_PSC)) > + if (atomic_read(&clk->usecount) == 0 && (clk->flags & CLK_PSC)) > davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 1); > + atomic_inc(&clk->usecount); > } > > static void __clk_disable(struct clk *clk) > { > - if (WARN_ON(clk->usecount == 0)) > + if (WARN_ON(atomic_read(&clk->usecount) == 0)) > return; > - if (--clk->usecount == 0 && !(clk->flags & CLK_PLL)) > + if (atomic_dec_and_test(&clk->usecount) && !(clk->flags & CLK_PLL)) > davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0); > if (clk->parent) > __clk_disable(clk->parent); > @@ -57,14 +57,10 @@ static void __clk_disable(struct clk *clk) > > int clk_enable(struct clk *clk) > { > - unsigned long flags; > - > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > - spin_lock_irqsave(&clockfw_lock, flags); > __clk_enable(clk); > - spin_unlock_irqrestore(&clockfw_lock, flags); > > return 0; > } > @@ -72,14 +68,10 @@ EXPORT_SYMBOL(clk_enable); > > void clk_disable(struct clk *clk) > { > - unsigned long flags; > - > if (clk == NULL || IS_ERR(clk)) > return; > > - spin_lock_irqsave(&clockfw_lock, flags); > __clk_disable(clk); > - spin_unlock_irqrestore(&clockfw_lock, flags); > } > EXPORT_SYMBOL(clk_disable); > > @@ -88,7 +80,7 @@ unsigned long clk_get_rate(struct clk *clk) > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > - return clk->rate; > + return atomic_read(&clk->rate); > } > EXPORT_SYMBOL(clk_get_rate); > > @@ -100,7 +92,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate) > if (clk->round_rate) > return clk->round_rate(clk, rate); > > - return clk->rate; > + return atomic_read(&clk->rate); > } > EXPORT_SYMBOL(clk_round_rate); > > @@ -111,28 +103,27 @@ static void propagate_rate(struct clk *root) > > list_for_each_entry(clk, &root->children, childnode) { > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > propagate_rate(clk); > } > } > > int clk_set_rate(struct clk *clk, unsigned long rate) > { > - unsigned long flags; > int ret = -EINVAL; > > if (clk == NULL || IS_ERR(clk)) > return ret; > > - spin_lock_irqsave(&clockfw_lock, flags); > if (clk->set_rate) > ret = clk->set_rate(clk, rate); > if (ret == 0) { > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > + mutex_lock(&clocks_mutex); > propagate_rate(clk); > + mutex_unlock(&clocks_mutex); > } > - spin_unlock_irqrestore(&clockfw_lock, flags); > > return ret; > } > @@ -140,26 +131,22 @@ EXPORT_SYMBOL(clk_set_rate); > > int clk_set_parent(struct clk *clk, struct clk *parent) > { > - unsigned long flags; > - > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > /* Cannot change parent on enabled clock */ > - if (WARN_ON(clk->usecount)) > + if (WARN_ON(atomic_read(&clk->usecount))) > return -EINVAL; > > mutex_lock(&clocks_mutex); > clk->parent = parent; > list_del_init(&clk->childnode); > list_add(&clk->childnode, &clk->parent->children); > - mutex_unlock(&clocks_mutex); > > - spin_lock_irqsave(&clockfw_lock, flags); > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > propagate_rate(clk); > - spin_unlock_irqrestore(&clockfw_lock, flags); > + mutex_unlock(&clocks_mutex); > > return 0; > } > @@ -170,7 +157,7 @@ int clk_register(struct clk *clk) > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > - if (WARN(clk->parent && !clk->parent->rate, > + if (WARN(clk->parent && !atomic_read(&clk->parent->rate), > "CLK: %s parent %s has no rate!\n", > clk->name, clk->parent->name)) > return -EINVAL; > @@ -184,16 +171,16 @@ int clk_register(struct clk *clk) > mutex_unlock(&clocks_mutex); > > /* If rate is already set, use it */ > - if (clk->rate) > + if (atomic_read(&clk->rate)) > return 0; > > /* Else, see if there is a way to calculate it */ > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > > /* Otherwise, default to parent rate */ > else if (clk->parent) > - clk->rate = clk->parent->rate; > + atomic_set(&clk->rate, atomic_read(&clk->parent->rate)); > > return 0; > } > @@ -219,9 +206,9 @@ static int __init clk_disable_unused(void) > { > struct clk *ck; > > - spin_lock_irq(&clockfw_lock); > + mutex_lock(&clocks_mutex); > list_for_each_entry(ck, &clocks, node) { > - if (ck->usecount > 0) > + if (atomic_read(&ck->usecount) > 0) > continue; > if (!(ck->flags & CLK_PSC)) > continue; > @@ -233,7 +220,7 @@ static int __init clk_disable_unused(void) > pr_info("Clocks: disable unused %s\n", ck->name); > davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, 0); > } > - spin_unlock_irq(&clockfw_lock); > + mutex_unlock(&clocks_mutex); > > return 0; > } > @@ -244,7 +231,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) > { > u32 v, plldiv; > struct pll_data *pll; > - unsigned long rate = clk->rate; > + unsigned long rate = atomic_read(&clk->rate); > > /* If this is the PLL base clock, no more calculations needed */ > if (clk->pll_data) > @@ -253,7 +240,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) > if (WARN_ON(!clk->parent)) > return rate; > > - rate = clk->parent->rate; > + rate = atomic_read(&clk->parent->rate); > > /* Otherwise, the parent must be a PLL */ > if (WARN_ON(!clk->parent->pll_data)) > @@ -281,9 +268,9 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) > static unsigned long clk_leafclk_recalc(struct clk *clk) > { > if (WARN_ON(!clk->parent)) > - return clk->rate; > + return atomic_read(&clk->rate); > > - return clk->parent->rate; > + return atomic_read(&clk->parent->rate); > } > > static unsigned long clk_pllclk_recalc(struct clk *clk) > @@ -291,11 +278,11 @@ static unsigned long clk_pllclk_recalc(struct clk *clk) > u32 ctrl, mult = 1, prediv = 1, postdiv = 1; > u8 bypass; > struct pll_data *pll = clk->pll_data; > - unsigned long rate = clk->rate; > + unsigned long rate = atomic_read(&clk->rate); > > pll->base = IO_ADDRESS(pll->phys_base); > ctrl = __raw_readl(pll->base + PLLCTL); > - rate = pll->input_rate = clk->parent->rate; > + rate = pll->input_rate = atomic_read(&clk->parent->rate); > > if (ctrl & PLLCTL_PLLEN) { > bypass = 0; > @@ -333,8 +320,8 @@ static unsigned long clk_pllclk_recalc(struct clk *clk) > rate /= postdiv; > } > > - pr_debug("PLL%d: input = %lu MHz [ ", > - pll->num, clk->parent->rate / 1000000); > + pr_debug("PLL%d: input = %u MHz [ ", > + pll->num, atomic_read(&clk->parent->rate) / 1000000); > if (bypass) > pr_debug("bypass "); > if (prediv > 1) > @@ -452,7 +439,7 @@ int __init davinci_clk_init(struct davinci_clk *clocks) > } > > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > > if (clk->lpsc) > clk->flags |= CLK_PSC; > @@ -514,7 +501,8 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) > min(i, (unsigned)(sizeof(buf) - 1 - nest))); > > seq_printf(s, "%s users=%2d %-3s %9ld Hz\n", > - buf, parent->usecount, state, clk_get_rate(parent)); > + buf, atomic_read(&parent->usecount), state, > + clk_get_rate(parent)); > /* REVISIT show device associations too */ > > /* cost is now small, but not linear... */ > diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h > index c92d77a..796a568 100644 > --- a/arch/arm/mach-davinci/clock.h > +++ b/arch/arm/mach-davinci/clock.h > @@ -67,8 +67,8 @@ struct clk { > struct list_head node; > struct module *owner; > const char *name; > - unsigned long rate; > - u8 usecount; > + atomic_t rate; > + atomic_t usecount; > u8 lpsc; > u8 gpsc; > u32 flags; > diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c > index b22b5cf..d1961d2 100644 > --- a/arch/arm/mach-davinci/da830.c > +++ b/arch/arm/mach-davinci/da830.c > @@ -43,7 +43,7 @@ static struct pll_data pll0_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DA830_REF_FREQ, > + .rate = ATOMIC_INIT(DA830_REF_FREQ), > }; > > static struct clk pll0_clk = { > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c > index 717806c..62f8c22 100644 > --- a/arch/arm/mach-davinci/da850.c > +++ b/arch/arm/mach-davinci/da850.c > @@ -54,7 +54,7 @@ static struct pll_data pll0_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DA850_REF_FREQ, > + .rate = ATOMIC_INIT(DA850_REF_FREQ), > }; > > static struct clk pll0_clk = { > @@ -1024,7 +1024,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long armrate) > > static int da850_round_armrate(struct clk *clk, unsigned long rate) > { > - return clk->rate; > + return atomic_read(&clk->rate); > } > #endif > > diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c > index dedf4d4..2244e8c 100644 > --- a/arch/arm/mach-davinci/dm355.c > +++ b/arch/arm/mach-davinci/dm355.c > @@ -55,7 +55,7 @@ static struct pll_data pll2_data = { > static struct clk ref_clk = { > .name = "ref_clk", > /* FIXME -- crystal rate is board-specific */ > - .rate = DM355_REF_FREQ, > + .rate = ATOMIC_INIT(DM355_REF_FREQ), > }; > > static struct clk pll1_clk = { > @@ -314,7 +314,7 @@ static struct clk timer2_clk = { > .name = "timer2", > .parent = &pll1_aux_clk, > .lpsc = DAVINCI_LPSC_TIMER2, > - .usecount = 1, /* REVISIT: why cant' this be disabled? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */ > }; > > static struct clk timer3_clk = { > diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c > index 2ec619e..cc3bae4 100644 > --- a/arch/arm/mach-davinci/dm365.c > +++ b/arch/arm/mach-davinci/dm365.c > @@ -52,7 +52,7 @@ static struct pll_data pll2_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DM365_REF_FREQ, > + .rate = ATOMIC_INIT(DM365_REF_FREQ), > }; > > static struct clk pll1_clk = { > @@ -358,7 +358,7 @@ static struct clk timer2_clk = { > .name = "timer2", > .parent = &pll1_aux_clk, > .lpsc = DAVINCI_LPSC_TIMER2, > - .usecount = 1, > + .usecount = ATOMIC_INIT(1), > }; > > static struct clk timer3_clk = { > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c > index 2cd0081..e65e29e 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c > @@ -47,7 +47,7 @@ static struct pll_data pll2_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DM644X_REF_FREQ, > + .rate = ATOMIC_INIT(DM644X_REF_FREQ), > }; > > static struct clk pll1_clk = { > @@ -131,7 +131,7 @@ static struct clk dsp_clk = { > .parent = &pll1_sysclk1, > .lpsc = DAVINCI_LPSC_GEM, > .flags = PSC_DSP, > - .usecount = 1, /* REVISIT how to disable? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ > }; > > static struct clk arm_clk = { > @@ -146,7 +146,7 @@ static struct clk vicp_clk = { > .parent = &pll1_sysclk2, > .lpsc = DAVINCI_LPSC_IMCOP, > .flags = PSC_DSP, > - .usecount = 1, /* REVISIT how to disable? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ > }; > > static struct clk vpss_master_clk = { > @@ -274,7 +274,7 @@ static struct clk timer2_clk = { > .name = "timer2", > .parent = &pll1_aux_clk, > .lpsc = DAVINCI_LPSC_TIMER2, > - .usecount = 1, /* REVISIT: why cant' this be disabled? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */ > }; > > struct davinci_clk dm644x_clks[] = { > diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c > index 515d3ed..6f80616 100644 > --- a/arch/arm/mach-davinci/dm646x.c > +++ b/arch/arm/mach-davinci/dm646x.c > @@ -60,7 +60,7 @@ static struct clk ref_clk = { > > static struct clk aux_clkin = { > .name = "aux_clkin", > - .rate = DM646X_AUX_FREQ, > + .rate = ATOMIC_INIT(DM646X_AUX_FREQ), > }; > > static struct clk pll1_clk = { > @@ -158,7 +158,7 @@ static struct clk dsp_clk = { > .parent = &pll1_sysclk1, > .lpsc = DM646X_LPSC_C64X_CPU, > .flags = PSC_DSP, > - .usecount = 1, /* REVISIT how to disable? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ > }; > > static struct clk arm_clk = { > @@ -262,14 +262,14 @@ static struct clk pwm0_clk = { > .name = "pwm0", > .parent = &pll1_sysclk3, > .lpsc = DM646X_LPSC_PWM0, > - .usecount = 1, /* REVIST: disabling hangs system */ > + .usecount = ATOMIC_INIT(1), /* REVIST: disabling hangs system */ > }; > > static struct clk pwm1_clk = { > .name = "pwm1", > .parent = &pll1_sysclk3, > .lpsc = DM646X_LPSC_PWM1, > - .usecount = 1, /* REVIST: disabling hangs system */ > + .usecount = ATOMIC_INIT(1), /* REVIST: disabling hangs system */ > }; > > static struct clk timer0_clk = { > diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c > index 04a3cb7..a9a4d08 100644 > --- a/arch/arm/mach-davinci/psc.c > +++ b/arch/arm/mach-davinci/psc.c > @@ -21,6 +21,7 @@ > #include > #include > #include > +#include > > #include > #include > @@ -64,6 +65,9 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, > void __iomem *psc_base; > struct davinci_soc_info *soc_info = &davinci_soc_info; > u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */ > + /* Protect against simultaneous enable/disable of PSCs */ > + DEFINE_SPINLOCK(lock); > + unsigned long flags; > > if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { > pr_warning("PSC: Bad psc data: 0x%x[%d]\n", > @@ -73,6 +77,7 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, > > psc_base = soc_info->psc_bases[ctlr]; > > + spin_lock_irqsave(&lock, flags); > mdctl = __raw_readl(psc_base + MDCTL + 4 * id); > mdctl &= ~MDSTAT_STATE_MASK; > mdctl |= next_state; > @@ -111,4 +116,5 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, > do { > mdstat = __raw_readl(psc_base + MDSTAT + 4 * id); > } while (!((mdstat & MDSTAT_STATE_MASK) == next_state)); > + spin_unlock_irqrestore(&lock, flags); > } > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source Sekhar Nori writes: > This patch modifies clock dump to take care of > clock tress rooted at multiple oscillators. > Current code assumes the entire tree is rooted > on a single oscillator. When using off-chip > clock synthesizers, some of the clocks can > be obtained from a different on-board oscillator. > > Signed-off-by: Sekhar Nori > --- > arch/arm/mach-davinci/clock.c | 11 +++++++---- > 1 files changed, 7 insertions(+), 4 deletions(-) > > diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c > index df884c8..ba0b68f 100644 > --- a/arch/arm/mach-davinci/clock.c > +++ b/arch/arm/mach-davinci/clock.c > @@ -513,12 +513,15 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) > > static int davinci_ck_show(struct seq_file *m, void *v) > { > - /* Show clock tree; we know the main oscillator is first. > - * We trust nonzero usecounts equate to PSC enables... > + struct clk *clk; > + > + /* > + * Show clock tree; We trust nonzero usecounts equate to PSC enables... > */ > mutex_lock(&clocks_mutex); > - if (!list_empty(&clocks)) > - dump_clock(m, 0, list_first_entry(&clocks, struct clk, node)); > + list_for_each_entry(clk, &clocks, node) > + if (!clk->parent) > + dump_clock(m, 0, clk); > mutex_unlock(&clocks_mutex); > > return 0; > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source Sekhar Nori writes: > Move /proc/davinci_clocks to /sys/kernel/debug/davinci_clocks > (debugfs). > > debugfs is more suited for this since the clock dump is > debug information. > > Signed-off-by: Sekhar Nori > --- > arch/arm/mach-davinci/clock.c | 42 ++++++++++------------------------------ > 1 files changed, 11 insertions(+), 31 deletions(-) > > diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c > index ba0b68f..c9ea503 100644 > --- a/arch/arm/mach-davinci/clock.c > +++ b/arch/arm/mach-davinci/clock.c > @@ -455,24 +455,10 @@ int __init davinci_clk_init(struct davinci_clk *clocks) > return 0; > } > > -#ifdef CONFIG_PROC_FS > -#include > -#include > - > -static void *davinci_ck_start(struct seq_file *m, loff_t *pos) > -{ > - return *pos < 1 ? (void *)1 : NULL; > -} > - > -static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos) > -{ > - ++*pos; > - return NULL; > -} > +#ifdef CONFIG_DEBUG_FS > > -static void davinci_ck_stop(struct seq_file *m, void *v) > -{ > -} > +#include > +#include > > #define CLKNAME_MAX 10 /* longest clock name */ > #define NEST_DELTA 2 > @@ -527,30 +513,24 @@ static int davinci_ck_show(struct seq_file *m, void *v) > return 0; > } > > -static const struct seq_operations davinci_ck_op = { > - .start = davinci_ck_start, > - .next = davinci_ck_next, > - .stop = davinci_ck_stop, > - .show = davinci_ck_show > -}; > - > static int davinci_ck_open(struct inode *inode, struct file *file) > { > - return seq_open(file, &davinci_ck_op); > + return single_open(file, davinci_ck_show, NULL); > } > > -static const struct file_operations proc_davinci_ck_operations = { > +static const struct file_operations davinci_ck_operations = { > .open = davinci_ck_open, > .read = seq_read, > .llseek = seq_lseek, > - .release = seq_release, > + .release = single_release, > }; > > -static int __init davinci_ck_proc_init(void) > +static int __init davinci_clk_debugfs_init(void) > { > - proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations); > + debugfs_create_file("davinci_clocks", S_IFREG | S_IRUGO, NULL, NULL, > + &davinci_ck_operations); > return 0; > > } > -__initcall(davinci_ck_proc_init); > -#endif /* CONFIG_DEBUG_PROC_FS */ > +device_initcall(davinci_clk_debugfs_init); > +#endif /* CONFIG_DEBUG_FS */ > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source Sekhar Nori writes: > From: Nageswari Srinivasan > > This patch adds support for TI's CDCE949 - a clock > synthesizer with 4 PLLs and 9 outputs. > > It is used on DM6467 EVM. On the EVM, it generates > clocks required for VPIF, TSIF and Audio modules. > > This patch adds it as part of the DaVinci clock framework. > > Testing: > The various frequency outputs on Y1 have been tested using > a out-of-tree VPIF video driver supporting HD video. > The register values for Y5 frequency outputs have been > derived from TSIF driver sources in MontaVista LSP kernel, > but actual output has not been tested for lack of TSIF > driver which actually works on the latest kernel. > > Signed-off-by: Nageswari Srinivasan > Signed-off-by: Sekhar Nori > --- > arch/arm/mach-davinci/cdce949.c | 289 ++++++++++++++++++++++++++ > arch/arm/mach-davinci/include/mach/cdce949.h | 19 ++ > 2 files changed, 308 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/mach-davinci/cdce949.c > create mode 100644 arch/arm/mach-davinci/include/mach/cdce949.h > > diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c > new file mode 100644 > index 0000000..5a08283 > --- /dev/null > +++ b/arch/arm/mach-davinci/cdce949.c > @@ -0,0 +1,289 @@ > +/* > + * TI CDCE949 clock synthesizer driver > + * > + * Note: This implementation assumes an input of 27MHz to the CDCE. > + * This is by no means constrained by CDCE hardware although the datasheet > + * does use this as an example for all illustrations and more importantly: > + * that is the crystal input on boards it is currently used on. > + * > + * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/ > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > +#include > +#include > +#include > +#include > + > +#include > + > +#include "clock.h" > + > +static struct i2c_client *cdce_i2c_client; > + > +/* CDCE register descriptor */ > +struct cdce_reg { > + u8 addr; > + u8 val; > +}; > + > +/* Per-Output (Y1, Y2 etc.) frequency descriptor */ > +struct cdce_freq { > + /* Frequency in KHz */ > + unsigned long frequency; > + /* > + * List of registers to program to obtain a particular frequency. > + * 0x0 in register address and value is the end of list marker. > + */ > + struct cdce_reg *reglist; > +}; > + > +#define CDCE_FREQ_TABLE_ENTRY(line, out) \ > +{ \ > + .reglist = cdce_y ##line## _ ##out, \ > + .frequency = out, \ > +} > + > +/* List of CDCE outputs */ > +struct cdce_output { > + /* List of frequencies on this output */ > + struct cdce_freq *freq_table; > + /* Number of possible frequencies */ > + int size; > +}; > + > +/* > + * Finding out the values to program into CDCE949 registers for a particular > + * frequency output is not a simple calculation. Have a look at the datasheet > + * for the details. There is desktop software available to help users with > + * the calculations. Here, we just depend on the output of that software > + * (or hand calculations) instead trying to runtime calculate the register > + * values and inflicting misery on ourselves. > + */ > +static struct cdce_reg cdce_y1_148500[] = { > + { 0x13, 0x00 }, > + /* program PLL1_0 multiplier */ > + { 0x18, 0xaf }, > + { 0x19, 0x50 }, > + { 0x1a, 0x02 }, > + { 0x1b, 0xc9 }, > + /* program PLL1_11 multiplier */ > + { 0x1c, 0x00 }, > + { 0x1d, 0x40 }, > + { 0x1e, 0x02 }, > + { 0x1f, 0xc9 }, > + /* output state selection */ > + { 0x15, 0x00 }, > + { 0x14, 0xef }, > + /* switch MUX to PLL1 output */ > + { 0x14, 0x6f }, > + { 0x16, 0x06 }, > + /* set P2DIV divider, P3DIV and input crystal */ > + { 0x17, 0x06 }, > + { 0x01, 0x00 }, > + { 0x05, 0x48 }, > + { 0x02, 0x80 }, > + /* enable and disable PLL */ > + { 0x02, 0xbc }, > + { 0x03, 0x01 }, > + { }, > +}; > + > +static struct cdce_reg cdce_y1_74250[] = { > + { 0x13, 0x00 }, > + { 0x18, 0xaf }, > + { 0x19, 0x50 }, > + { 0x1a, 0x02 }, > + { 0x1b, 0xc9 }, > + { 0x1c, 0x00 }, > + { 0x1d, 0x40 }, > + { 0x1e, 0x02 }, > + { 0x1f, 0xc9 }, > + /* output state selection */ > + { 0x15, 0x00 }, > + { 0x14, 0xef }, > + /* switch MUX to PLL1 output */ > + { 0x14, 0x6f }, > + { 0x16, 0x06 }, > + /* set P2DIV divider, P3DIV and input crystal */ > + { 0x17, 0x06 }, > + { 0x01, 0x00 }, > + { 0x05, 0x48 }, > + { 0x02, 0x80 }, > + /* enable and disable PLL */ > + { 0x02, 0xbc }, > + { 0x03, 0x02 }, > + { }, > +}; > + > +static struct cdce_reg cdce_y1_27000[] = { > + { 0x13, 0x00 }, > + { 0x18, 0x00 }, > + { 0x19, 0x40 }, > + { 0x1a, 0x02 }, > + { 0x1b, 0x08 }, > + { 0x1c, 0x00 }, > + { 0x1d, 0x40 }, > + { 0x1e, 0x02 }, > + { 0x1f, 0x08 }, > + { 0x15, 0x02 }, > + { 0x14, 0xed }, > + { 0x16, 0x01 }, > + { 0x17, 0x01 }, > + { 0x01, 0x00 }, > + { 0x05, 0x50 }, > + { 0x02, 0xb4 }, > + { 0x03, 0x01 }, > + { }, > +}; > + > +static struct cdce_freq cdce_y1_freqs[] = { > + CDCE_FREQ_TABLE_ENTRY(1, 148500), > + CDCE_FREQ_TABLE_ENTRY(1, 74250), > + CDCE_FREQ_TABLE_ENTRY(1, 27000), > +}; > + > +static struct cdce_reg cdce_y5_13500[] = { > + { 0x27, 0x08 }, > + { 0x28, 0x00 }, > + { 0x29, 0x40 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x08 }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_reg cdce_y5_16875[] = { > + { 0x27, 0x08 }, > + { 0x28, 0x9f }, > + { 0x29, 0xb0 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x89 }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_reg cdce_y5_27000[] = { > + { 0x27, 0x04 }, > + { 0x28, 0x00 }, > + { 0x29, 0x40 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x08 }, > + { 0x24, 0x6f }, > + { }, > +}; > +static struct cdce_reg cdce_y5_54000[] = { > + { 0x27, 0x04 }, > + { 0x28, 0xff }, > + { 0x29, 0x80 }, > + { 0x2a, 0x02 }, > + { 0x2b, 0x07 }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_reg cdce_y5_81000[] = { > + { 0x27, 0x02 }, > + { 0x28, 0xbf }, > + { 0x29, 0xa0 }, > + { 0x2a, 0x03 }, > + { 0x2b, 0x0a }, > + { 0x24, 0x6f }, > + { }, > +}; > + > +static struct cdce_freq cdce_y5_freqs[] = { > + CDCE_FREQ_TABLE_ENTRY(5, 13500), > + CDCE_FREQ_TABLE_ENTRY(5, 16875), > + CDCE_FREQ_TABLE_ENTRY(5, 27000), > + CDCE_FREQ_TABLE_ENTRY(5, 54000), > + CDCE_FREQ_TABLE_ENTRY(5, 81000), > +}; > + > + > +static struct cdce_output output_list[] = { > + [1] = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) }, > + [5] = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) }, > +}; > + > +int cdce_set_rate(struct clk *clk, unsigned long rate) > +{ > + int i, ret = 0; > + struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table; > + struct cdce_reg *regs = NULL; > + > + if (!cdce_i2c_client) > + return -ENODEV; > + > + if (!freq_table) > + return -EINVAL; > + > + for (i = 0; i < output_list[clk->lpsc].size; i++) { > + if (freq_table[i].frequency == rate / 1000) { > + regs = freq_table[i].reglist; > + break; > + } > + } > + > + if (!regs) > + return -EINVAL; > + > + for (i = 0; regs[i].addr; i++) { > + ret = i2c_smbus_write_byte_data(cdce_i2c_client, > + regs[i].addr | 0x80, regs[i].val); > + if (ret) > + return ret; > + } > + > + atomic_set(&clk->rate, rate); > + > + return 0; > +} > + > +static int cdce_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + cdce_i2c_client = client; > + return 0; > +} > + > +static int __devexit cdce_remove(struct i2c_client *client) > +{ > + cdce_i2c_client = NULL; > + return 0; > +} > + > +static const struct i2c_device_id cdce_id[] = { > + {"cdce949", 0}, > + {}, > +}; > +MODULE_DEVICE_TABLE(i2c, cdce_id); > + > +static struct i2c_driver cdce_driver = { > + .driver = { > + .owner = THIS_MODULE, > + .name = "cdce949", > + }, > + .probe = cdce_probe, > + .remove = __devexit_p(cdce_remove), > + .id_table = cdce_id, > +}; > + > +static int __init cdce_init(void) > +{ > + return i2c_add_driver(&cdce_driver); > +} > +subsys_initcall(cdce_init); > + > +static void __exit cdce_exit(void) > +{ > + i2c_del_driver(&cdce_driver); > +} > +module_exit(cdce_exit); > + > +MODULE_AUTHOR("Texas Instruments"); > +MODULE_DESCRIPTION("CDCE949 clock synthesizer driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach-davinci/include/mach/cdce949.h > new file mode 100644 > index 0000000..c73331f > --- /dev/null > +++ b/arch/arm/mach-davinci/include/mach/cdce949.h > @@ -0,0 +1,19 @@ > +/* > + * TI CDCE949 off-chip clock synthesizer support > + * > + * 2009 (C) Texas Instruments, Inc. http://www.ti.com/ > + * > + * This file is licensed under the terms of the GNU General Public License > + * version 2. This program is licensed "as is" without any warranty of any > + * kind, whether express or implied. > + */ > +#ifndef _MACH_DAVINCI_CDCE949_H > +#define _MACH_DAVINCI_CDCE949_H > + > +#include > + > +#include > + > +int cdce_set_rate(struct clk *clk, unsigned long rate); > + > +#endif > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source Sekhar Nori writes: > From: Nageswari Srinivasan > > This patch adds the CDCE949 reference oscillator to > the davinci clock list. > > On the DM6467T EVM, the CDCE949 is responsible for > generating the pixel clock for display. On the DM6467 > EVM, this pixel clock was being obtained from an > internal source. This is not possible on the DM6467T > EVM because of the presence of a 33MHz oscillator. > > The TSIF module also requires the CDCE949 to generate > the data clocks. > > The actual clock definitions will be added by patches > adding support for DM6467T VPIF and TSIF. This patch > mearly lays the foundation for that work. > > Signed-off-by: Nageswari Srinivasan > Signed-off-by: Sekhar Nori > --- > arch/arm/mach-davinci/Makefile | 2 +- > arch/arm/mach-davinci/board-dm646x-evm.c | 32 ++++++++++++++++++++++++++++++ > 2 files changed, 33 insertions(+), 1 deletions(-) > > diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile > index eeb9230..7e806b0 100644 > --- a/arch/arm/mach-davinci/Makefile > +++ b/arch/arm/mach-davinci/Makefile > @@ -26,7 +26,7 @@ obj-$(CONFIG_MACH_SFFSDR) += board-sffsdr.o > obj-$(CONFIG_MACH_NEUROS_OSD2) += board-neuros-osd2.o > obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o > obj-$(CONFIG_MACH_DM355_LEOPARD) += board-dm355-leopard.o > -obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o > +obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o cdce949.o > obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o > obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o > obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o > diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c > index 6ff3411..5d9283f 100644 > --- a/arch/arm/mach-davinci/board-dm646x-evm.c > +++ b/arch/arm/mach-davinci/board-dm646x-evm.c > @@ -40,6 +40,8 @@ > #include > #include > #include > +#include > +#include > > #include "clock.h" > > @@ -389,6 +391,9 @@ static struct i2c_board_info __initdata i2c_info[] = { > { > I2C_BOARD_INFO("cpld_video", 0x3b), > }, > + { > + I2C_BOARD_INFO("cdce949", 0x6c), > + }, > }; > > static struct davinci_i2c_platform_data i2c_pdata = { > @@ -681,9 +686,36 @@ static void __init evm_init_i2c(void) > evm_init_video(); > } > > +#define CDCE949_XIN_RATE 27000000 > + > +/* CDCE949 support - "lpsc" field is overridden to work as clock number */ > +static struct clk cdce_clk_in = { > + .name = "cdce_xin", > + .flags = ALWAYS_ENABLED, Why do you need ALWAYS_ENABLED here. I'd rather see clk_get()/clk_enable() used when this clock is required. To do this, we'll need to add enable/disable functionaltiy for non-PSC clocks. Probably the best way to do this is to add add an 'enable' hook to 'struct clk' and clk_enable() can use that. Kevin From khilman at deeprootsystems.com Mon Dec 7 18:05:28 2009 From: khilman at deeprootsystems.com (Kevin Hilman) Date: Mon, 07 Dec 2009 16:05:28 -0800 Subject: [PATCH 1/5] davinci: clock framework: remove spinlock usage In-Reply-To: <1259834814-4817-2-git-send-email-nsekhar@ti.com> (Sekhar Nori's message of "Thu\, 3 Dec 2009 15\:36\:50 +0530") References: <1259834814-4817-1-git-send-email-nsekhar@ti.com> <1259834814-4817-2-git-send-email-nsekhar@ti.com> Message-ID: <87ocma5nzr.fsf@deeprootsystems.com> Sekhar Nori writes: > Currently, the spinlock in DaVinci clock framework is being > used to: > > 1) Protect clock structure variables usecount and rate against > concurrent modification. > > 2) Protect against simultaneous PSC enables/disables ie. > serialize davinci_psc_config(). > > 3) Serialize clk_set_rate(): > i. Prevent simultaneous setting of clock rates > ii. Ensure clock list remains sane during rate > propagation (also in clk_set_parent). > > Remove the spinlock usage in clock framework by: > > 1) Making clock rate and usecount as atomic variables. > > 2) Making davinci_psc_config() protect itself instead of > relying on serialization by caller. > > 3) (i) Allowing the clk->set_rate to serialize itself. There > should be no need to serialize all clock rate settings. > Currently the only user of rate setting is cpufreq driver on > DA850. cpufreq naturally serializes the calls to set CPU rate. > Also, there appears no need to lock IRQs during CPU rate > transtitions. If required, IRQs can be locked in the actual > set_rate function. > > 3) (ii) Use the mutex already in place for serialzing clock list > manipulation for serializing clock rate propagation as well. > > Apart from the general benefit of reducing locking granurlarity, > the main motivation behind this change is to enable usage of > clock framework for off-chip clock synthesizers. One such > synthesizer, CDCE949, is present on DM6467 EVM. Access to the > synthesizer happens through I2C bus - accessing which can lead to > CPU sleep. Having IRQs locked in clk_set_rate prevents the > clk->set_rate function from sleeping. > > Signed-off-by: Sekhar Nori I like this cleanup a lot. Applying patches 1-3 to davinci git and queued for 2.6.34. Kevin > --- > arch/arm/mach-davinci/board-dm646x-evm.c | 4 +- > arch/arm/mach-davinci/clock.c | 74 ++++++++++++----------------- > arch/arm/mach-davinci/clock.h | 4 +- > arch/arm/mach-davinci/da830.c | 2 +- > arch/arm/mach-davinci/da850.c | 4 +- > arch/arm/mach-davinci/dm355.c | 4 +- > arch/arm/mach-davinci/dm365.c | 4 +- > arch/arm/mach-davinci/dm644x.c | 8 ++-- > arch/arm/mach-davinci/dm646x.c | 8 ++-- > arch/arm/mach-davinci/psc.c | 6 ++ > 10 files changed, 56 insertions(+), 62 deletions(-) > > diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c > index 542bfdb..6ff3411 100644 > --- a/arch/arm/mach-davinci/board-dm646x-evm.c > +++ b/arch/arm/mach-davinci/board-dm646x-evm.c > @@ -722,9 +722,9 @@ static __init void davinci_dm646x_evm_irq_init(void) > void __init dm646x_board_setup_refclk(struct clk *clk) > { > if (machine_is_davinci_dm6467tevm()) > - clk->rate = DM6467T_EVM_REF_FREQ; > + atomic_set(&clk->rate, DM6467T_EVM_REF_FREQ); > else > - clk->rate = DM646X_EVM_REF_FREQ; > + atomic_set(&clk->rate, DM646X_EVM_REF_FREQ); > } > > MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") > diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c > index baece65..df884c8 100644 > --- a/arch/arm/mach-davinci/clock.c > +++ b/arch/arm/mach-davinci/clock.c > @@ -28,7 +28,6 @@ > > static LIST_HEAD(clocks); > static DEFINE_MUTEX(clocks_mutex); > -static DEFINE_SPINLOCK(clockfw_lock); > > static unsigned psc_domain(struct clk *clk) > { > @@ -41,15 +40,16 @@ static void __clk_enable(struct clk *clk) > { > if (clk->parent) > __clk_enable(clk->parent); > - if (clk->usecount++ == 0 && (clk->flags & CLK_PSC)) > + if (atomic_read(&clk->usecount) == 0 && (clk->flags & CLK_PSC)) > davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 1); > + atomic_inc(&clk->usecount); > } > > static void __clk_disable(struct clk *clk) > { > - if (WARN_ON(clk->usecount == 0)) > + if (WARN_ON(atomic_read(&clk->usecount) == 0)) > return; > - if (--clk->usecount == 0 && !(clk->flags & CLK_PLL)) > + if (atomic_dec_and_test(&clk->usecount) && !(clk->flags & CLK_PLL)) > davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0); > if (clk->parent) > __clk_disable(clk->parent); > @@ -57,14 +57,10 @@ static void __clk_disable(struct clk *clk) > > int clk_enable(struct clk *clk) > { > - unsigned long flags; > - > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > - spin_lock_irqsave(&clockfw_lock, flags); > __clk_enable(clk); > - spin_unlock_irqrestore(&clockfw_lock, flags); > > return 0; > } > @@ -72,14 +68,10 @@ EXPORT_SYMBOL(clk_enable); > > void clk_disable(struct clk *clk) > { > - unsigned long flags; > - > if (clk == NULL || IS_ERR(clk)) > return; > > - spin_lock_irqsave(&clockfw_lock, flags); > __clk_disable(clk); > - spin_unlock_irqrestore(&clockfw_lock, flags); > } > EXPORT_SYMBOL(clk_disable); > > @@ -88,7 +80,7 @@ unsigned long clk_get_rate(struct clk *clk) > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > - return clk->rate; > + return atomic_read(&clk->rate); > } > EXPORT_SYMBOL(clk_get_rate); > > @@ -100,7 +92,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate) > if (clk->round_rate) > return clk->round_rate(clk, rate); > > - return clk->rate; > + return atomic_read(&clk->rate); > } > EXPORT_SYMBOL(clk_round_rate); > > @@ -111,28 +103,27 @@ static void propagate_rate(struct clk *root) > > list_for_each_entry(clk, &root->children, childnode) { > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > propagate_rate(clk); > } > } > > int clk_set_rate(struct clk *clk, unsigned long rate) > { > - unsigned long flags; > int ret = -EINVAL; > > if (clk == NULL || IS_ERR(clk)) > return ret; > > - spin_lock_irqsave(&clockfw_lock, flags); > if (clk->set_rate) > ret = clk->set_rate(clk, rate); > if (ret == 0) { > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > + mutex_lock(&clocks_mutex); > propagate_rate(clk); > + mutex_unlock(&clocks_mutex); > } > - spin_unlock_irqrestore(&clockfw_lock, flags); > > return ret; > } > @@ -140,26 +131,22 @@ EXPORT_SYMBOL(clk_set_rate); > > int clk_set_parent(struct clk *clk, struct clk *parent) > { > - unsigned long flags; > - > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > /* Cannot change parent on enabled clock */ > - if (WARN_ON(clk->usecount)) > + if (WARN_ON(atomic_read(&clk->usecount))) > return -EINVAL; > > mutex_lock(&clocks_mutex); > clk->parent = parent; > list_del_init(&clk->childnode); > list_add(&clk->childnode, &clk->parent->children); > - mutex_unlock(&clocks_mutex); > > - spin_lock_irqsave(&clockfw_lock, flags); > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > propagate_rate(clk); > - spin_unlock_irqrestore(&clockfw_lock, flags); > + mutex_unlock(&clocks_mutex); > > return 0; > } > @@ -170,7 +157,7 @@ int clk_register(struct clk *clk) > if (clk == NULL || IS_ERR(clk)) > return -EINVAL; > > - if (WARN(clk->parent && !clk->parent->rate, > + if (WARN(clk->parent && !atomic_read(&clk->parent->rate), > "CLK: %s parent %s has no rate!\n", > clk->name, clk->parent->name)) > return -EINVAL; > @@ -184,16 +171,16 @@ int clk_register(struct clk *clk) > mutex_unlock(&clocks_mutex); > > /* If rate is already set, use it */ > - if (clk->rate) > + if (atomic_read(&clk->rate)) > return 0; > > /* Else, see if there is a way to calculate it */ > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > > /* Otherwise, default to parent rate */ > else if (clk->parent) > - clk->rate = clk->parent->rate; > + atomic_set(&clk->rate, atomic_read(&clk->parent->rate)); > > return 0; > } > @@ -219,9 +206,9 @@ static int __init clk_disable_unused(void) > { > struct clk *ck; > > - spin_lock_irq(&clockfw_lock); > + mutex_lock(&clocks_mutex); > list_for_each_entry(ck, &clocks, node) { > - if (ck->usecount > 0) > + if (atomic_read(&ck->usecount) > 0) > continue; > if (!(ck->flags & CLK_PSC)) > continue; > @@ -233,7 +220,7 @@ static int __init clk_disable_unused(void) > pr_info("Clocks: disable unused %s\n", ck->name); > davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, 0); > } > - spin_unlock_irq(&clockfw_lock); > + mutex_unlock(&clocks_mutex); > > return 0; > } > @@ -244,7 +231,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) > { > u32 v, plldiv; > struct pll_data *pll; > - unsigned long rate = clk->rate; > + unsigned long rate = atomic_read(&clk->rate); > > /* If this is the PLL base clock, no more calculations needed */ > if (clk->pll_data) > @@ -253,7 +240,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) > if (WARN_ON(!clk->parent)) > return rate; > > - rate = clk->parent->rate; > + rate = atomic_read(&clk->parent->rate); > > /* Otherwise, the parent must be a PLL */ > if (WARN_ON(!clk->parent->pll_data)) > @@ -281,9 +268,9 @@ static unsigned long clk_sysclk_recalc(struct clk *clk) > static unsigned long clk_leafclk_recalc(struct clk *clk) > { > if (WARN_ON(!clk->parent)) > - return clk->rate; > + return atomic_read(&clk->rate); > > - return clk->parent->rate; > + return atomic_read(&clk->parent->rate); > } > > static unsigned long clk_pllclk_recalc(struct clk *clk) > @@ -291,11 +278,11 @@ static unsigned long clk_pllclk_recalc(struct clk *clk) > u32 ctrl, mult = 1, prediv = 1, postdiv = 1; > u8 bypass; > struct pll_data *pll = clk->pll_data; > - unsigned long rate = clk->rate; > + unsigned long rate = atomic_read(&clk->rate); > > pll->base = IO_ADDRESS(pll->phys_base); > ctrl = __raw_readl(pll->base + PLLCTL); > - rate = pll->input_rate = clk->parent->rate; > + rate = pll->input_rate = atomic_read(&clk->parent->rate); > > if (ctrl & PLLCTL_PLLEN) { > bypass = 0; > @@ -333,8 +320,8 @@ static unsigned long clk_pllclk_recalc(struct clk *clk) > rate /= postdiv; > } > > - pr_debug("PLL%d: input = %lu MHz [ ", > - pll->num, clk->parent->rate / 1000000); > + pr_debug("PLL%d: input = %u MHz [ ", > + pll->num, atomic_read(&clk->parent->rate) / 1000000); > if (bypass) > pr_debug("bypass "); > if (prediv > 1) > @@ -452,7 +439,7 @@ int __init davinci_clk_init(struct davinci_clk *clocks) > } > > if (clk->recalc) > - clk->rate = clk->recalc(clk); > + atomic_set(&clk->rate, clk->recalc(clk)); > > if (clk->lpsc) > clk->flags |= CLK_PSC; > @@ -514,7 +501,8 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) > min(i, (unsigned)(sizeof(buf) - 1 - nest))); > > seq_printf(s, "%s users=%2d %-3s %9ld Hz\n", > - buf, parent->usecount, state, clk_get_rate(parent)); > + buf, atomic_read(&parent->usecount), state, > + clk_get_rate(parent)); > /* REVISIT show device associations too */ > > /* cost is now small, but not linear... */ > diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h > index c92d77a..796a568 100644 > --- a/arch/arm/mach-davinci/clock.h > +++ b/arch/arm/mach-davinci/clock.h > @@ -67,8 +67,8 @@ struct clk { > struct list_head node; > struct module *owner; > const char *name; > - unsigned long rate; > - u8 usecount; > + atomic_t rate; > + atomic_t usecount; > u8 lpsc; > u8 gpsc; > u32 flags; > diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c > index b22b5cf..d1961d2 100644 > --- a/arch/arm/mach-davinci/da830.c > +++ b/arch/arm/mach-davinci/da830.c > @@ -43,7 +43,7 @@ static struct pll_data pll0_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DA830_REF_FREQ, > + .rate = ATOMIC_INIT(DA830_REF_FREQ), > }; > > static struct clk pll0_clk = { > diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c > index 717806c..62f8c22 100644 > --- a/arch/arm/mach-davinci/da850.c > +++ b/arch/arm/mach-davinci/da850.c > @@ -54,7 +54,7 @@ static struct pll_data pll0_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DA850_REF_FREQ, > + .rate = ATOMIC_INIT(DA850_REF_FREQ), > }; > > static struct clk pll0_clk = { > @@ -1024,7 +1024,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long armrate) > > static int da850_round_armrate(struct clk *clk, unsigned long rate) > { > - return clk->rate; > + return atomic_read(&clk->rate); > } > #endif > > diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c > index dedf4d4..2244e8c 100644 > --- a/arch/arm/mach-davinci/dm355.c > +++ b/arch/arm/mach-davinci/dm355.c > @@ -55,7 +55,7 @@ static struct pll_data pll2_data = { > static struct clk ref_clk = { > .name = "ref_clk", > /* FIXME -- crystal rate is board-specific */ > - .rate = DM355_REF_FREQ, > + .rate = ATOMIC_INIT(DM355_REF_FREQ), > }; > > static struct clk pll1_clk = { > @@ -314,7 +314,7 @@ static struct clk timer2_clk = { > .name = "timer2", > .parent = &pll1_aux_clk, > .lpsc = DAVINCI_LPSC_TIMER2, > - .usecount = 1, /* REVISIT: why cant' this be disabled? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */ > }; > > static struct clk timer3_clk = { > diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c > index 2ec619e..cc3bae4 100644 > --- a/arch/arm/mach-davinci/dm365.c > +++ b/arch/arm/mach-davinci/dm365.c > @@ -52,7 +52,7 @@ static struct pll_data pll2_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DM365_REF_FREQ, > + .rate = ATOMIC_INIT(DM365_REF_FREQ), > }; > > static struct clk pll1_clk = { > @@ -358,7 +358,7 @@ static struct clk timer2_clk = { > .name = "timer2", > .parent = &pll1_aux_clk, > .lpsc = DAVINCI_LPSC_TIMER2, > - .usecount = 1, > + .usecount = ATOMIC_INIT(1), > }; > > static struct clk timer3_clk = { > diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c > index 2cd0081..e65e29e 100644 > --- a/arch/arm/mach-davinci/dm644x.c > +++ b/arch/arm/mach-davinci/dm644x.c > @@ -47,7 +47,7 @@ static struct pll_data pll2_data = { > > static struct clk ref_clk = { > .name = "ref_clk", > - .rate = DM644X_REF_FREQ, > + .rate = ATOMIC_INIT(DM644X_REF_FREQ), > }; > > static struct clk pll1_clk = { > @@ -131,7 +131,7 @@ static struct clk dsp_clk = { > .parent = &pll1_sysclk1, > .lpsc = DAVINCI_LPSC_GEM, > .flags = PSC_DSP, > - .usecount = 1, /* REVISIT how to disable? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ > }; > > static struct clk arm_clk = { > @@ -146,7 +146,7 @@ static struct clk vicp_clk = { > .parent = &pll1_sysclk2, > .lpsc = DAVINCI_LPSC_IMCOP, > .flags = PSC_DSP, > - .usecount = 1, /* REVISIT how to disable? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ > }; > > static struct clk vpss_master_clk = { > @@ -274,7 +274,7 @@ static struct clk timer2_clk = { > .name = "timer2", > .parent = &pll1_aux_clk, > .lpsc = DAVINCI_LPSC_TIMER2, > - .usecount = 1, /* REVISIT: why cant' this be disabled? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */ > }; > > struct davinci_clk dm644x_clks[] = { > diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c > index 515d3ed..6f80616 100644 > --- a/arch/arm/mach-davinci/dm646x.c > +++ b/arch/arm/mach-davinci/dm646x.c > @@ -60,7 +60,7 @@ static struct clk ref_clk = { > > static struct clk aux_clkin = { > .name = "aux_clkin", > - .rate = DM646X_AUX_FREQ, > + .rate = ATOMIC_INIT(DM646X_AUX_FREQ), > }; > > static struct clk pll1_clk = { > @@ -158,7 +158,7 @@ static struct clk dsp_clk = { > .parent = &pll1_sysclk1, > .lpsc = DM646X_LPSC_C64X_CPU, > .flags = PSC_DSP, > - .usecount = 1, /* REVISIT how to disable? */ > + .usecount = ATOMIC_INIT(1), /* REVISIT how to disable? */ > }; > > static struct clk arm_clk = { > @@ -262,14 +262,14 @@ static struct clk pwm0_clk = { > .name = "pwm0", > .parent = &pll1_sysclk3, > .lpsc = DM646X_LPSC_PWM0, > - .usecount = 1, /* REVIST: disabling hangs system */ > + .usecount = ATOMIC_INIT(1), /* REVIST: disabling hangs system */ > }; > > static struct clk pwm1_clk = { > .name = "pwm1", > .parent = &pll1_sysclk3, > .lpsc = DM646X_LPSC_PWM1, > - .usecount = 1, /* REVIST: disabling hangs system */ > + .usecount = ATOMIC_INIT(1), /* REVIST: disabling hangs system */ > }; > > static struct clk timer0_clk = { > diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c > index 04a3cb7..a9a4d08 100644 > --- a/arch/arm/mach-davinci/psc.c > +++ b/arch/arm/mach-davinci/psc.c > @@ -21,6 +21,7 @@ > #include > #include > #include > +#include > > #include > #include > @@ -64,6 +65,9 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, > void __iomem *psc_base; > struct davinci_soc_info *soc_info = &davinci_soc_info; > u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */ > + /* Protect against simultaneous enable/disable of PSCs */ > + DEFINE_SPINLOCK(lock); > + unsigned long flags; > > if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { > pr_warning("PSC: Bad psc data: 0x%x[%d]\n", > @@ -73,6 +77,7 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, > > psc_base = soc_info->psc_bases[ctlr]; > > + spin_lock_irqsave(&lock, flags); > mdctl = __raw_readl(psc_base + MDCTL + 4 * id); > mdctl &= ~MDSTAT_STATE_MASK; > mdctl |= next_state; > @@ -111,4 +116,5 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, > do { > mdstat = __raw_readl(psc_base + MDSTAT + 4 * id); > } while (!((mdstat & MDSTAT_STATE_MASK) == next_state)); > + spin_unlock_irqrestore(&lock, flags); > } > -- > 1.6.2.4 > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source at linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source From m-karicheri2 at ti.com Mon Dec 7 18:11:37 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Mon, 7 Dec 2009 19:11:37 -0500 Subject: [PATCH v1 - 1/4] V4L: vpfe_capture - remove clock and ccdc resource handling Message-ID: <1260231100-1226-1-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This combines the two patches sent earlier to change the clock configuration and converting ccdc drivers to platform drivers. This has updated comments against v0 of these patches. In this patch, the clock configuration is moved to ccdc driver since clocks are configured for ccdc. Also adding proper error codes for ccdc register function and removing the ccdc memory resource handling. Reviewed-by: Vaibhav Hiremath Signed-off-by: Muralidharan Karicheri --- drivers/media/video/davinci/vpfe_capture.c | 131 +++------------------------- 1 files changed, 13 insertions(+), 118 deletions(-) diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 12a1b3d..091750e 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -108,9 +108,6 @@ struct ccdc_config { int vpfe_probed; /* name of ccdc device */ char name[32]; - /* for storing mem maps for CCDC */ - int ccdc_addr_size; - void *__iomem ccdc_addr; }; /* data structures */ @@ -230,7 +227,6 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) BUG_ON(!dev->hw_ops.set_image_window); BUG_ON(!dev->hw_ops.get_image_window); BUG_ON(!dev->hw_ops.get_line_length); - BUG_ON(!dev->hw_ops.setfbaddr); BUG_ON(!dev->hw_ops.getfid); mutex_lock(&ccdc_lock); @@ -241,25 +237,23 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) * walk through it during vpfe probe */ printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -1; + ret = -EFAULT; goto unlock; } if (strcmp(dev->name, ccdc_cfg->name)) { /* ignore this ccdc */ - ret = -1; + ret = -EINVAL; goto unlock; } if (ccdc_dev) { printk(KERN_ERR "ccdc already registered\n"); - ret = -1; + ret = -EINVAL; goto unlock; } ccdc_dev = dev; - dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr, - ccdc_cfg->ccdc_addr_size); unlock: mutex_unlock(&ccdc_lock); return ret; @@ -1787,61 +1781,6 @@ static struct vpfe_device *vpfe_initialize(void) return vpfe_dev; } -static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - - clk_disable(vpfe_cfg->vpssclk); - clk_put(vpfe_cfg->vpssclk); - clk_disable(vpfe_cfg->slaveclk); - clk_put(vpfe_cfg->slaveclk); - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master & slave clocks disabled\n"); -} - -static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int ret = -ENOENT; - - vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master"); - if (NULL == vpfe_cfg->vpssclk) { - v4l2_err(vpfe_dev->pdev->driver, "No clock defined for" - "vpss_master\n"); - return ret; - } - - if (clk_enable(vpfe_cfg->vpssclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss master clock not enabled\n"); - goto out; - } - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master clock enabled\n"); - - vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave"); - if (NULL == vpfe_cfg->slaveclk) { - v4l2_err(vpfe_dev->pdev->driver, - "No clock defined for vpss slave\n"); - goto out; - } - - if (clk_enable(vpfe_cfg->slaveclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss slave clock not enabled\n"); - goto out; - } - v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n"); - return 0; -out: - if (vpfe_cfg->vpssclk) - clk_put(vpfe_cfg->vpssclk); - if (vpfe_cfg->slaveclk) - clk_put(vpfe_cfg->slaveclk); - - return -1; -} - /* * vpfe_probe : This function creates device entries by register * itself to the V4L2 driver and initializes fields of each @@ -1871,7 +1810,7 @@ static __init int vpfe_probe(struct platform_device *pdev) if (NULL == pdev->dev.platform_data) { v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENOENT; + ret = -ENODEV; goto probe_free_dev_mem; } @@ -1885,18 +1824,13 @@ static __init int vpfe_probe(struct platform_device *pdev) goto probe_free_dev_mem; } - /* enable vpss clocks */ - ret = vpfe_enable_clock(vpfe_dev); - if (ret) - goto probe_free_dev_mem; - mutex_lock(&ccdc_lock); /* Allocate memory for ccdc configuration */ ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); if (NULL == ccdc_cfg) { v4l2_err(pdev->dev.driver, "Memory allocation failed for ccdc_cfg\n"); - goto probe_disable_clock; + goto probe_free_dev_mem; } strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); @@ -1905,61 +1839,34 @@ static __init int vpfe_probe(struct platform_device *pdev) if (!res1) { v4l2_err(pdev->dev.driver, "Unable to get interrupt for VINT0\n"); - ret = -ENOENT; - goto probe_disable_clock; + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; } vpfe_dev->ccdc_irq0 = res1->start; /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, - IORESOURCE_IRQ, 1); + res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (!res1) { v4l2_err(pdev->dev.driver, "Unable to get interrupt for VINT1\n"); - ret = -ENOENT; - goto probe_disable_clock; + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; } vpfe_dev->ccdc_irq1 = res1->start; - /* Get address base of CCDC */ - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get register address map\n"); - ret = -ENOENT; - goto probe_disable_clock; - } - - ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1; - if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size, - pdev->dev.driver->name)) { - v4l2_err(pdev->dev.driver, - "Failed request_mem_region for ccdc base\n"); - ret = -ENXIO; - goto probe_disable_clock; - } - ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start, - ccdc_cfg->ccdc_addr_size); - if (!ccdc_cfg->ccdc_addr) { - v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n"); - ret = -ENXIO; - goto probe_out_release_mem1; - } - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, "vpfe_capture0", vpfe_dev); if (0 != ret) { v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_out_unmap1; + goto probe_free_ccdc_cfg_mem; } /* Allocate memory for video device */ vfd = video_device_alloc(); if (NULL == vfd) { ret = -ENOMEM; - v4l2_err(pdev->dev.driver, - "Unable to alloc video device\n"); + v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); goto probe_out_release_irq; } @@ -2075,12 +1982,7 @@ probe_out_video_release: video_device_release(vpfe_dev->video_dev); probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_out_unmap1: - iounmap(ccdc_cfg->ccdc_addr); -probe_out_release_mem1: - release_mem_region(res1->start, res1->end - res1->start + 1); -probe_disable_clock: - vpfe_disable_clock(vpfe_dev); +probe_free_ccdc_cfg_mem: mutex_unlock(&ccdc_lock); kfree(ccdc_cfg); probe_free_dev_mem: @@ -2094,7 +1996,6 @@ probe_free_dev_mem: static int vpfe_remove(struct platform_device *pdev) { struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - struct resource *res; v4l2_info(pdev->dev.driver, "vpfe_remove\n"); @@ -2102,12 +2003,6 @@ static int vpfe_remove(struct platform_device *pdev) kfree(vpfe_dev->sd); v4l2_device_unregister(&vpfe_dev->v4l2_dev); video_unregister_device(vpfe_dev->video_dev); - mutex_lock(&ccdc_lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); - iounmap(ccdc_cfg->ccdc_addr); - mutex_unlock(&ccdc_lock); - vpfe_disable_clock(vpfe_dev); kfree(vpfe_dev); kfree(ccdc_cfg); return 0; -- 1.6.0.4 From m-karicheri2 at ti.com Mon Dec 7 18:11:39 2009 From: m-karicheri2 at ti.com (m-karicheri2 at ti.com) Date: Mon, 7 Dec 2009 19:11:39 -0500 Subject: [PATCH v1 - 3/4] V4L - vpfe capture - Make dm355 ccdc a platform driver In-Reply-To: <1260231100-1226-2-git-send-email-m-karicheri2@ti.com> References: <1260231100-1226-1-git-send-email-m-karicheri2@ti.com> <1260231100-1226-2-git-send-email-m-karicheri2@ti.com> Message-ID: <1260231100-1226-3-git-send-email-m-karicheri2@ti.com> From: Muralidharan Karicheri This combines the two patches sent earlier to change the clock configuration and converting ccdc drivers to platform drivers. This has updated comments against v0 of these patches. In this patch, the probe() function is modified to do the vpss master and slave clock configuration. It is assumed that the clock names are same across all ccdc IPs. If not, this will have to use configurable clock names as done in previous patch (Vaibhav to check this for OMAP). The static variables used in the driver are encapsulated inside a structure (ccdc_cfg) as part of clean up. Reviewed-by: Vaibhav Hiremath Signed-off-by: Muralidharan Karicheri --- Applies to v4l-dvb linux-next drivers/media/video/davinci/dm355_ccdc.c | 409 +++++++++++++++++++----------- 1 files changed, 256 insertions(+), 153 deletions(-) diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index 56fbefe..36cde21 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -37,8 +37,11 @@ #include #include #include +#include + #include #include + #include "dm355_ccdc_regs.h" #include "ccdc_hw_device.h" @@ -46,67 +49,75 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CCDC Driver for DM355"); MODULE_AUTHOR("Texas Instruments"); -static struct device *dev; - -/* Object for CCDC raw mode */ -static struct ccdc_params_raw ccdc_hw_params_raw = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = 256, - .gb_g = 256, - .gr_cy = 256, - .b_mg = 256 - }, - .config_params = { - .datasft = 2, - .data_sz = CCDC_DATA_10BITS, - .mfilt1 = CCDC_NO_MEDIAN_FILTER1, - .mfilt2 = CCDC_NO_MEDIAN_FILTER2, - .alaw = { - .gama_wd = 2, +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = 256, + .gb_g = 256, + .gr_cy = 256, + .b_mg = 256 }, - .blk_clamp = { - .sample_pixel = 1, - .dc_sub = 25 - }, - .col_pat_field0 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - .col_pat_field1 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED + .config_params = { + .datasft = 2, + .mfilt1 = CCDC_NO_MEDIAN_FILTER1, + .mfilt2 = CCDC_NO_MEDIAN_FILTER2, + .alaw = { + .gama_wd = 2, + }, + .blk_clamp = { + .sample_pixel = 1, + .dc_sub = 25 + }, + .col_pat_field0 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED + }, + .col_pat_field1 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED + }, }, }, + /* YCbCr configuration */ + .ycbcr = { + .win = CCDC_WIN_PAL, + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED + }, }; -/* Object for CCDC ycbcr mode */ -static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { - .win = CCDC_WIN_PAL, - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED -}; - -static enum vpfe_hw_if_type ccdc_if_type; -static void *__iomem ccdc_base_addr; -static int ccdc_addr_size; - /* Raw Bayer formats */ static u32 ccdc_raw_bayer_pix_formats[] = {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; @@ -118,18 +129,12 @@ static u32 ccdc_raw_yuv_pix_formats[] = /* register access routines */ static inline u32 regr(u32 offset) { - return __raw_readl(ccdc_base_addr + offset); + return __raw_readl(ccdc_cfg.base_addr + offset); } static inline void regw(u32 val, u32 offset) { - __raw_writel(val, ccdc_base_addr + offset); -} - -static void ccdc_set_ccdc_base(void *addr, int size) -{ - ccdc_base_addr = addr; - ccdc_addr_size = size; + __raw_writel(val, ccdc_cfg.base_addr + offset); } static void ccdc_enable(int en) @@ -153,12 +158,12 @@ static void ccdc_enable_output_to_sdram(int en) static void ccdc_config_gain_offset(void) { /* configure gain */ - regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN); - regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN); - regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN); - regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN); + regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); + regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); + regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); + regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); /* configure offset */ - regw(ccdc_hw_params_raw.ccdc_offset, OFFSET); + regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); } /* @@ -169,7 +174,7 @@ static int ccdc_restore_defaults(void) { int i; - dev_dbg(dev, "\nstarting ccdc_restore_defaults..."); + dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); /* set all registers to zero */ for (i = 0; i <= CCDC_REG_LAST; i += 4) regw(0, i); @@ -180,30 +185,29 @@ static int ccdc_restore_defaults(void) regw(CULH_DEFAULT, CULH); regw(CULV_DEFAULT, CULV); /* Set default Gain and Offset */ - ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT; - ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT; - ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT; - ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; ccdc_config_gain_offset(); regw(OUTCLIP_DEFAULT, OUTCLIP); regw(LSCCFG2_DEFAULT, LSCCFG2); /* select ccdc input */ if (vpss_select_ccdc_source(VPSS_CCDCIN)) { - dev_dbg(dev, "\ncouldn't select ccdc input source"); + dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); return -EFAULT; } /* select ccdc clock */ if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { - dev_dbg(dev, "\ncouldn't enable ccdc clock"); + dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); return -EFAULT; } - dev_dbg(dev, "\nEnd of ccdc_restore_defaults..."); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); return 0; } static int ccdc_open(struct device *device) { - dev = device; return ccdc_restore_defaults(); } @@ -226,7 +230,7 @@ static void ccdc_setwin(struct v4l2_rect *image_win, int vert_start, vert_nr_lines; int mid_img = 0; - dev_dbg(dev, "\nStarting ccdc_setwin..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); /* * ppc - per pixel count. indicates how many pixels per cell @@ -260,45 +264,46 @@ static void ccdc_setwin(struct v4l2_rect *image_win, regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); - dev_dbg(dev, "\nEnd of ccdc_setwin..."); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); } static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) { if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { - dev_dbg(dev, "Invalid value of data shift\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); return -EINVAL; } if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { - dev_dbg(dev, "Invalid value of median filter1\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); return -EINVAL; } if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { - dev_dbg(dev, "Invalid value of median filter2\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); return -EINVAL; } if ((ccdcparam->med_filt_thres < 0) || (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { - dev_dbg(dev, "Invalid value of median filter thresold\n"); + dev_dbg(ccdc_cfg.dev, + "Invalid value of median filter thresold\n"); return -EINVAL; } if (ccdcparam->data_sz < CCDC_DATA_16BITS || ccdcparam->data_sz > CCDC_DATA_8BITS) { - dev_dbg(dev, "Invalid value of data size\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); return -EINVAL; } if (ccdcparam->alaw.enable) { if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { - dev_dbg(dev, "Invalid value of ALAW\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); return -EINVAL; } } @@ -306,12 +311,14 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) if (ccdcparam->blk_clamp.b_clamp_enable) { if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { - dev_dbg(dev, "Invalid value of sample pixel\n"); + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample pixel\n"); return -EINVAL; } if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { - dev_dbg(dev, "Invalid value of sample lines\n"); + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample lines\n"); return -EINVAL; } } @@ -325,18 +332,18 @@ static int ccdc_set_params(void __user *params) int x; /* only raw module parameters can be set through the IOCTL */ - if (ccdc_if_type != VPFE_RAW_BAYER) + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) return -EINVAL; x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); if (x) { - dev_dbg(dev, "ccdc_set_params: error in copying ccdc" + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" "params, %d\n", x); return -EFAULT; } if (!validate_ccdc_param(&ccdc_raw_params)) { - memcpy(&ccdc_hw_params_raw.config_params, + memcpy(&ccdc_cfg.bayer.config_params, &ccdc_raw_params, sizeof(ccdc_raw_params)); return 0; @@ -347,11 +354,11 @@ static int ccdc_set_params(void __user *params) /* This function will configure CCDC for YCbCr video capture */ static void ccdc_config_ycbcr(void) { - struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; u32 temp; /* first set the CCDC power on defaults values in all registers */ - dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); ccdc_restore_defaults(); /* configure pixel format & video frame format */ @@ -403,7 +410,7 @@ static void ccdc_config_ycbcr(void) regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); } - dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); } /* @@ -483,7 +490,7 @@ int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) */ if (count) { - dev_err(dev, "defect table write timeout !!!\n"); + dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); return -1; } return 0; @@ -605,12 +612,12 @@ static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, /* This function will configure CCDC for Raw mode image capture */ static int ccdc_config_raw(void) { - struct ccdc_params_raw *params = &ccdc_hw_params_raw; + struct ccdc_params_raw *params = &ccdc_cfg.bayer; struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int val; - dev_dbg(dev, "\nStarting ccdc_config_raw..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); /* restore power on defaults to register */ ccdc_restore_defaults(); @@ -659,7 +666,7 @@ static int ccdc_config_raw(void) val |= (config_params->datasft & CCDC_DATASFT_MASK) << CCDC_DATASFT_SHIFT; regw(val , MODESET); - dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); /* Configure the Median Filter threshold */ regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); @@ -681,7 +688,7 @@ static int ccdc_config_raw(void) (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); regw(val, GAMMAWD); - dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); /* configure video window */ ccdc_setwin(¶ms->win, params->frm_fmt, 1); @@ -706,7 +713,7 @@ static int ccdc_config_raw(void) /* Configure the Gain & offset control */ ccdc_config_gain_offset(); - dev_dbg(dev, "\nWriting %x to COLPTN...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); /* Configure DATAOFST register */ val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << @@ -726,7 +733,7 @@ static int ccdc_config_raw(void) CCDC_HSIZE_VAL_MASK; /* adjust to multiple of 32 */ - dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", (((params->win.width) + 31) >> 5) & CCDC_HSIZE_VAL_MASK); } else { @@ -734,7 +741,7 @@ static int ccdc_config_raw(void) val |= (((params->win.width * 2) + 31) >> 5) & CCDC_HSIZE_VAL_MASK; - dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", (((params->win.width * 2) + 31) >> 5) & CCDC_HSIZE_VAL_MASK); } @@ -745,34 +752,34 @@ static int ccdc_config_raw(void) if (params->image_invert_enable) { /* For interlace inverse mode */ regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_INTERLACE_INVERSE); } else { /* For interlace non inverse mode */ regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_INTERLACE_NORMAL); } } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { if (params->image_invert_enable) { /* For progessive inverse mode */ regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_PROGRESSIVE_INVERSE); } else { /* For progessive non inverse mode */ regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_PROGRESSIVE_NORMAL); } } - dev_dbg(dev, "\nend of ccdc_config_raw..."); + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); return 0; } static int ccdc_configure(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) return ccdc_config_raw(); else ccdc_config_ycbcr(); @@ -781,23 +788,23 @@ static int ccdc_configure(void) static int ccdc_set_buftype(enum ccdc_buftype buf_type) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.buf_type = buf_type; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_