Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-21 Thread Archit Taneja

Hi,

On Tuesday 20 August 2013 07:26 PM, Laurent Pinchart wrote:

Hi Archit,

On Tuesday 20 August 2013 18:46:38 Archit Taneja wrote:

On Tuesday 20 August 2013 05:09 PM, Laurent Pinchart wrote:

snip


+static int vpdma_load_firmware(struct vpdma_data *vpdma)
+{
+   int r;
+   struct device *dev = vpdma-pdev-dev;
+
+   r = request_firmware_nowait(THIS_MODULE, 1,
+   (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma,
+   vpdma_firmware_cb);


Is there a reason not to use the synchronous interface ? That would
simplify both this code and the callers, as they won't have to check
whether the firmware has been correctly loaded.


I'm not clear what you mean by that, the firmware would be stored in the
filesystem. If the driver is built-in, then the synchronous interface
wouldn't work unless the firmware is appended to the kernel image. Am I
missing something here? I'm not very aware of the firmware api.


request_firmware() would just sleep (with a 30 seconds timeout if I'm not
mistaken) until userspace provides the firmware. As devices are probed
asynchronously (in kernel threads) the system will just boot normally, and
the request_firmware() call will return when the firmware is available.


Sorry, I sent the previous mail bit too early.

With request_firmware() and the driver built-in, I see that the kernel
stalls for 10 seconds at the driver's probe, and the firware loading fails
since we didn't enter userspace where the file is.

The probing of devices asynchronously with kernel threads makes sense, so
it's possible that I'm doing something wrong here. I'll give it a try again


I might have spoken too fast. It looks like module initcalls are not run in
threads. I've most probably mistaken that with asynchronous probing of hot-
pluggable devices.

If your driver is built-in then it looks like the correct solution is to build
the firmware in the kernel image as well, or use the asynchronous API as you
did.


Okay, thanks for clarifying that.

We could use the request_firmware synchronous version if we call it in 
the open v4l2 file op.


Maybe I could load the firmware when the device is opened the first 
time(one instance).


I'll have to see whether it slows things down, and if I'd need to load 
firmware more often. But I'd probably leave this experiment for later.


Archit



--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-20 Thread Laurent Pinchart
Hi Archit,

On Wednesday 14 August 2013 16:27:57 Archit Taneja wrote:
 On Friday 09 August 2013 03:34 AM, Laurent Pinchart wrote:
  On Friday 02 August 2013 19:33:38 Archit Taneja wrote:
  The primary function of VPDMA is to move data between external memory and
  internal processing modules(in our case, VPE) that source or sink data.
  VPDMA is capable of buffering this data and then delivering the data as
  demanded to the modules as programmed. The modules that source or sink
  data are referred to as clients or ports. A channel is setup inside the
  VPDMA to connect a specific memory buffer to a specific client. The VPDMA
  centralizes the DMA control functions and buffering required to allow all
  the clients to minimize the effect of long latency times.
  
  Add the following to the VPDMA helper:
  
  - A data struct which describe VPDMA channels. For now, these channels
  are the ones used only by VPE, the list of channels will increase when
  VIP(Video Input Port) also uses the VPDMA library. This channel
  information will be used to populate fields required by data descriptors.
  
  - Data structs which describe the different data types supported by
  VPDMA. This data type information will be used to populate fields
  required by data descriptors and used by the VPE driver to map a V4L2
  format to the corresponding VPDMA data type.
  
  - Provide VPDMA register offset definitions, functions to read, write and
  modify VPDMA registers.
  
  - Functions to create and submit a VPDMA list. A list is a group of
  descriptors that makes up a set of DMA transfers that need to be
  completed. Each descriptor will either perform a DMA transaction to fetch
  input buffers and write to output buffers(data descriptors), or configure
  the MMRs of sub blocks of VPE(configuration descriptors), or provide
  control information to VPDMA (control descriptors).
  
  - Functions to allocate, map and unmap buffers needed for the descriptor
  list, payloads containing MMR values and motion vector buffers. These use
  the DMA mapping APIs to ensure exclusive access to VPDMA.
  
  - Functions to enable VPDMA interrupts. VPDMA can trigger an interrupt on
  the VPE interrupt line when a descriptor list is parsed completely and
  the DMA transactions are completed. This requires masking the events in
  VPDMA registers and configuring some top level VPE interrupt registers.
  
  - Enable some VPDMA specific parameters: frame start event(when to start
  DMA for a client) and line mode(whether each line fetched should be
  mirrored or not).
  
  - Function to load firmware required by VPDMA. VPDMA requires a firmware
  for it's internal list manager. We add the required request_firmware
  apis to fetch this firmware from user space.
  
  - Function to dump VPDMA registers.
  
  - A function to initialize VPDMA, this will be called by the VPE driver
  with it's platform device pointer, this function will take care of
  loading VPDMA firmware and returning a handle back to the VPE driver.
  The VIP driver will also call the same init function to initialize it's
  own VPDMA instance.
  
  Signed-off-by: Archit Taneja arc...@ti.com

[snip]

  +/*
  + * Allocate a DMA buffer
  + */
  +int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
  +{
  +  buf-size = size;
  +  buf-mapped = 0;
  +  buf-addr = kzalloc(size, GFP_KERNEL);
  
  You should use the dma allocation API (depending on your needs,
  dma_alloc_coherent for instance) to allocate DMA-able buffers.
 
 I'm not sure about this, dma_map_single() api works fine on kzalloc'd
 buffers. The above function is used to allocate small contiguous buffers
 (never more than 1024 bytes) needed for descriptors for the DMA IP. I
 thought of using DMA pool, but that creates small buffers of the same size.
 So I finally went with kzalloc.

OK, I mistakenly thought it would allocate larger buffers as well. If it's 
used to allocate descriptors only, would it be better to rename it to 
vpdma_desc_alloc() (or something similar) ?

  +  if (!buf-addr)
  +  return -ENOMEM;
  +
  +  WARN_ON((u32) buf-addr  VPDMA_DESC_ALIGN);
  +
  +  return 0;
  +}

[snip]

  +static int vpdma_load_firmware(struct vpdma_data *vpdma)
  +{
  +  int r;
  +  struct device *dev = vpdma-pdev-dev;
  +
  +  r = request_firmware_nowait(THIS_MODULE, 1,
  +  (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma,
  +  vpdma_firmware_cb);
  
  Is there a reason not to use the synchronous interface ? That would
  simplify both this code and the callers, as they won't have to check
  whether the firmware has been correctly loaded.
 
 I'm not clear what you mean by that, the firmware would be stored in the
 filesystem. If the driver is built-in, then the synchronous interface
 wouldn't work unless the firmware is appended to the kernel image. Am I
 missing something here? I'm not very aware of the firmware api.

request_firmware() would just sleep (with a 30 seconds timeout if I'm not 
mistaken) 

Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-20 Thread Archit Taneja

On Tuesday 20 August 2013 05:09 PM, Laurent Pinchart wrote:

Hi Archit,

On Wednesday 14 August 2013 16:27:57 Archit Taneja wrote:

On Friday 09 August 2013 03:34 AM, Laurent Pinchart wrote:

On Friday 02 August 2013 19:33:38 Archit Taneja wrote:

The primary function of VPDMA is to move data between external memory and
internal processing modules(in our case, VPE) that source or sink data.
VPDMA is capable of buffering this data and then delivering the data as
demanded to the modules as programmed. The modules that source or sink
data are referred to as clients or ports. A channel is setup inside the
VPDMA to connect a specific memory buffer to a specific client. The VPDMA
centralizes the DMA control functions and buffering required to allow all
the clients to minimize the effect of long latency times.

Add the following to the VPDMA helper:

- A data struct which describe VPDMA channels. For now, these channels
are the ones used only by VPE, the list of channels will increase when
VIP(Video Input Port) also uses the VPDMA library. This channel
information will be used to populate fields required by data descriptors.

- Data structs which describe the different data types supported by
VPDMA. This data type information will be used to populate fields
required by data descriptors and used by the VPE driver to map a V4L2
format to the corresponding VPDMA data type.

- Provide VPDMA register offset definitions, functions to read, write and
modify VPDMA registers.

- Functions to create and submit a VPDMA list. A list is a group of
descriptors that makes up a set of DMA transfers that need to be
completed. Each descriptor will either perform a DMA transaction to fetch
input buffers and write to output buffers(data descriptors), or configure
the MMRs of sub blocks of VPE(configuration descriptors), or provide
control information to VPDMA (control descriptors).

- Functions to allocate, map and unmap buffers needed for the descriptor
list, payloads containing MMR values and motion vector buffers. These use
the DMA mapping APIs to ensure exclusive access to VPDMA.

- Functions to enable VPDMA interrupts. VPDMA can trigger an interrupt on
the VPE interrupt line when a descriptor list is parsed completely and
the DMA transactions are completed. This requires masking the events in
VPDMA registers and configuring some top level VPE interrupt registers.

- Enable some VPDMA specific parameters: frame start event(when to start
DMA for a client) and line mode(whether each line fetched should be
mirrored or not).

- Function to load firmware required by VPDMA. VPDMA requires a firmware
for it's internal list manager. We add the required request_firmware
apis to fetch this firmware from user space.

- Function to dump VPDMA registers.

- A function to initialize VPDMA, this will be called by the VPE driver
with it's platform device pointer, this function will take care of
loading VPDMA firmware and returning a handle back to the VPE driver.
The VIP driver will also call the same init function to initialize it's
own VPDMA instance.

Signed-off-by: Archit Taneja arc...@ti.com


[snip]


+/*
+ * Allocate a DMA buffer
+ */
+int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
+{
+   buf-size = size;
+   buf-mapped = 0;
+   buf-addr = kzalloc(size, GFP_KERNEL);


You should use the dma allocation API (depending on your needs,
dma_alloc_coherent for instance) to allocate DMA-able buffers.


I'm not sure about this, dma_map_single() api works fine on kzalloc'd
buffers. The above function is used to allocate small contiguous buffers
(never more than 1024 bytes) needed for descriptors for the DMA IP. I
thought of using DMA pool, but that creates small buffers of the same size.
So I finally went with kzalloc.


OK, I mistakenly thought it would allocate larger buffers as well. If it's
used to allocate descriptors only, would it be better to rename it to
vpdma_desc_alloc() (or something similar) ?


Actually, I just thought about this again. We use this api to allocate a 
motion vector buffer for the de-interlacer, that's a buffer which is 
proportional to the size of the frame, it takes up 4 bits per pixel. So 
for a 1080i frame(our limit), it would take around 51 kilobytes for it. 
I should probably use dma_alloc_coherent there.





+   if (!buf-addr)
+   return -ENOMEM;
+
+   WARN_ON((u32) buf-addr  VPDMA_DESC_ALIGN);
+
+   return 0;
+}


[snip]


+static int vpdma_load_firmware(struct vpdma_data *vpdma)
+{
+   int r;
+   struct device *dev = vpdma-pdev-dev;
+
+   r = request_firmware_nowait(THIS_MODULE, 1,
+   (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma,
+   vpdma_firmware_cb);


Is there a reason not to use the synchronous interface ? That would
simplify both this code and the callers, as they won't have to check
whether the firmware has been correctly loaded.


I'm not clear what you mean by that, the firmware would be stored in the

Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-20 Thread Archit Taneja

Hi Laurent,

On Tuesday 20 August 2013 05:09 PM, Laurent Pinchart wrote:

snip


+static int vpdma_load_firmware(struct vpdma_data *vpdma)
+{
+   int r;
+   struct device *dev = vpdma-pdev-dev;
+
+   r = request_firmware_nowait(THIS_MODULE, 1,
+   (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma,
+   vpdma_firmware_cb);


Is there a reason not to use the synchronous interface ? That would
simplify both this code and the callers, as they won't have to check
whether the firmware has been correctly loaded.


I'm not clear what you mean by that, the firmware would be stored in the
filesystem. If the driver is built-in, then the synchronous interface
wouldn't work unless the firmware is appended to the kernel image. Am I
missing something here? I'm not very aware of the firmware api.


request_firmware() would just sleep (with a 30 seconds timeout if I'm not
mistaken) until userspace provides the firmware. As devices are probed
asynchronously (in kernel threads) the system will just boot normally, and the
request_firmware() call will return when the firmware is available.


Sorry, I sent the previous mail bit too early.

With request_firmware() and the driver built-in, I see that the kernel 
stalls for 10 seconds at the driver's probe, and the firware loading 
fails since we didn't enter userspace where the file is.


The probing of devices asynchronously with kernel threads makes sense, 
so it's possible that I'm doing something wrong here. I'll give it a try 
again


Archit

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-20 Thread Laurent Pinchart
Hi Archit,

On Tuesday 20 August 2013 18:46:38 Archit Taneja wrote:
 On Tuesday 20 August 2013 05:09 PM, Laurent Pinchart wrote:
 
 snip
 
  +static int vpdma_load_firmware(struct vpdma_data *vpdma)
  +{
  +int r;
  +struct device *dev = vpdma-pdev-dev;
  +
  +r = request_firmware_nowait(THIS_MODULE, 1,
  +(const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma,
  +vpdma_firmware_cb);
  
  Is there a reason not to use the synchronous interface ? That would
  simplify both this code and the callers, as they won't have to check
  whether the firmware has been correctly loaded.
  
  I'm not clear what you mean by that, the firmware would be stored in the
  filesystem. If the driver is built-in, then the synchronous interface
  wouldn't work unless the firmware is appended to the kernel image. Am I
  missing something here? I'm not very aware of the firmware api.
  
  request_firmware() would just sleep (with a 30 seconds timeout if I'm not
  mistaken) until userspace provides the firmware. As devices are probed
  asynchronously (in kernel threads) the system will just boot normally, and
  the request_firmware() call will return when the firmware is available.

 Sorry, I sent the previous mail bit too early.
 
 With request_firmware() and the driver built-in, I see that the kernel
 stalls for 10 seconds at the driver's probe, and the firware loading fails
 since we didn't enter userspace where the file is.
 
 The probing of devices asynchronously with kernel threads makes sense, so
 it's possible that I'm doing something wrong here. I'll give it a try again

I might have spoken too fast. It looks like module initcalls are not run in 
threads. I've most probably mistaken that with asynchronous probing of hot-
pluggable devices.

If your driver is built-in then it looks like the correct solution is to build 
the firmware in the kernel image as well, or use the asynchronous API as you 
did.

-- 
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-14 Thread Archit Taneja

On Friday 09 August 2013 03:05 AM, Laurent Pinchart wrote:

Hi Archit,

On Monday 05 August 2013 16:56:46 Archit Taneja wrote:

On Monday 05 August 2013 01:43 PM, Tomi Valkeinen wrote:

On 02/08/13 17:03, Archit Taneja wrote:

+struct vpdma_data_format vpdma_yuv_fmts[] = {
+   [VPDMA_DATA_FMT_Y444] = {
+   .data_type  = DATA_TYPE_Y444,
+   .depth  = 8,
+   },


This, and all the other tables, should probably be consts?


That's true, I'll fix those.


+static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
+{
+   u32 val = *valp;
+
+   val = ~(mask  shift);
+   val |= (field  mask)  shift;
+   *valp = val;
+}


I think insert normally means, well, inserting a thing in between
something. What you do here is overwriting.

Why not just call it write_field?


sure, will change it.


+ * Allocate a DMA buffer
+ */
+int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
+{
+   buf-size = size;
+   buf-mapped = 0;


Maybe true/false is clearer here that 0/1.


okay.


+/*
+ * submit a list of DMA descriptors to the VPE VPDMA, do not wait for
completion + */
+int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list
*list) +{
+   /* we always use the first list */
+   int list_num = 0;
+   int list_size;
+
+   if (vpdma_list_busy(vpdma, list_num))
+   return -EBUSY;
+
+   /* 16-byte granularity */
+   list_size = (list-next - list-buf.addr)  4;
+
+   write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list-buf.dma_addr);
+   wmb();


What is the wmb() for?


VPDMA_LIST_ADDR needs to be written before VPDMA_LIST_ATTR, otherwise
VPDMA doesn't work. wmb() ensures the ordering.


write_reg() calls iowrite32(), which already includes an __iowmb().


I wasn't aware of that. I'll remove the wmb() call. Thanks for sharing 
this info.


Archit

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-14 Thread Archit Taneja

On Friday 09 August 2013 03:34 AM, Laurent Pinchart wrote:

Hi Archit,

Thank you for the patch.

On Friday 02 August 2013 19:33:38 Archit Taneja wrote:

The primary function of VPDMA is to move data between external memory and
internal processing modules(in our case, VPE) that source or sink data.
VPDMA is capable of buffering this data and then delivering the data as
demanded to the modules as programmed. The modules that source or sink data
are referred to as clients or ports. A channel is setup inside the VPDMA to
connect a specific memory buffer to a specific client. The VPDMA
centralizes the DMA control functions and buffering required to allow all
the clients to minimize the effect of long latency times.

Add the following to the VPDMA helper:

- A data struct which describe VPDMA channels. For now, these channels are
the ones used only by VPE, the list of channels will increase when
VIP(Video Input Port) also uses the VPDMA library. This channel information
will be used to populate fields required by data descriptors.

- Data structs which describe the different data types supported by VPDMA.
This data type information will be used to populate fields required by data
descriptors and used by the VPE driver to map a V4L2 format to the
corresponding VPDMA data type.

- Provide VPDMA register offset definitions, functions to read, write and
modify VPDMA registers.

- Functions to create and submit a VPDMA list. A list is a group of
descriptors that makes up a set of DMA transfers that need to be completed.
Each descriptor will either perform a DMA transaction to fetch input
buffers and write to output buffers(data descriptors), or configure the
MMRs of sub blocks of VPE(configuration descriptors), or provide control
information to VPDMA (control descriptors).

- Functions to allocate, map and unmap buffers needed for the descriptor
list, payloads containing MMR values and motion vector buffers. These use
the DMA mapping APIs to ensure exclusive access to VPDMA.

- Functions to enable VPDMA interrupts. VPDMA can trigger an interrupt on
the VPE interrupt line when a descriptor list is parsed completely and the
DMA transactions are completed. This requires masking the events in VPDMA
registers and configuring some top level VPE interrupt registers.

- Enable some VPDMA specific parameters: frame start event(when to start DMA
for a client) and line mode(whether each line fetched should be mirrored or
not).

- Function to load firmware required by VPDMA. VPDMA requires a firmware for
it's internal list manager. We add the required request_firmware apis to
fetch this firmware from user space.

- Function to dump VPDMA registers.

- A function to initialize VPDMA, this will be called by the VPE driver with
it's platform device pointer, this function will take care of loading VPDMA
firmware and returning a handle back to the VPE driver. The VIP driver will
also call the same init function to initialize it's own VPDMA instance.

Signed-off-by: Archit Taneja arc...@ti.com
---
  drivers/media/platform/ti-vpe/vpdma.c  | 589 ++
  drivers/media/platform/ti-vpe/vpdma.h  | 154 
  drivers/media/platform/ti-vpe/vpdma_priv.h | 119 ++
  3 files changed, 862 insertions(+)
  create mode 100644 drivers/media/platform/ti-vpe/vpdma.c
  create mode 100644 drivers/media/platform/ti-vpe/vpdma.h
  create mode 100644 drivers/media/platform/ti-vpe/vpdma_priv.h

diff --git a/drivers/media/platform/ti-vpe/vpdma.c
b/drivers/media/platform/ti-vpe/vpdma.c new file mode 100644
index 000..b15b3dd
--- /dev/null
+++ b/drivers/media/platform/ti-vpe/vpdma.c
@@ -0,0 +1,589 @@


[snip]


+static int get_field(u32 value, u32 mask, int shift)
+{
+   return (value  (mask  shift))  shift;
+}
+
+static int get_field_reg(struct vpdma_data *vpdma, int offset,
+   u32 mask, int shift)


I would call this read_field_reg().


+{
+   return get_field(read_reg(vpdma, offset), mask, shift);
+}
+
+static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
+{
+   u32 val = *valp;
+
+   val = ~(mask  shift);
+   val |= (field  mask)  shift;
+   *valp = val;
+}


get_field() and insert_field() are used in a single location, you can manually
inline them.


Thanks, I'll make these modifications.




+static void insert_field_reg(struct vpdma_data *vpdma, int offset, u32
field,
+   u32 mask, int shift)
+{
+   u32 val = read_reg(vpdma, offset);
+
+   insert_field(val, field, mask, shift);
+
+   write_reg(vpdma, offset, val);
+}


[snip]


+/*
+ * Allocate a DMA buffer
+ */
+int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
+{
+   buf-size = size;
+   buf-mapped = 0;
+   buf-addr = kzalloc(size, GFP_KERNEL);


You should use the dma allocation API (depending on your needs,
dma_alloc_coherent for instance) to allocate DMA-able buffers.


I'm not sure about this, dma_map_single() api works fine on kzalloc'd 
buffers. The above 

Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-08 Thread Laurent Pinchart
Hi Archit,

On Monday 05 August 2013 16:56:46 Archit Taneja wrote:
 On Monday 05 August 2013 01:43 PM, Tomi Valkeinen wrote:
  On 02/08/13 17:03, Archit Taneja wrote:
  +struct vpdma_data_format vpdma_yuv_fmts[] = {
  +  [VPDMA_DATA_FMT_Y444] = {
  +  .data_type  = DATA_TYPE_Y444,
  +  .depth  = 8,
  +  },
  
  This, and all the other tables, should probably be consts?
 
 That's true, I'll fix those.
 
  +static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
  +{
  +  u32 val = *valp;
  +
  +  val = ~(mask  shift);
  +  val |= (field  mask)  shift;
  +  *valp = val;
  +}
  
  I think insert normally means, well, inserting a thing in between
  something. What you do here is overwriting.
  
  Why not just call it write_field?
 
 sure, will change it.
 
  + * Allocate a DMA buffer
  + */
  +int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
  +{
  +  buf-size = size;
  +  buf-mapped = 0;
  
  Maybe true/false is clearer here that 0/1.
 
 okay.
 
  +/*
  + * submit a list of DMA descriptors to the VPE VPDMA, do not wait for
  completion + */
  +int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list
  *list) +{
  +  /* we always use the first list */
  +  int list_num = 0;
  +  int list_size;
  +
  +  if (vpdma_list_busy(vpdma, list_num))
  +  return -EBUSY;
  +
  +  /* 16-byte granularity */
  +  list_size = (list-next - list-buf.addr)  4;
  +
  +  write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list-buf.dma_addr);
  +  wmb();
  
  What is the wmb() for?
 
 VPDMA_LIST_ADDR needs to be written before VPDMA_LIST_ATTR, otherwise
 VPDMA doesn't work. wmb() ensures the ordering.

write_reg() calls iowrite32(), which already includes an __iowmb().

  +  write_reg(vpdma, VPDMA_LIST_ATTR,
  +  (list_num  VPDMA_LIST_NUM_SHFT) |
  +  (list-type  VPDMA_LIST_TYPE_SHFT) |
  +  list_size);
  +
  +  return 0;
  +}
  
  +static void vpdma_firmware_cb(const struct firmware *f, void *context)
  +{
  +  struct vpdma_data *vpdma = context;
  +  struct vpdma_buf fw_dma_buf;
  +  int i, r;
  +
  +  dev_dbg(vpdma-pdev-dev, firmware callback\n);
  +
  +  if (!f || !f-data) {
  +  dev_err(vpdma-pdev-dev, couldn't get firmware\n);
  +  return;
  +  }
  +
  +  /* already initialized */
  +  if (get_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
  +  VPDMA_LIST_RDY_SHFT)) {
  +  vpdma-ready = true;
  +  return;
  +  }
  +
  +  r = vpdma_buf_alloc(fw_dma_buf, f-size);
  +  if (r) {
  +  dev_err(vpdma-pdev-dev,
  +  failed to allocate dma buffer for firmware\n);
  +  goto rel_fw;
  +  }
  +
  +  memcpy(fw_dma_buf.addr, f-data, f-size);
  +
  +  vpdma_buf_map(vpdma, fw_dma_buf);
  +
  +  write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr);
  +
  +  for (i = 0; i  100; i++) { /* max 1 second */
  +  msleep_interruptible(10);
  
  You call interruptible version here, but you don't handle the
  interrupted case. I believe the loop will just continue looping, even if
  the user interrupted.
 
 Okay. I think I don't understand the interruptible version correctly. We
 don't need to msleep_interruptible here, we aren't waiting on any wake
 up event, we just want to wait till a bit gets set.
 
 I am thinking of implementing something similar to wait_for_bit_change()
 in 'drivers/video/omap2/dss/dsi.c'

-- 
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-08 Thread Laurent Pinchart
Hi Archit,

Thank you for the patch.

On Friday 02 August 2013 19:33:38 Archit Taneja wrote:
 The primary function of VPDMA is to move data between external memory and
 internal processing modules(in our case, VPE) that source or sink data.
 VPDMA is capable of buffering this data and then delivering the data as
 demanded to the modules as programmed. The modules that source or sink data
 are referred to as clients or ports. A channel is setup inside the VPDMA to
 connect a specific memory buffer to a specific client. The VPDMA
 centralizes the DMA control functions and buffering required to allow all
 the clients to minimize the effect of long latency times.
 
 Add the following to the VPDMA helper:
 
 - A data struct which describe VPDMA channels. For now, these channels are
 the ones used only by VPE, the list of channels will increase when
 VIP(Video Input Port) also uses the VPDMA library. This channel information
 will be used to populate fields required by data descriptors.
 
 - Data structs which describe the different data types supported by VPDMA.
 This data type information will be used to populate fields required by data
 descriptors and used by the VPE driver to map a V4L2 format to the
 corresponding VPDMA data type.
 
 - Provide VPDMA register offset definitions, functions to read, write and
 modify VPDMA registers.
 
 - Functions to create and submit a VPDMA list. A list is a group of
 descriptors that makes up a set of DMA transfers that need to be completed.
 Each descriptor will either perform a DMA transaction to fetch input
 buffers and write to output buffers(data descriptors), or configure the
 MMRs of sub blocks of VPE(configuration descriptors), or provide control
 information to VPDMA (control descriptors).
 
 - Functions to allocate, map and unmap buffers needed for the descriptor
 list, payloads containing MMR values and motion vector buffers. These use
 the DMA mapping APIs to ensure exclusive access to VPDMA.
 
 - Functions to enable VPDMA interrupts. VPDMA can trigger an interrupt on
 the VPE interrupt line when a descriptor list is parsed completely and the
 DMA transactions are completed. This requires masking the events in VPDMA
 registers and configuring some top level VPE interrupt registers.
 
 - Enable some VPDMA specific parameters: frame start event(when to start DMA
 for a client) and line mode(whether each line fetched should be mirrored or
 not).
 
 - Function to load firmware required by VPDMA. VPDMA requires a firmware for
 it's internal list manager. We add the required request_firmware apis to
 fetch this firmware from user space.
 
 - Function to dump VPDMA registers.
 
 - A function to initialize VPDMA, this will be called by the VPE driver with
 it's platform device pointer, this function will take care of loading VPDMA
 firmware and returning a handle back to the VPE driver. The VIP driver will
 also call the same init function to initialize it's own VPDMA instance.
 
 Signed-off-by: Archit Taneja arc...@ti.com
 ---
  drivers/media/platform/ti-vpe/vpdma.c  | 589 ++
  drivers/media/platform/ti-vpe/vpdma.h  | 154 
  drivers/media/platform/ti-vpe/vpdma_priv.h | 119 ++
  3 files changed, 862 insertions(+)
  create mode 100644 drivers/media/platform/ti-vpe/vpdma.c
  create mode 100644 drivers/media/platform/ti-vpe/vpdma.h
  create mode 100644 drivers/media/platform/ti-vpe/vpdma_priv.h
 
 diff --git a/drivers/media/platform/ti-vpe/vpdma.c
 b/drivers/media/platform/ti-vpe/vpdma.c new file mode 100644
 index 000..b15b3dd
 --- /dev/null
 +++ b/drivers/media/platform/ti-vpe/vpdma.c
 @@ -0,0 +1,589 @@

[snip]

 +static int get_field(u32 value, u32 mask, int shift)
 +{
 + return (value  (mask  shift))  shift;
 +}
 +
 +static int get_field_reg(struct vpdma_data *vpdma, int offset,
 + u32 mask, int shift)

I would call this read_field_reg().

 +{
 + return get_field(read_reg(vpdma, offset), mask, shift);
 +}
 +
 +static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
 +{
 + u32 val = *valp;
 +
 + val = ~(mask  shift);
 + val |= (field  mask)  shift;
 + *valp = val;
 +}

get_field() and insert_field() are used in a single location, you can manually 
inline them.

 +static void insert_field_reg(struct vpdma_data *vpdma, int offset, u32
 field,
 + u32 mask, int shift)
 +{
 + u32 val = read_reg(vpdma, offset);
 +
 + insert_field(val, field, mask, shift);
 +
 + write_reg(vpdma, offset, val);
 +}

[snip]

 +/*
 + * Allocate a DMA buffer
 + */
 +int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
 +{
 + buf-size = size;
 + buf-mapped = 0;
 + buf-addr = kzalloc(size, GFP_KERNEL);

You should use the dma allocation API (depending on your needs, 
dma_alloc_coherent for instance) to allocate DMA-able buffers.

 + if (!buf-addr)
 + return -ENOMEM;
 +
 + WARN_ON((u32) buf-addr  VPDMA_DESC_ALIGN);
 +
 + return 0;
 +}
 +
 

Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-05 Thread Tomi Valkeinen
Hi,

On 02/08/13 17:03, Archit Taneja wrote:

 +struct vpdma_data_format vpdma_yuv_fmts[] = {
 + [VPDMA_DATA_FMT_Y444] = {
 + .data_type  = DATA_TYPE_Y444,
 + .depth  = 8,
 + },

This, and all the other tables, should probably be consts?

 +static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
 +{
 + u32 val = *valp;
 +
 + val = ~(mask  shift);
 + val |= (field  mask)  shift;
 + *valp = val;
 +}

I think insert normally means, well, inserting a thing in between
something. What you do here is overwriting.

Why not just call it write_field?

 + * Allocate a DMA buffer
 + */
 +int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
 +{
 + buf-size = size;
 + buf-mapped = 0;

Maybe true/false is clearer here that 0/1.

 +/*
 + * submit a list of DMA descriptors to the VPE VPDMA, do not wait for 
 completion
 + */
 +int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list 
 *list)
 +{
 + /* we always use the first list */
 + int list_num = 0;
 + int list_size;
 +
 + if (vpdma_list_busy(vpdma, list_num))
 + return -EBUSY;
 +
 + /* 16-byte granularity */
 + list_size = (list-next - list-buf.addr)  4;
 +
 + write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list-buf.dma_addr);
 + wmb();

What is the wmb() for?

 + write_reg(vpdma, VPDMA_LIST_ATTR,
 + (list_num  VPDMA_LIST_NUM_SHFT) |
 + (list-type  VPDMA_LIST_TYPE_SHFT) |
 + list_size);
 +
 + return 0;
 +}

 +static void vpdma_firmware_cb(const struct firmware *f, void *context)
 +{
 + struct vpdma_data *vpdma = context;
 + struct vpdma_buf fw_dma_buf;
 + int i, r;
 +
 + dev_dbg(vpdma-pdev-dev, firmware callback\n);
 +
 + if (!f || !f-data) {
 + dev_err(vpdma-pdev-dev, couldn't get firmware\n);
 + return;
 + }
 +
 + /* already initialized */
 + if (get_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 + VPDMA_LIST_RDY_SHFT)) {
 + vpdma-ready = true;
 + return;
 + }
 +
 + r = vpdma_buf_alloc(fw_dma_buf, f-size);
 + if (r) {
 + dev_err(vpdma-pdev-dev,
 + failed to allocate dma buffer for firmware\n);
 + goto rel_fw;
 + }
 +
 + memcpy(fw_dma_buf.addr, f-data, f-size);
 +
 + vpdma_buf_map(vpdma, fw_dma_buf);
 +
 + write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr);
 +
 + for (i = 0; i  100; i++) { /* max 1 second */
 + msleep_interruptible(10);

You call interruptible version here, but you don't handle the
interrupted case. I believe the loop will just continue looping, even if
the user interrupted.

 + if (get_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
 + VPDMA_LIST_RDY_SHFT))
 + break;
 + }
 +
 + if (i == 100) {
 + dev_err(vpdma-pdev-dev, firmware upload failed\n);
 + goto free_buf;
 + }
 +
 + vpdma-ready = true;
 +
 +free_buf:
 + vpdma_buf_unmap(vpdma, fw_dma_buf);
 +
 + vpdma_buf_free(fw_dma_buf);
 +rel_fw:
 + release_firmware(f);
 +}

 Tomi




signature.asc
Description: OpenPGP digital signature


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-05 Thread Archit Taneja

On Monday 05 August 2013 01:43 PM, Tomi Valkeinen wrote:

Hi,

On 02/08/13 17:03, Archit Taneja wrote:


+struct vpdma_data_format vpdma_yuv_fmts[] = {
+   [VPDMA_DATA_FMT_Y444] = {
+   .data_type  = DATA_TYPE_Y444,
+   .depth  = 8,
+   },


This, and all the other tables, should probably be consts?


That's true, I'll fix those.




+static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
+{
+   u32 val = *valp;
+
+   val = ~(mask  shift);
+   val |= (field  mask)  shift;
+   *valp = val;
+}


I think insert normally means, well, inserting a thing in between
something. What you do here is overwriting.

Why not just call it write_field?


sure, will change it.




+ * Allocate a DMA buffer
+ */
+int vpdma_buf_alloc(struct vpdma_buf *buf, size_t size)
+{
+   buf-size = size;
+   buf-mapped = 0;


Maybe true/false is clearer here that 0/1.


okay.




+/*
+ * submit a list of DMA descriptors to the VPE VPDMA, do not wait for 
completion
+ */
+int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list)
+{
+   /* we always use the first list */
+   int list_num = 0;
+   int list_size;
+
+   if (vpdma_list_busy(vpdma, list_num))
+   return -EBUSY;
+
+   /* 16-byte granularity */
+   list_size = (list-next - list-buf.addr)  4;
+
+   write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list-buf.dma_addr);
+   wmb();


What is the wmb() for?


VPDMA_LIST_ADDR needs to be written before VPDMA_LIST_ATTR, otherwise 
VPDMA doesn't work. wmb() ensures the ordering.





+   write_reg(vpdma, VPDMA_LIST_ATTR,
+   (list_num  VPDMA_LIST_NUM_SHFT) |
+   (list-type  VPDMA_LIST_TYPE_SHFT) |
+   list_size);
+
+   return 0;
+}



+static void vpdma_firmware_cb(const struct firmware *f, void *context)
+{
+   struct vpdma_data *vpdma = context;
+   struct vpdma_buf fw_dma_buf;
+   int i, r;
+
+   dev_dbg(vpdma-pdev-dev, firmware callback\n);
+
+   if (!f || !f-data) {
+   dev_err(vpdma-pdev-dev, couldn't get firmware\n);
+   return;
+   }
+
+   /* already initialized */
+   if (get_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
+   VPDMA_LIST_RDY_SHFT)) {
+   vpdma-ready = true;
+   return;
+   }
+
+   r = vpdma_buf_alloc(fw_dma_buf, f-size);
+   if (r) {
+   dev_err(vpdma-pdev-dev,
+   failed to allocate dma buffer for firmware\n);
+   goto rel_fw;
+   }
+
+   memcpy(fw_dma_buf.addr, f-data, f-size);
+
+   vpdma_buf_map(vpdma, fw_dma_buf);
+
+   write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr);
+
+   for (i = 0; i  100; i++) {  /* max 1 second */
+   msleep_interruptible(10);


You call interruptible version here, but you don't handle the
interrupted case. I believe the loop will just continue looping, even if
the user interrupted.


Okay. I think I don't understand the interruptible version correctly. We 
don't need to msleep_interruptible here, we aren't waiting on any wake 
up event, we just want to wait till a bit gets set.


I am thinking of implementing something similar to wait_for_bit_change() 
in 'drivers/video/omap2/dss/dsi.c'


Archit

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/6] v4l: ti-vpe: Create a vpdma helper library

2013-08-05 Thread Tomi Valkeinen
On 05/08/13 14:26, Archit Taneja wrote:
 On Monday 05 August 2013 01:43 PM, Tomi Valkeinen wrote:

 +/*
 + * submit a list of DMA descriptors to the VPE VPDMA, do not wait
 for completion
 + */
 +int vpdma_submit_descs(struct vpdma_data *vpdma, struct
 vpdma_desc_list *list)
 +{
 +/* we always use the first list */
 +int list_num = 0;
 +int list_size;
 +
 +if (vpdma_list_busy(vpdma, list_num))
 +return -EBUSY;
 +
 +/* 16-byte granularity */
 +list_size = (list-next - list-buf.addr)  4;
 +
 +write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list-buf.dma_addr);
 +wmb();

 What is the wmb() for?
 
 VPDMA_LIST_ADDR needs to be written before VPDMA_LIST_ATTR, otherwise
 VPDMA doesn't work. wmb() ensures the ordering.

Are you sure it's needed? Here's an interesting thread about writing and
reading to registers: http://marc.info/?t=13058859492r=1w=2

 +
 +for (i = 0; i  100; i++) {/* max 1 second */
 +msleep_interruptible(10);

 You call interruptible version here, but you don't handle the
 interrupted case. I believe the loop will just continue looping, even if
 the user interrupted.
 
 Okay. I think I don't understand the interruptible version correctly. We
 don't need to msleep_interruptible here, we aren't waiting on any wake
 up event, we just want to wait till a bit gets set.

Well, I think the interruptible versions should be used when the user
(wel, userspace program) initiates the action. The user should have the
option to interrupt a possibly long running operation, which is what
msleep_interruptible() makes possible.

 Tomi




signature.asc
Description: OpenPGP digital signature