OSDN Git Service

DaVinci: DM646x - platform changes for vpif capture and display drivers
authorMuralidharan Karicheri <m-karicheri2@ti.com>
Wed, 16 Sep 2009 17:15:30 +0000 (13:15 -0400)
committerKevin Hilman <khilman@deeprootsystems.com>
Wed, 16 Sep 2009 17:28:46 +0000 (10:28 -0700)
VPIF display changes (Chaithrika)

Add platform device and resource structures. Also define a platform specific
clock setup function that can be accessed by the driver to configure the clock
and CPLD.

VPIF caputure changes (Murali)

1) Modify vpif_subdev_info to add board_info, routing information and
   vpif interface configuration. Remove addr since it is part of
   board_info

2) Add code to setup channel mode and input decoder path for vpif
   capture driver

Also incorporated comments against version v0 of the patch series and
added a spinlock to protect writes to common registers

Tested on DM6467 on channel 0 using TVP514x. Following bootargs used
for drivers:

   vpif_capture.ch0_bufsize=829440 vpif_display.ch2_bufsize=829440

Signed-off-by: Manjunath Hadli <mrh@ti.com>
Signed-off-by: Brijesh Jadav <brijesh.j@ti.com>
Signed-off-by: Chaithrika U S <chaithrika@ti.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Muralidharan Karicheri <m-karicheri2@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-davinci/dm646x.c
arch/arm/mach-davinci/include/mach/dm646x.h

index 2054704..24e0e13 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/i2c/pcf857x.h>
 #include <linux/etherdevice.h>
 
+#include <media/tvp514x.h>
+
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #define DM646X_EVM_PHY_MASK            (0x2)
 #define DM646X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
 
+#define VIDCLKCTL_OFFSET       (DAVINCI_SYSTEM_MODULE_BASE + 0x38)
+#define VSCLKDIS_OFFSET                (DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
+#define VCH2CLK_MASK           (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
+#define VCH2CLK_SYSCLK8                (BIT(9))
+#define VCH2CLK_AUXCLK         (BIT(9) | BIT(8))
+#define VCH3CLK_MASK           (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
+#define VCH3CLK_SYSCLK8                (BIT(13))
+#define VCH3CLK_AUXCLK         (BIT(14) | BIT(13))
+
+#define VIDCH2CLK              (BIT(10))
+#define VIDCH3CLK              (BIT(11))
+#define VIDCH1CLK              (BIT(4))
+#define TVP7002_INPUT          (BIT(4))
+#define TVP5147_INPUT          (~BIT(4))
+#define VPIF_INPUT_ONE_CHANNEL (BIT(5))
+#define VPIF_INPUT_TWO_CHANNEL (~BIT(5))
+#define TVP5147_CH0            "tvp514x-0"
+#define TVP5147_CH1            "tvp514x-1"
+
+static void __iomem *vpif_vidclkctl_reg;
+static void __iomem *vpif_vsclkdis_reg;
+/* spin lock for updating above registers */
+static spinlock_t vpif_reg_lock;
+
 static struct davinci_uart_config uart_config __initdata = {
        .enabled_uarts = (1 << 0),
 };
@@ -287,6 +313,40 @@ static struct snd_platform_data dm646x_evm_snd_data[] = {
        },
 };
 
