From 256b02332a0ba1d7382d736d776e605be63ded17 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Tue, 31 Mar 2009 03:44:21 -0300 Subject: V4L/DVB (11321): pxa_camera: Redesign DMA handling The DMA transfers in pxa_camera showed some weaknesses in multiple queued buffers context : - poll/select problem The bug shows up with capture_example tool from v4l2 hg tree. The process just "stalls" on a "select timeout". - multiple buffers DMA starting When multiple buffers were queued, the DMA channels were always started right away. This is not optimal, as a special case appears when the first EOF was not yet reached, and the DMA channels were prematurely started. - Maintainability DMA code was a bit obfuscated. Rationalize the code to be easily maintainable by anyone. - DMA hot chaining DMA is not stopped anymore to queue a buffer, the buffer is queued with DMA running. As a tribute, a corner case exists where chaining happens while DMA finishes the chain, and the capture is restarted to deal with the missed link buffer. This patch attemps to address these issues / improvements. create mode 100644 Documentation/video4linux/pxa_camera.txt Signed-off-by: Robert Jarzmik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/pxa_camera.txt | 125 +++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 Documentation/video4linux/pxa_camera.txt (limited to 'Documentation') diff --git a/Documentation/video4linux/pxa_camera.txt b/Documentation/video4linux/pxa_camera.txt new file mode 100644 index 00000000000..b1137f9a53e --- /dev/null +++ b/Documentation/video4linux/pxa_camera.txt @@ -0,0 +1,125 @@ + PXA-Camera Host Driver + ====================== + +Constraints +----------- + a) Image size for YUV422P format + All YUV422P images are enforced to have width x height % 16 = 0. + This is due to DMA constraints, which transfers only planes of 8 byte + multiples. + + +Global video workflow +--------------------- + a) QCI stopped + Initialy, the QCI interface is stopped. + When a buffer is queued (pxa_videobuf_ops->buf_queue), the QCI starts. + + b) QCI started + More buffers can be queued while the QCI is started without halting the + capture. The new buffers are "appended" at the tail of the DMA chain, and + smoothly captured one frame after the other. + + Once a buffer is filled in the QCI interface, it is marked as "DONE" and + removed from the active buffers list. It can be then requeud or dequeued by + userland application. + + Once the last buffer is filled in, the QCI interface stops. + + +DMA usage +--------- + a) DMA flow + - first buffer queued for capture + Once a first buffer is queued for capture, the QCI is started, but data + transfer is not started. On "End Of Frame" interrupt, the irq handler + starts the DMA chain. + - capture of one videobuffer + The DMA chain starts transfering data into videobuffer RAM pages. + When all pages are transfered, the DMA irq is raised on "ENDINTR" status + - finishing one videobuffer + The DMA irq handler marks the videobuffer as "done", and removes it from + the active running queue + Meanwhile, the next videobuffer (if there is one), is transfered by DMA + - finishing the last videobuffer + On the DMA irq of the last videobuffer, the QCI is stopped. + + b) DMA prepared buffer will have this structure + + +------------+-----+---------------+-----------------+ + | desc-sg[0] | ... | desc-sg[last] | finisher/linker | + +------------+-----+---------------+-----------------+ + + This structure is pointed by dma->sg_cpu. + The descriptors are used as follows : + - desc-sg[i]: i-th descriptor, transfering the i-th sg + element to the video buffer scatter gather + - finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN + - linker: has ddadr= desc-sg[0] of next video buffer, dcmd=0 + + For the next schema, let's assume d0=desc-sg[0] .. dN=desc-sg[N], + "f" stands for finisher and "l" for linker. + A typical running chain is : + + Videobuffer 1 Videobuffer 2 + +---------+----+---+ +----+----+----+---+ + | d0 | .. | dN | l | | d0 | .. | dN | f | + +---------+----+-|-+ ^----+----+----+---+ + | | + +----+ + + After the chaining is finished, the chain looks like : + + Videobuffer 1 Videobuffer 2 Videobuffer 3 + +---------+----+---+ +----+----+----+---+ +----+----+----+---+ + | d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f | + +---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+ + | | | | + +----+ +----+ + new_link + + c) DMA hot chaining timeslice issue + + As DMA chaining is done while DMA _is_ running, the linking may be done + while the DMA jumps from one Videobuffer to another. On the schema, that + would be a problem if the following sequence is encountered : + + - DMA chain is Videobuffer1 + Videobuffer2 + - pxa_videobuf_queue() is called to queue Videobuffer3 + - DMA controller finishes Videobuffer2, and DMA stops + => + Videobuffer 1 Videobuffer 2 + +---------+----+---+ +----+----+----+---+ + | d0 | .. | dN | l | | d0 | .. | dN | f | + +---------+----+-|-+ ^----+----+----+-^-+ + | | | + +----+ +-- DMA DDADR loads DDADR_STOP + + - pxa_dma_add_tail_buf() is called, the Videobuffer2 "finisher" is + replaced by a "linker" to Videobuffer3 (creation of new_link) + - pxa_videobuf_queue() finishes + - the DMA irq handler is called, which terminates Videobuffer2 + - Videobuffer3 capture is not scheduled on DMA chain (as it stopped !!!) + + Videobuffer 1 Videobuffer 2 Videobuffer 3 + +---------+----+---+ +----+----+----+---+ +----+----+----+---+ + | d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f | + +---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+ + | | | | + +----+ +----+ + new_link + DMA DDADR still is DDADR_STOP + + - pxa_camera_check_link_miss() is called + This checks if the DMA is finished and a buffer is still on the + pcdev->capture list. If that's the case, the capture will be restarted, + and Videobuffer3 is scheduled on DMA chain. + - the DMA irq handler finishes + + Note: if DMA stops just after pxa_camera_check_link_miss() reads DDADR() + value, we have the guarantee that the DMA irq handler will be called back + when the DMA will finish the buffer, and pxa_camera_check_link_miss() will + be called again, to reschedule Videobuffer3. + +-- +Author: Robert Jarzmik -- cgit v1.2.3 From 073d696d547ef933e1f0748086da785e95cb8395 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 1 Apr 2009 08:30:06 -0300 Subject: V4L/DVB (11351): v4l: use usb_interface for v4l2_device_register If usb_interface.dev is used as dev parameter for v4l2_device_register v4l2_dev.name contains the v4l driver/module name and usb device and interface instead of a simple "usb x-y". It also matches the recommendation to set the parent devices for usb drivers. Signed-off-by: Janne Grunau Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-framework.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index a31177390e5..4b54c629bc5 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -90,7 +90,7 @@ up before calling v4l2_device_register then it will be untouched. If dev is NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register. The first 'dev' argument is normally the struct device pointer of a pci_dev, -usb_device or platform_device. It is rare for dev to be NULL, but it happens +usb_interface or platform_device. It is rare for dev to be NULL, but it happens with ISA devices or when one device creates multiple PCI devices, thus making it impossible to associate v4l2_dev with a particular parent. -- cgit v1.2.3 From 78a3b4db2e53a1903c86e2856e175d85a3849e84 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 1 Apr 2009 03:41:09 -0300 Subject: V4L/DVB (11367): v4l2-common: remove legacy code Now that all drivers are converted to v4l2_subdev we can remove legacy code in v4l2-common. Also move the documentation of the internal API to v4l2-subdev.h where it really belongs. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-framework.txt | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index 4b54c629bc5..c9ae70a37a6 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -351,17 +351,6 @@ And this to go from an i2c_client to a v4l2_subdev struct: struct v4l2_subdev *sd = i2c_get_clientdata(client); -Finally you need to make a command function to make driver->command() -call the right subdev_ops functions: - -static int subdev_command(struct i2c_client *client, unsigned cmd, void *arg) -{ - return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); -} - -If driver->command is never used then you can leave this out. Eventually the -driver->command usage should be removed from v4l. - Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback is called. This will unregister the sub-device from the bridge driver. It is safe to call this even if the sub-device was never registered. -- cgit v1.2.3 From e6574f2fbecdb8af807169d345c10131ae060a88 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 1 Apr 2009 03:57:53 -0300 Subject: V4L/DVB (11373): v4l2-common: add explicit v4l2_device pointer as first arg to new_(probed)_subdev The functions v4l2_i2c_new_subdev and v4l2_i2c_new_probed_subdev relied on i2c_get_adapdata to return the v4l2_device. However, this is not always possible on embedded platforms. So modify the API to pass the v4l2_device pointer explicitly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-framework.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index c9ae70a37a6..854808b67fa 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -364,14 +364,12 @@ from the remove() callback ensures that this is always done correctly. The bridge driver also has some helper functions it can use: -struct v4l2_subdev *sd = v4l2_i2c_new_subdev(adapter, "module_foo", "chipid", 0x36); +struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter, + "module_foo", "chipid", 0x36); This loads the given module (can be NULL if no module needs to be loaded) and calls i2c_new_device() with the given i2c_adapter and chip/address arguments. -If all goes well, then it registers the subdev with the v4l2_device. It gets -the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure -to call i2c_set_adapdata(adapter, v4l2_device) when you setup the i2c_adapter -in your driver. +If all goes well, then it registers the subdev with the v4l2_device. You can also use v4l2_i2c_new_probed_subdev() which is very similar to v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses -- cgit v1.2.3