diff options
author | Rakesh Movva | 2014-05-01 14:36:43 -0500 |
---|---|---|
committer | Rakesh Movva | 2014-05-01 14:36:43 -0500 |
commit | eb5cb3a183ce2d1d4ab4c83602b67d9e974a0c63 (patch) | |
tree | 68b69a70236eee6845c1256e428d6ee1814ddc35 | |
parent | dffc0c9166ccae9d6a66af99ba47cfae2684c10b (diff) | |
parent | ad429e8ade4bd66323f02e16ac6db79aa45a06ba (diff) | |
download | kernel-video-eb5cb3a183ce2d1d4ab4c83602b67d9e974a0c63.tar.gz kernel-video-eb5cb3a183ce2d1d4ab4c83602b67d9e974a0c63.tar.xz kernel-video-eb5cb3a183ce2d1d4ab4c83602b67d9e974a0c63.zip |
Merge branch 'vip' into p-ti-linux-3.8.y-videop-ti-linux-3.8.y-video
* vip:
v4l: ti-vps: vip: Different list_head for dequeue list
v4l: ti-vps: vip: Populate sequence number for frame
v4l: ti-vps: vip: Handle short frames irqs
arm: dts: dra7xx: Add gpio properties for fpdlink camera
i2c: fpdlink: Parse and set gpios in probe
v4l: ti-vps: vip: Populate field ID for interlaced capture
v4l: ti-vps: vpdma: Use write desciptor bit in dtd
v4l: ti-vps: vpdma: Add enum for max width height
v4l: ti-vps: vip: Dequeue only once while dropping
v4l: ti-vps: vip: Improve buffer dropping logic
Conflicts:
drivers/media/platform/ti-vps/vpdma.c
drivers/media/platform/ti-vps/vpe.c
-rw-r--r-- | arch/arm/boot/dts/dra7-evm.dts | 2 | ||||
-rw-r--r-- | drivers/media/i2c/fpdlink.c | 68 | ||||
-rw-r--r-- | drivers/media/platform/ti-vps/vip.c | 175 | ||||
-rw-r--r-- | drivers/media/platform/ti-vps/vip.h | 7 | ||||
-rw-r--r-- | drivers/media/platform/ti-vps/vpdma.c | 33 | ||||
-rw-r--r-- | drivers/media/platform/ti-vps/vpdma.h | 30 | ||||
-rw-r--r-- | drivers/media/platform/ti-vps/vpdma_priv.h | 39 | ||||
-rw-r--r-- | drivers/media/platform/ti-vps/vpe.c | 1 |
8 files changed, 219 insertions, 136 deletions
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index 763493311e1..81ddc3dac60 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts | |||
@@ -699,6 +699,8 @@ | |||
699 | fpdlink_camera { | 699 | fpdlink_camera { |
700 | compatible = "ti,fpdlink"; | 700 | compatible = "ti,fpdlink"; |
701 | reg = <0x20>; | 701 | reg = <0x20>; |
702 | gpios = <&pcf_hdmi 3 0>, | ||
703 | <&pcf_lcd3 8 0>; | ||
702 | port { | 704 | port { |
703 | cam_fpdlink: endpoint { | 705 | cam_fpdlink: endpoint { |
704 | hsync-active = <1>; | 706 | hsync-active = <1>; |
diff --git a/drivers/media/i2c/fpdlink.c b/drivers/media/i2c/fpdlink.c index 42e8bca6f51..7b927bd864c 100644 --- a/drivers/media/i2c/fpdlink.c +++ b/drivers/media/i2c/fpdlink.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/i2c.h> | 1 | #include <linux/i2c.h> |
2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
3 | #include <linux/gpio.h> | ||
3 | #include <linux/module.h> | 4 | #include <linux/module.h> |
4 | #include <linux/regmap.h> | 5 | #include <linux/regmap.h> |
5 | #include <linux/slab.h> | 6 | #include <linux/slab.h> |
@@ -12,6 +13,8 @@ | |||
12 | #include <media/v4l2-ctrls.h> | 13 | #include <media/v4l2-ctrls.h> |
13 | 14 | ||
14 | #include <linux/pm_runtime.h> | 15 | #include <linux/pm_runtime.h> |
16 | #include <linux/of_gpio.h> | ||
17 | |||
15 | 18 | ||
16 | struct fpdlink_color_format { | 19 | struct fpdlink_color_format { |
17 | enum v4l2_mbus_pixelcode code; | 20 | enum v4l2_mbus_pixelcode code; |
@@ -25,6 +28,57 @@ static const struct fpdlink_color_format fpdlink_cfmts[] = { | |||
25 | }, | 28 | }, |
26 | }; | 29 | }; |
27 | 30 | ||
31 | struct fpdlink_priv { | ||
32 | struct v4l2_subdev subdev; | ||
33 | int cam_fpd_mux_s0_gpio; | ||
34 | int sel_tvp_fpd_s0; | ||
35 | }; | ||
36 | |||
37 | static int fpdlink_set_gpios(struct i2c_client *client) | ||
38 | { | ||
39 | struct fpdlink_priv *priv = i2c_get_clientdata(client); | ||
40 | struct gpio gpios[] = { | ||
41 | { priv->sel_tvp_fpd_s0, GPIOF_OUT_INIT_HIGH, | ||
42 | "tvp_fpd_mux_s0" }, | ||
43 | { priv->cam_fpd_mux_s0_gpio, GPIOF_OUT_INIT_HIGH, | ||
44 | "cam_fpd_mux_s0" }, | ||
45 | }; | ||
46 | int ret = -1; | ||
47 | |||
48 | ret = gpio_request_array(gpios, ARRAY_SIZE(gpios)); | ||
49 | if (ret) | ||
50 | return ret; | ||
51 | |||
52 | gpio_free_array(gpios, ARRAY_SIZE(gpios)); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int fpdlink_parse_gpios(struct i2c_client *client, | ||
58 | struct device_node *node) | ||
59 | { | ||
60 | |||
61 | struct fpdlink_priv *priv = i2c_get_clientdata(client); | ||
62 | int gpio; | ||
63 | |||
64 | gpio = of_get_gpio(node, 0); | ||
65 | if (gpio_is_valid(gpio)) { | ||
66 | priv->cam_fpd_mux_s0_gpio = gpio; | ||
67 | } else { | ||
68 | dev_err(&client->dev, "failed to parse CAM_FPD_MUX_S0 gpio\n"); | ||
69 | return -EINVAL; | ||
70 | } | ||
71 | gpio = of_get_gpio(node, 1); | ||
72 | if (gpio_is_valid(gpio)) { | ||
73 | priv->sel_tvp_fpd_s0 = gpio; | ||
74 | } else { | ||
75 | dev_err(&client->dev, "failed to parse TVP_FPD_MUX_S0 gpio\n"); | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
28 | static int fpdlink_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | 82 | static int fpdlink_enum_fmt(struct v4l2_subdev *sd, unsigned int index, |
29 | enum v4l2_mbus_pixelcode *code) | 83 | enum v4l2_mbus_pixelcode *code) |
30 | { | 84 | { |
@@ -51,6 +105,9 @@ static int fpdlink_try_fmt(struct v4l2_subdev *sd, | |||
51 | static int fpdlink_s_fmt(struct v4l2_subdev *sd, | 105 | static int fpdlink_s_fmt(struct v4l2_subdev *sd, |
52 | struct v4l2_mbus_framefmt *mf) | 106 | struct v4l2_mbus_framefmt *mf) |
53 | { | 107 | { |
108 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
109 | |||
110 | fpdlink_set_gpios(client); | ||
54 | return 0; | 111 | return 0; |
55 | } | 112 | } |
56 | 113 | ||
@@ -88,20 +145,25 @@ static const struct of_device_id fpdlink_dt_id[] = { | |||
88 | static int fpdlink_probe(struct i2c_client *client, | 145 | static int fpdlink_probe(struct i2c_client *client, |
89 | const struct i2c_device_id *did) | 146 | const struct i2c_device_id *did) |
90 | { | 147 | { |
148 | struct fpdlink_priv *priv; | ||
91 | struct v4l2_subdev *sd; | 149 | struct v4l2_subdev *sd; |
92 | int ret = -1; | 150 | int ret = -1; |
93 | 151 | ||
94 | sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL); | 152 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); |
95 | if (!sd) | 153 | if (!priv) |
96 | return -ENOMEM; | 154 | return -ENOMEM; |
155 | i2c_set_clientdata(client, priv); | ||
156 | |||
157 | fpdlink_parse_gpios(client, client->dev.of_node); | ||
158 | fpdlink_set_gpios(client); | ||
97 | 159 | ||
160 | sd = &priv->subdev; | ||
98 | v4l2_i2c_subdev_init(sd, client, &fpdlink_subdev_ops); | 161 | v4l2_i2c_subdev_init(sd, client, &fpdlink_subdev_ops); |
99 | 162 | ||
100 | /* V4l2 asyn subdev register */ | 163 | /* V4l2 asyn subdev register */ |
101 | sd->dev = &client->dev; | 164 | sd->dev = &client->dev; |
102 | ret = v4l2_async_register_subdev(sd); | 165 | ret = v4l2_async_register_subdev(sd); |
103 | if (!ret) { | 166 | if (!ret) { |
104 | i2c_set_clientdata(client, sd); | ||
105 | v4l2_info(sd, "Camera sensor driver registered\n"); | 167 | v4l2_info(sd, "Camera sensor driver registered\n"); |
106 | pm_runtime_enable(&client->dev); | 168 | pm_runtime_enable(&client->dev); |
107 | } | 169 | } |
diff --git a/drivers/media/platform/ti-vps/vip.c b/drivers/media/platform/ti-vps/vip.c index 648baceb3cf..38982275f05 100644 --- a/drivers/media/platform/ti-vps/vip.c +++ b/drivers/media/platform/ti-vps/vip.c | |||
@@ -52,7 +52,7 @@ MODULE_VERSION("0.1"); | |||
52 | 52 | ||
53 | /* | 53 | /* |
54 | * Need a descriptor entry for each of up to 15 outputs, | 54 | * Need a descriptor entry for each of up to 15 outputs, |
55 | * and up to 2 control transfers. | 55 | * and up to 2 write descriptor. |
56 | */ | 56 | */ |
57 | #define VIP_DESC_LIST_SIZE (17 * sizeof(struct vpdma_dtd)) | 57 | #define VIP_DESC_LIST_SIZE (17 * sizeof(struct vpdma_dtd)) |
58 | 58 | ||
@@ -757,6 +757,7 @@ static int add_out_dtd(struct vip_stream *stream, int srce_type) | |||
757 | struct vip_fmt *fmt = port->fmt; | 757 | struct vip_fmt *fmt = port->fmt; |
758 | struct vpdma_dtd *dtd; | 758 | struct vpdma_dtd *dtd; |
759 | int channel, plane = 0; | 759 | int channel, plane = 0; |
760 | int vpdma_max_width, vpdma_max_height; | ||
760 | dma_addr_t dma_addr; | 761 | dma_addr_t dma_addr; |
761 | u32 flags; | 762 | u32 flags; |
762 | 763 | ||
@@ -795,14 +796,8 @@ static int add_out_dtd(struct vip_stream *stream, int srce_type) | |||
795 | return -1; | 796 | return -1; |
796 | } | 797 | } |
797 | 798 | ||
798 | vpdma_add_out_dtd(&dev->desc_list, c_rect->width, | ||
799 | fmt->vpdma_fmt[plane], dma_addr, channel, flags); | ||
800 | |||
801 | /* | 799 | /* |
802 | * add_out_dtd sets the max WIDTH and HEIGHT to be 1920x1080 | 800 | * Use VPDMA_MAX_SIZE1 or VPDMA_MAX_SIZE2 register for slice0/1 |
803 | * Change this later so that max WIDTH and HEIGHT are taken from | ||
804 | * VPDMA_MAX_SIZE1 or VPDMA_MAX_SIZE2 register | ||
805 | * This allows to use different sets for different slices | ||
806 | */ | 801 | */ |
807 | 802 | ||
808 | dtd = dev->desc_list.buf.addr; | 803 | dtd = dev->desc_list.buf.addr; |
@@ -810,16 +805,20 @@ static int add_out_dtd(struct vip_stream *stream, int srce_type) | |||
810 | vpdma_set_max_size(dev->shared->vpdma, VPDMA_MAX_SIZE1, | 805 | vpdma_set_max_size(dev->shared->vpdma, VPDMA_MAX_SIZE1, |
811 | stream->width, stream->height); | 806 | stream->width, stream->height); |
812 | 807 | ||
813 | dtd_set_max_width_height(dtd, | 808 | vpdma_max_width = MAX_OUT_WIDTH_REG1; |
814 | MAX_OUT_WIDTH_REG1, MAX_OUT_HEIGHT_REG1); | 809 | vpdma_max_height = MAX_OUT_HEIGHT_REG1; |
815 | } else { | 810 | } else { |
816 | vpdma_set_max_size(dev->shared->vpdma, VPDMA_MAX_SIZE2, | 811 | vpdma_set_max_size(dev->shared->vpdma, VPDMA_MAX_SIZE2, |
817 | stream->width, stream->height); | 812 | stream->width, stream->height); |
818 | 813 | ||
819 | dtd_set_max_width_height(dtd, | 814 | vpdma_max_width = MAX_OUT_WIDTH_REG2; |
820 | MAX_OUT_WIDTH_REG2, MAX_OUT_HEIGHT_REG2); | 815 | vpdma_max_height = MAX_OUT_HEIGHT_REG2; |
821 | } | 816 | } |
822 | 817 | ||
818 | vpdma_add_out_dtd(&dev->desc_list, c_rect->width, | ||
819 | fmt->vpdma_fmt[plane], dma_addr, | ||
820 | vpdma_max_width, vpdma_max_height, channel, flags); | ||
821 | |||
823 | return 0; | 822 | return 0; |
824 | } | 823 | } |
825 | 824 | ||
@@ -892,6 +891,7 @@ static void populate_desc_list(struct vip_stream *stream) | |||
892 | static void start_dma(struct vip_dev *dev, struct vip_buffer *buf) | 891 | static void start_dma(struct vip_dev *dev, struct vip_buffer *buf) |
893 | { | 892 | { |
894 | struct vpdma_data *vpdma = dev->shared->vpdma; | 893 | struct vpdma_data *vpdma = dev->shared->vpdma; |
894 | struct vpdma_dtd *write_dtd; | ||
895 | dma_addr_t dma_addr; | 895 | dma_addr_t dma_addr; |
896 | int drop_data; | 896 | int drop_data; |
897 | 897 | ||
@@ -913,8 +913,12 @@ static void start_dma(struct vip_dev *dev, struct vip_buffer *buf) | |||
913 | 913 | ||
914 | enable_irqs(dev, dev->slice_id); | 914 | enable_irqs(dev, dev->slice_id); |
915 | 915 | ||
916 | vpdma_buf_unmap(dev->shared->vpdma, &dev->desc_list.buf); | ||
917 | |||
916 | vpdma_update_dma_addr(dev->shared->vpdma, &dev->desc_list, | 918 | vpdma_update_dma_addr(dev->shared->vpdma, &dev->desc_list, |
917 | dma_addr, drop_data); | 919 | dma_addr, dev->write_desc, drop_data); |
920 | vpdma_buf_map(dev->shared->vpdma, &dev->desc_list.buf); | ||
921 | |||
918 | vpdma_submit_descs(dev->shared->vpdma, &dev->desc_list, dev->slice_id); | 922 | vpdma_submit_descs(dev->shared->vpdma, &dev->desc_list, dev->slice_id); |
919 | } | 923 | } |
920 | 924 | ||
@@ -926,59 +930,74 @@ static void vip_active_buf_next(struct vip_stream *stream) | |||
926 | 930 | ||
927 | spin_lock_irqsave(&dev->slock, flags); | 931 | spin_lock_irqsave(&dev->slock, flags); |
928 | if (list_empty(&stream->vidq)) { | 932 | if (list_empty(&stream->vidq)) { |
929 | v4l2_dbg(1, debug, &dev->v4l2_dev, "%s No buffers to queue, dropping frame, Queue faster or increase no of buffers"); | 933 | vip_dprintk(dev, "Dropping frame"); |
930 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | 934 | /* Increment drop_count for last buffer in the list */ |
931 | if (!buf) { | 935 | buf = list_entry(dev->vip_bufs.prev, |
932 | v4l2_err(&dev->v4l2_dev, "No memory!!"); | 936 | struct vip_buffer, dq_list); |
933 | spin_unlock_irqrestore(&dev->slock, flags); | 937 | buf->drop_count++; |
934 | return; | 938 | buf = NULL; |
935 | } | 939 | |
936 | buf->drop = true; | 940 | } else if (vb2_is_streaming(&stream->vb_vidq)) { |
937 | list_add_tail(&buf->list, &dev->vip_bufs); | 941 | buf = list_entry(stream->vidq.next, struct vip_buffer, list); |
938 | spin_unlock_irqrestore(&dev->slock, flags); | 942 | buf->drop_count = 0; |
939 | start_dma(dev, NULL); | 943 | buf->allow_dq = true; |
940 | } else if (vb2_is_streaming(&stream->vb_vidq)) { | 944 | list_del(&buf->list); |
941 | buf = list_entry(stream->vidq.next, | 945 | list_add_tail(&buf->dq_list, &dev->vip_bufs); |
942 | struct vip_buffer, list); | 946 | } else { |
943 | list_move_tail(&buf->list, &dev->vip_bufs); | 947 | v4l2_err(&dev->v4l2_dev, "IRQ occurred when not streaming"); |
944 | spin_unlock_irqrestore(&dev->slock, flags); | 948 | spin_unlock_irqrestore(&dev->slock, flags); |
945 | start_dma(dev, buf); | 949 | return; |
946 | } else | 950 | } |
947 | spin_unlock_irqrestore(&dev->slock, flags); | ||
948 | 951 | ||
949 | if (list_empty(&dev->vip_bufs)) | 952 | spin_unlock_irqrestore(&dev->slock, flags); |
950 | stream->cur_buf = NULL; | 953 | start_dma(dev, buf); |
951 | else | ||
952 | stream->cur_buf = list_first_entry(&dev->vip_bufs, | ||
953 | struct vip_buffer, list); | ||
954 | } | 954 | } |
955 | 955 | ||
956 | static void vip_process_buffer_complete(struct vip_stream *stream) | 956 | static void vip_process_buffer_complete(struct vip_stream *stream) |
957 | { | 957 | { |
958 | struct vip_dev *dev = stream->port->dev; | 958 | struct vip_dev *dev = stream->port->dev; |
959 | struct vb2_buffer *vb = NULL; | 959 | struct vb2_buffer *vb = NULL; |
960 | unsigned long flags; | 960 | struct vip_buffer *buf; |
961 | unsigned long flags, fld; | ||
962 | |||
963 | buf = list_first_entry(&dev->vip_bufs, struct vip_buffer, dq_list); | ||
964 | |||
965 | if (stream->port->flags & FLAG_INTERLACED) { | ||
966 | vpdma_buf_unmap(dev->shared->vpdma, &dev->desc_list.buf); | ||
967 | |||
968 | fld = dtd_get_field(dev->write_desc); | ||
969 | stream->field = fld ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; | ||
961 | 970 | ||
962 | if (stream->cur_buf) { | 971 | vpdma_buf_map(dev->shared->vpdma, &dev->desc_list.buf); |
963 | vb = &stream->cur_buf->vb; | 972 | } |
973 | |||
974 | if (buf) { | ||
975 | vb = &buf->vb; | ||
976 | vb->v4l2_buf.field = stream->field; | ||
977 | vb->v4l2_buf.sequence = stream->sequence; | ||
964 | do_gettimeofday(&vb->v4l2_buf.timestamp); | 978 | do_gettimeofday(&vb->v4l2_buf.timestamp); |
965 | 979 | ||
966 | spin_lock_irqsave(&dev->slock, flags); | 980 | if (buf->drop_count-- == 0) { |
967 | list_del(&stream->cur_buf->list); | 981 | spin_lock_irqsave(&dev->slock, flags); |
968 | spin_unlock_irqrestore(&dev->slock, flags); | 982 | list_del(&buf->dq_list); |
983 | spin_unlock_irqrestore(&dev->slock, flags); | ||
984 | } | ||
969 | 985 | ||
970 | if (stream->cur_buf->drop) | 986 | if (buf->allow_dq) { |
971 | kfree(stream->cur_buf); | 987 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); |
972 | else | 988 | buf->allow_dq = false; |
973 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | 989 | } |
974 | } | 990 | } else { |
991 | BUG(); | ||
992 | } | ||
975 | 993 | ||
976 | vip_active_buf_next(stream); | 994 | stream->sequence++; |
977 | } | 995 | } |
978 | 996 | ||
979 | static irqreturn_t vip_irq(int irq_vip, void *data) | 997 | static irqreturn_t vip_irq(int irq_vip, void *data) |
980 | { | 998 | { |
981 | struct vip_dev *dev = (struct vip_dev *)data; | 999 | struct vip_dev *dev = (struct vip_dev *)data; |
1000 | struct vip_stream *stream; | ||
982 | int list_num = dev->slice_id; | 1001 | int list_num = dev->slice_id; |
983 | int irq_num = dev->slice_id; | 1002 | int irq_num = dev->slice_id; |
984 | u32 irqst, reg_addr; | 1003 | u32 irqst, reg_addr; |
@@ -1003,14 +1022,17 @@ static irqreturn_t vip_irq(int irq_vip, void *data) | |||
1003 | irqst &= ~((1 << list_num * 2)); | 1022 | irqst &= ~((1 << list_num * 2)); |
1004 | } | 1023 | } |
1005 | 1024 | ||
1025 | disable_irqs(dev, dev->slice_id); | ||
1026 | |||
1027 | stream = dev->ports[0]->cap_streams[0]; | ||
1028 | |||
1006 | if (dev->num_skip_irq) { | 1029 | if (dev->num_skip_irq) { |
1007 | dev->num_skip_irq--; | 1030 | dev->num_skip_irq--; |
1008 | return IRQ_HANDLED; | 1031 | } else { |
1032 | vip_process_buffer_complete(stream); | ||
1009 | } | 1033 | } |
1010 | 1034 | ||
1011 | /* disable_irqs(dev); */ | 1035 | vip_active_buf_next(stream); |
1012 | |||
1013 | vip_process_buffer_complete(dev->ports[0]->cap_streams[0]); | ||
1014 | 1036 | ||
1015 | return IRQ_HANDLED; | 1037 | return IRQ_HANDLED; |
1016 | } | 1038 | } |
@@ -1215,7 +1237,7 @@ static int vip_try_fmt_vid_cap(struct file *file, void *priv, | |||
1215 | 1237 | ||
1216 | if (field == V4L2_FIELD_ANY) | 1238 | if (field == V4L2_FIELD_ANY) |
1217 | field = V4L2_FIELD_NONE; | 1239 | field = V4L2_FIELD_NONE; |
1218 | else if (V4L2_FIELD_NONE != field) | 1240 | else if (V4L2_FIELD_NONE != field && V4L2_FIELD_ALTERNATE != field) |
1219 | return -EINVAL; | 1241 | return -EINVAL; |
1220 | 1242 | ||
1221 | f->fmt.pix.field = field; | 1243 | f->fmt.pix.field = field; |
@@ -1498,36 +1520,30 @@ static int vip_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
1498 | return -EIO; | 1520 | return -EIO; |
1499 | } | 1521 | } |
1500 | 1522 | ||
1501 | stream->cur_buf = list_entry(stream->vidq.next, | 1523 | buf = list_entry(stream->vidq.next, struct vip_buffer, list); |
1502 | struct vip_buffer, list); | 1524 | buf->drop_count = 0; |
1503 | stream->cur_buf->vb.state = VB2_BUF_STATE_ACTIVE; | 1525 | buf->allow_dq = true; |
1526 | |||
1527 | stream->cur_buf = buf; | ||
1528 | stream->sequence = 0; | ||
1504 | stream->field = V4L2_FIELD_TOP; | 1529 | stream->field = V4L2_FIELD_TOP; |
1505 | 1530 | ||
1506 | populate_desc_list(stream); | 1531 | populate_desc_list(stream); |
1507 | dev->num_skip_irq = VIP_VPDMA_FIFO_SIZE; | 1532 | dev->num_skip_irq = VIP_VPDMA_FIFO_SIZE; |
1508 | 1533 | ||
1509 | for (i = 0; i < count; i++) { | 1534 | spin_lock_irqsave(&dev->slock, flags); |
1510 | 1535 | if (vpdma_list_busy(dev->shared->vpdma, dev->slice_id)) { | |
1511 | spin_lock_irqsave(&dev->slock, flags); | 1536 | spin_unlock_irqrestore(&dev->slock, flags); |
1512 | if (!vpdma_list_busy(dev->shared->vpdma, dev->slice_id)) { | 1537 | vpdma_buf_unmap(dev->shared->vpdma, &dev->desc_list.buf); |
1513 | 1538 | vpdma_reset_desc_list(&dev->desc_list); | |
1514 | buf = list_entry(stream->vidq.next, | 1539 | return -EBUSY; |
1515 | struct vip_buffer, list); | 1540 | } |
1516 | list_move_tail(&buf->list, &dev->vip_bufs); | ||
1517 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1518 | 1541 | ||
1519 | if (!stream->cur_buf) | 1542 | list_del(&buf->list); |
1520 | stream->cur_buf = buf; | 1543 | list_add_tail(&buf->dq_list, &dev->vip_bufs); |
1521 | start_dma(dev, buf); | 1544 | spin_unlock_irqrestore(&dev->slock, flags); |
1522 | 1545 | ||
1523 | if (i == VIP_VPDMA_FIFO_SIZE) | 1546 | start_dma(dev, buf); |
1524 | break; | ||
1525 | while (vpdma_list_busy(dev->shared->vpdma, | ||
1526 | dev->slice_id)) | ||
1527 | ; | ||
1528 | } else | ||
1529 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1530 | } | ||
1531 | 1547 | ||
1532 | return 0; | 1548 | return 0; |
1533 | } | 1549 | } |
@@ -1551,8 +1567,9 @@ static int vip_stop_streaming(struct vb2_queue *vq) | |||
1551 | disable_irqs(dev, dev->slice_id); | 1567 | disable_irqs(dev, dev->slice_id); |
1552 | /* release all active buffers */ | 1568 | /* release all active buffers */ |
1553 | while (!list_empty(&dev->vip_bufs)) { | 1569 | while (!list_empty(&dev->vip_bufs)) { |
1554 | buf = list_entry(dev->vip_bufs.next, struct vip_buffer, list); | 1570 | buf = list_entry(dev->vip_bufs.next, |
1555 | list_del(&buf->list); | 1571 | struct vip_buffer, dq_list); |
1572 | list_del(&buf->dq_list); | ||
1556 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | 1573 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); |
1557 | } | 1574 | } |
1558 | while (!list_empty(&stream->vidq)) { | 1575 | while (!list_empty(&stream->vidq)) { |
@@ -1606,6 +1623,8 @@ static int vip_init_dev(struct vip_dev *dev) | |||
1606 | if (ret != 0) | 1623 | if (ret != 0) |
1607 | return ret; | 1624 | return ret; |
1608 | 1625 | ||
1626 | dev->write_desc = (struct vpdma_dtd *)dev->desc_list.buf.addr | ||
1627 | + 15; | ||
1609 | vip_set_clock_enable(dev, 1); | 1628 | vip_set_clock_enable(dev, 1); |
1610 | done: | 1629 | done: |
1611 | dev->num_ports++; | 1630 | dev->num_ports++; |
diff --git a/drivers/media/platform/ti-vps/vip.h b/drivers/media/platform/ti-vps/vip.h index 8ff8d337e99..1b41164f788 100644 --- a/drivers/media/platform/ti-vps/vip.h +++ b/drivers/media/platform/ti-vps/vip.h | |||
@@ -38,7 +38,11 @@ struct vip_buffer { | |||
38 | /* common v4l buffer stuff */ | 38 | /* common v4l buffer stuff */ |
39 | struct vb2_buffer vb; | 39 | struct vb2_buffer vb; |
40 | struct list_head list; | 40 | struct list_head list; |
41 | bool drop; | 41 | struct list_head dq_list; |
42 | /* Number of buffers to drop after this */ | ||
43 | int drop_count; | ||
44 | /* To make sure same buffer isn't dequeued again */ | ||
45 | bool allow_dq; | ||
42 | }; | 46 | }; |
43 | 47 | ||
44 | /* | 48 | /* |
@@ -89,6 +93,7 @@ struct vip_dev { | |||
89 | void __iomem *base; | 93 | void __iomem *base; |
90 | 94 | ||
91 | struct vpdma_desc_list desc_list; /* DMA descriptor list */ | 95 | struct vpdma_desc_list desc_list; /* DMA descriptor list */ |
96 | struct vpdma_dtd *write_desc; | ||
92 | void *desc_next; /* next unused desc_list addr */ | 97 | void *desc_next; /* next unused desc_list addr */ |
93 | struct list_head vip_bufs; /* vip_bufs to be DMAed */ | 98 | struct list_head vip_bufs; /* vip_bufs to be DMAed */ |
94 | struct vb2_alloc_ctx *alloc_ctx; | 99 | struct vb2_alloc_ctx *alloc_ctx; |
diff --git a/drivers/media/platform/ti-vps/vpdma.c b/drivers/media/platform/ti-vps/vpdma.c index d8252d26856..370a8cc1846 100644 --- a/drivers/media/platform/ti-vps/vpdma.c +++ b/drivers/media/platform/ti-vps/vpdma.c | |||
@@ -343,7 +343,7 @@ void vpdma_buf_map(struct vpdma_data *vpdma, struct vpdma_buf *buf) | |||
343 | 343 | ||
344 | WARN_ON(buf->mapped != 0); | 344 | WARN_ON(buf->mapped != 0); |
345 | buf->dma_addr = dma_map_single(dev, buf->addr, buf->size, | 345 | buf->dma_addr = dma_map_single(dev, buf->addr, buf->size, |
346 | DMA_TO_DEVICE); | 346 | DMA_BIDIRECTIONAL); |
347 | buf->mapped = 1; | 347 | buf->mapped = 1; |
348 | WARN_ON(dma_mapping_error(dev, buf->dma_addr)); | 348 | WARN_ON(dma_mapping_error(dev, buf->dma_addr)); |
349 | } | 349 | } |
@@ -363,7 +363,8 @@ void vpdma_buf_unmap(struct vpdma_data *vpdma, struct vpdma_buf *buf) | |||
363 | } | 363 | } |
364 | 364 | ||
365 | if (buf->mapped) | 365 | if (buf->mapped) |
366 | dma_unmap_single(dev, buf->dma_addr, buf->size, DMA_TO_DEVICE); | 366 | dma_unmap_single(dev, buf->dma_addr, buf->size, |
367 | DMA_BIDIRECTIONAL); | ||
367 | 368 | ||
368 | buf->mapped = 0; | 369 | buf->mapped = 0; |
369 | } | 370 | } |
@@ -450,24 +451,25 @@ int vpdma_submit_descs(struct vpdma_data *vpdma, | |||
450 | EXPORT_SYMBOL(vpdma_submit_descs); | 451 | EXPORT_SYMBOL(vpdma_submit_descs); |
451 | 452 | ||
452 | void vpdma_update_dma_addr(struct vpdma_data *vpdma, | 453 | void vpdma_update_dma_addr(struct vpdma_data *vpdma, |
453 | struct vpdma_desc_list *list, dma_addr_t dma_addr, int drop) | 454 | struct vpdma_desc_list *list, dma_addr_t dma_addr, |
455 | struct vpdma_dtd *write_dtd, int drop) | ||
454 | { | 456 | { |
455 | struct vpdma_dtd *dtd = list->buf.addr; | 457 | struct vpdma_dtd *dtd = list->buf.addr; |
456 | unsigned int write_desc_addr; | 458 | dma_addr_t write_desc_addr; |
457 | 459 | int offset; | |
458 | vpdma_buf_unmap(vpdma, &list->buf); | ||
459 | 460 | ||
460 | dtd_set_start_addr(dtd, dma_addr); | 461 | dtd_set_start_addr(dtd, dma_addr); |
461 | 462 | ||
462 | if (drop) { | 463 | /* Calculate write address from the offset of write_dtd from start |
463 | write_desc_addr = virt_to_phys( | 464 | * of the list->buf |
464 | (struct vpdma_dtd *)list->buf.dma_addr + 2); | 465 | */ |
466 | offset = (void *)write_dtd - list->buf.addr; | ||
467 | write_desc_addr = list->buf.dma_addr + offset; | ||
465 | 468 | ||
469 | if (drop) | ||
466 | dtd_set_desc_write_addr(dtd, write_desc_addr, 1, 1, 0); | 470 | dtd_set_desc_write_addr(dtd, write_desc_addr, 1, 1, 0); |
467 | } else | 471 | else |
468 | dtd_set_desc_write_addr(dtd, 0, 0, 0, 0); | 472 | dtd_set_desc_write_addr(dtd, write_desc_addr, 1, 0, 0); |
469 | |||
470 | vpdma_buf_map(vpdma, &list->buf); | ||
471 | } | 473 | } |
472 | EXPORT_SYMBOL(vpdma_update_dma_addr); | 474 | EXPORT_SYMBOL(vpdma_update_dma_addr); |
473 | 475 | ||
@@ -676,11 +678,14 @@ static void dump_dtd(struct vpdma_dtd *dtd) | |||
676 | * @width: width of the image in pixels in memory | 678 | * @width: width of the image in pixels in memory |
677 | * @fmt: vpdma data format of the buffer | 679 | * @fmt: vpdma data format of the buffer |
678 | * dma_addr: dma address as seen by VPDMA | 680 | * dma_addr: dma address as seen by VPDMA |
681 | * max_width: enum for maximum width of data transfer | ||
682 | * max_height: enum for maximum height of data transfer | ||
679 | * chan: VPDMA channel | 683 | * chan: VPDMA channel |
680 | * flags: VPDMA flags to configure some descriptor fileds | 684 | * flags: VPDMA flags to configure some descriptor fileds |
681 | */ | 685 | */ |
682 | int vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, | 686 | int vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, |
683 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 687 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
688 | enum vpdma_max_width max_w, enum vpdma_max_height max_h, | ||
684 | int channel, u32 flags) | 689 | int channel, u32 flags) |
685 | { | 690 | { |
686 | int priority = 0; | 691 | int priority = 0; |
@@ -714,7 +719,7 @@ int vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, | |||
714 | channel, priority, next_chan); | 719 | channel, priority, next_chan); |
715 | 720 | ||
716 | dtd_set_desc_write_addr(dtd, 0, 0, 0, 0); | 721 | dtd_set_desc_write_addr(dtd, 0, 0, 0, 0); |
717 | dtd_set_max_width_height(dtd, MAX_OUT_WIDTH_1920, MAX_OUT_HEIGHT_1080); | 722 | dtd_set_max_width_height(dtd, max_w, max_h); |
718 | dtd_set_client_attr0(dtd, 0); | 723 | dtd_set_client_attr0(dtd, 0); |
719 | dtd_set_client_attr1(dtd, 0); | 724 | dtd_set_client_attr1(dtd, 0); |
720 | 725 | ||
diff --git a/drivers/media/platform/ti-vps/vpdma.h b/drivers/media/platform/ti-vps/vpdma.h index 657d8a842a5..55563a1d84f 100644 --- a/drivers/media/platform/ti-vps/vpdma.h +++ b/drivers/media/platform/ti-vps/vpdma.h | |||
@@ -28,7 +28,7 @@ struct vpdma_buf { | |||
28 | 28 | ||
29 | struct vpdma_desc_list { | 29 | struct vpdma_desc_list { |
30 | struct vpdma_buf buf; | 30 | struct vpdma_buf buf; |
31 | void *next; | 31 | void *next, *current_desc; |
32 | int type; | 32 | int type; |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -119,6 +119,30 @@ enum vpdma_frame_start_event { | |||
119 | VPDMA_FSEVENT_CHANNEL_ACTIVE, | 119 | VPDMA_FSEVENT_CHANNEL_ACTIVE, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | /* max width configurations */ | ||
123 | enum vpdma_max_width { | ||
124 | MAX_OUT_WIDTH_UNLIMITED = 0, | ||
125 | MAX_OUT_WIDTH_REG1, | ||
126 | MAX_OUT_WIDTH_REG2, | ||
127 | MAX_OUT_WIDTH_REG3, | ||
128 | MAX_OUT_WIDTH_352, | ||
129 | MAX_OUT_WIDTH_768, | ||
130 | MAX_OUT_WIDTH_1280, | ||
131 | MAX_OUT_WIDTH_1920, | ||
132 | }; | ||
133 | |||
134 | /* max height configurations */ | ||
135 | enum vpdma_max_height { | ||
136 | MAX_OUT_HEIGHT_UNLIMITED = 0, | ||
137 | MAX_OUT_HEIGHT_REG1, | ||
138 | MAX_OUT_HEIGHT_REG2, | ||
139 | MAX_OUT_HEIGHT_REG3, | ||
140 | MAX_OUT_HEIGHT_288, | ||
141 | MAX_OUT_HEIGHT_576, | ||
142 | MAX_OUT_HEIGHT_720, | ||
143 | MAX_OUT_HEIGHT_1080, | ||
144 | }; | ||
145 | |||
122 | #define VIP_CHAN_VIP2_OFFSET 70 | 146 | #define VIP_CHAN_VIP2_OFFSET 70 |
123 | #define VIP_CHAN_MULT_PORTB_OFFSET 16 | 147 | #define VIP_CHAN_MULT_PORTB_OFFSET 16 |
124 | #define VIP_CHAN_YUV_PORTB_OFFSET 2 | 148 | #define VIP_CHAN_YUV_PORTB_OFFSET 2 |
@@ -177,6 +201,7 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, | |||
177 | void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, int channel); | 201 | void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, int channel); |
178 | int vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, | 202 | int vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, |
179 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 203 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
204 | enum vpdma_max_width max_w, enum vpdma_max_height max_h, | ||
180 | int channel, u32 flags); | 205 | int channel, u32 flags); |
181 | void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, | 206 | void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, |
182 | const struct v4l2_rect *c_rect, | 207 | const struct v4l2_rect *c_rect, |
@@ -190,7 +215,8 @@ void vpdma_free_desc_list(struct vpdma_desc_list *list); | |||
190 | int vpdma_submit_descs(struct vpdma_data *vpdma, | 215 | int vpdma_submit_descs(struct vpdma_data *vpdma, |
191 | struct vpdma_desc_list *list, int list_num); | 216 | struct vpdma_desc_list *list, int list_num); |
192 | void vpdma_update_dma_addr(struct vpdma_data *vpdma, | 217 | void vpdma_update_dma_addr(struct vpdma_data *vpdma, |
193 | struct vpdma_desc_list *list, dma_addr_t dma_addr, int drop); | 218 | struct vpdma_desc_list *list, dma_addr_t dma_addr, |
219 | struct vpdma_dtd *write_dtd, int drop); | ||
194 | 220 | ||
195 | void vpdma_enable_channel_3_irq(struct vpdma_data *vpdma, bool enable); | 221 | void vpdma_enable_channel_3_irq(struct vpdma_data *vpdma, bool enable); |
196 | void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, | 222 | void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, |
diff --git a/drivers/media/platform/ti-vps/vpdma_priv.h b/drivers/media/platform/ti-vps/vpdma_priv.h index 74881c5422f..78425eb75a7 100644 --- a/drivers/media/platform/ti-vps/vpdma_priv.h +++ b/drivers/media/platform/ti-vps/vpdma_priv.h | |||
@@ -219,7 +219,7 @@ struct vpdma_dtd { | |||
219 | #define DTD_V_START_MASK 0xffff | 219 | #define DTD_V_START_MASK 0xffff |
220 | #define DTD_V_START_SHFT 0 | 220 | #define DTD_V_START_SHFT 0 |
221 | 221 | ||
222 | #define DTD_DESC_START_MASK 0xffe0 | 222 | #define DTD_DESC_START_MASK 0xffffffe0 |
223 | #define DTD_DESC_START_SHIFT 5 | 223 | #define DTD_DESC_START_SHIFT 5 |
224 | #define DTD_WRITE_DESC_MASK 0x01 | 224 | #define DTD_WRITE_DESC_MASK 0x01 |
225 | #define DTD_WRITE_DESC_SHIFT 2 | 225 | #define DTD_WRITE_DESC_SHIFT 2 |
@@ -234,43 +234,6 @@ struct vpdma_dtd { | |||
234 | #define DTD_MAX_HEIGHT_MASK 0x07 | 234 | #define DTD_MAX_HEIGHT_MASK 0x07 |
235 | #define DTD_MAX_HEIGHT_SHFT 0 | 235 | #define DTD_MAX_HEIGHT_SHFT 0 |
236 | 236 | ||
237 | /* max width configurations */ | ||
238 | /* unlimited width */ | ||
239 | #define MAX_OUT_WIDTH_UNLIMITED 0 | ||
240 | /* as specified in max_size1 reg */ | ||
241 | #define MAX_OUT_WIDTH_REG1 1 | ||
242 | /* as specified in max_size2 reg */ | ||
243 | #define MAX_OUT_WIDTH_REG2 2 | ||
244 | /* as specified in max_size3 reg */ | ||
245 | #define MAX_OUT_WIDTH_REG3 3 | ||
246 | /* maximum of 352 pixels as width */ | ||
247 | #define MAX_OUT_WIDTH_352 4 | ||
248 | /* maximum of 768 pixels as width */ | ||
249 | #define MAX_OUT_WIDTH_768 5 | ||
250 | /* maximum of 1280 pixels width */ | ||
251 | #define MAX_OUT_WIDTH_1280 6 | ||
252 | /* maximum of 1920 pixels as width */ | ||
253 | #define MAX_OUT_WIDTH_1920 7 | ||
254 | |||
255 | /* max height configurations */ | ||
256 | /* unlimited height */ | ||
257 | #define MAX_OUT_HEIGHT_UNLIMITED 0 | ||
258 | /* as specified in max_size1 reg */ | ||
259 | #define MAX_OUT_HEIGHT_REG1 1 | ||
260 | /* as specified in max_size2 reg */ | ||
261 | #define MAX_OUT_HEIGHT_REG2 2 | ||
262 | /* as specified in max_size3 reg */ | ||
263 | #define MAX_OUT_HEIGHT_REG3 3 | ||
264 | /* maximum of 288 lines as height */ | ||
265 | #define MAX_OUT_HEIGHT_288 4 | ||
266 | /* maximum of 576 lines as height */ | ||
267 | #define MAX_OUT_HEIGHT_576 5 | ||
268 | /* maximum of 720 lines as height */ | ||
269 | #define MAX_OUT_HEIGHT_720 6 | ||
270 | /* maximum of 1080 lines as height */ | ||
271 | #define MAX_OUT_HEIGHT_1080 7 | ||
272 | |||
273 | |||
274 | /* | 237 | /* |
275 | * The following macros may be useful for structure initialization | 238 | * The following macros may be useful for structure initialization |
276 | */ | 239 | */ |
diff --git a/drivers/media/platform/ti-vps/vpe.c b/drivers/media/platform/ti-vps/vpe.c index 2833f82f6b4..2256a8bbbd6 100644 --- a/drivers/media/platform/ti-vps/vpe.c +++ b/drivers/media/platform/ti-vps/vpe.c | |||
@@ -1039,6 +1039,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) | |||
1039 | flags |= VPDMA_DATA_MODE_TILED; | 1039 | flags |= VPDMA_DATA_MODE_TILED; |
1040 | 1040 | ||
1041 | vpdma_add_out_dtd(&ctx->desc_list, q_data->width, vpdma_fmt, dma_addr, | 1041 | vpdma_add_out_dtd(&ctx->desc_list, q_data->width, vpdma_fmt, dma_addr, |
1042 | MAX_OUT_WIDTH_1920, MAX_OUT_HEIGHT_1080, | ||
1042 | p_data->channel, flags); | 1043 | p_data->channel, flags); |
1043 | } | 1044 | } |
1044 | 1045 | ||