+static struct i2c_client *cpld_client;
+
+static int cpld_video_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       cpld_client = client;
+       return 0;
+}
+
+static int __devexit cpld_video_remove(struct i2c_client *client)
+{
+       cpld_client = NULL;
+       return 0;
+}
+
+static const struct i2c_device_id cpld_video_id[] = {
+       { "cpld_video", 0 },
+       { }
+};
+
+static struct i2c_driver cpld_video_driver = {
+       .driver = {
+               .name   = "cpld_video",
+       },
+       .probe          = cpld_video_probe,
+       .remove         = cpld_video_remove,
+       .id_table       = cpld_video_id,
+};
+
+static void evm_init_cpld(void)
+{
+       i2c_add_driver(&cpld_video_driver);
+}
+
 static struct i2c_board_info __initdata i2c_info[] =  {
        {
                I2C_BOARD_INFO("24c256", 0x50),
@@ -301,7 +361,10 @@ static struct i2c_board_info __initdata i2c_info[] =  {
        },
        {
                I2C_BOARD_INFO("tlv320aic33", 0x18),
-       }
+       },
+       {
+               I2C_BOARD_INFO("cpld_video", 0x3b),
+       },
 };
 
 static struct davinci_i2c_platform_data i2c_pdata = {
@@ -309,11 +372,265 @@ static struct davinci_i2c_platform_data i2c_pdata = {
        .bus_delay      = 0 /* usec */,
 };
 
+static int set_vpif_clock(int mux_mode, int hd)
+{
+       unsigned long flags;
+       unsigned int value;
+       int val = 0;
+       int err = 0;
+
+       if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg || !cpld_client)
+               return -ENXIO;
+
+       /* disable the clock */
+       spin_lock_irqsave(&vpif_reg_lock, flags);
+       value = __raw_readl(vpif_vsclkdis_reg);
+       value |= (VIDCH3CLK | VIDCH2CLK);
+       __raw_writel(value, vpif_vsclkdis_reg);
+       spin_unlock_irqrestore(&vpif_reg_lock, flags);
+
+       val = i2c_smbus_read_byte(cpld_client);
+       if (val < 0)
+               return val;
+
+       if (mux_mode == 1)
+               val &= ~0x40;
+       else
+               val |= 0x40;
+
+       err = i2c_smbus_write_byte(cpld_client, val);
+       if (err)
+               return err;
+
+       value = __raw_readl(vpif_vidclkctl_reg);
+       value &= ~(VCH2CLK_MASK);
+       value &= ~(VCH3CLK_MASK);
+
+       if (hd >= 1)
+               value |= (VCH2CLK_SYSCLK8 | VCH3CLK_SYSCLK8);
+       else
+               value |= (VCH2CLK_AUXCLK | VCH3CLK_AUXCLK);
+
+       __raw_writel(value, vpif_vidclkctl_reg);
+
+       spin_lock_irqsave(&vpif_reg_lock, flags);
+       value = __raw_readl(vpif_vsclkdis_reg);
+       /* enable the clock */
+       value &= ~(VIDCH3CLK | VIDCH2CLK);
+       __raw_writel(value, vpif_vsclkdis_reg);
+       spin_unlock_irqrestore(&vpif_reg_lock, flags);
+
+       return 0;
+}
+
+static struct vpif_subdev_info dm646x_vpif_subdev[] = {
+       {
+               .name   = "adv7343",
+               .board_info = {
+                       I2C_BOARD_INFO("adv7343", 0x2a),
+               },
+       },
+       {
+               .name   = "ths7303",
+               .board_info = {
+                       I2C_BOARD_INFO("ths7303", 0x2c),
+               },
+       },
+};
+
+static const char *output[] = {
+       "Composite",
+       "Component",
+       "S-Video",
+};
+
+static struct vpif_display_config dm646x_vpif_display_config = {
+       .set_clock      = set_vpif_clock,
+       .subdevinfo     = dm646x_vpif_subdev,
+       .subdev_count   = ARRAY_SIZE(dm646x_vpif_subdev),
+       .output         = output,
+       .output_count   = ARRAY_SIZE(output),
+       .card_name      = "DM646x EVM",
+};
+
+/**
+ * setup_vpif_input_path()
+ * @channel: channel id (0 - CH0, 1 - CH1)
+ * @sub_dev_name: ptr sub device name
+ *
+ * This will set vpif input to capture data from tvp514x or
+ * tvp7002.
+ */
+static int setup_vpif_input_path(int channel, const char *sub_dev_name)
+{
+       int err = 0;
+       int val;
+
+       /* for channel 1, we don't do anything */
+       if (channel != 0)
+               return 0;
+
+       if (!cpld_client)
+               return -ENXIO;
+
+       val = i2c_smbus_read_byte(cpld_client);
+       if (val < 0)
+               return val;
+
+       if (!strcmp(sub_dev_name, TVP5147_CH0) ||
+           !strcmp(sub_dev_name, TVP5147_CH1))
+               val &= TVP5147_INPUT;
+       else
+               val |= TVP7002_INPUT;
+
+       err = i2c_smbus_write_byte(cpld_client, val);
+       if (err)
+               return err;
+       return 0;
+}
+
+/**
+ * setup_vpif_input_channel_mode()
+ * @mux_mode:  mux mode. 0 - 1 channel or (1) - 2 channel
+ *
+ * This will setup input mode to one channel (TVP7002) or 2 channel (TVP5147)
+ */
+static int setup_vpif_input_channel_mode(int mux_mode)
+{
+       unsigned long flags;
+       int err = 0;
+       int val;
+       u32 value;
+
+       if (!vpif_vsclkdis_reg || !cpld_client)
+               return -ENXIO;
+
+       val = i2c_smbus_read_byte(cpld_client);
+       if (val < 0)
+               return val;
+
+       spin_lock_irqsave(&vpif_reg_lock, flags);
+       value = __raw_readl(vpif_vsclkdis_reg);
+       if (mux_mode) {
+               val &= VPIF_INPUT_TWO_CHANNEL;
+               value |= VIDCH1CLK;
+       } else {
+               val |= VPIF_INPUT_ONE_CHANNEL;
+               value &= ~VIDCH1CLK;
+       }
+       __raw_writel(value, vpif_vsclkdis_reg);
+       spin_unlock_irqrestore(&vpif_reg_lock, flags);
+
+       err = i2c_smbus_write_byte(cpld_client, val);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+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)
+
+static struct vpif_subdev_info vpif_capture_sdev_info[] = {
+       {
+               .name   = TVP5147_CH0,
+               .board_info = {
+                       I2C_BOARD_INFO("tvp5146", 0x5d),
+                       .platform_data = &tvp5146_pdata,
+               },
+               .input = INPUT_CVBS_VI2B,
+               .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
+               .can_route = 1,
+               .vpif_if = {
+                       .if_type = VPIF_IF_BT656,
+                       .hd_pol = 1,
+                       .vd_pol = 1,
+                       .fid_pol = 0,
+               },
+       },
+       {
+               .name   = TVP5147_CH1,
+               .board_info = {
+                       I2C_BOARD_INFO("tvp5146", 0x5c),
+                       .platform_data = &tvp5146_pdata,
+               },
+               .input = INPUT_SVIDEO_VI2C_VI1C,
+               .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
+               .can_route = 1,
+               .vpif_if = {
+                       .if_type = VPIF_IF_BT656,
+                       .hd_pol = 1,
+                       .vd_pol = 1,
+                       .fid_pol = 0,
+               },
+       },
+};
+
+static const struct vpif_input dm6467_ch0_inputs[] = {
+       {
+               .input = {
+                       .index = 0,
+                       .name = "Composite",
+                       .type = V4L2_INPUT_TYPE_CAMERA,
+                       .std = TVP514X_STD_ALL,
+               },
+               .subdev_name = TVP5147_CH0,
+       },
+};
+
+static const struct vpif_input dm6467_ch1_inputs[] = {
+       {
+               .input = {
+                       .index = 0,
+                       .name = "S-Video",
+                       .type = V4L2_INPUT_TYPE_CAMERA,
+                       .std = TVP514X_STD_ALL,
+               },
+               .subdev_name = TVP5147_CH1,
+       },
+};
+
+static struct vpif_capture_config dm646x_vpif_capture_cfg = {
+       .setup_input_path = setup_vpif_input_path,
+       .setup_input_channel_mode = setup_vpif_input_channel_mode,
+       .subdev_info = vpif_capture_sdev_info,
+       .subdev_count = ARRAY_SIZE(vpif_capture_sdev_info),
+       .chan_config[0] = {
+               .inputs = dm6467_ch0_inputs,
+               .input_count = ARRAY_SIZE(dm6467_ch0_inputs),
+       },
+       .chan_config[1] = {
+               .inputs = dm6467_ch1_inputs,
+               .input_count = ARRAY_SIZE(dm6467_ch1_inputs),
+       },
+};
+
+static void __init evm_init_video(void)
+{
+       vpif_vidclkctl_reg = ioremap(VIDCLKCTL_OFFSET, 4);
+       vpif_vsclkdis_reg = ioremap(VSCLKDIS_OFFSET, 4);
+       if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg) {
+               pr_err("Can't map VPIF VIDCLKCTL or VSCLKDIS registers\n");
+               return;
+       }
+       spin_lock_init(&vpif_reg_lock);
+
+       dm646x_setup_vpif(&dm646x_vpif_display_config,
+                         &dm646x_vpif_capture_cfg);
+}
+
 static void __init evm_init_i2c(void)
 {
        davinci_init_i2c(&i2c_pdata);
        i2c_add_driver(&dm6467evm_cpld_driver);
        i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+       evm_init_cpld();
+       evm_init_video();
 }
 
 static void __init davinci_map_io(void)
index 8fa2803..0976049 100644 (file)
 #include "clock.h"
 #include "mux.h"
 
+#define DAVINCI_VPIF_BASE       (0x01C12000)
+#define VDD3P3V_PWDN_OFFSET    (0x48)
+#define VSCLKDIS_OFFSET                (0x6C)
+
+#define VDD3P3V_VID_MASK       (BIT_MASK(3) | BIT_MASK(2) | BIT_MASK(1) |\
+                                       BIT_MASK(0))
+#define VSCLKDIS_MASK          (BIT_MASK(11) | BIT_MASK(10) | BIT_MASK(9) |\
+                                       BIT_MASK(8))
+
 /*
  * Device specific clocks
  */
@@ -686,6 +695,75 @@ static struct platform_device dm646x_dit_device = {
        .id     = -1,
 };
 
+static u64 vpif_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource vpif_resource[] = {
+       {
+               .start  = DAVINCI_VPIF_BASE,
+               .end    = DAVINCI_VPIF_BASE + 0x03ff,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device vpif_dev = {
+       .name           = "vpif",
+       .id             = -1,
+       .dev            = {
+                       .dma_mask               = &vpif_dma_mask,
+                       .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = vpif_resource,
+       .num_resources  = ARRAY_SIZE(vpif_resource),
+};
+
+static struct resource vpif_display_resource[] = {
+       {
+               .start = IRQ_DM646X_VP_VERTINT2,
+               .end   = IRQ_DM646X_VP_VERTINT2,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_DM646X_VP_VERTINT3,
+               .end   = IRQ_DM646X_VP_VERTINT3,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device vpif_display_dev = {
+       .name           = "vpif_display",
+       .id             = -1,
+       .dev            = {
+                       .dma_mask               = &vpif_dma_mask,
+                       .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = vpif_display_resource,
+       .num_resources  = ARRAY_SIZE(vpif_display_resource),
+};
+
+static struct resource vpif_capture_resource[] = {
+       {
+               .start = IRQ_DM646X_VP_VERTINT0,
+               .end   = IRQ_DM646X_VP_VERTINT0,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_DM646X_VP_VERTINT1,
+               .end   = IRQ_DM646X_VP_VERTINT1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device vpif_capture_dev = {
+       .name           = "vpif_capture",
+       .id             = -1,
+       .dev            = {
+                       .dma_mask               = &vpif_dma_mask,
+                       .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = vpif_capture_resource,
+       .num_resources  = ARRAY_SIZE(vpif_capture_resource),
+};
+
 /*----------------------------------------------------------------------*/
 
 static struct map_desc dm646x_io_desc[] = {
@@ -814,6 +892,32 @@ void __init dm646x_init_mcasp1(struct snd_platform_data *pdata)
        platform_device_register(&dm646x_dit_device);
 }
 
+void dm646x_setup_vpif(struct vpif_display_config *display_config,
+                      struct vpif_capture_config *capture_config)
+{
+       unsigned int value;
+       void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
+
+       value = __raw_readl(base + VSCLKDIS_OFFSET);
+       value &= ~VSCLKDIS_MASK;
+       __raw_writel(value, base + VSCLKDIS_OFFSET);
+
+       value = __raw_readl(base + VDD3P3V_PWDN_OFFSET);
+       value &= ~VDD3P3V_VID_MASK;
+       __raw_writel(value, base + VDD3P3V_PWDN_OFFSET);
+
+       davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
+       davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
+       davinci_cfg_reg(DM646X_PTSOMUX_DISABLE);
+       davinci_cfg_reg(DM646X_PTSIMUX_DISABLE);
+
+       vpif_display_dev.dev.platform_data = display_config;
+       vpif_capture_dev.dev.platform_data = capture_config;
+       platform_device_register(&vpif_dev);
+       platform_device_register(&vpif_display_dev);
+       platform_device_register(&vpif_capture_dev);
+}
+
 void __init dm646x_init(void)
 {
        davinci_common_init(&davinci_soc_info_dm646x);
index feb1e02..8cec746 100644 (file)
@@ -14,6 +14,8 @@
 #include <mach/hardware.h>
 #include <mach/emac.h>
 #include <mach/asp.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
 
 #define DM646X_EMAC_BASE               (0x01C80000)
 #define DM646X_EMAC_CNTRL_OFFSET       (0x0000)
@@ -29,4 +31,61 @@ void __init dm646x_init_ide(void);
 void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
 void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
 
+void dm646x_video_init(void);
+
+enum vpif_if_type {
+       VPIF_IF_BT656,
+       VPIF_IF_BT1120,
+       VPIF_IF_RAW_BAYER
+};
+
+struct vpif_interface {
+       enum vpif_if_type if_type;
+       unsigned hd_pol:1;
+       unsigned vd_pol:1;
+       unsigned fid_pol:1;
+};
+
+struct vpif_subdev_info {
+       const char *name;
+       struct i2c_board_info board_info;
+       u32 input;
+       u32 output;
+       unsigned can_route:1;
+       struct vpif_interface vpif_if;
+};
+
+struct vpif_display_config {
+       int (*set_clock)(int, int);
+       struct vpif_subdev_info *subdevinfo;
+       int subdev_count;
+       const char **output;
+       int output_count;
+       const char *card_name;
+};
+
+struct vpif_input {
+       struct v4l2_input input;
+       const char *subdev_name;
+};
+
+#define VPIF_CAPTURE_MAX_CHANNELS      2
+
+struct vpif_capture_chan_config {
+       const struct vpif_input *inputs;
+       int input_count;
+};
+
+struct vpif_capture_config {
+       int (*setup_input_channel_mode)(int);
+       int (*setup_input_path)(int, const char *);
+       struct vpif_capture_chan_config chan_config[VPIF_CAPTURE_MAX_CHANNELS];
+       struct vpif_subdev_info *subdev_info;
+       int subdev_count;
+       const char *card_name;
+};
+
+void dm646x_setup_vpif(struct vpif_display_config *,
+                      struct vpif_capture_config *);
+
 #endif /* __ASM_ARCH_DM646X_H */