Re: [PATCH 1/4] ARM/omap1: switch to use dma_direct_set_offset for lbus DMA offsets

2020-09-19 Thread Janusz Krzysztofik
Hi Tony,

On Friday, September 18, 2020 7:49:33 A.M. CEST Tony Lindgren wrote:
> * Christoph Hellwig  [200917 17:37]:
> > Switch the omap1510 platform ohci device to use dma_direct_set_offset
> > to set the DMA offset instead of using direct hooks into the DMA
> > mapping code and remove the now unused hooks.
> 
> Looks nice to me :) I still can't test this probably for few more weeks
> though but hopefully Aaro or Janusz (Added to Cc) can test it.

Works for me on Amstrad Delta (tested with a USB ethernet adapter).

Tested-by: Janusz Krzysztofik 

Thanks,
Janusz

> 
> Regards,
> 
> Tony
> 
> > Signed-off-by: Christoph Hellwig 
> > ---
> >  arch/arm/include/asm/dma-direct.h | 18 -
> >  arch/arm/mach-omap1/include/mach/memory.h | 31 ---
> >  arch/arm/mach-omap1/usb.c | 22 
> >  3 files changed, 22 insertions(+), 49 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/dma-direct.h 
> > b/arch/arm/include/asm/dma-direct.h
> > index 436544aeb83405..77fcb7ee5ec907 100644
> > --- a/arch/arm/include/asm/dma-direct.h
> > +++ b/arch/arm/include/asm/dma-direct.h
> > @@ -9,7 +9,6 @@
> >   * functions used internally by the DMA-mapping API to provide DMA
> >   * addresses. They must not be used by drivers.
> >   */
> > -#ifndef __arch_pfn_to_dma
> >  static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
> >  {
> > if (dev && dev->dma_range_map)
> > @@ -34,23 +33,6 @@ static inline dma_addr_t virt_to_dma(struct device *dev, 
> > void *addr)
> > return (dma_addr_t)__virt_to_bus((unsigned long)(addr));
> >  }
> >  
> > -#else
> > -static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
> > -{
> > -   return __arch_pfn_to_dma(dev, pfn);
> > -}
> > -
> > -static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
> > -{
> > -   return __arch_dma_to_pfn(dev, addr);
> > -}
> > -
> > -static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
> > -{
> > -   return __arch_virt_to_dma(dev, addr);
> > -}
> > -#endif
> > -
> >  static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
> >  {
> > unsigned int offset = paddr & ~PAGE_MASK;
> > diff --git a/arch/arm/mach-omap1/include/mach/memory.h 
> > b/arch/arm/mach-omap1/include/mach/memory.h
> > index 1142560e0078f5..36bccb6ab8 100644
> > --- a/arch/arm/mach-omap1/include/mach/memory.h
> > +++ b/arch/arm/mach-omap1/include/mach/memory.h
> > @@ -14,42 +14,11 @@
> >   * OMAP-1510 bus address is translated into a Local Bus address if the
> >   * OMAP bus type is lbus. We do the address translation based on the
> >   * device overriding the defaults used in the dma-mapping API.
> > - * Note that the is_lbus_device() test is not very efficient on 1510
> > - * because of the strncmp().
> >   */
> > -#if defined(CONFIG_ARCH_OMAP15XX) && !defined(__ASSEMBLER__)
> >  
> >  /*
> >   * OMAP-1510 Local Bus address offset
> >   */
> >  #define OMAP1510_LB_OFFSET UL(0x3000)
> >  
> > -#define virt_to_lbus(x)((x) - PAGE_OFFSET + OMAP1510_LB_OFFSET)
> > -#define lbus_to_virt(x)((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET)
> > -#define is_lbus_device(dev)(cpu_is_omap15xx() && dev && 
> > (strncmp(dev_name(dev), "ohci", 4) == 0))
> > -
> > -#define __arch_pfn_to_dma(dev, pfn)\
> > -   ({ dma_addr_t __dma = __pfn_to_phys(pfn); \
> > -  if (is_lbus_device(dev)) \
> > -   __dma = __dma - PHYS_OFFSET + OMAP1510_LB_OFFSET; \
> > -  __dma; })
> > -
> > -#define __arch_dma_to_pfn(dev, addr)   \
> > -   ({ dma_addr_t __dma = addr; \
> > -  if (is_lbus_device(dev)) \
> > -   __dma += PHYS_OFFSET - OMAP1510_LB_OFFSET;  \
> > -  __phys_to_pfn(__dma);\
> > -   })
> > -
> > -#define __arch_dma_to_virt(dev, addr)  ({ (void *) 
> > (is_lbus_device(dev) ? \
> > -   lbus_to_virt(addr) : \
> > -   __phys_to_virt(addr)); })
> > -
> > -#define __arch_virt_to_dma(dev, addr)  ({ unsigned long __addr = 
> > (unsigned long)(addr); \
> > -  (dma_addr_t) (is_lbus_device(dev) ? \
> > -  

[PATCH] mtd: rawnand: ams-delta: Fix non-OF build warning

2020-09-19 Thread Janusz Krzysztofik
Commit 7c2f66a960fc ("mtd: rawnand: ams-delta: Add module device
tables") introduced an OF module device table but wrapped a reference
to it with of_match_ptr() which resolves to NULL in non-OF configs.
That resulted in a clang compiler warning on unused variable in non-OF
builds.  Fix it.

drivers/mtd/nand/raw/ams-delta.c:373:34: warning: unused variable 
'gpio_nand_of_id_table' [-Wunused-const-variable]
   static const struct of_device_id gpio_nand_of_id_table[] = {
^
   1 warning generated.

Fixes: 7c2f66a960fc ("mtd: rawnand: ams-delta: Add module device tables")
Reported-by: kernel test robot 
Signed-off-by: Janusz Krzysztofik 
---
 drivers/mtd/nand/raw/ams-delta.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index fdba155416d2..0bf4cfc25147 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -400,12 +400,14 @@ static int gpio_nand_remove(struct platform_device *pdev)
return 0;
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id gpio_nand_of_id_table[] = {
{
/* sentinel */
},
 };
 MODULE_DEVICE_TABLE(of, gpio_nand_of_id_table);
+#endif
 
 static const struct platform_device_id gpio_nand_plat_id_table[] = {
{
-- 
2.26.2



Re: [PATCH 6/6] media: ov6650: Fix arbitrary selection of master clock rate

2019-10-18 Thread Janusz Krzysztofik
Hi Sakari,

On Friday, October 18, 2019 8:54:19 P.M. CEST Sakari Ailus wrote:
> Hi Janusz,
> 
> On Sun, Oct 13, 2019 at 02:50:50PM +0200, Janusz Krzysztofik wrote:
> > A hardcoded 12 MHz master clock frequency has been assumed since
> > conversion of the driver from soc_camera sensor to a standalone V4L2
> > subdevice by commit 23a52386fabe ("media: ov6650: convert to standalone
> > v4l2 subdevice").  Fix it.
> > 
> > Define a static table of supported master clock rates (fix misnamed
> > symbol while being at it), then use v4l2_clk_get/set_rate() to obtain
> > a clock rate matching one of those supported.  On success, apply
> > respective master clock hardware divisor provided by the matching
> > element of the table.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> >  drivers/media/i2c/ov6650.c | 64 ++
> >  1 file changed, 58 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
> > index f4723c0b5c70..13fd7c4699b2 100644
> > --- a/drivers/media/i2c/ov6650.c
> > +++ b/drivers/media/i2c/ov6650.c
> > @@ -124,7 +124,7 @@
> >  
> >  #define DEF_AECH   0x4D
> >  
> > -#define CLKRC_6MHz 0x00
> > +#define CLKRC_8MHz 0x00
> >  #define CLKRC_12MHz0x40
> >  #define CLKRC_16MHz0x80
> >  #define CLKRC_24MHz0xc0
> > @@ -201,6 +201,29 @@ struct ov6650 {
> > u32 code;
> >  };
> >  
> > +struct ov6650_xclk {
> > +   unsigned long   rate;
> > +   u8  clkrc;
> > +};
> > +
> > +static const struct ov6650_xclk ov6650_xclk[] = {
> > +{
> > +   .rate   = 800,
> > +   .clkrc  = CLKRC_8MHz,
> > +},
> > +{
> > +   .rate   = 1200,
> > +   .clkrc  = CLKRC_12MHz,
> > +},
> > +{
> > +   .rate   = 1600,
> > +   .clkrc  = CLKRC_16MHz,
> > +},
> > +{
> > +   .rate   = 2400,
> > +   .clkrc  = CLKRC_24MHz,
> > +},
> > +};
> >  
> >  static u32 ov6650_codes[] = {
> > MEDIA_BUS_FMT_YUYV8_2X8,
> > @@ -774,7 +797,7 @@ static int ov6650_reset(struct i2c_client *client)
> >  }
> >  
> >  /* program default register values */
> > -static int ov6650_prog_dflt(struct i2c_client *client)
> > +static int ov6650_prog_dflt(struct i2c_client *client, u8 clkrc)
> >  {
> > int ret;
> >  
> > @@ -782,7 +805,7 @@ static int ov6650_prog_dflt(struct i2c_client *client)
> >  
> > ret = ov6650_reg_write(client, REG_COMA, 0);/* ~COMA_RESET */
> > if (!ret)
> > -   ret = ov6650_reg_write(client, REG_CLKRC, CLKRC_12MHz);
> > +   ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
> > if (!ret)
> > ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
> >  
> > @@ -793,8 +816,10 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
> >  {
> > struct i2c_client *client = v4l2_get_subdevdata(sd);
> > struct ov6650 *priv = to_ov6650(client);
> > -   u8  pidh, pidl, midh, midl;
> > -   int ret;
> > +   const struct ov6650_xclk *xclk;
> > +   unsigned long rate;
> > +   u8 pidh, pidl, midh, midl;
> > +   int i, ret;
> >  
> > priv->clk = v4l2_clk_get(&client->dev, NULL);
> > if (IS_ERR(priv->clk)) {
> > @@ -803,6 +828,33 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
> > return ret;
> > }
> >  
> > +   rate = v4l2_clk_get_rate(priv->clk);
> > +   for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) {
> > +   if (rate != ov6650_xclk[i].rate)
> > +   continue;
> > +
> > +   xclk = &ov6650_xclk[i];
> > +   dev_info(&client->dev, "using host default clock rate %lukHz\n",
> > +rate / 1000);
> > +   break;
> > +   }
> 
> xclk is undefined unless it was set in the previous loop. 

Indeed, sorry for that.

> Please initialise
> to to NULL. I can fix that, too, while applying the patch.

OK, please do if you can.

Thanks,
Janusz


> > +   for (i = 0; !xclk && i < ARRAY_SIZE(ov6650_xclk); i++) {
> > +   ret = v4l2_clk_set_rate(priv->clk, ov6650_xclk[i].rate);
> > +   if (ret || v4l2_clk_get_rate(priv->clk) != ov6650_xclk[i].rate)
> > +   continue;
> > +
> > +   xclk = &ov6650_xclk[i];
> &g

[PATCH 2/6] media: ov6650: Drop obsolete .pclk_limit attribute

2019-10-13 Thread Janusz Krzysztofik
That attribute used to be obtained from platform data by a soc_camera
host interface and passed to the sensor driver for .s_mbus_fmt() video
operation callback, later reused as .set_fmt() pad operation callback,
to be able to limit frame rate.  The driver stored that value in its
private structure for further use from .g/s_parm(), later converted to
g/s_frame_interval().

On conversion of the driver from soc_camera sensor to a standalone V4L2
subdevice by commit 23a52386fabe ("media: ov6650: convert to standalone
v4l2 subdevice"), that attribute had been replaced by a constant and
hardcoded to an arbitrarily chosen pixel clock limit.  Drop it.  Host
interfaces can limit frame rate if needed by calling
.s_frame_interval().

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 14 --
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index f60aeb1f7813..a50244401491 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -197,7 +197,6 @@ struct ov6650 {
struct v4l2_clk *clk;
boolhalf_scale; /* scale down output by 2 */
struct v4l2_rectrect;   /* sensor cropping window */
-   unsigned long   pclk_limit; /* from host */
unsigned long   pclk_max;   /* from resolution and format */
struct v4l2_fract   tpf;/* as requested with 
s_frame_interval */
u32 code;
@@ -546,8 +545,7 @@ static bool is_unscaled_ok(int width, int height, struct 
v4l2_rect *rect)
return width > rect->width >> 1 || height > rect->height >> 1;
 }
 
-static u8 to_clkrc(struct v4l2_fract *timeperframe,
-   unsigned long pclk_limit, unsigned long pclk_max)
+static u8 to_clkrc(struct v4l2_fract *timeperframe, unsigned long pclk_max)
 {
unsigned long pclk;
 
@@ -557,9 +555,6 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe,
else
pclk = pclk_max;
 
-   if (pclk_limit && pclk_limit < pclk)
-   pclk = pclk_limit;
-
return (pclk_max - 1) / pclk;
 }
 
@@ -653,10 +648,9 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
 
clkrc = CLKRC_12MHz;
mclk = 1200;
-   priv->pclk_limit = 1334000;
dev_dbg(&client->dev, "using 12MHz input clock\n");
 
-   clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+   clkrc |= to_clkrc(&priv->tpf, priv->pclk_max);
 
pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
@@ -756,7 +750,7 @@ static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
struct ov6650 *priv = to_ov6650(client);
 
ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
-   priv->pclk_limit, priv->pclk_max));
+ priv->pclk_max));
ival->interval.denominator = FRAME_RATE_MAX;
 
dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
@@ -787,7 +781,7 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
tpf->numerator = div;
tpf->denominator = FRAME_RATE_MAX;
 
-   clkrc = to_clkrc(tpf, priv->pclk_limit, priv->pclk_max);
+   clkrc = to_clkrc(tpf, priv->pclk_max);
 
ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
if (!ret) {
-- 
2.21.0



[PATCH 4/6] media: ov6650: Don't reapply pixel clock divisor on format change

2019-10-13 Thread Janusz Krzysztofik
As calculation of pixel clock hardware divisor no longer depends on
mbus format specific maximum pixel clock, there is no need to reapply
the divisor on format change.  Drop related code from ov6650_s_fmt()
helper.

Since a master clock hardware divisor, so far applied only together
with the pixel clock divisor in a single operation, will no longer be
applied from ov6650_s_fmt(), apply it, still using a hardcoded value
for now, from  ov6650_prog_dflt() helper so hardware is still
initialised correctly on device probe.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 17 +++--
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 61ddd4ea4c26..e95ea132ef06 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -564,8 +564,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
.r.height = mf->height << half_scale,
};
u32 code = mf->code;
-   unsigned long mclk, pclk;
-   u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
+   u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask;
int ret;
 
/* select color matrix configuration for given color encoding */
@@ -635,21 +634,9 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
coma_mask |= COMA_QCIF;
}
 
-   clkrc = CLKRC_12MHz;
-   mclk = 1200;
-   dev_dbg(&client->dev, "using 12MHz input clock\n");
-
-   clkrc |= to_clkrc(priv->tpf.numerator);
-
-   pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
-   dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
-   mclk / pclk, 10 * mclk % pclk / pclk);
-
ret = ov6650_set_selection(sd, NULL, &sel);
if (!ret)
ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
-   if (!ret)
-   ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
if (!ret) {
priv->half_scale = half_scale;
 
@@ -798,6 +785,8 @@ static int ov6650_prog_dflt(struct i2c_client *client)
dev_dbg(&client->dev, "initializing\n");
 
ret = ov6650_reg_write(client, REG_COMA, 0);/* ~COMA_RESET */
+   if (!ret)
+   ret = ov6650_reg_write(client, REG_CLKRC, CLKRC_12MHz);
if (!ret)
ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
 
-- 
2.21.0



[PATCH 1/6] media: ov6650: Fix stored frame interval not in sync with hardware

2019-10-13 Thread Janusz Krzysztofik
The driver stores a frame interval value supposed to be in line with
hardware state in a device private structure.  Since the driver initial
submission, the respective field of the structure has never been
initialised on device probe.  Moreover, if updated from
.s_frame_interval(), a new value is stored before it is applied on
hardware.  If an error occurs during device update, the stored value
may no longer reflect hardware state and consecutive calls to
.g_frame_interval() may return incorrect information.

Assuming a failed update of the device means its actual state hasn't
changed, update the frame interval field of the device private
structure with a new value only after it is successfully applied on
hardware so it always reflects actual hardware state to the extent
possible.  Also, initialise the field with hardware default frame
interval on device probe.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 21 -
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 16887049f0cd..f60aeb1f7813 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -130,6 +130,7 @@
 #define CLKRC_24MHz0xc0
 #define CLKRC_DIV_MASK 0x3f
 #define GET_CLKRC_DIV(x)   (((x) & CLKRC_DIV_MASK) + 1)
+#define DEF_CLKRC  0x00
 
 #define COMA_RESET BIT(7)
 #define COMA_QCIF  BIT(5)
@@ -783,19 +784,17 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
 
-   /*
-* Keep result to be used as tpf limit
-* for subsequent clock divider calculations
-*/
-   priv->tpf.numerator = div;
-   priv->tpf.denominator = FRAME_RATE_MAX;
+   tpf->numerator = div;
+   tpf->denominator = FRAME_RATE_MAX;
 
-   clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+   clkrc = to_clkrc(tpf, priv->pclk_limit, priv->pclk_max);
 
ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
if (!ret) {
-   tpf->numerator = GET_CLKRC_DIV(clkrc);
-   tpf->denominator = FRAME_RATE_MAX;
+   priv->tpf.numerator = GET_CLKRC_DIV(clkrc);
+   priv->tpf.denominator = FRAME_RATE_MAX;
+
+   *tpf = priv->tpf;
}
 
return ret;
@@ -1038,6 +1037,10 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.width  = W_CIF;
priv->rect.height = H_CIF;
 
+   /* Hardware default frame interval */
+   priv->tpf.numerator   = GET_CLKRC_DIV(DEF_CLKRC);
+   priv->tpf.denominator = FRAME_RATE_MAX;
+
priv->subdev.internal_ops = &ov6650_internal_ops;
 
ret = v4l2_async_register_subdev(&priv->subdev);
-- 
2.21.0



[PATCH 5/6] media: ov6650: Drop unused .pclk_max field

2019-10-13 Thread Janusz Krzysztofik
This field of the driver private structure is no longer used, drop it.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index e95ea132ef06..f4723c0b5c70 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -197,7 +197,6 @@ struct ov6650 {
struct v4l2_clk *clk;
boolhalf_scale; /* scale down output by 2 */
struct v4l2_rectrect;   /* sensor cropping window */
-   unsigned long   pclk_max;   /* from resolution and format */
struct v4l2_fract   tpf;/* as requested with 
s_frame_interval */
u32 code;
 };
@@ -618,17 +617,14 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
code == MEDIA_BUS_FMT_SBGGR8_1X8) {
coml_mask = COML_ONE_CHANNEL;
coml_set = 0;
-   priv->pclk_max = 400;
} else {
coml_mask = 0;
coml_set = COML_ONE_CHANNEL;
-   priv->pclk_max = 800;
}
 
if (half_scale) {
dev_dbg(&client->dev, "max resolution: QCIF\n");
coma_set |= COMA_QCIF;
-   priv->pclk_max /= 2;
} else {
dev_dbg(&client->dev, "max resolution: CIF\n");
coma_mask |= COMA_QCIF;
-- 
2.21.0



[PATCH 0/6] media: ov6650: Master and pixel clock handling fixes

2019-10-13 Thread Janusz Krzysztofik
Fix issues with handling of master and pixel clock, mostly those
introduced as temporary workarounds when the driver was converted form
soc_camera sensor to a standalone V4L2 subdevice driver.

Janusz Krzysztofik (6):
  media: ov6650: Fix stored frame interval not in sync with hardware
  media: ov6650: Drop obsolete .pclk_limit attribute
  media: ov6650: Simplify clock divisor calculation
  media: ov6650: Don't reapply pixel clock divisor on format change
  media: ov6650: Drop unused .pclk_max field
  media: ov6650: Fix arbitrary selection of master clock rate

 drivers/media/i2c/ov6650.c | 129 +
 1 file changed, 72 insertions(+), 57 deletions(-)

-- 
2.21.0



[PATCH 6/6] media: ov6650: Fix arbitrary selection of master clock rate

2019-10-13 Thread Janusz Krzysztofik
A hardcoded 12 MHz master clock frequency has been assumed since
conversion of the driver from soc_camera sensor to a standalone V4L2
subdevice by commit 23a52386fabe ("media: ov6650: convert to standalone
v4l2 subdevice").  Fix it.

Define a static table of supported master clock rates (fix misnamed
symbol while being at it), then use v4l2_clk_get/set_rate() to obtain
a clock rate matching one of those supported.  On success, apply
respective master clock hardware divisor provided by the matching
element of the table.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 64 ++
 1 file changed, 58 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index f4723c0b5c70..13fd7c4699b2 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -124,7 +124,7 @@
 
 #define DEF_AECH   0x4D
 
-#define CLKRC_6MHz 0x00
+#define CLKRC_8MHz 0x00
 #define CLKRC_12MHz0x40
 #define CLKRC_16MHz0x80
 #define CLKRC_24MHz0xc0
@@ -201,6 +201,29 @@ struct ov6650 {
u32 code;
 };
 
+struct ov6650_xclk {
+   unsigned long   rate;
+   u8  clkrc;
+};
+
+static const struct ov6650_xclk ov6650_xclk[] = {
+{
+   .rate   = 800,
+   .clkrc  = CLKRC_8MHz,
+},
+{
+   .rate   = 1200,
+   .clkrc  = CLKRC_12MHz,
+},
+{
+   .rate   = 1600,
+   .clkrc  = CLKRC_16MHz,
+},
+{
+   .rate   = 2400,
+   .clkrc  = CLKRC_24MHz,
+},
+};
 
 static u32 ov6650_codes[] = {
MEDIA_BUS_FMT_YUYV8_2X8,
@@ -774,7 +797,7 @@ static int ov6650_reset(struct i2c_client *client)
 }
 
 /* program default register values */
-static int ov6650_prog_dflt(struct i2c_client *client)
+static int ov6650_prog_dflt(struct i2c_client *client, u8 clkrc)
 {
int ret;
 
@@ -782,7 +805,7 @@ static int ov6650_prog_dflt(struct i2c_client *client)
 
ret = ov6650_reg_write(client, REG_COMA, 0);/* ~COMA_RESET */
if (!ret)
-   ret = ov6650_reg_write(client, REG_CLKRC, CLKRC_12MHz);
+   ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
if (!ret)
ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
 
@@ -793,8 +816,10 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
 {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
-   u8  pidh, pidl, midh, midl;
-   int ret;
+   const struct ov6650_xclk *xclk;
+   unsigned long rate;
+   u8 pidh, pidl, midh, midl;
+   int i, ret;
 
priv->clk = v4l2_clk_get(&client->dev, NULL);
if (IS_ERR(priv->clk)) {
@@ -803,6 +828,33 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
return ret;
}
 
+   rate = v4l2_clk_get_rate(priv->clk);
+   for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) {
+   if (rate != ov6650_xclk[i].rate)
+   continue;
+
+   xclk = &ov6650_xclk[i];
+   dev_info(&client->dev, "using host default clock rate %lukHz\n",
+rate / 1000);
+   break;
+   }
+   for (i = 0; !xclk && i < ARRAY_SIZE(ov6650_xclk); i++) {
+   ret = v4l2_clk_set_rate(priv->clk, ov6650_xclk[i].rate);
+   if (ret || v4l2_clk_get_rate(priv->clk) != ov6650_xclk[i].rate)
+   continue;
+
+   xclk = &ov6650_xclk[i];
+   dev_info(&client->dev, "using negotiated clock rate %lukHz\n",
+xclk->rate / 1000);
+   break;
+   }
+   if (!xclk) {
+   dev_err(&client->dev, "unable to get supported clock rate\n");
+   if (!ret)
+   ret = -EINVAL;
+   goto eclkput;
+   }
+
ret = ov6650_s_power(sd, 1);
if (ret < 0)
goto eclkput;
@@ -836,7 +888,7 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
 
ret = ov6650_reset(client);
if (!ret)
-   ret = ov6650_prog_dflt(client);
+   ret = ov6650_prog_dflt(client, xclk->clkrc);
if (!ret) {
struct v4l2_mbus_framefmt mf = ov6650_def_fmt;
 
-- 
2.21.0



[PATCH 3/6] media: ov6650: Simplify clock divisor calculation

2019-10-13 Thread Janusz Krzysztofik
As appears from an analysis of to_clkrc() helper code after its
pclk_limit argument has been dropped, its result no longer depends on
another argument - pclk_max.  Moreover, assuming that a constant value
of FRAME_RATE_MAX is always used as a denominator of the only
significant argument left - a struct v4l2_fract, the result in fact
depends only on the numerator value of that argument.  As a further
consequence, it no longer makes sense to recalculate frame intervals by
converting them forth and back with a GET_CLKRC_DIV(to_clkrc(tpf))
construct.

Drop use of GET_CLKRC_DIV() on results of to_clkrc() where possible -
use the frame interval value directly.  Furthermore, replace the
to_clkrc() helper function with a simple macro and update its users to
always use FRAME_RATE_MAX as frame interval denominator and pass only
its numerator as an argument.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 29 +
 1 file changed, 5 insertions(+), 24 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index a50244401491..61ddd4ea4c26 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -545,18 +545,7 @@ static bool is_unscaled_ok(int width, int height, struct 
v4l2_rect *rect)
return width > rect->width >> 1 || height > rect->height >> 1;
 }
 
-static u8 to_clkrc(struct v4l2_fract *timeperframe, unsigned long pclk_max)
-{
-   unsigned long pclk;
-
-   if (timeperframe->numerator && timeperframe->denominator)
-   pclk = pclk_max * timeperframe->denominator /
-   (FRAME_RATE_MAX * timeperframe->numerator);
-   else
-   pclk = pclk_max;
-
-   return (pclk_max - 1) / pclk;
-}
+#define to_clkrc(div)  ((div) - 1)
 
 /* set the format we will capture in */
 static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
@@ -650,7 +639,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
mclk = 1200;
dev_dbg(&client->dev, "using 12MHz input clock\n");
 
-   clkrc |= to_clkrc(&priv->tpf, priv->pclk_max);
+   clkrc |= to_clkrc(priv->tpf.numerator);
 
pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
@@ -749,9 +738,7 @@ static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
 
-   ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
- priv->pclk_max));
-   ival->interval.denominator = FRAME_RATE_MAX;
+   ival->interval = priv->tpf;
 
dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
ival->interval.numerator, ival->interval.denominator);
@@ -766,7 +753,6 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
struct ov6650 *priv = to_ov6650(client);
struct v4l2_fract *tpf = &ival->interval;
int div, ret;
-   u8 clkrc;
 
if (tpf->numerator == 0 || tpf->denominator == 0)
div = 1;  /* Reset to full rate */
@@ -778,14 +764,9 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
 
-   tpf->numerator = div;
-   tpf->denominator = FRAME_RATE_MAX;
-
-   clkrc = to_clkrc(tpf, priv->pclk_max);
-
-   ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
+   ret = ov6650_reg_rmw(client, REG_CLKRC, to_clkrc(div), CLKRC_DIV_MASK);
if (!ret) {
-   priv->tpf.numerator = GET_CLKRC_DIV(clkrc);
+   priv->tpf.numerator = div;
priv->tpf.denominator = FRAME_RATE_MAX;
 
*tpf = priv->tpf;
-- 
2.21.0



[PATCH v3 8/9] media: ov6650: Fix stored frame format not in sync with hardware

2019-09-03 Thread Janusz Krzysztofik
The driver stores frame format settings supposed to be in line with
hardware state in a device private structure.  Since the driver initial
submission, those settings are updated before they are actually applied
on hardware.  If an error occurs on device update, the stored settings
my not reflect hardware state anymore and consecutive calls to
.get_fmt() may return incorrect information.  That in turn may affect
ability of a bridge device to use correct DMA transfer settings if such
incorrect informmation on active frame format returned by .get_fmt() is
used.

Assuming a failed device update means its state hasn't changed, update
frame format related settings stored in the device private structure
only after they are successfully applied so the stored values always
reflect hardware state as closely as possible.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 4fd8ac8e3994..126a662be301 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -627,7 +627,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
return -EINVAL;
}
-   priv->code = code;
 
if (code == MEDIA_BUS_FMT_Y8_1X8 ||
code == MEDIA_BUS_FMT_SBGGR8_1X8) {
@@ -648,7 +647,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
dev_dbg(&client->dev, "max resolution: CIF\n");
coma_mask |= COMA_QCIF;
}
-   priv->half_scale = half_scale;
 
clkrc = CLKRC_12MHz;
mclk = 1200;
@@ -666,8 +664,13 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
if (!ret)
ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
-   if (!ret)
+   if (!ret) {
+   priv->half_scale = half_scale;
+
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+   }
+   if (!ret)
+   priv->code = code;
 
return ret;
 }
-- 
2.21.0



[PATCH v3 3/9] media: ov6650: Fix crop rectangle alignment not passed back

2019-09-03 Thread Janusz Krzysztofik
Commit 4f996594ceaf ("[media] v4l2: make vidioc_s_crop const")
introduced a writable copy of constified user requested crop rectangle
in order to be able to perform hardware alignments on it.  Later
on, commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video
ops") replaced s_crop() video operation using that const argument with
set_selection() pad operation which had a corresponding argument not
constified, however the original behavior of the driver was not
restored.  Since that time, any hardware alignment applied on a user
requested crop rectangle is not passed back to the user calling
.set_selection() as it should be.

Fix the issue by dropping the copy and replacing all references to it
with references to the crop rectangle embedded in the user argument.

Fixes: 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 31 +++
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index cb2aa76cd6cc..983b72f33930 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -465,38 +465,37 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
 {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
-   struct v4l2_rect rect = sel->r;
int ret;
 
if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
 
-   v4l_bound_align_image(&rect.width, 2, W_CIF, 1,
- &rect.height, 2, H_CIF, 1, 0);
-   v4l_bound_align_image(&rect.left, DEF_HSTRT << 1,
- (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1,
- &rect.top, DEF_VSTRT << 1,
- (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1,
- 0);
+   v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1,
+ &sel->r.height, 2, H_CIF, 1, 0);
+   v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1,
+ (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1,
+ &sel->r.top, DEF_VSTRT << 1,
+ (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height,
+ 1, 0);
 
-   ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1);
+   ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
if (!ret) {
-   priv->rect.left = rect.left;
+   priv->rect.left = sel->r.left;
ret = ov6650_reg_write(client, REG_HSTOP,
-   (rect.left + rect.width) >> 1);
+  (sel->r.left + sel->r.width) >> 1);
}
if (!ret) {
-   priv->rect.width = rect.width;
-   ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1);
+   priv->rect.width = sel->r.width;
+   ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
}
if (!ret) {
-   priv->rect.top = rect.top;
+   priv->rect.top = sel->r.top;
ret = ov6650_reg_write(client, REG_VSTOP,
-   (rect.top + rect.height) >> 1);
+  (sel->r.top + sel->r.height) >> 1);
}
if (!ret)
-   priv->rect.height = rect.height;
+   priv->rect.height = sel->r.height;
 
return ret;
 }
-- 
2.21.0



[PATCH v3 2/9] media: ov6650: Fix control handler not freed on init error

2019-09-03 Thread Janusz Krzysztofik
Since commit afd9690c72c3 ("[media] ov6650: convert to the control
framework"), if an error occurs during initialization of a control
handler, resources possibly allocated to the handler are not freed
before device initialiaton is aborted.  Fix it.

Fixes: afd9690c72c3 ("[media] ov6650: convert to the control framework")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 53550cae2353..cb2aa76cd6cc 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -989,8 +989,10 @@ static int ov6650_probe(struct i2c_client *client,
V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
 
priv->subdev.ctrl_handler = &priv->hdl;
-   if (priv->hdl.error)
-   return priv->hdl.error;
+   if (priv->hdl.error) {
+   ret = priv->hdl.error;
+   goto ectlhdlfree;
+   }
 
v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
@@ -1008,8 +1010,10 @@ static int ov6650_probe(struct i2c_client *client,
priv->subdev.internal_ops = &ov6650_internal_ops;
 
ret = v4l2_async_register_subdev(&priv->subdev);
-   if (ret)
-   v4l2_ctrl_handler_free(&priv->hdl);
+   if (!ret)
+   return 0;
+ectlhdlfree:
+   v4l2_ctrl_handler_free(&priv->hdl);
 
return ret;
 }
-- 
2.21.0



[PATCH v3 6/9] media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support

2019-09-03 Thread Janusz Krzysztofik
Commit da298c6d98d5 ("[media] v4l2: replace video op g_mbus_fmt by pad
op get_fmt") converted a former ov6650_g_fmt() video operation callback
to an ov6650_get_fmt() pad operation callback.  However, the converted
function disregards a format->which flag that pad operations should
obey and always returns active frame format settings.

That can be fixed by always responding to V4L2_SUBDEV_FORMAT_TRY with
-EINVAL, or providing the response from a pad config argument, likely
updated by a former user call to V4L2_SUBDEV_FORMAT_TRY .set_fmt().
Since implementation of the latter is trivial, go for it.

Fixes: da298c6d98d5 ("[media] v4l2: replace video op g_mbus_fmt by pad op 
get_fmt")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index fd608aebb68d..b62a238a83d0 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -525,10 +525,16 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
*mf = ov6650_def_fmt;
 
/* update media bus format code and frame size */
-   mf->width   = priv->rect.width >> priv->half_scale;
-   mf->height  = priv->rect.height >> priv->half_scale;
-   mf->code= priv->code;
+   if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+   mf->width = cfg->try_fmt.width;
+   mf->height = cfg->try_fmt.height;
+   mf->code = cfg->try_fmt.code;
 
+   } else {
+   mf->width = priv->rect.width >> priv->half_scale;
+   mf->height = priv->rect.height >> priv->half_scale;
+   mf->code = priv->code;
+   }
return 0;
 }
 
-- 
2.21.0



[PATCH v3 4/9] media: ov6650: Fix incorrect use of JPEG colorspace

2019-09-03 Thread Janusz Krzysztofik
Since its initial submission, the driver selects V4L2_COLORSPACE_JPEG
for supported formats other than V4L2_MBUS_FMT_SBGGR8_1X8.  According
to v4l2-compliance test program, V4L2_COLORSPACE_JPEG applies
exclusively to V4L2_PIX_FMT_JPEG.  Since the sensor does not support
JPEG format, fix it to always select V4L2_COLORSPACE_SRGB.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 983b72f33930..a7930ace3744 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -200,7 +200,6 @@ struct ov6650 {
unsigned long   pclk_max;   /* from resolution and format */
struct v4l2_fract   tpf;/* as requested with 
s_frame_interval */
u32 code;
-   enum v4l2_colorspacecolorspace;
 };
 
 
@@ -514,7 +513,7 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
mf->width   = priv->rect.width >> priv->half_scale;
mf->height  = priv->rect.height >> priv->half_scale;
mf->code= priv->code;
-   mf->colorspace  = priv->colorspace;
+   mf->colorspace  = V4L2_COLORSPACE_SRGB;
mf->field   = V4L2_FIELD_NONE;
 
return 0;
@@ -622,11 +621,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
priv->pclk_max = 800;
}
 
-   if (code == MEDIA_BUS_FMT_SBGGR8_1X8)
-   priv->colorspace = V4L2_COLORSPACE_SRGB;
-   else if (code != 0)
-   priv->colorspace = V4L2_COLORSPACE_JPEG;
-
if (half_scale) {
dev_dbg(&client->dev, "max resolution: QCIF\n");
coma_set |= COMA_QCIF;
@@ -657,7 +651,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 
if (!ret) {
-   mf->colorspace  = priv->colorspace;
mf->width = priv->rect.width >> half_scale;
mf->height = priv->rect.height >> half_scale;
}
@@ -680,6 +673,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
&mf->height, 2, H_CIF, 1, 0);
 
mf->field = V4L2_FIELD_NONE;
+   mf->colorspace = V4L2_COLORSPACE_SRGB;
 
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
@@ -690,13 +684,11 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
case MEDIA_BUS_FMT_YUYV8_2X8:
case MEDIA_BUS_FMT_VYUY8_2X8:
case MEDIA_BUS_FMT_UYVY8_2X8:
-   mf->colorspace = V4L2_COLORSPACE_JPEG;
break;
default:
mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
/* fall through */
case MEDIA_BUS_FMT_SBGGR8_1X8:
-   mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
}
 
@@ -1004,7 +996,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.height = H_CIF;
priv->half_scale  = false;
priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
-   priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
 
-- 
2.21.0



[PATCH v3 5/9] media: ov6650: Fix some format attributes not under control

2019-09-03 Thread Janusz Krzysztofik
User arguments passed to .get/set_fmt() pad operation callbacks may
contain unsupported values.  The driver takes control over frame size
and pixel code as well as colorspace and field attributes but has never
cared for remainig format attributes, i.e., ycbcr_enc, quantization
and xfer_func, introduced by commit 11ff030c7365 ("[media]
v4l2-mediabus: improve colorspace support").  Fix it.

Set up a static v4l2_mbus_framefmt structure with attributes
initialized to reasonable defaults and use it for updating content of
user provided arguments.  In case of V4L2_SUBDEV_FORMAT_ACTIVE,
postpone frame size update, now performed from inside ov6650_s_fmt()
helper, util the user argument is first updated in ov6650_set_fmt() with
default frame format content.  For V4L2_SUBDEV_FORMAT_TRY, don't copy
all attributes to pad config, only those handled by the driver, then
fill the response with the default frame format updated with resulting
pad config format code and frame size.

Fixes: 11ff030c7365 ("[media] v4l2-mediabus: improve colorspace support")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 51 +-
 1 file changed, 39 insertions(+), 12 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index a7930ace3744..fd608aebb68d 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -212,6 +212,17 @@ static u32 ov6650_codes[] = {
MEDIA_BUS_FMT_Y8_1X8,
 };
 
+static const struct v4l2_mbus_framefmt ov6650_def_fmt = {
+   .width  = W_CIF,
+   .height = H_CIF,
+   .code   = MEDIA_BUS_FMT_SBGGR8_1X8,
+   .colorspace = V4L2_COLORSPACE_SRGB,
+   .field  = V4L2_FIELD_NONE,
+   .ycbcr_enc  = V4L2_YCBCR_ENC_DEFAULT,
+   .quantization   = V4L2_QUANTIZATION_DEFAULT,
+   .xfer_func  = V4L2_XFER_FUNC_DEFAULT,
+};
+
 /* read a register */
 static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
 {
@@ -510,11 +521,13 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
if (format->pad)
return -EINVAL;
 
+   /* initialize response with default media bus frame format */
+   *mf = ov6650_def_fmt;
+
+   /* update media bus format code and frame size */
mf->width   = priv->rect.width >> priv->half_scale;
mf->height  = priv->rect.height >> priv->half_scale;
mf->code= priv->code;
-   mf->colorspace  = V4L2_COLORSPACE_SRGB;
-   mf->field   = V4L2_FIELD_NONE;
 
return 0;
 }
@@ -650,10 +663,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
if (!ret)
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 
-   if (!ret) {
-   mf->width = priv->rect.width >> half_scale;
-   mf->height = priv->rect.height >> half_scale;
-   }
return ret;
 }
 
@@ -672,9 +681,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
&mf->height, 2, H_CIF, 1, 0);
 
-   mf->field = V4L2_FIELD_NONE;
-   mf->colorspace = V4L2_COLORSPACE_SRGB;
-
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
mf->code = MEDIA_BUS_FMT_Y8_1X8;
@@ -692,10 +698,31 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
break;
}
 
-   if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-   return ov6650_s_fmt(sd, mf);
-   cfg->try_fmt = *mf;
+   if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+   /* store media bus format code and frame size in pad config */
+   cfg->try_fmt.width = mf->width;
+   cfg->try_fmt.height = mf->height;
+   cfg->try_fmt.code = mf->code;
 
+   /* return default mbus frame format updated with pad config */
+   *mf = ov6650_def_fmt;
+   mf->width = cfg->try_fmt.width;
+   mf->height = cfg->try_fmt.height;
+   mf->code = cfg->try_fmt.code;
+
+   } else {
+   /* apply new media bus format code and frame size */
+   int ret = ov6650_s_fmt(sd, mf);
+
+   if (ret)
+   return ret;
+
+   /* return default format updated with active size and code */
+   *mf = ov6650_def_fmt;
+   mf->width = priv->rect.width >> priv->half_scale;
+   mf->height = priv->rect.height >> priv->half_scale;
+   mf->code = priv->code;
+   }
return 0;
 }
 
-- 
2.21.0



[PATCH v3 7/9] media: ov6650: Fix default format not applied on device probe

2019-09-03 Thread Janusz Krzysztofik
It is not clear what pixel format is actually configured in hardware on
reset.  MEDIA_BUS_FMT_YUYV8_2X8, assumed on device probe since the
driver was intiially submitted, is for sure not the one.

Fix it by explicitly applying a known, driver default frame format just
after initial device reset.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index b62a238a83d0..4fd8ac8e3994 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -873,6 +873,11 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
ret = ov6650_reset(client);
if (!ret)
ret = ov6650_prog_dflt(client);
+   if (!ret) {
+   struct v4l2_mbus_framefmt mf = ov6650_def_fmt;
+
+   ret = ov6650_s_fmt(sd, &mf);
+   }
if (!ret)
ret = v4l2_ctrl_handler_setup(&priv->hdl);
 
@@ -1027,8 +1032,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.top= DEF_VSTRT << 1;
priv->rect.width  = W_CIF;
priv->rect.height = H_CIF;
-   priv->half_scale  = false;
-   priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
 
-- 
2.21.0



[PATCH v3 0/9] media: ov6650: A collection of fixes

2019-09-03 Thread Janusz Krzysztofik
Janusz Krzysztofik (9):
  media: ov6650: Fix MODULE_DESCRIPTION
  media: ov6650: Fix control handler not freed on init error
  media: ov6650: Fix crop rectangle alignment not passed back
  media: ov6650: Fix incorrect use of JPEG colorspace
  media: ov6650: Fix some format attributes not under control
  media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support
  media: ov6650: Fix default format not applied on device probe
  media: ov6650: Fix stored frame format not in sync with hardware
  media: ov6650: Fix stored crop rectangle not in sync with hardware

 drivers/media/i2c/ov6650.c | 137 +++--
 1 file changed, 86 insertions(+), 51 deletions(-)

v2: dropped patches 3/14 through 7/14 which were adding parameter checks
now called from v4l2_subdev_call() - inspired by Sakari's request, 
thanks!
v3: * drop Cc: sta...@vger.kernel.org on Greg rquest (non-critical fixes)
* fix typos and some wording in commit messages
* rebase on media/v5.3-3
-- 
2.21.0



[PATCH v3 1/9] media: ov6650: Fix MODULE_DESCRIPTION

2019-09-03 Thread Janusz Krzysztofik
Commit 23a52386fabe ("media: ov6650: convert to standalone v4l2
subdevice") converted the driver from a soc_camera sensor to a
standalone V4L subdevice driver.  Unfortunately, module description was
not updated to reflect the change.  Fix it.

While being at it, update email address of the module author.

Fixes: 23a52386fabe ("media: ov6650: convert to standalone v4l2 subdevice")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 5b9af5e5b7f1..53550cae2353 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -1041,6 +1041,6 @@ static struct i2c_driver ov6650_i2c_driver = {
 
 module_i2c_driver(ov6650_i2c_driver);
 
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
-MODULE_AUTHOR("Janusz Krzysztofik ");
+MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera 
sensor");
+MODULE_AUTHOR("Janusz Krzysztofik 

[PATCH v3 9/9] media: ov6650: Fix stored crop rectangle not in sync with hardware

2019-09-03 Thread Janusz Krzysztofik
The driver stores crop rectangle settings supposed to be in line with
hardware state in a device private structure.  Since the driver initial
submission, crop rectangle width and height settings are not updated
correctly when rectangle offset settings are applied on hardware.  If
an error occurs while the device is updated, the stored settings my no
longer reflect hardware state and consecutive calls to .get_selection()
as well as .get/set_fmt() may return incorrect information.  That in
turn may affect ability of a bridge device to use correct DMA transfer
settings if such incorrect informamtion on active frame format returned
by .get/set_fmt() is used.

Assuming a failed update of the device means its actual settings haven't
changed, update crop rectangle width and height settings stored in the
device private structure correctly while the rectangle offset is
successfully applied on hardware so the stored values always reflect
actual hardware state to the extent possible.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 126a662be301..16887049f0cd 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -491,6 +491,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
 
ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
if (!ret) {
+   priv->rect.width += priv->rect.left - sel->r.left;
priv->rect.left = sel->r.left;
ret = ov6650_reg_write(client, REG_HSTOP,
   (sel->r.left + sel->r.width) >> 1);
@@ -500,6 +501,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
}
if (!ret) {
+   priv->rect.height += priv->rect.top - sel->r.top;
priv->rect.top = sel->r.top;
ret = ov6650_reg_write(client, REG_VSTOP,
   (sel->r.top + sel->r.height) >> 1);
-- 
2.21.0



Re: [RFC PATCH] iommu/vt-d: Fix IOMMU field not populated on device hot re-plug

2019-09-03 Thread Janusz Krzysztofik
Hi Baolu,

On Tuesday, September 3, 2019 3:29:40 AM CEST Lu Baolu wrote:
> Hi Janusz,
> 
> On 9/2/19 4:37 PM, Janusz Krzysztofik wrote:
> >> I am not saying that keeping data is not acceptable. I just want to
> >> check whether there are any other solutions.
> > Then reverting 458b7c8e0dde and applying this patch still resolves the 
issue
> > for me.  No errors appear when mappings are unmapped on device close after 
the
> > device has been removed, and domain info preserved on device removal is
> > successfully reused on device re-plug.
> 
> This patch doesn't look good to me although I agree that keeping data is
> acceptable. It updates dev->archdata.iommu, but leaves the hardware
> context/pasid table unchanged. This might cause problems somewhere.
> 
> > 
> > Is there anything else I can do to help?
> 
> Can you please tell me how to reproduce the problem? 

The most simple way to reproduce the issue, assuming there are no non-Intel 
graphics adapters installed, is to run the following shell commands:

#!/bin/sh
# load i915 module
modprobe i915
# open an i915 device and keep it open in background
cat /dev/dri/card0 >/dev/null &
sleep 2
# simulate device unplug
echo 1 >/sys/class/drm/card0/device/remove
# make the background process close the device on exit
kill $!

Thanks,
Janusz


> Keeping the per
> device domain info while device is unplugged is a bit dangerous because
> info->dev might be a wild pointer. We need to work out a clean fix.
> 
> > 
> > Thanks,
> > Janusz
> > 
> 
> Best regards,
> Baolu
> 






[RFC PATCH] iommu/vt-d: Fix IOMMU field not populated on device hot re-plug

2019-08-22 Thread Janusz Krzysztofik
When a perfectly working i915 device is hot unplugged (via sysfs) and
hot re-plugged again, its dev->archdata.iommu field is not populated
again with an IOMMU pointer.  As a result, the device probe fails on
DMA mapping error during scratch page setup.

It looks like that happens because devices are not detached from their
MMUIO bus before they are removed on device unplug.  Then, when an
already registered device/IOMMU association is identified by the
reinstantiated device's bus and function IDs on IOMMU bus re-attach
attempt, the device's archdata is not populated with IOMMU information
and the bad happens.

I'm not sure if this is a proper fix but it works for me so at least it
confirms correctness of my analysis results, I believe.  So far I
haven't been able to identify a good place where the possibly missing
IOMMU bus detach on device unplug operation could be added.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/iommu/intel-iommu.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 12d094d08c0a..7cdcd0595408 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2477,6 +2477,9 @@ static struct dmar_domain 
*dmar_insert_one_dev_info(struct intel_iommu *iommu,
if (info2) {
found  = info2->domain;
info2->dev = dev;
+
+   if (dev && !dev->archdata.iommu)
+   dev->archdata.iommu = info2;
}
}
 
-- 
2.21.0



[PATCH for v5.3] ARM: OMAP1: ams-delta-fiq: Fix missing irq_ack

2019-08-11 Thread Janusz Krzysztofik
Non-serio path of Amstrad Delta FIQ deferred handler depended on
irq_ack() method provided by OMAP GPIO driver.  That method has been
removed by commit 693de831c6e5 ("gpio: omap: remove irq_ack method").
Remove useless code from the deferred handler and reimplement the
missing operation inside the base FIQ handler.

Should another dependency - irq_unmask() - be ever removed from the OMAP
GPIO driver, WARN once if missing.

Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/ams-delta-fiq-handler.S | 3 ++-
 arch/arm/mach-omap1/ams-delta-fiq.c | 4 +---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S 
b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index 81159af44862..14a6c3eb3298 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -126,6 +126,8 @@ restart:
orr r11, r11, r13   @ mask all requested interrupts
str r11, [r12, #OMAP1510_GPIO_INT_MASK]
 
+   str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts
+
ands r10, r13, #KEYBRD_CLK_MASK @ extract keyboard status - set?
beq hksw@ no - try next source
 
@@ -133,7 +135,6 @@ restart:
@@
@ Keyboard clock FIQ mode interrupt handler
@ r10 now contains KEYBRD_CLK_MASK, use it
-   str r10, [r12, #OMAP1510_GPIO_INT_STATUS]   @ ack the interrupt
bic r11, r11, r10   @ unmask it
str r11, [r12, #OMAP1510_GPIO_INT_MASK]
 
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c 
b/arch/arm/mach-omap1/ams-delta-fiq.c
index 43899fa56674..0254eb9cf8c6 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -70,9 +70,7 @@ static irqreturn_t deferred_fiq(int irq, void *dev_id)
 * interrupts default to since commit 80ac93c27441
 * requires interrupt already acked and unmasked.
 */
-   if (irq_chip->irq_ack)
-   irq_chip->irq_ack(d);
-   if (irq_chip->irq_unmask)
+   if (!WARN_ON_ONCE(!irq_chip->irq_unmask))
irq_chip->irq_unmask(d);
}
for (; irq_counter[gpio] < fiq_count; irq_counter[gpio]++)
-- 
2.21.0



[RFC PATCH 3/6] drm/i915: Propagate "_release" function name suffix down

2019-07-10 Thread Janusz Krzysztofik
Replace mixed "_fini"/"_cleanup"/"_cleanup_hw" suffixes found in names
of fucntions called from i915_driver_release() with "_release" suffix
consistently.  This provides better code readability, especially
helpful when trying to work out which phase the code is in.

Functions names starting with "i915_driver_", i.e., those defined in
drivers/gpu/dri/i915/i915_drv.c, just have their "cleanup" or "fini"
parts of their names replaced with the "_release" suffix, while names
of functions coming from other source files have been suffixed with
"_driver_release" to avoid ambiguity with other possible .release entry
points.

Suggested-by: Chris Wilson 
Signed-off-by: Janusz Krzysztofik 
---
 drivers/gpu/drm/i915/i915_drv.c | 33 +
 drivers/gpu/drm/i915/i915_drv.h |  2 +-
 drivers/gpu/drm/i915/i915_gem.c |  2 +-
 drivers/gpu/drm/i915/i915_gem_gtt.c |  4 +--
 drivers/gpu/drm/i915/i915_gem_gtt.h |  2 +-
 drivers/gpu/drm/i915/intel_runtime_pm.c |  2 +-
 drivers/gpu/drm/i915/intel_runtime_pm.h |  2 +-
 7 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index ad24957ad86d..36c872220f68 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -752,7 +752,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 cleanup_gem:
i915_gem_suspend(dev_priv);
i915_gem_fini_hw(dev_priv);
-   i915_gem_fini(dev_priv);
+   i915_gem_driver_release(dev_priv);
 cleanup_modeset:
intel_modeset_cleanup(dev);
 cleanup_irq:
@@ -962,10 +962,11 @@ static int i915_driver_init_early(struct drm_i915_private 
*dev_priv)
 }
 
 /**
- * i915_driver_cleanup_early - cleanup the setup done in 
i915_driver_init_early()
+ * i915_driver_early_release - cleanup the setup done in
+ *i915_driver_init_early()
  * @dev_priv: device private
  */
-static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv)
+static void i915_driver_early_release(struct drm_i915_private *dev_priv)
 {
intel_irq_fini(dev_priv);
intel_power_domains_cleanup(dev_priv);
@@ -1028,10 +1029,10 @@ static int i915_driver_init_mmio(struct 
drm_i915_private *dev_priv)
 }
 
 /**
- * i915_driver_cleanup_mmio - cleanup the setup done in i915_driver_init_mmio()
+ * i915_driver_mmio_release - cleanup the setup done in i915_driver_init_mmio()
  * @dev_priv: device private
  */
-static void i915_driver_cleanup_mmio(struct drm_i915_private *dev_priv)
+static void i915_driver_mmio_release(struct drm_i915_private *dev_priv)
 {
intel_teardown_mchbar(dev_priv);
intel_uncore_fini_mmio(&dev_priv->uncore);
@@ -1684,7 +1685,7 @@ static int i915_driver_init_hw(struct drm_i915_private 
*dev_priv)
pci_disable_msi(pdev);
pm_qos_remove_request(&dev_priv->pm_qos);
 err_ggtt:
-   i915_ggtt_cleanup_hw(dev_priv);
+   i915_ggtt_driver_release(dev_priv);
 err_perf:
i915_perf_fini(dev_priv);
return ret;
@@ -1929,15 +1930,15 @@ int i915_driver_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
 
 out_cleanup_hw:
i915_driver_cleanup_hw(dev_priv);
-   i915_ggtt_cleanup_hw(dev_priv);
+   i915_ggtt_driver_release(dev_priv);
 
/* Paranoia: make sure we have disabled everything before we exit. */
intel_sanitize_gt_powersave(dev_priv);
 out_cleanup_mmio:
-   i915_driver_cleanup_mmio(dev_priv);
+   i915_driver_mmio_release(dev_priv);
 out_runtime_pm_put:
enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
-   i915_driver_cleanup_early(dev_priv);
+   i915_driver_early_release(dev_priv);
 out_pci_disable:
pci_disable_device(pdev);
 out_fini:
@@ -2000,19 +2001,19 @@ static void i915_driver_release(struct drm_device *dev)
 
disable_rpm_wakeref_asserts(rpm);
 
-   i915_gem_fini(dev_priv);
+   i915_gem_driver_release(dev_priv);
 
-   i915_ggtt_cleanup_hw(dev_priv);
+   i915_ggtt_driver_release(dev_priv);
 
/* Paranoia: make sure we have disabled everything before we exit. */
intel_sanitize_gt_powersave(dev_priv);
 
-   i915_driver_cleanup_mmio(dev_priv);
+   i915_driver_mmio_release(dev_priv);
 
enable_rpm_wakeref_asserts(rpm);
-   intel_runtime_pm_cleanup(rpm);
+   intel_runtime_pm_driver_release(rpm);
 
-   i915_driver_cleanup_early(dev_priv);
+   i915_driver_early_release(dev_priv);
i915_driver_destroy(dev_priv);
 }
 
@@ -2205,7 +2206,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, 
bool hibernation)
 out:
enable_rpm_wakeref_asserts(rpm);
if (!dev_priv->uncore.user_forcewake.count)
-   intel_runtime_pm_cleanup(rpm);
+   intel_runtime_pm_driver_release(rpm);
 
return ret;
 }
@@ -2969,7 +

[RFC PATCH 5/6] drm/i915: Propagate "_probe" function name suffix down

2019-07-10 Thread Janusz Krzysztofik
Similar to the "_release" and "_remove" cases, consequently replace
"_init" components of names of functions called from
i915_driver_probe() with "_probe" suffixes for better code readability.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/gpu/drm/i915/i915_drv.c | 26 +-
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 6e83fe96d930..7241a7d14e9b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -675,7 +675,7 @@ static const struct vga_switcheroo_client_ops 
i915_switcheroo_ops = {
.can_switch = i915_switcheroo_can_switch,
 };
 
-static int i915_load_modeset_init(struct drm_device *dev)
+static int i915_driver_modeset_probe(struct drm_device *dev)
 {
struct drm_i915_private *dev_priv = to_i915(dev);
struct pci_dev *pdev = dev_priv->drm.pdev;
@@ -884,7 +884,7 @@ static void intel_detect_preproduction_hw(struct 
drm_i915_private *dev_priv)
 }
 
 /**
- * i915_driver_init_early - setup state not requiring device access
+ * i915_driver_early_probe - setup state not requiring device access
  * @dev_priv: device private
  *
  * Initialize everything that is a "SW-only" state, that is state not
@@ -893,7 +893,7 @@ static void intel_detect_preproduction_hw(struct 
drm_i915_private *dev_priv)
  * system memory allocation, setting up device specific attributes and
  * function hooks not requiring accessing the device.
  */
-static int i915_driver_init_early(struct drm_i915_private *dev_priv)
+static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
 {
int ret = 0;
 
@@ -963,7 +963,7 @@ static int i915_driver_init_early(struct drm_i915_private 
*dev_priv)
 
 /**
  * i915_driver_early_release - cleanup the setup done in
- *i915_driver_init_early()
+ *i915_driver_early_probe()
  * @dev_priv: device private
  */
 static void i915_driver_early_release(struct drm_i915_private *dev_priv)
@@ -980,7 +980,7 @@ static void i915_driver_early_release(struct 
drm_i915_private *dev_priv)
 }
 
 /**
- * i915_driver_init_mmio - setup device MMIO
+ * i915_driver_mmio_probe - setup device MMIO
  * @dev_priv: device private
  *
  * Setup minimal device state necessary for MMIO accesses later in the
@@ -988,7 +988,7 @@ static void i915_driver_early_release(struct 
drm_i915_private *dev_priv)
  * side effects or exposing the driver via kernel internal or user space
  * interfaces.
  */
-static int i915_driver_init_mmio(struct drm_i915_private *dev_priv)
+static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
 {
int ret;
 
@@ -1029,7 +1029,7 @@ static int i915_driver_init_mmio(struct drm_i915_private 
*dev_priv)
 }
 
 /**
- * i915_driver_mmio_release - cleanup the setup done in i915_driver_init_mmio()
+ * i915_driver_mmio_release - cleanup the setup done in 
i915_driver_mmio_probe()
  * @dev_priv: device private
  */
 static void i915_driver_mmio_release(struct drm_i915_private *dev_priv)
@@ -1525,13 +1525,13 @@ static void edram_detect(struct drm_i915_private 
*dev_priv)
 }
 
 /**
- * i915_driver_init_hw - setup state requiring device access
+ * i915_driver_hw_probe - setup state requiring device access
  * @dev_priv: device private
  *
  * Setup state that requires accessing the device, but doesn't require
  * exposing the driver via kernel internal or userspace interfaces.
  */
-static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
+static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
 {
struct pci_dev *pdev = dev_priv->drm.pdev;
int ret;
@@ -1900,7 +1900,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
if (ret)
goto out_fini;
 
-   ret = i915_driver_init_early(dev_priv);
+   ret = i915_driver_early_probe(dev_priv);
if (ret < 0)
goto out_pci_disable;
 
@@ -1908,15 +1908,15 @@ int i915_driver_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
 
i915_detect_vgpu(dev_priv);
 
-   ret = i915_driver_init_mmio(dev_priv);
+   ret = i915_driver_mmio_probe(dev_priv);
if (ret < 0)
goto out_runtime_pm_put;
 
-   ret = i915_driver_init_hw(dev_priv);
+   ret = i915_driver_hw_probe(dev_priv);
if (ret < 0)
goto out_cleanup_mmio;
 
-   ret = i915_load_modeset_init(&dev_priv->drm);
+   ret = i915_driver_modeset_probe(&dev_priv->drm);
if (ret < 0)
goto out_cleanup_hw;
 
-- 
2.21.0



[PATCH] media: ov6650: Fix device node exposed without proper locking

2019-06-02 Thread Janusz Krzysztofik
Commit c62b96050bee ("media: ov6650: Register with asynchronous
subdevice framework") carelessly requested creation of a video device
node by setting a V4L2_SUBDEV_FL_HAS_DEVNODE flag.  The driver is not
ready for that as it doesn't implement proper locking required for
serialization of IOCTLs.

Fix it by dropping the flag assignment.

Fixes: c62b96050bee ("media: ov6650: Register with asynchronous subdevice 
framework")
Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 1b972e591b48..ace95ba7dd19 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -1009,7 +1009,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
-   priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
ret = v4l2_async_register_subdev(&priv->subdev);
if (ret)
-- 
2.21.0



[PATCH] ASoC: ti: Fix SDMA users not providing channel names

2019-06-02 Thread Janusz Krzysztofik
McBSP used to work correctly as long as compat DMA probing, removed by
commit 642aafea8889 ("ASoC: ti: remove compat dma probing"), was
available.  New method of DMA probing apparently requires users to
provide channel names when registering with SDMA, while McBSP passes
NULLs.  Fix it.

The same probably applies to McASP (not tested), hence the patch fixes
both.

Fixes: 642aafea8889 ("ASoC: ti: remove compat dma probing")
Signed-off-by: Janusz Krzysztofik 
---
 sound/soc/ti/davinci-mcasp.c | 2 +-
 sound/soc/ti/omap-mcbsp.c| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 9fbc759fdefe..f31805920e3e 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -2237,7 +2237,7 @@ static int davinci_mcasp_probe(struct platform_device 
*pdev)
ret = edma_pcm_platform_register(&pdev->dev);
break;
case PCM_SDMA:
-   ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+   ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
break;
default:
dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index a395598f1f20..610c5e706fd2 100644
--- a/sound/soc/ti/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -1438,7 +1438,7 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
if (ret)
return ret;
 
-   return sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
+   return sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
 }
 
 static int asoc_mcbsp_remove(struct platform_device *pdev)
-- 
2.21.0



Re: [RFC PATCH 4/5] media: ov6650: Fix frame scaling not reset on crop

2019-06-02 Thread Janusz Krzysztofik
Hi Sakari,

On Sunday, June 2, 2019 12:37:55 AM CEST Sakari Ailus wrote:
> 
> ... I realised that the subtle effect of "media:
> ov6650: Register with asynchronous subdevice framework" is that the driver
> is now responsible for serialising the access to its own data structures
> now. 

Indeed, I must have been not thinking much while preparing it, only following 
patterns from other implementations blindly, sorry.

> And it doesn't do that. Could you submit a fix, please? It'd be good to
> get that to 5.2 through the fixes branch.

How about dropping that V4L2_SUBDEV_FL_HAS_DEVNODE flag for now?  I think that 
will be the most safe approach for a quick fix.  I'd then re-add it together 
with proper locking in a separate patch later.  What do yo think?

Thanks,
Janusz




Re: [RFC PATCH 4/5] media: ov6650: Fix frame scaling not reset on crop

2019-05-31 Thread Janusz Krzysztofik
Hi Sakari,

On Friday, May 31, 2019 1:42:58 PM CEST Sakari Ailus wrote:
> Hi Janusz,
> 
> On Sun, May 26, 2019 at 10:47:57PM +0200, Janusz Krzysztofik wrote:
> > According to V4L2 subdevice interface specification, frame scaling
> > factors should be reset to default values on modification of input frame
> > format.  Assuming that requirement also applies in case of crop
> > rectangle modification unless V4L2_SEL_FLAG_KEEP_CONFIG is requested,
> > the driver now does not respect it.
> > 
> > The KEEP_CONFIG case is already implemented, fix the other path.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> >  drivers/media/i2c/ov6650.c | 8 
> >  1 file changed, 8 insertions(+)
> > 
> > diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
> > index 47590cd51190..cc70d8952999 100644
> > --- a/drivers/media/i2c/ov6650.c
> > +++ b/drivers/media/i2c/ov6650.c
> > @@ -472,6 +472,8 @@ static int ov6650_get_selection(struct v4l2_subdev 
*sd,
> > }
> >  }
> >  
> > +static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool 
half_scale);
> > +
> 
> Would it be possible to rearrange the functions in the file so you wouldn't
> need extra prototypes? Preferrably that'd be a new patch.

Sure. I've intentionally done it like that for better readability of the 
patches, but I have a task in my queue for rearrangement of functions order as 
soon as other modifications are in place.

> >  static int ov6650_set_selection(struct v4l2_subdev *sd,
> > struct v4l2_subdev_pad_config *cfg,
> > struct v4l2_subdev_selection *sel)
> > @@ -515,7 +517,13 @@ static int ov6650_set_selection(struct v4l2_subdev 
*sd,
> > }
> > if (!ret)
> > priv->rect.height = sel->r.height;
> > +   else
> > +   return ret;
> 
> if (ret)
>   return ret;

OK

Perhaps you will have more comments on other patches so I'll wait a bit and 
then resubmit the series as v2.

Thanks,
Janusz

> ...
> 
> >  
> > +   if (priv->half_scale) {
> > +   /* turn off half scaling, preserve media bus format */
> > +   ret = ov6650_s_fmt(sd, priv->code, false);
> > +   }
> > return ret;
> >  }
> >  
> 
> 






[RFC PATCH 4/5] media: ov6650: Fix frame scaling not reset on crop

2019-05-26 Thread Janusz Krzysztofik
According to V4L2 subdevice interface specification, frame scaling
factors should be reset to default values on modification of input frame
format.  Assuming that requirement also applies in case of crop
rectangle modification unless V4L2_SEL_FLAG_KEEP_CONFIG is requested,
the driver now does not respect it.

The KEEP_CONFIG case is already implemented, fix the other path.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 47590cd51190..cc70d8952999 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -472,6 +472,8 @@ static int ov6650_get_selection(struct v4l2_subdev *sd,
}
 }
 
+static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool half_scale);
+
 static int ov6650_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
@@ -515,7 +517,13 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
}
if (!ret)
priv->rect.height = sel->r.height;
+   else
+   return ret;
 
+   if (priv->half_scale) {
+   /* turn off half scaling, preserve media bus format */
+   ret = ov6650_s_fmt(sd, priv->code, false);
+   }
return ret;
 }
 
-- 
2.21.0



[RFC PATCH 1/5] media: ov6650: Fix V4L2_SEL_FLAG_KEEP_CONFIG handling

2019-05-26 Thread Janusz Krzysztofik
This flag is now ignored - output frame size is affected by new crop
settings regardless of the flag value.  Fix it.

Since keeping output frame size untouched while applying new crop
settings is not supported, simply return results of .get_selection() if
V4L2_SEL_FLAG_KEEP_CONFIG is passed to .set_selection().

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index c728f718716b..1b02479b616f 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -484,6 +484,10 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
 
+   /* No support for changing crop rectangle with frame size preserved */
+   if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG)
+   return ov6650_get_selection(sd, cfg, sel);
+
v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1,
  &sel->r.height, 2, H_CIF, 1, 0);
v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1,
-- 
2.21.0



[RFC PATCH 2/5] media: ov6650: Refactor ov6650_s_fmt() helper

2019-05-26 Thread Janusz Krzysztofik
The driver suffers from a few compliance and implementation issues:
- crop rectangle is affected by .set_fmt() pad operation callback,
- frame scaling is not reset on modification of crop rectangle,
- V4L2_SUBDEV_FORMAT_TRY support in .set_fmt() uses active crop
  rectangle, not the one from a pad config, as a reference.

For easy resolution of those issues, ov6650_s_fmt() will first be
refactored.

The ov6650_s_fmt() helper function, mostly called form .set_fmt() pad
operation callback, now takes a decision if half scaling is applicable
for current crop rectangle and requested frame size, then possibly
adjusts hardware crop settings, frame scaling and media bus frame
format.  It accepts a struct v4l2_mbus_framefmt argument passed by a
user to .set_fmt().

Move the decision on applicability of half scaling up to .set_fmt(),
then modify the ov6650_s_fmt() API so it accepts a half scaling flag.
In order to avoid passing full struct v4l2_mbus_framefmt argument to it
when called from functions other than .set_fmt(), also accept a target
pixel code as an argument and make the struct v4l2_mbus_framefmt used
for crop rectangle modification optional.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 38 --
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 1b02479b616f..8cb30f3e4851 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -570,25 +570,18 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe,
 }
 
 /* set the format we will capture in */
-static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf,
+   u32 code, bool half_scale)
 {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
-   bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
struct v4l2_subdev_selection sel = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
.target = V4L2_SEL_TGT_CROP,
-   .r.left = priv->rect.left + (priv->rect.width >> 1) -
-   (mf->width >> (1 - half_scale)),
-   .r.top = priv->rect.top + (priv->rect.height >> 1) -
-   (mf->height >> (1 - half_scale)),
-   .r.width = mf->width << half_scale,
-   .r.height = mf->height << half_scale,
};
-   u32 code = mf->code;
unsigned long mclk, pclk;
u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
-   int ret;
+   int ret = 0;
 
/* select color matrix configuration for given color encoding */
switch (code) {
@@ -668,7 +661,16 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
mclk / pclk, 10 * mclk % pclk / pclk);
 
-   ret = ov6650_set_selection(sd, NULL, &sel);
+   if (mf) {
+   sel.r.left = priv->rect.left + (priv->rect.width >> 1) -
+   (mf->width >> (1 - half_scale)),
+   sel.r.top = priv->rect.top + (priv->rect.height >> 1) -
+   (mf->height >> (1 - half_scale)),
+   sel.r.width = mf->width << half_scale,
+   sel.r.height = mf->height << half_scale,
+
+   ret = ov6650_set_selection(sd, NULL, &sel);
+   }
if (!ret)
ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
if (!ret)
@@ -691,11 +693,14 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf = &format->format;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
+   bool half_scale;
 
if (format->pad)
return -EINVAL;
 
-   if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
+   half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
+
+   if (!half_scale)
v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
&mf->height, 2, H_CIF, 1, 0);
 
@@ -730,7 +735,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
 
} else {
/* apply new media bus format code and frame size */
-   int ret = ov6650_s_fmt(sd, mf);
+   int ret = ov6650_s_fmt(sd, mf, mf->code, half_scale);
 
if (ret)
return ret;
@@ -885,11 +890,8 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
ret = ov6650_reset(client);
if (!ret)
ret = ov6650_prog_d

[RFC PATCH 5/5] media: ov6650: Add .init_cfg() pad operation callback

2019-05-26 Thread Janusz Krzysztofik
The driver now supports V4L2_SUBDEV_FORMAT_TRY operation mode only in
.get/set_fmt() pad operation callbacks.  That means only .try_format
member of pad config is maintained.  As a consequence, active crop
rectangle is used as a referece while V4L2_SUBDEV_FORMAT_TRY requests
are processed.  In order to fix that, a method for initialization of
.try_crop pad config member is needed.

Implement .init_cfg() pad operation callback which initializes the pad
config from current active format and selection settings.  From now on,
and before the driver V4L2_SUBDEV_FORMAT_TRY support is further
modified, host interface drivers should call .init_cfg() on a pad
config before passing it to V4L2_SUBDEV_FORMAT_TRY operations.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index cc70d8952999..c3d4c1f598b2 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -447,6 +447,26 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on)
return ret;
 }
 
+static int ov6650_init_cfg(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg)
+{
+   struct i2c_client *client = v4l2_get_subdevdata(sd);
+   struct ov6650 *priv = to_ov6650(client);
+   struct v4l2_mbus_framefmt *mf;
+   struct v4l2_rect *rect;
+
+   mf = &cfg->try_fmt;
+   *mf = ov6650_def_fmt;
+   mf->width = priv->rect.width >> priv->half_scale;
+   mf->height = priv->rect.height >> priv->half_scale;
+   mf->code = priv->code;
+
+   rect = &cfg->try_crop;
+   *rect = priv->rect;
+
+   return 0;
+}
+
 static int ov6650_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
@@ -959,6 +979,7 @@ static const struct v4l2_subdev_video_ops ov6650_video_ops 
= {
 };
 
 static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
+   .init_cfg   = ov6650_init_cfg,
.enum_mbus_code = ov6650_enum_mbus_code,
.get_selection  = ov6650_get_selection,
.set_selection  = ov6650_set_selection,
-- 
2.21.0



[RFC PATCH 3/5] media: ov6650: Fix active crop rectangle affected by .set_fmt()

2019-05-26 Thread Janusz Krzysztofik
According to subdevice interface specification found in V4L2 API
documentation, .set_fmt() pad operation callback should not affect
image geometry set in preceding image processing steps. Unfortunately,
ov6650_s_fmt() helper, when called from .set_fmt() with new user
requested frame size passed to it, does not respect that requirement
as that was not the case before, when the helper was still called from
.mbus_set_fmt() video operation callback.

Remmove a call to .set_selection() from ov6650_s_fmt() helper so it no
longer modifies the active crop rectangle and simplify its API by
removing no longer needed struct v4l2_mbus_framefmt argument.  For
consistency of its results with active format processing, also update
try format path inside .set_fmt() (still using active crop rectangle as
a reference instead of the try one from pad config which is not yet
maintained by the driver).

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 32 ++--
 1 file changed, 6 insertions(+), 26 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 8cb30f3e4851..47590cd51190 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -570,15 +570,10 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe,
 }
 
 /* set the format we will capture in */
-static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf,
-   u32 code, bool half_scale)
+static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool half_scale)
 {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
-   struct v4l2_subdev_selection sel = {
-   .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-   .target = V4L2_SEL_TGT_CROP,
-   };
unsigned long mclk, pclk;
u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
int ret = 0;
@@ -661,18 +656,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf,
dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
mclk / pclk, 10 * mclk % pclk / pclk);
 
-   if (mf) {
-   sel.r.left = priv->rect.left + (priv->rect.width >> 1) -
-   (mf->width >> (1 - half_scale)),
-   sel.r.top = priv->rect.top + (priv->rect.height >> 1) -
-   (mf->height >> (1 - half_scale)),
-   sel.r.width = mf->width << half_scale,
-   sel.r.height = mf->height << half_scale,
-
-   ret = ov6650_set_selection(sd, NULL, &sel);
-   }
-   if (!ret)
-   ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
+   ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
if (!ret)
ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
if (!ret) {
@@ -700,10 +684,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
 
half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
 
-   if (!half_scale)
-   v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
-   &mf->height, 2, H_CIF, 1, 0);
-
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
mf->code = MEDIA_BUS_FMT_Y8_1X8;
@@ -723,8 +703,8 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
 
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
/* store media bus format code and frame size in pad config */
-   cfg->try_fmt.width = mf->width;
-   cfg->try_fmt.height = mf->height;
+   cfg->try_fmt.width = priv->rect.width >> half_scale;
+   cfg->try_fmt.height = priv->rect.height >> half_scale;
cfg->try_fmt.code = mf->code;
 
/* return default mbus frame format updated with pad config */
@@ -735,7 +715,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
 
} else {
/* apply new media bus format code and frame size */
-   int ret = ov6650_s_fmt(sd, mf, mf->code, half_scale);
+   int ret = ov6650_s_fmt(sd, mf->code, half_scale);
 
if (ret)
return ret;
@@ -891,7 +871,7 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
if (!ret)
ret = ov6650_prog_dflt(client);
if (!ret)
-   ret = ov6650_s_fmt(sd, NULL, ov6650_def_fmt.code, false);
+   ret = ov6650_s_fmt(sd, ov6650_def_fmt.code, false);
if (!ret)
ret = v4l2_ctrl_handler_setup(&priv->hdl);
 
-- 
2.21.0



[RFC PATCH 0/5] media: ov6650: V4L2 subdev compliance fixes

2019-05-26 Thread Janusz Krzysztofik
An attepmt to make the driver more compliant with V4L2 subdevice
interface specification.

Non-compliant frame half scaling is kept in .set_fmt() until composing
is implemented.

Janusz Krzysztofik (5):
  media: ov6650: Fix V4L2_SEL_FLAG_KEEP_CONFIG handling
  media: ov6650: Refactor ov6650_s_fmt() helper
  media: ov6650: Fix active crop rectangle affected by .set_fmt()
  media: ov6650: Fix frame scaling not reset on crop
  media: ov6650: Add .init_cfg() pad operation callback

 drivers/media/i2c/ov6650.c | 71 +++---
 1 file changed, 43 insertions(+), 28 deletions(-)

-- 
2.21.0



Re: [PATCH v2 1/9] media: ov6650: Fix MODDULE_DESCRIPTION

2019-05-21 Thread Janusz Krzysztofik
On Tuesday, May 21, 2019 7:15:37 AM CEST Greg KH wrote:
> On Tue, May 21, 2019 at 12:49:59AM +0200, Janusz Krzysztofik wrote:
> > Commit 23a52386fabe ("media: ov6650: convert to standalone v4l2
> > subdevice") converted the driver from a soc_camera sensor to a
> > standalone V4L subdevice driver.  Unfortunately, module description was
> > not updated to reflect the change.  Fix it.
> > 
> > While being at it, update email address of the module author.
> > 
> > Fixes: 23a52386fabe ("media: ov6650: convert to standalone v4l2 subdevice")
> > Signed-off-by: Janusz Krzysztofik 
> > cc: sta...@vger.kernel.org
> > ---
> >  drivers/media/i2c/ov6650.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
> > index 1b972e591b48..a3d00afcb0c8 100644
> > --- a/drivers/media/i2c/ov6650.c
> > +++ b/drivers/media/i2c/ov6650.c
> > @@ -1045,6 +1045,6 @@ static struct i2c_driver ov6650_i2c_driver = {
> >  
> >  module_i2c_driver(ov6650_i2c_driver);
> >  
> > -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
> > -MODULE_AUTHOR("Janusz Krzysztofik ");
> > +MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera 
> > sensor");
> > +MODULE_AUTHOR("Janusz Krzysztofik  >  MODULE_LICENSE("GPL v2");
> 
> is this _really_ a patch that meets the stable kernel requirements?
> Same for this whole series...

Hi Greg,

My bad, I'm sorry.  Please ignore the whole series, and I'll be more careful
in the future.

Thanks,
Janusz

> 
> thanks,
> 
> greg k-h
> 






[PATCH v2 6/9] media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support

2019-05-20 Thread Janusz Krzysztofik
Commit da298c6d98d5 ("[media] v4l2: replace video op g_mbus_fmt by pad
op get_fmt") converted a former ov6650_g_fmt() video operation callback
to an ov6650_get_fmt() pad operation callback.  However, the converted
function disregards a format->which flag that pad operations should
obey and always returns active frame format settings.

That can be fixed by always responding to V4L2_SUBDEV_FORMAT_TRY with
-EINVAL, or providing the response from a pad config argument, likely
updated by a former user call to V4L2_SUBDEV_FORMAT_TRY .set_fmt().
Since implementation of the latter is trivial, go for it.

Fixes: da298c6d98d5 ("[media] v4l2: replace video op g_mbus_fmt by pad op 
get_fmt")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 731b03bef7a5..1915a43bff87 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -528,10 +528,16 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
*mf = ov6650_def_fmt;
 
/* update media bus format code and frame size */
-   mf->width   = priv->rect.width >> priv->half_scale;
-   mf->height  = priv->rect.height >> priv->half_scale;
-   mf->code= priv->code;
+   if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+   mf->width = cfg->try_fmt.width;
+   mf->height = cfg->try_fmt.height;
+   mf->code = cfg->try_fmt.code;
 
+   } else {
+   mf->width = priv->rect.width >> priv->half_scale;
+   mf->height = priv->rect.height >> priv->half_scale;
+   mf->code = priv->code;
+   }
return 0;
 }
 
-- 
2.21.0



[PATCH v2 2/9] media: ov6650: Fix control handler not freed on init error

2019-05-20 Thread Janusz Krzysztofik
Since commit afd9690c72c3 ("[media] ov6650: convert to the control
framework"), if an error occurs during initialization of a control
handler, resources possibly allocated to the handler are not freed
before device initialiaton is aborted.  Fix it.

Fixes: afd9690c72c3 ("[media] ov6650: convert to the control framework")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index a3d00afcb0c8..007f0ca24913 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -992,8 +992,10 @@ static int ov6650_probe(struct i2c_client *client,
V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
 
priv->subdev.ctrl_handler = &priv->hdl;
-   if (priv->hdl.error)
-   return priv->hdl.error;
+   if (priv->hdl.error) {
+   ret = priv->hdl.error;
+   goto ectlhdlfree;
+   }
 
v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
@@ -1012,8 +1014,10 @@ static int ov6650_probe(struct i2c_client *client,
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
ret = v4l2_async_register_subdev(&priv->subdev);
-   if (ret)
-   v4l2_ctrl_handler_free(&priv->hdl);
+   if (!ret)
+   return 0;
+ectlhdlfree:
+   v4l2_ctrl_handler_free(&priv->hdl);
 
return ret;
 }
-- 
2.21.0



[PATCH v2 4/9] media: ov6650: Fix incorrect use of JPEG colorspace

2019-05-20 Thread Janusz Krzysztofik
Since its initial submission, the driver selects V4L2_COLORSPACE_JPEG
for supported formats other than V4L2_MBUS_FMT_SBGGR8_1X8.  According
to v4l2-compliance test program, V4L2_COLORSPACE_JPEG applies
exclusively to V4L2_PIX_FMT_JPEG.  Since the sensor does not support
JPEG format, fix it to always select V4L2_COLORSPACE_SRGB.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 751b48483f27..e7790e9b8887 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -203,7 +203,6 @@ struct ov6650 {
unsigned long   pclk_max;   /* from resolution and format */
struct v4l2_fract   tpf;/* as requested with 
s_frame_interval */
u32 code;
-   enum v4l2_colorspacecolorspace;
 };
 
 
@@ -517,7 +516,7 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
mf->width   = priv->rect.width >> priv->half_scale;
mf->height  = priv->rect.height >> priv->half_scale;
mf->code= priv->code;
-   mf->colorspace  = priv->colorspace;
+   mf->colorspace  = V4L2_COLORSPACE_SRGB;
mf->field   = V4L2_FIELD_NONE;
 
return 0;
@@ -625,11 +624,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
priv->pclk_max = 800;
}
 
-   if (code == MEDIA_BUS_FMT_SBGGR8_1X8)
-   priv->colorspace = V4L2_COLORSPACE_SRGB;
-   else if (code != 0)
-   priv->colorspace = V4L2_COLORSPACE_JPEG;
-
if (half_scale) {
dev_dbg(&client->dev, "max resolution: QCIF\n");
coma_set |= COMA_QCIF;
@@ -660,7 +654,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 
if (!ret) {
-   mf->colorspace  = priv->colorspace;
mf->width = priv->rect.width >> half_scale;
mf->height = priv->rect.height >> half_scale;
}
@@ -683,6 +676,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
&mf->height, 2, H_CIF, 1, 0);
 
mf->field = V4L2_FIELD_NONE;
+   mf->colorspace = V4L2_COLORSPACE_SRGB;
 
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
@@ -693,13 +687,11 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
case MEDIA_BUS_FMT_YUYV8_2X8:
case MEDIA_BUS_FMT_VYUY8_2X8:
case MEDIA_BUS_FMT_UYVY8_2X8:
-   mf->colorspace = V4L2_COLORSPACE_JPEG;
break;
default:
mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
/* fall through */
case MEDIA_BUS_FMT_SBGGR8_1X8:
-   mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
}
 
@@ -1007,7 +999,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.height = H_CIF;
priv->half_scale  = false;
priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
-   priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-- 
2.21.0



[PATCH v2 9/9] media: ov6650: Fix stored crop rectangle not in sync with hardware

2019-05-20 Thread Janusz Krzysztofik
The driver stores crop rectangle settings supposed to be in line with
hardware state in a device private structure.  Since the driver initial
submission, crop rectangle width and height settings are not updated
correctly when rectangle offset settings are applied on hardware.  If
an error occurs while the device is updated, the stored settings my no
longer reflect hardware state and consecutive calls to .get_selection()
as well as .get/set_fmt() may return incorrect information.  That in
turn may affect ability of a bridge device to use correct DMA transfer
settings if such incorrect informamtion on active frame format returned
by .get/set_fmt() is used.

Assuming a failed update of the device means its actual settings haven't
changed, update crop rectangle width and height settings stored in the
device private structure correctly while the rectangle offset is
successfully applied on hardware so the stored values always reflect
actual hardware state to the extent possible.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 65d43390dbeb..c728f718716b 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -494,6 +494,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
 
ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
if (!ret) {
+   priv->rect.width += priv->rect.left - sel->r.left;
priv->rect.left = sel->r.left;
ret = ov6650_reg_write(client, REG_HSTOP,
   (sel->r.left + sel->r.width) >> 1);
@@ -503,6 +504,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
}
if (!ret) {
+   priv->rect.height += priv->rect.top - sel->r.top;
priv->rect.top = sel->r.top;
ret = ov6650_reg_write(client, REG_VSTOP,
   (sel->r.top + sel->r.height) >> 1);
-- 
2.21.0



[PATCH v2 1/9] media: ov6650: Fix MODDULE_DESCRIPTION

2019-05-20 Thread Janusz Krzysztofik
Commit 23a52386fabe ("media: ov6650: convert to standalone v4l2
subdevice") converted the driver from a soc_camera sensor to a
standalone V4L subdevice driver.  Unfortunately, module description was
not updated to reflect the change.  Fix it.

While being at it, update email address of the module author.

Fixes: 23a52386fabe ("media: ov6650: convert to standalone v4l2 subdevice")
Signed-off-by: Janusz Krzysztofik 
cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 1b972e591b48..a3d00afcb0c8 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -1045,6 +1045,6 @@ static struct i2c_driver ov6650_i2c_driver = {
 
 module_i2c_driver(ov6650_i2c_driver);
 
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
-MODULE_AUTHOR("Janusz Krzysztofik ");
+MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera 
sensor");
+MODULE_AUTHOR("Janusz Krzysztofik 

[PATCH v2 7/9] media: ov6650: Fix default format not applied on device probe

2019-05-20 Thread Janusz Krzysztofik
It is not clear what pixel format is actually configured in hardware on
reset.  MEDIA_BUS_FMT_YUYV8_2X8, assumed on device probe since the
driver was intiially submitted, is for sure not the one.

Fix it by explicitly applying a known, driver default frame format just
after initial device reset.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 1915a43bff87..b199332f62d7 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -876,6 +876,11 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
ret = ov6650_reset(client);
if (!ret)
ret = ov6650_prog_dflt(client);
+   if (!ret) {
+   struct v4l2_mbus_framefmt mf = ov6650_def_fmt;
+
+   ret = ov6650_s_fmt(sd, &mf);
+   }
if (!ret)
ret = v4l2_ctrl_handler_setup(&priv->hdl);
 
@@ -1030,8 +1035,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.top= DEF_VSTRT << 1;
priv->rect.width  = W_CIF;
priv->rect.height = H_CIF;
-   priv->half_scale  = false;
-   priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-- 
2.21.0



[PATCH v2 3/9] media: ov6650: Fix crop rectangle alignment not passed back

2019-05-20 Thread Janusz Krzysztofik
Commit 4f996594ceaf ("[media] v4l2: make vidioc_s_crop const")
introduced a writable copy of constified user requested crop rectangle
in order to be able to perform hardware alignments on it.  Later
on, commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video
ops") replaced s_crop() video operaion using that const argument with
set_selection() pad operation which had a corresponding argument not
constified, however the original behavior of the driver was not
restored.  Since that time, any hardware alignment applied on a user
requested crop rectangle is not passed back to the user calling
.set_selection() as it should be.

Fix the issue by dropping the copy and replacing all references to it
with references to the crop rectangle embedded in the user argument.

Fixes: 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 31 +++
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 007f0ca24913..751b48483f27 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -468,38 +468,37 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
 {
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
-   struct v4l2_rect rect = sel->r;
int ret;
 
if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
 
-   v4l_bound_align_image(&rect.width, 2, W_CIF, 1,
- &rect.height, 2, H_CIF, 1, 0);
-   v4l_bound_align_image(&rect.left, DEF_HSTRT << 1,
- (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1,
- &rect.top, DEF_VSTRT << 1,
- (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1,
- 0);
+   v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1,
+ &sel->r.height, 2, H_CIF, 1, 0);
+   v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1,
+ (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1,
+ &sel->r.top, DEF_VSTRT << 1,
+ (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height,
+ 1, 0);
 
-   ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1);
+   ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1);
if (!ret) {
-   priv->rect.left = rect.left;
+   priv->rect.left = sel->r.left;
ret = ov6650_reg_write(client, REG_HSTOP,
-   (rect.left + rect.width) >> 1);
+  (sel->r.left + sel->r.width) >> 1);
}
if (!ret) {
-   priv->rect.width = rect.width;
-   ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1);
+   priv->rect.width = sel->r.width;
+   ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1);
}
if (!ret) {
-   priv->rect.top = rect.top;
+   priv->rect.top = sel->r.top;
ret = ov6650_reg_write(client, REG_VSTOP,
-   (rect.top + rect.height) >> 1);
+  (sel->r.top + sel->r.height) >> 1);
}
if (!ret)
-   priv->rect.height = rect.height;
+   priv->rect.height = sel->r.height;
 
return ret;
 }
-- 
2.21.0



[PATCH v2 0/9] media: ov6650: A collection of fixes

2019-05-20 Thread Janusz Krzysztofik
Janusz Krzysztofik (9):
  media: ov6650: Fix MODDULE_DESCRIPTION
  media: ov6650: Fix control handler not freed on init error
  media: ov6650: Fix crop rectangle alignment not passed back
  media: ov6650: Fix incorrect use of JPEG colorspace
  media: ov6650: Fix some format attributes not under control
  media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support
  media: ov6650: Fix default format not applied on device probe
  media: ov6650: Fix stored frame format not in sync with hardware
  media: ov6650: Fix stored crop rectangle not in sync with hardware

 drivers/media/i2c/ov6650.c | 137 +++--
 1 file changed, 86 insertions(+), 51 deletions(-)

Changelog
v1->v2:
- dropped patches 3/14 through 7/14 which were adding parameter checks
  now called from v4l2_subdev_call() - inspired by Sakari's requiest, 
  thanks!

-- 
2.21.0



[PATCH v2 8/9] media: ov6650: Fix stored frame format not in sync with hardware

2019-05-20 Thread Janusz Krzysztofik
The driver stores frame format settings supposed to be in line with
hardware state in a device private structure.  Since the driver initial
submission, those settings are updated before they are actually applied
on hardware.  If an error occurs on device update, the stored settings
my not reflect hardware state anymore and consecutive calls to
.get_fmt() may return incorrect information.  That in turn may affect
ability of a bridge device to use correct DMA transfer settings if such
incorrect informmation on active frame format returned by .get_fmt() is
used.

Assuming a failed device update mean its state hasn't changed, update
frame format related settings stored in the device private structure
only after they are successfully applied so the stored values always
reflect hardware state as closely as possible.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index b199332f62d7..65d43390dbeb 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -630,7 +630,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
return -EINVAL;
}
-   priv->code = code;
 
if (code == MEDIA_BUS_FMT_Y8_1X8 ||
code == MEDIA_BUS_FMT_SBGGR8_1X8) {
@@ -651,7 +650,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
dev_dbg(&client->dev, "max resolution: CIF\n");
coma_mask |= COMA_QCIF;
}
-   priv->half_scale = half_scale;
 
clkrc = CLKRC_12MHz;
mclk = 1200;
@@ -669,8 +667,13 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
if (!ret)
ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
-   if (!ret)
+   if (!ret) {
+   priv->half_scale = half_scale;
+
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+   }
+   if (!ret)
+   priv->code = code;
 
return ret;
 }
-- 
2.21.0



[PATCH v2 5/9] media: ov6650: Fix some format attributes not under control

2019-05-20 Thread Janusz Krzysztofik
User arguments passed to .get/set_fmt() pad operation callbacks may
contain unsupported values.  The driver takes control over frame size
and pixel code as well as colorspace and field attributes but has never
cared for remainig format attributes, i.e., ycbcr_enc, quantization
and xfer_func, introduced by commit 11ff030c7365 ("[media]
v4l2-mediabus: improve colorspace support").  Fix it.

Set up a static v4l2_mbus_framefmt structure with attributes
initialized to reasonable defaults and use it for updating content of
user provided arguments.  In case of V4L2_SUBDEV_FORMAT_ACTIVE,
postpone frame size update, now performed from inside ov6650_s_fmt()
helper, util the user argument is first updated in ov6650_set_fmt() with
default frame format content.  For V4L2_SUBDEV_FORMAT_TRY, don't copy
all attributes to pad config, only those handled by the driver, then
fill the response with the default frame format updated with updated
pad config format code and frame size.

Fixes: 11ff030c7365 ("[media] v4l2-mediabus: improve colorspace support")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 51 +-
 1 file changed, 39 insertions(+), 12 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index e7790e9b8887..731b03bef7a5 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -215,6 +215,17 @@ static u32 ov6650_codes[] = {
MEDIA_BUS_FMT_Y8_1X8,
 };
 
+static const struct v4l2_mbus_framefmt ov6650_def_fmt = {
+   .width  = W_CIF,
+   .height = H_CIF,
+   .code   = MEDIA_BUS_FMT_SBGGR8_1X8,
+   .colorspace = V4L2_COLORSPACE_SRGB,
+   .field  = V4L2_FIELD_NONE,
+   .ycbcr_enc  = V4L2_YCBCR_ENC_DEFAULT,
+   .quantization   = V4L2_QUANTIZATION_DEFAULT,
+   .xfer_func  = V4L2_XFER_FUNC_DEFAULT,
+};
+
 /* read a register */
 static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
 {
@@ -513,11 +524,13 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
if (format->pad)
return -EINVAL;
 
+   /* initialize response with default media bus frame format */
+   *mf = ov6650_def_fmt;
+
+   /* update media bus format code and frame size */
mf->width   = priv->rect.width >> priv->half_scale;
mf->height  = priv->rect.height >> priv->half_scale;
mf->code= priv->code;
-   mf->colorspace  = V4L2_COLORSPACE_SRGB;
-   mf->field   = V4L2_FIELD_NONE;
 
return 0;
 }
@@ -653,10 +666,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
if (!ret)
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 
-   if (!ret) {
-   mf->width = priv->rect.width >> half_scale;
-   mf->height = priv->rect.height >> half_scale;
-   }
return ret;
 }
 
@@ -675,9 +684,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
&mf->height, 2, H_CIF, 1, 0);
 
-   mf->field = V4L2_FIELD_NONE;
-   mf->colorspace = V4L2_COLORSPACE_SRGB;
-
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
mf->code = MEDIA_BUS_FMT_Y8_1X8;
@@ -695,10 +701,31 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
break;
}
 
-   if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-   return ov6650_s_fmt(sd, mf);
-   cfg->try_fmt = *mf;
+   if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+   /* store media bus format code and frame size in pad config */
+   cfg->try_fmt.width = mf->width;
+   cfg->try_fmt.height = mf->height;
+   cfg->try_fmt.code = mf->code;
 
+   /* return default mbus frame format updated with pad config */
+   *mf = ov6650_def_fmt;
+   mf->width = cfg->try_fmt.width;
+   mf->height = cfg->try_fmt.height;
+   mf->code = cfg->try_fmt.code;
+
+   } else {
+   /* apply new media bus format code and frame size */
+   int ret = ov6650_s_fmt(sd, mf);
+
+   if (ret)
+   return ret;
+
+   /* return default format updated with active size and code */
+   *mf = ov6650_def_fmt;
+   mf->width = priv->rect.width >> priv->half_scale;
+   mf->height = priv->rect.height >> priv->half_scale;
+   mf->code = priv->code;
+   }
return 0;
 }
 
-- 
2.21.0



[PATCH v7 0/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-20 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad ID parameters passed
to subdevice operation callbacks is now verified only for IOCTL calls.
However, those callbacks are also used by drivers, e.g., V4L2 host
interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call().  Also, add check for
non-NULL pointers, including pad config if V4L2_SUBDEV_FORMAT_TRY is
requested.

Having that done, we can avoid taking care of those checks inside
drivers.

Janusz Krzysztofik (3):
  media: v4l2-subdev: Verify arguments in v4l2_subdev_call()
  media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments
  media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

 drivers/media/v4l2-core/v4l2-subdev.c | 268 +-
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 188 insertions(+), 86 deletions(-)

Changelog:
v6->v7:
Changes suggested by Sakari - thanks!
- never succeed pad check on media entities with pad_num == 0,
- allow pad 0 on subdevies not registered as media entities.

v5->v6:
- rename wrappers to call_something() as suggested by Sakari - thanks!
- make check_ functions inline - also on Sakari's suggestion, thanks!
- drop patch 2/4 and remove WARN_ONs from remaining patches to avoid
  kernel WARNs on non-kernel bugs - thanks Hans for pointing this out!

v4->v5:
- a few coding style and code formatting changes,
- require CONFIG_MEDIA_CONTROLLER, not CONFIG_VIDEO_V4L2_SUBDEV_API,
  for a valid pad ID check,
- perform pad ID check only if at least one pad is configured so
  drivers which don't configure pads are not affected if built with
  CONFIG_MEDIA_CONTROLLER defined,
- issue kernel warnings on invalid parameters (new patch - 2/4),
- validate pointers before using them (new patch - 3/4).

v3->v4:
- fix 'struct' keyword missing from patch 2/2,
- fix checkpatch reported style issue in patch 2/2
Sorry for that.

v2->v3:
- add patch 2/2 with pad config check,
- adjust continuation line alignments in patch 1/2 to match those
  used in 2/2.

v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!

-- 
2.21.0



[PATCH v7 2/3] media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments

2019-05-20 Thread Janusz Krzysztofik
Parameters passed to check helpers are now obtained by dereferencing
unverified pointer arguments.  Check validity of those pointers first.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 59fdc0f08870..957c8e5cdfe1 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -147,6 +147,9 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 
pad)
 static inline int check_format(struct v4l2_subdev *sd,
   struct v4l2_subdev_format *format)
 {
+   if (!format)
+   return -EINVAL;
+
return check_which(format->which) ? : check_pad(sd, format->pad);
 }
 
@@ -170,6 +173,9 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_mbus_code_enum *code)
 {
+   if (!code)
+   return -EINVAL;
+
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
@@ -178,6 +184,9 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
 {
+   if (!fse)
+   return -EINVAL;
+
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
@@ -185,6 +194,9 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
 static inline int check_frame_interval(struct v4l2_subdev *sd,
   struct v4l2_subdev_frame_interval *fi)
 {
+   if (!fi)
+   return -EINVAL;
+
return check_pad(sd, fi->pad);
 }
 
@@ -206,6 +218,9 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
 {
+   if (!fie)
+   return -EINVAL;
+
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
@@ -213,6 +228,9 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
 static inline int check_selection(struct v4l2_subdev *sd,
  struct v4l2_subdev_selection *sel)
 {
+   if (!sel)
+   return -EINVAL;
+
return check_which(sel->which) ? : check_pad(sd, sel->pad);
 }
 
@@ -235,6 +253,9 @@ static int call_set_selection(struct v4l2_subdev *sd,
 static inline int check_edid(struct v4l2_subdev *sd,
 struct v4l2_subdev_edid *edid)
 {
+   if (!edid)
+   return -EINVAL;
+
if (edid->blocks && edid->edid == NULL)
return -EINVAL;
 
@@ -254,6 +275,9 @@ static int call_set_edid(struct v4l2_subdev *sd, struct 
v4l2_subdev_edid *edid)
 static int call_dv_timings_cap(struct v4l2_subdev *sd,
   struct v4l2_dv_timings_cap *cap)
 {
+   if (!cap)
+   return -EINVAL;
+
return check_pad(sd, cap->pad) ? :
   sd->ops->pad->dv_timings_cap(sd, cap);
 }
@@ -261,6 +285,9 @@ static int call_dv_timings_cap(struct v4l2_subdev *sd,
 static int call_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *dvt)
 {
+   if (!dvt)
+   return -EINVAL;
+
return check_pad(sd, dvt->pad) ? :
   sd->ops->pad->enum_dv_timings(sd, dvt);
 }
-- 
2.21.0



[PATCH v7 1/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-20 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid taking care
of those checks inside drivers.

Define a wrapper function for each operation callback in scope, then
gather those wrappers in a static v4l2_subdev_ops structure so the
v4l2_subdev_call() macro can find them easy if provided.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 238 --
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 152 insertions(+), 92 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..59fdc0f08870 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -120,56 +120,175 @@ static int subdev_close(struct file *file)
return 0;
 }
 
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
-   struct v4l2_subdev_format *format)
+static inline int check_which(__u32 which)
 {
-   if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
-
-   if (format->pad >= sd->entity.num_pads)
+   if (which != V4L2_SUBDEV_FORMAT_TRY &&
+   which != V4L2_SUBDEV_FORMAT_ACTIVE)
return -EINVAL;
 
return 0;
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
-   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+#if defined(CONFIG_MEDIA_CONTROLLER)
+   if (sd->entity.graph_obj.mdev) {
+   if (pad >= sd->entity.num_pads)
+   return -EINVAL;
+   return 0;
+   }
+#endif
+   /* allow pad 0 on subdevices not registered as media entities */
+   if (pad > 0)
return -EINVAL;
+   return 0;
+}
 
-   if (crop->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static inline int check_format(struct v4l2_subdev *sd,
+  struct v4l2_subdev_format *format)
+{
+   return check_which(format->which) ? : check_pad(sd, format->pad);
+}
 
-   return 0;
+static int call_get_fmt(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
-static int check_selection(struct v4l2_subdev *sd,
-  struct v4l2_subdev_selection *sel)
+static int call_set_fmt(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_format *format)
 {
-   if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-   sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_format(sd, format) ? :
+  sd->ops->pad->set_fmt(sd, cfg, format);
+}
 
-   if (sel->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int call_enum_mbus_code(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
+  struct v4l2_subdev_mbus_code_enum *code)
+{
+   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  sd->ops->pad->enum_mbus_code(sd, cfg, code);
+}
 
-   return 0;
+static int call_enum_frame_size(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_frame_size_enum *fse)
+{
+   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
-static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static inline int check_frame_interval(struct v4l2_subdev *sd,
+  struct v4l2_subdev_frame_interval *fi)
 {
-   if (edid->pad >= sd->entity.num_pads)
-   return -EINVAL;
+   return check_pad(sd, fi->pad);
+}
+
+static int call_g_frame_interval(struct v4l2_subdev *sd,
+struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int

[PATCH v7 3/3] media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

2019-05-20 Thread Janusz Krzysztofik
Extend parameter checks performed by v4l2_subdev_call() with a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_TRY format type is
requested so drivers don't need to care.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 27 +--
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 957c8e5cdfe1..34219e489be2 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -144,20 +144,30 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 
pad)
return 0;
 }
 
+static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg)
+{
+   if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
+   return -EINVAL;
+
+   return 0;
+}
+
 static inline int check_format(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_format *format)
 {
if (!format)
return -EINVAL;
 
-   return check_which(format->which) ? : check_pad(sd, format->pad);
+   return check_which(format->which) ? : check_pad(sd, format->pad) ? :
+  check_cfg(format->which, cfg);
 }
 
 static int call_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
@@ -165,7 +175,7 @@ static int call_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
@@ -177,6 +187,7 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;
 
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  check_cfg(code->which, cfg) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
 
@@ -188,6 +199,7 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
 
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  check_cfg(fse->which, cfg) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
@@ -222,23 +234,26 @@ static int call_enum_frame_interval(struct v4l2_subdev 
*sd,
return -EINVAL;
 
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+  check_cfg(fie->which, cfg) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static inline int check_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
  struct v4l2_subdev_selection *sel)
 {
if (!sel)
return -EINVAL;
 
-   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+   return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
+  check_cfg(sel->which, cfg);
 }
 
 static int call_get_selection(struct v4l2_subdev *sd,
  struct v4l2_subdev_pad_config *cfg,
  struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->get_selection(sd, cfg, sel);
 }
 
@@ -246,7 +261,7 @@ static int call_set_selection(struct v4l2_subdev *sd,
  struct v4l2_subdev_pad_config *cfg,
  struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->set_selection(sd, cfg, sel);
 }
 
-- 
2.21.0



[PATCH v7 0/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-20 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad ID parameters passed
to subdevice operation callbacks is now verified only for IOCTL calls.
However, those callbacks are also used by drivers, e.g., V4L2 host
interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call().  Also, add check for
non-NULL pointers, including pad config if V4L2_SUBDEV_FORMAT_TRY is
requested.

Having that done, we can avoid taking care of those checks inside
drivers.

Janusz Krzysztofik (3):
  media: v4l2-subdev: Verify arguments in v4l2_subdev_call()
  media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments
  media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

 drivers/media/v4l2-core/v4l2-subdev.c | 268 +-
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 188 insertions(+), 86 deletions(-)

Changelog:
v6->v7:
Changes suggested by Sakari - thanks!
- never succeed pad check on media entities with pad_num == 0,
- allow pad 0 on subdevies not registered as media entities.

v5->v6:
- rename wrappers to call_something() as suggested by Sakari - thanks!
- make check_ functions inline - also on Sakari's suggestion, thanks!
- drop patch 2/4 and remove WARN_ONs from remaining patches to avoid
  kernel WARNs on non-kernel bugs - thanks Hans for pointing this out!

v4->v5:
- a few coding style and code formatting changes,
- require CONFIG_MEDIA_CONTROLLER, not CONFIG_VIDEO_V4L2_SUBDEV_API,
  for a valid pad ID check,
- perform pad ID check only if at least one pad is configured so
  drivers which don't configure pads are not affected if built with
  CONFIG_MEDIA_CONTROLLER defined,
- issue kernel warnings on invalid parameters (new patch - 2/4),
- validate pointers before using them (new patch - 3/4).

v3->v4:
- fix 'struct' keyword missing from patch 2/2,
- fix checkpatch reported style issue in patch 2/2
Sorry for that.

v2->v3:
- add patch 2/2 with pad config check,
- adjust continuation line alignments in patch 1/2 to match those
  used in 2/2.

v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!

-- 
2.21.0



Re: [PATCH v6 1/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-17 Thread Janusz Krzysztofik
On Friday, May 17, 2019 5:58:40 PM CEST Sakari Ailus wrote:
> Hi Janusz,
> 
> On Wed, May 15, 2019 at 10:56:36PM +0200, Janusz Krzysztofik wrote:
> > Hi Sakari,
> > 
> > On Wednesday, May 15, 2019 9:16:02 AM CEST Sakari Ailus wrote:
> > > Hi Janusz,
> > > 
> > > On Wed, May 15, 2019 at 12:48:21AM +0200, Janusz Krzysztofik wrote:
> > > > -static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop 
> > *crop)
> > > > +static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
> > > >  {
> > > > -   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
> > > > -   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> > > > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > > > +   if (sd->entity.num_pads && pad >= sd->entity.num_pads)
> > > 
> > > One more comment.
> > > 
> > > The num_pads doesn't really tell whether a given op is valid for a 
device.
> > > Well, in this case it would have to be a bug in the driver, but those do
> > > happen. How about checking for sd->entity.graph_obj.mdev instead? It's
> > > non-NULL if the entity is registered with a media device, i.e. when 
these
> > > callback functions are supposed to be called.
> > 
> > Before I do that, let me undestand your point better.
> > 
> > My intentions were:
> > 1) to provide a check for validity of a pad ID passed to an operation, not 
ann 
> > eligibility of a driver to support the operation,
> > 2) to not break drivers which don't set pad_num, especially when building 
them 
> > with CONFIG_MEDIA_CONTROLLER turned on for whatever reason.
> 
> Indeed.
> 
> But these checks still allow calling the pad operations on sub-devices that
> have no pads. That should not be allowed. Pads are a Media controller
> concept, they do not exist outside it; therefore checking for pads only if
> the subdev is a part of the media device would be entirely correct.

OK, now I see your point.  You don't want the check to succeed if a media 
entity has num_pads == 0.

> It should probably accompany a check that requires the pad number is zero
> if the subdev doesn't have a graph object, even if the pad field isn't
> supposedly used for any purpose. Would that address your concern?

Yes, that's acceptable.  Let's require subdevice drivers to register as media 
entities if they want to use pads > 0.

I'll update the patches and submit as v7 soon.

Thanks,
Janusz

> > Since pad IDs are verified against pad_num which may be not set, we should 
> > obviously check validity of pad_num before comparing against it.  Since 
media 
> > controller compatible subdevices need at least one pad, I think the check 
for 
> > non-zero pad_num is quite reasonable.
> > 
> > Moreover, old drivers are actually using those pad operations you describe 
as 
> > not supposed to be called.  They are using them because they were 
converted to 
> > use them in place of former video ops.  Already dealing with pad IDs, they 
may 
> > decide to turn on CONFIG_MEDIA_CONTROLLER and use selected functionality, 
for 
> > example register pads, without implementing fulll media controller 
support.  
> > Why should we refuse to perform pad ID verification for them?
> 
> 






Re: [PATCH v6 1/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-15 Thread Janusz Krzysztofik
Hi Sakari,

On Wednesday, May 15, 2019 9:16:02 AM CEST Sakari Ailus wrote:
> Hi Janusz,
> 
> On Wed, May 15, 2019 at 12:48:21AM +0200, Janusz Krzysztofik wrote:
> > -static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop 
*crop)
> > +static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
> >  {
> > -   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
> > -   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
> > +#if defined(CONFIG_MEDIA_CONTROLLER)
> > +   if (sd->entity.num_pads && pad >= sd->entity.num_pads)
> 
> One more comment.
> 
> The num_pads doesn't really tell whether a given op is valid for a device.
> Well, in this case it would have to be a bug in the driver, but those do
> happen. How about checking for sd->entity.graph_obj.mdev instead? It's
> non-NULL if the entity is registered with a media device, i.e. when these
> callback functions are supposed to be called.

Before I do that, let me undestand your point better.

My intentions were:
1) to provide a check for validity of a pad ID passed to an operation, not ann 
eligibility of a driver to support the operation,
2) to not break drivers which don't set pad_num, especially when building them 
with CONFIG_MEDIA_CONTROLLER turned on for whatever reason.

Since pad IDs are verified against pad_num which may be not set, we should 
obviously check validity of pad_num before comparing against it.  Since media 
controller compatible subdevices need at least one pad, I think the check for 
non-zero pad_num is quite reasonable.

Moreover, old drivers are actually using those pad operations you describe as 
not supposed to be called.  They are using them because they were converted to 
use them in place of former video ops.  Already dealing with pad IDs, they may 
decide to turn on CONFIG_MEDIA_CONTROLLER and use selected functionality, for 
example register pads, without implementing fulll media controller support.  
Why should we refuse to perform pad ID verification for them?

Thanks,
Janusz






[PATCH v6 2/3] media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments

2019-05-14 Thread Janusz Krzysztofik
Parameters passed to check helpers are now obtained by dereferencing
unverified pointer arguments.  Check validity of those pointers first.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index c61c95007d89..6933f30e5041 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -141,6 +141,9 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 
pad)
 static inline int check_format(struct v4l2_subdev *sd,
   struct v4l2_subdev_format *format)
 {
+   if (!format)
+   return -EINVAL;
+
return check_which(format->which) ? : check_pad(sd, format->pad);
 }
 
@@ -164,6 +167,9 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_mbus_code_enum *code)
 {
+   if (!code)
+   return -EINVAL;
+
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
@@ -172,6 +178,9 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
 {
+   if (!fse)
+   return -EINVAL;
+
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
@@ -179,6 +188,9 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
 static inline int check_frame_interval(struct v4l2_subdev *sd,
   struct v4l2_subdev_frame_interval *fi)
 {
+   if (!fi)
+   return -EINVAL;
+
return check_pad(sd, fi->pad);
 }
 
@@ -200,6 +212,9 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
 {
+   if (!fie)
+   return -EINVAL;
+
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
@@ -207,6 +222,9 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
 static inline int check_selection(struct v4l2_subdev *sd,
  struct v4l2_subdev_selection *sel)
 {
+   if (!sel)
+   return -EINVAL;
+
return check_which(sel->which) ? : check_pad(sd, sel->pad);
 }
 
@@ -229,6 +247,9 @@ static int call_set_selection(struct v4l2_subdev *sd,
 static inline int check_edid(struct v4l2_subdev *sd,
 struct v4l2_subdev_edid *edid)
 {
+   if (!edid)
+   return -EINVAL;
+
if (edid->blocks && edid->edid == NULL)
return -EINVAL;
 
@@ -248,6 +269,9 @@ static int call_set_edid(struct v4l2_subdev *sd, struct 
v4l2_subdev_edid *edid)
 static int call_dv_timings_cap(struct v4l2_subdev *sd,
   struct v4l2_dv_timings_cap *cap)
 {
+   if (!cap)
+   return -EINVAL;
+
return check_pad(sd, cap->pad) ? :
   sd->ops->pad->dv_timings_cap(sd, cap);
 }
@@ -255,6 +279,9 @@ static int call_dv_timings_cap(struct v4l2_subdev *sd,
 static int call_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *dvt)
 {
+   if (!dvt)
+   return -EINVAL;
+
return check_pad(sd, dvt->pad) ? :
   sd->ops->pad->enum_dv_timings(sd, dvt);
 }
-- 
2.21.0



[PATCH v6 3/3] media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

2019-05-14 Thread Janusz Krzysztofik
Extend parameter checks performed by v4l2_subdev_call() with a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_TRY format type is
requested so drivers don't need to care.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 27 +--
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 6933f30e5041..6a5c4f046723 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -138,20 +138,30 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 
pad)
return 0;
 }
 
+static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg)
+{
+   if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
+   return -EINVAL;
+
+   return 0;
+}
+
 static inline int check_format(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_format *format)
 {
if (!format)
return -EINVAL;
 
-   return check_which(format->which) ? : check_pad(sd, format->pad);
+   return check_which(format->which) ? : check_pad(sd, format->pad) ? :
+  check_cfg(format->which, cfg);
 }
 
 static int call_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
@@ -159,7 +169,7 @@ static int call_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
@@ -171,6 +181,7 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;
 
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  check_cfg(code->which, cfg) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
 
@@ -182,6 +193,7 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
 
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  check_cfg(fse->which, cfg) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
@@ -216,23 +228,26 @@ static int call_enum_frame_interval(struct v4l2_subdev 
*sd,
return -EINVAL;
 
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+  check_cfg(fie->which, cfg) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static inline int check_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
  struct v4l2_subdev_selection *sel)
 {
if (!sel)
return -EINVAL;
 
-   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+   return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
+  check_cfg(sel->which, cfg);
 }
 
 static int call_get_selection(struct v4l2_subdev *sd,
  struct v4l2_subdev_pad_config *cfg,
  struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->get_selection(sd, cfg, sel);
 }
 
@@ -240,7 +255,7 @@ static int call_set_selection(struct v4l2_subdev *sd,
  struct v4l2_subdev_pad_config *cfg,
  struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->set_selection(sd, cfg, sel);
 }
 
-- 
2.21.0



[PATCH v6 1/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-14 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid taking care
of those checks inside drivers.

Define a wrapper function for each operation callback in scope, then
gather those wrappers in a static v4l2_subdev_ops structure so the
v4l2_subdev_call() macro can find them easy if provided.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 232 --
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 146 insertions(+), 92 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..c61c95007d89 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -120,56 +120,169 @@ static int subdev_close(struct file *file)
return 0;
 }
 
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
-   struct v4l2_subdev_format *format)
+static inline int check_which(__u32 which)
 {
-   if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
-
-   if (format->pad >= sd->entity.num_pads)
+   if (which != V4L2_SUBDEV_FORMAT_TRY &&
+   which != V4L2_SUBDEV_FORMAT_ACTIVE)
return -EINVAL;
 
return 0;
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
-   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+#if defined(CONFIG_MEDIA_CONTROLLER)
+   if (sd->entity.num_pads && pad >= sd->entity.num_pads)
return -EINVAL;
+#endif
+   return 0;
+}
 
-   if (crop->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static inline int check_format(struct v4l2_subdev *sd,
+  struct v4l2_subdev_format *format)
+{
+   return check_which(format->which) ? : check_pad(sd, format->pad);
+}
 
-   return 0;
+static int call_get_fmt(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
-static int check_selection(struct v4l2_subdev *sd,
-  struct v4l2_subdev_selection *sel)
+static int call_set_fmt(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_format *format)
 {
-   if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-   sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_format(sd, format) ? :
+  sd->ops->pad->set_fmt(sd, cfg, format);
+}
 
-   if (sel->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int call_enum_mbus_code(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
+  struct v4l2_subdev_mbus_code_enum *code)
+{
+   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  sd->ops->pad->enum_mbus_code(sd, cfg, code);
+}
 
-   return 0;
+static int call_enum_frame_size(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_frame_size_enum *fse)
+{
+   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
-static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static inline int check_frame_interval(struct v4l2_subdev *sd,
+  struct v4l2_subdev_frame_interval *fi)
 {
-   if (edid->pad >= sd->entity.num_pads)
-   return -EINVAL;
+   return check_pad(sd, fi->pad);
+}
+
+static int call_g_frame_interval(struct v4l2_subdev *sd,
+struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int call_s_frame_interval(struct v4l2_subdev *sd,
+struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->op

[PATCH v6 0/3] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-14 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad ID parameters passed
to subdevice operation callbacks is now verified only for IOCTL calls.
However, those callbacks are also used by drivers, e.g., V4L2 host
interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call().  Also, add check for
non-NULL pointers, including pad config if V4L2_SUBDEV_FORMAT_tRY is
requested.

Having that done, we can avoid taking care of those checks inside
drivers.

Janusz Krzysztofik (3):
  media: v4l2-subdev: Verify arguments in v4l2_subdev_call()
  media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments
  media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

 drivers/media/v4l2-core/v4l2-subdev.c | 262 +-
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 182 insertions(+), 86 deletions(-)

Changelog:
v5->v6:
- rename wrappers to call_something() as suggested by Sakari - thanks!
- make check_ functions inline - also on Sakari's suggestion, thanks!
- drop patch 2/4 and remove WARN_ONs from remaining patches to avoid
  kernel WARNs on non-kernel bugs - thanks Hans for pointing this out!

v4->v5:
- a few coding style and code formatting changes,
- require CONFIG_MEDIA_CONTROLLER, not CONFIG_VIDEO_V4L2_SUBDEV_API,
  for a valid pad ID check,
- perform pad ID check only if at least one pad is configured so
  drivers which don't configure pads are not affected if built with
  CONFIG_MEDIA_CONTROLLER defined,
- issue kernel warnings on invalid parameters (new patch - 2/4),
- validate pointers before using them (new patch - 3/4).

v3->v4:
- fix 'struct' keyword missing from patch 2/2,
- fix checkpatch reported style issue in patch 2/2
Sorry for that.

v2->v3:
- add patch 2/2 with pad config check,
- adjust continuation line alignments in patch 1/2 to match those
  used in 2/2.

v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!

-- 
2.21.0



[PATCH v5 3/4] media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments

2019-05-12 Thread Janusz Krzysztofik
Parameters passed to check helpers are now obtained by dereferencing
unverified pointer arguments.  Check validity of those pointers first.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 5f2264575cd7..3fc07af26c5b 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -141,6 +141,9 @@ static int check_pad(struct v4l2_subdev *sd, __u32 pad)
 static int check_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
 {
+   if (WARN_ON(!format))
+   return -EINVAL;
+
return check_which(format->which) ? : check_pad(sd, format->pad);
 }
 
@@ -164,6 +167,9 @@ static int check_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
 {
+   if (WARN_ON(!code))
+   return -EINVAL;
+
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
@@ -172,6 +178,9 @@ static int check_enum_frame_size(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_frame_size_enum *fse)
 {
+   if (WARN_ON(!fse))
+   return -EINVAL;
+
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
@@ -179,6 +188,9 @@ static int check_enum_frame_size(struct v4l2_subdev *sd,
 static int check_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *fi)
 {
+   if (WARN_ON(!fi))
+   return -EINVAL;
+
return check_pad(sd, fi->pad);
 }
 
@@ -200,6 +212,9 @@ static int check_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
 {
+   if (WARN_ON(!fie))
+   return -EINVAL;
+
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
@@ -207,6 +222,9 @@ static int check_enum_frame_interval(struct v4l2_subdev *sd,
 static int check_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_selection *sel)
 {
+   if (WARN_ON(!sel))
+   return -EINVAL;
+
return check_which(sel->which) ? : check_pad(sd, sel->pad);
 }
 
@@ -228,6 +246,9 @@ static int check_set_selection(struct v4l2_subdev *sd,
 
 static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
 {
+   if (WARN_ON(!edid))
+   return -EINVAL;
+
if (WARN_ON(edid->blocks && edid->edid == NULL))
return -EINVAL;
 
@@ -247,6 +268,9 @@ static int check_set_edid(struct v4l2_subdev *sd, struct 
v4l2_subdev_edid *edid)
 static int check_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
 {
+   if (WARN_ON(!cap))
+   return -EINVAL;
+
return check_pad(sd, cap->pad) ? :
   sd->ops->pad->dv_timings_cap(sd, cap);
 }
@@ -254,6 +278,9 @@ static int check_dv_timings_cap(struct v4l2_subdev *sd,
 static int check_enum_dv_timings(struct v4l2_subdev *sd,
 struct v4l2_enum_dv_timings *dvt)
 {
+   if (WARN_ON(!dvt))
+   return -EINVAL;
+
return check_pad(sd, dvt->pad) ? :
   sd->ops->pad->enum_dv_timings(sd, dvt);
 }
-- 
2.21.0



[PATCH v5 2/4] media: v4l2-subdev: WARN_ON invalid v4l2_subdev_call() arguments

2019-05-12 Thread Janusz Krzysztofik
Invalid arguments passed to v4l2_subdev_call generally mean bugs.  Be
noisy if that happens.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 890916674d42..5f2264575cd7 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -122,8 +122,8 @@ static int subdev_close(struct file *file)
 
 static int check_which(__u32 which)
 {
-   if (which != V4L2_SUBDEV_FORMAT_TRY &&
-   which != V4L2_SUBDEV_FORMAT_ACTIVE)
+   if (WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY &&
+   which != V4L2_SUBDEV_FORMAT_ACTIVE))
return -EINVAL;
 
return 0;
@@ -132,7 +132,7 @@ static int check_which(__u32 which)
 static int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
 #if defined(CONFIG_MEDIA_CONTROLLER)
-   if (sd->entity.num_pads && pad >= sd->entity.num_pads)
+   if (WARN_ON(sd->entity.num_pads && pad >= sd->entity.num_pads))
return -EINVAL;
 #endif
return 0;
@@ -228,7 +228,7 @@ static int check_set_selection(struct v4l2_subdev *sd,
 
 static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
 {
-   if (edid->blocks && edid->edid == NULL)
+   if (WARN_ON(edid->blocks && edid->edid == NULL))
return -EINVAL;
 
return check_pad(sd, edid->pad);
-- 
2.21.0



[PATCH v5 4/4] media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

2019-05-12 Thread Janusz Krzysztofik
Extend parameter checks performed by v4l2_subdev_call() with a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_TRY format type is
requested so drivers don't need to care.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 27 +--
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 3fc07af26c5b..fc8c308fb060 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -138,20 +138,30 @@ static int check_pad(struct v4l2_subdev *sd, __u32 pad)
return 0;
 }
 
+static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg)
+{
+   if (WARN_ON(which == V4L2_SUBDEV_FORMAT_TRY && !cfg))
+   return -EINVAL;
+
+   return 0;
+}
+
 static int check_format(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
if (WARN_ON(!format))
return -EINVAL;
 
-   return check_which(format->which) ? : check_pad(sd, format->pad);
+   return check_which(format->which) ? : check_pad(sd, format->pad) ? :
+  check_cfg(format->which, cfg);
 }
 
 static int check_get_fmt(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
@@ -159,7 +169,7 @@ static int check_set_fmt(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
@@ -171,6 +181,7 @@ static int check_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;
 
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  check_cfg(code->which, cfg) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
 
@@ -182,6 +193,7 @@ static int check_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
 
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  check_cfg(fse->which, cfg) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
@@ -216,23 +228,26 @@ static int check_enum_frame_interval(struct v4l2_subdev 
*sd,
return -EINVAL;
 
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+  check_cfg(fie->which, cfg) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
if (WARN_ON(!sel))
return -EINVAL;
 
-   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+   return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
+  check_cfg(sel->which, cfg);
 }
 
 static int check_get_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->get_selection(sd, cfg, sel);
 }
 
@@ -240,7 +255,7 @@ static int check_set_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->set_selection(sd, cfg, sel);
 }
 
-- 
2.21.0



[PATCH v5 1/4] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-12 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad ID parameters passed
to subdevice operation callbacks is now verified only for IOCTL calls.
However, those callbacks are also used by drivers, e.g., V4L2 host
interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid taking care
of those checks inside drivers.

Define a wrapper function for each operation callback in scope, then
gather those wrappers in a static v4l2_subdev_ops structure so the
v4l2_subdev_call() macro can find them easy if provided.  Move reusable
code to helpers.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 227 --
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 143 insertions(+), 90 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..890916674d42 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -120,56 +120,168 @@ static int subdev_close(struct file *file)
return 0;
 }
 
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
-   struct v4l2_subdev_format *format)
+static int check_which(__u32 which)
 {
-   if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
-
-   if (format->pad >= sd->entity.num_pads)
+   if (which != V4L2_SUBDEV_FORMAT_TRY &&
+   which != V4L2_SUBDEV_FORMAT_ACTIVE)
return -EINVAL;
 
return 0;
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
-   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+#if defined(CONFIG_MEDIA_CONTROLLER)
+   if (sd->entity.num_pads && pad >= sd->entity.num_pads)
return -EINVAL;
+#endif
+   return 0;
+}
 
-   if (crop->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_format(struct v4l2_subdev *sd,
+   struct v4l2_subdev_format *format)
+{
+   return check_which(format->which) ? : check_pad(sd, format->pad);
+}
 
-   return 0;
+static int check_get_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->get_fmt(sd, cfg, format);
+}
+
+static int check_set_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->set_fmt(sd, cfg, format);
+}
+
+static int check_enum_mbus_code(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_mbus_code_enum *code)
+{
+   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  sd->ops->pad->enum_mbus_code(sd, cfg, code);
+}
+
+static int check_enum_frame_size(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_frame_size_enum *fse)
+{
+   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  sd->ops->pad->enum_frame_size(sd, cfg, fse);
+}
+
+static int check_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_frame_interval *fi)
+{
+   return check_pad(sd, fi->pad);
+}
+
+static int check_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int check_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->s_frame_interval(sd, fi);
+}
+
+static int check_enum_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_frame_interval_enum *fie)
+{
+   return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+  sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_selection *sel)
 {
-   if (s

[PATCH v5 0/4] media: v4l2-subdev: Verify arguments in v4l2_subdev_call()

2019-05-12 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad ID parameters passed
to subdevice operation callbacks is now verified only for IOCTL calls.
However, those callbacks are also used by drivers, e.g., V4L2 host
interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call().  Also, add check for
non-NULL pointers, including pad config if V4L2_SUBDEV_FORMAT_tRY is
requested.  Since invalid arguments generally mean bugs, be noisy about
them.

Having that done, we can avoid taking care of those checks inside
drivers.

Janusz Krzysztofik (4):
  media: v4l2-subdev: Verify arguments in v4l2_subdev_call()
  media: v4l2-subdev: WARN_ON invalid v4l2_subdev_call() arguments
  media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments
  media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument

 drivers/media/v4l2-core/v4l2-subdev.c | 257 +-
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 179 insertions(+), 84 deletions(-)

Changelog:
v4->v5:
- a few coding style and code formatting changes,
- require CONFIG_MEDIA_CONTROLLER, not CONFIG_VIDEO_V4L2_SUBDEV_API,
  for a valid pad ID check,
- perform pad ID check only if at least one pad is configured so
  drivers which don't configure pads are not affected if built with
  CONFIG_MEDIA_CONTROLLER defined,
- issue kernel warnings on invalid parameters (new patch - 2/4),
- validate pointers before using them (new patch - 3/4).

v3->v4:
- fix 'struct' keyword missing from patch 2/2,
- fix checkpatch reported style issue in patch 2/2
Sorry for that.

v2->v3:
- add patch 2/2 with pad config check,
- adjust continuation line alignments in patch 1/2 to match those
  used in 2/2.

v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!

-- 
2.21.0



[PATCH v4 2/2] media: v4l2-subdev: Verify pad config argument

2019-05-11 Thread Janusz Krzysztofik
Extend parameter checks performed by v4l2_subdev_call() with a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_TRY format type is
requested so drivers don't need to care.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 30 +++
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index cd50fcb86c47..4540d8abff5f 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -126,6 +126,11 @@ static inline int check_which(__u32 which)
   which != V4L2_SUBDEV_FORMAT_ACTIVE ? -EINVAL : 0;
 }
 
+static inline int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg)
+{
+   return which == V4L2_SUBDEV_FORMAT_TRY && !cfg ? -EINVAL : 0;
+}
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
@@ -136,16 +141,18 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 
pad)
 #endif
 
 static int check_format(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
-   return check_which(format->which) ? : check_pad(sd, format->pad);
+   return check_which(format->which) ? :
+  check_cfg(format->which, cfg) ? : check_pad(sd, format->pad);
 }
 
 static int check_get_fmt(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
@@ -153,7 +160,7 @@ static int check_set_fmt(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
@@ -161,7 +168,8 @@ static int check_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
 {
-   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+   return check_which(code->which) ? : check_cfg(code->which, cfg) ? :
+  check_pad(sd, code->pad) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
 
@@ -169,7 +177,8 @@ static int check_enum_frame_size(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_frame_size_enum *fse)
 {
-   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+   return check_which(fse->which) ? : check_cfg(fse->which, cfg) ? :
+  check_pad(sd, fse->pad) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
@@ -197,21 +206,24 @@ static int check_enum_frame_interval(struct v4l2_subdev 
*sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
 {
-   return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+   return check_which(fie->which) ? : check_cfg(fie->which, cfg) ? :
+  check_pad(sd, fie->pad) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+   return check_which(sel->which) ? : check_cfg(sel->which, cfg) ? :
+  check_pad(sd, sel->pad);
 }
 
 static int check_get_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->get_selection(sd, cfg, sel);
 }
 
@@ -219,7 +231,7 @@ static int check_set_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->set_selection(sd, cfg, sel);
 }
 
-- 
2.21.0



[PATCH v4 0/2] media: v4l2-subdev: Verify arguments of v4l2_subdev_call()

2019-05-11 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call().  Also, add a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_tRY is requested.

This way we can avoid taking care of those checks inside drivers.

Janusz Krzysztofik (2):
  media: v4l2-subdev: Verify arguments of v4l2_subdev_call()
  media: v4l2-subdev: Verify pad config argument

 drivers/media/v4l2-core/v4l2-subdev.c | 234 --
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 151 insertions(+), 89 deletions(-)

Changelog:
v3->v4:
- fix 'struct' keyword missing from patch 2/2,
- fix checkpatch reported style issue in patch 2/2
Sorry for that.

v2->v3:
- add patch 2/2 with pad config check,
- adjust continuation line alignments in patch 1/2 to match those 
  used in 2/2.

v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!

-- 
2.21.0



[PATCH v4 1/2] media: v4l2-subdev: Verify arguments of v4l2_subdev_call()

2019-05-11 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid taking care
of those checks inside drivers.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 222 +++---
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 139 insertions(+), 89 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..cd50fcb86c47 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -120,56 +120,165 @@ static int subdev_close(struct file *file)
return 0;
 }
 
+static inline int check_which(__u32 which)
+{
+   return which != V4L2_SUBDEV_FORMAT_TRY &&
+  which != V4L2_SUBDEV_FORMAT_ACTIVE ? -EINVAL : 0;
+}
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
+{
+   return pad >= sd->entity.num_pads ? -EINVAL : 0;
+}
+#else
+#define check_pad(...) 0
+#endif
+
 static int check_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
 {
-   if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(format->which) ? : check_pad(sd, format->pad);
+}
 
-   if (format->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_get_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->get_fmt(sd, cfg, format);
+}
 
-   return 0;
+static int check_set_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int check_enum_mbus_code(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_mbus_code_enum *code)
 {
-   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  sd->ops->pad->enum_mbus_code(sd, cfg, code);
+}
 
-   if (crop->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_enum_frame_size(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_frame_size_enum *fse)
+{
+   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  sd->ops->pad->enum_frame_size(sd, cfg, fse);
+}
 
-   return 0;
+static int check_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_frame_interval *fi)
+{
+   return check_pad(sd, fi->pad);
+}
+
+static int check_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int check_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->s_frame_interval(sd, fi);
+}
+
+static int check_enum_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_frame_interval_enum *fie)
+{
+   return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+  sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_selection *sel)
 {
-   if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-   sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+}
 
-   if (sel->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_get_selection(struct v4l2_su

[PATCH v3 1/2] media: v4l2-subdev: Verify arguments of v4l2_subdev_call()

2019-05-11 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid taking
care of those checks inside drivers.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 222 +++---
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 139 insertions(+), 89 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..cd50fcb86c47 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -120,56 +120,165 @@ static int subdev_close(struct file *file)
return 0;
 }
 
+static inline int check_which(__u32 which)
+{
+   return which != V4L2_SUBDEV_FORMAT_TRY &&
+  which != V4L2_SUBDEV_FORMAT_ACTIVE ? -EINVAL : 0;
+}
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
+{
+   return pad >= sd->entity.num_pads ? -EINVAL : 0;
+}
+#else
+#define check_pad(...) 0
+#endif
+
 static int check_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
 {
-   if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(format->which) ? : check_pad(sd, format->pad);
+}
 
-   if (format->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_get_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->get_fmt(sd, cfg, format);
+}
 
-   return 0;
+static int check_set_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+  sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int check_enum_mbus_code(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_mbus_code_enum *code)
 {
-   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+  sd->ops->pad->enum_mbus_code(sd, cfg, code);
+}
 
-   if (crop->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_enum_frame_size(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_frame_size_enum *fse)
+{
+   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+  sd->ops->pad->enum_frame_size(sd, cfg, fse);
+}
 
-   return 0;
+static int check_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_frame_interval *fi)
+{
+   return check_pad(sd, fi->pad);
+}
+
+static int check_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int check_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+  sd->ops->video->s_frame_interval(sd, fi);
+}
+
+static int check_enum_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_frame_interval_enum *fie)
+{
+   return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+  sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_selection *sel)
 {
-   if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-   sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+}
 
-   if (sel->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_get_selection(struct v4l2_su

[PATCH v3 2/2] media: v4l2-subdev: Verify pad config argument

2019-05-11 Thread Janusz Krzysztofik
Extend parameter checks performed by v4l2_subdev_call() with a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_TRY format type is
requested so drivers don't need to care.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/v4l2-core/v4l2-subdev.c | 30 +++
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index cd50fcb86c47..52eb23112804 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -126,6 +126,11 @@ static inline int check_which(__u32 which)
   which != V4L2_SUBDEV_FORMAT_ACTIVE ? -EINVAL : 0;
 }
 
+static inline int check_cfg(__u32 which, v4l2_subdev_pad_config *cfg)
+{
+   return which == V4L2_SUBDEV_FORMAT_TRY && !cfg ? -EINVAL : 0;
+}
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
 {
@@ -136,16 +141,18 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 
pad)
 #endif
 
 static int check_format(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
 {
-   return check_which(format->which) ? : check_pad(sd, format->pad);
+   return check_which(format->which) ? :
+  check_cfg(format->which, cfg) ? : check_pad(sd, format->pad);
 }
 
 static int check_get_fmt(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->get_fmt(sd, cfg, format);
 }
 
@@ -153,7 +160,7 @@ static int check_set_fmt(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_format *format)
 {
-   return check_format(sd, format) ? :
+   return check_format(sd, cfg, format) ? :
   sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
@@ -161,7 +168,8 @@ static int check_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
 {
-   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+   return check_which(code->which) ? : check_cfg(code->which, cfg) ? :
+  check_pad(sd, code->pad) ? :
   sd->ops->pad->enum_mbus_code(sd, cfg, code);
 }
 
@@ -169,7 +177,8 @@ static int check_enum_frame_size(struct v4l2_subdev *sd,
 struct v4l2_subdev_pad_config *cfg,
 struct v4l2_subdev_frame_size_enum *fse)
 {
-   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+   return check_which(fse->which) ? : check_cfg(fse->which, cfg) ? :
+  check_pad(sd, fse->pad) ? :
   sd->ops->pad->enum_frame_size(sd, cfg, fse);
 }
 
@@ -197,21 +206,24 @@ static int check_enum_frame_interval(struct v4l2_subdev 
*sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie)
 {
-   return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+   return check_which(fie->which) ? : check_cfg(fie->which, cfg) ? :
+  check_pad(sd, fie->pad) ? :
   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_which(sel->which) ? : check_pad(sd, sel->pad);
+   return check_which(sel->which) ? :check_cfg(sel->which, cfg) ? :
+  check_pad(sd, sel->pad);
 }
 
 static int check_get_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->get_selection(sd, cfg, sel);
 }
 
@@ -219,7 +231,7 @@ static int check_set_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_pad_config *cfg,
   struct v4l2_subdev_selection *sel)
 {
-   return check_selection(sd, sel) ? :
+   return check_selection(sd, cfg, sel) ? :
   sd->ops->pad->set_selection(sd, cfg, sel);
 }
 
-- 
2.21.0



[PATCH v3 0/2] media: v4l2-subdev: Verify arguments of v4l2_subdev_call()

2019-05-11 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call().  Also, add a check for
a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_tRY is requested.

This way we can avoid taking care of those checks inside drivers.

Janusz Krzysztofik (2):
  media: v4l2-subdev: Verify arguments of v4l2_subdev_call()
  media: v4l2-subdev: Verify pad config argument

 drivers/media/v4l2-core/v4l2-subdev.c | 234 --
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 151 insertions(+), 89 deletions(-)

Changelog:
v2->v3:
- add patch 2/2 with pad config check,
- adjust continuation line alignments in patch 1/2 to match those 
  used in 2/2.

v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!

-- 
2.21.0



[PATCH v2] media: v4l2-subdev: Verify arguments of v4l2_subdev_call()

2019-05-10 Thread Janusz Krzysztofik
Correctness of format type (try or active) and pad number parameters
passed to subdevice operation callbacks is now verified only for IOCTL
calls.  However, those callbacks are also used by drivers, e.g., V4L2
host interfaces.

Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call()
macro while calling subdevice operations, move those parameter checks
from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid
reimplementing those checks inside drivers.

Signed-off-by: Janusz Krzysztofik 
---
Changelog:
v1->v2:
- replace the horrible macro with a structure of wrapper functions;
  inspired by Hans' and Sakari's comments - thanks!
 
drivers/media/v4l2-core/v4l2-subdev.c | 222 +++---
 include/media/v4l2-subdev.h   |   6 +
 2 files changed, 139 insertions(+), 89 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index d75815ab0d7b..213194660d52 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -120,56 +120,165 @@ static int subdev_close(struct file *file)
return 0;
 }
 
+static inline int check_which(__u32 which)
+{
+   return which != V4L2_SUBDEV_FORMAT_TRY &&
+  which != V4L2_SUBDEV_FORMAT_ACTIVE ? -EINVAL : 0;
+}
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
+{
+   return pad >= sd->entity.num_pads ? -EINVAL : 0;
+}
+#else
+#define check_pad(...) 0
+#endif
+
 static int check_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
 {
-   if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(format->which) ? : check_pad(sd, format->pad);
+}
 
-   if (format->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_get_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+   sd->ops->pad->get_fmt(sd, cfg, format);
+}
 
-   return 0;
+static int check_set_fmt(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_format *format)
+{
+   return check_format(sd, format) ? :
+   sd->ops->pad->set_fmt(sd, cfg, format);
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int check_enum_mbus_code(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_mbus_code_enum *code)
 {
-   if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   return -EINVAL;
+   return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+   sd->ops->pad->enum_mbus_code(sd, cfg, code);
+}
 
-   if (crop->pad >= sd->entity.num_pads)
-   return -EINVAL;
+static int check_enum_frame_size(struct v4l2_subdev *sd,
+struct v4l2_subdev_pad_config *cfg,
+struct v4l2_subdev_frame_size_enum *fse)
+{
+   return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+   sd->ops->pad->enum_frame_size(sd, cfg, fse);
+}
 
-   return 0;
+static int check_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_frame_interval *fi)
+{
+   return check_pad(sd, fi->pad);
+}
+
+static int check_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+   sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int check_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+   return check_frame_interval(sd, fi) ? :
+   sd->ops->video->s_frame_interval(sd, fi);
+}
+
+static int check_enum_frame_interval(struct v4l2_subdev *sd,
+   struct v4l2_subdev_pad_config *cfg,
+   struct v4l2_subdev_frame_interval_enum *fie)
+{
+   return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+   sd->ops->pad->enum_frame_interval(sd, cfg, fie);
 }
 
 static int check_selection(struct v4l2_subdev *sd,
   struct v4l2_subdev_selection *sel)
 {
-   if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-   sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-   

Re: [PATCH 03/14] media: ov6650: Fix unverified arguments used in .set_fmt()

2019-05-07 Thread Janusz Krzysztofik
Hi Sakari,

Sorry for late answer, I've just found your message in Gmail spam folder.

On Tuesday, April 30, 2019 3:58:09 PM CEST Sakari Ailus wrote:
> Hi Janusz,
> 
> On Mon, Apr 08, 2019 at 11:42:31PM +0200, Janusz Krzysztofik wrote:
> > Commit 717fd5b4907ad ("[media] v4l2: replace try_mbus_fmt by set_fmt")
> > converted a former ov6650_try_fmt() video operation callback to an
> > ov6650_set_fmt() pad operation callback.  However, the function does not
> > verify correctness of user provided format->which flag and pad config
> > pointer arguments.  Fix it.
> > 
> > Fixes: 717fd5b4907ad ("[media] v4l2: replace try_mbus_fmt by set_fmt")
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: sta...@vger.kernel.org
> > ---
> >  drivers/media/i2c/ov6650.c | 11 +++
> >  1 file changed, 11 insertions(+)
> > 
> > diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
> > index 007f0ca24913..3062c9a6c57b 100644
> > --- a/drivers/media/i2c/ov6650.c
> > +++ b/drivers/media/i2c/ov6650.c
> > @@ -679,6 +679,17 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
> > if (format->pad)
> > return -EINVAL;
> >  
> > +   switch (format->which) {
> > +   case V4L2_SUBDEV_FORMAT_ACTIVE:
> > +   break;
> > +   case V4L2_SUBDEV_FORMAT_TRY:
> > +   if (cfg)
> > +   break;
> > +   /* fall through */
> > +   default:
> > +   return -EINVAL;
> > +   }
> 
> For this to return an error, there would need to be a problem on the
> caller's side. In other words, this isn't supposed to happen.

How about raising a bug if that happens nevertheless?

@@ -677,10 +677,20 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
struct ov6650 *priv = to_ov6650(client);
 
if (format->pad)
return -EINVAL;
 
+   switch (format->which) {
+   case V4L2_SUBDEV_FORMAT_TRY:
+   BUG_ON(!cfg);
+   /* fall through */
+   case V4L2_SUBDEV_FORMAT_ACTIVE:
+   break;
+   default:
+   BUG();
+   }
+
if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
&mf->height, 2, H_CIF, 1, 0);
 
mf->field = V4L2_FIELD_NONE;


Thanks,
Janusz

> 
> Instead of adding such checks to all drivers, I think they instead should
> be added to the caller's side. The checks already exist for uAPI, but not
> for other drivers.
> 
> The same applies to patches until 7th (including).
> 
> > +
> > if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
> > v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
> > &mf->height, 2, H_CIF, 1, 0);
> 
> 






Re: [PATCH v3] mtd: rawnand: ams-delta: Drop board specific partition info

2019-04-25 Thread Janusz Krzysztofik
Hi Ladislav,

On Thursday, April 25, 2019 12:14:28 AM CEST Ladislav Michl wrote:
> Hi Janusz,
> 
> On Wed, Apr 24, 2019 at 08:02:12PM +0200, Janusz Krzysztofik wrote:
> > After recent modifications, only a hardcoded partition info makes
> > the driver device specific.  Other than that, the driver uses GPIO
> > exclusively and can be used on any hardware.
> > 
> > Drop the partition info and use MTD partition parser with default list
> > of parser names instead.  For the OF parser to work correctly, pass
> > device of_node to mtd.
> > 
> > Amstrad Delta users should append the following partition info to their
> > kernel command line, possibly embedding it in CONFIG_CMDLINE:
> > 
> > mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),\
> > 256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved)
> 
> now, when driver is no longer Amstrad Delta specific, why would you want
> to have ams-delta-nand hardcoded on kernel cmdline? I'm assuming at some
> point this driver will become gpio-nand [*] or something like that and
> asking users to change their kernel cmdline twice is just unwise :)

Hmm, I have no idea of a good name for the driver if not "gpio-nand". Can you 
suggest one?
As a workaround, I can add a platform device id table to the driver with "ams-
delta-nand" as a supported device name in hope that survives possible future 
driver renaming.

> [*] btw, it is really shame gpio-nand name is already taken by driver
> living in drivers/mtd/nand/raw/gpio.c which is more likely gpio-mem-nand
> used by at least CompuLab CM-X255 and Picochip picoXcell.

I think the best approach would be to expose NAND data ports of those machines 
as GPIO ports, possibly reusing the "gpio-nand" driver code while creating a 
new GPIO driver for them if "basic-mmio-gpio" occurs inappropriate, and use 
the pure GPIO NAND driver on top.

> Otherwise your work on this driver is so amazing that I just spent
> couple of hours finding that phone and compiling some decent userspace
> for it :) Thank you!

I'm glad you like it :-)
Janusz

> 
> > For their convenience, that information is added to the board Kconfig
> > entry help text, as well as CONFIG_MTD_CMDLINE_PARTS symbol is selected
> > automatically from the board Kconfig entry if the NAND driver is also
> > selected.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: Tony Lindgren 
> > Cc: Aaro Koskinen 
> > ---
> > Changelog:
> > v2->v3:
> > - add information on the requirement for passing partition info via
> >   kernel command line to the board Kconfig entry help text
> > v1->v2:
> > - fix a typo poitned out by Aaro - thanks!
> > - fix device_node not passed to OF parser via mtd_info
> > - commit message reworded and reformatted a bit for better readability
> > 
> >  arch/arm/mach-omap1/Kconfig  |  7 ++-
> >  drivers/mtd/nand/raw/ams-delta.c | 29 ++---
> >  2 files changed, 8 insertions(+), 28 deletions(-)
> > 
> > diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
> > index c4694f26b5c4..41a47d251cac 100644
> > --- a/arch/arm/mach-omap1/Kconfig
> > +++ b/arch/arm/mach-omap1/Kconfig
> > @@ -164,17 +164,22 @@ config MACH_NOKIA770
> >   have such a device.
> >  
> >  config MACH_AMS_DELTA
> > -   bool "Amstrad E3 (Delta)"
> > +   bool "Amstrad E3 (Delta) - see help for important information"
> > depends on ARCH_OMAP1 && ARCH_OMAP15XX
> > select FIQ
> > select GPIO_GENERIC_PLATFORM
> > select LEDS_GPIO_REGISTER
> > select REGULATOR
> > select REGULATOR_FIXED_VOLTAGE
> > +   select MTD_CMDLINE_PARTS if MTD_NAND_AMS_DELTA
> > help
> >   Support for the Amstrad E3 (codename Delta) videophone. Say Y 
here
> >   if you have such a device.
> >  
> > + If you are using built-in NAND, append the following partition
> > + info to kernel command line:
> > + mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-
boot_params),256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved)
> > +
> >  config MACH_OMAP_GENERIC
> > bool "Generic OMAP board"
> > depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
> > diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-
delta.c
> > index 8312182088c1..e0f09179bbda 100644
> > --- a/drivers/mtd/nand/raw/ams-delta.c
> > +++ b/drivers/mtd/nand/raw/ams-delta.c
> > @@ -41,31 +41,6 @@ struct ams_delta_nand {
> > bool  

[PATCH v3] mtd: rawnand: ams-delta: Drop board specific partition info

2019-04-24 Thread Janusz Krzysztofik
After recent modifications, only a hardcoded partition info makes
the driver device specific.  Other than that, the driver uses GPIO
exclusively and can be used on any hardware.

Drop the partition info and use MTD partition parser with default list
of parser names instead.  For the OF parser to work correctly, pass
device of_node to mtd.

Amstrad Delta users should append the following partition info to their
kernel command line, possibly embedding it in CONFIG_CMDLINE:

mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),\
256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved)

For their convenience, that information is added to the board Kconfig
entry help text, as well as CONFIG_MTD_CMDLINE_PARTS symbol is selected
automatically from the board Kconfig entry if the NAND driver is also
selected.

Signed-off-by: Janusz Krzysztofik 
Cc: Tony Lindgren 
Cc: Aaro Koskinen 
---
Changelog:
v2->v3:
- add information on the requirement for passing partition info via
  kernel command line to the board Kconfig entry help text
v1->v2:
- fix a typo poitned out by Aaro - thanks!
- fix device_node not passed to OF parser via mtd_info
- commit message reworded and reformatted a bit for better readability

 arch/arm/mach-omap1/Kconfig  |  7 ++-
 drivers/mtd/nand/raw/ams-delta.c | 29 ++---
 2 files changed, 8 insertions(+), 28 deletions(-)

diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index c4694f26b5c4..41a47d251cac 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -164,17 +164,22 @@ config MACH_NOKIA770
  have such a device.
 
 config MACH_AMS_DELTA
-   bool "Amstrad E3 (Delta)"
+   bool "Amstrad E3 (Delta) - see help for important information"
depends on ARCH_OMAP1 && ARCH_OMAP15XX
select FIQ
select GPIO_GENERIC_PLATFORM
select LEDS_GPIO_REGISTER
select REGULATOR
select REGULATOR_FIXED_VOLTAGE
+   select MTD_CMDLINE_PARTS if MTD_NAND_AMS_DELTA
help
  Support for the Amstrad E3 (codename Delta) videophone. Say Y here
  if you have such a device.
 
+ If you are using built-in NAND, append the following partition
+ info to kernel command line:
+ 
mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved)
+
 config MACH_OMAP_GENERIC
bool "Generic OMAP board"
depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index 8312182088c1..e0f09179bbda 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -41,31 +41,6 @@ struct ams_delta_nand {
booldata_in;
 };
 
-/*
- * Define partitions for flash devices
- */
-
-static const struct mtd_partition partition_info[] = {
-   { .name = "Kernel",
- .offset   = 0,
- .size = 3 * SZ_1M + SZ_512K },
-   { .name = "u-boot",
- .offset   = 3 * SZ_1M + SZ_512K,
- .size = SZ_256K },
-   { .name = "u-boot params",
- .offset   = 3 * SZ_1M + SZ_512K + SZ_256K,
- .size = SZ_256K },
-   { .name = "Amstrad LDR",
- .offset   = 4 * SZ_1M,
- .size = SZ_256K },
-   { .name = "File system",
- .offset   = 4 * SZ_1M + 1 * SZ_256K,
- .size = 27 * SZ_1M },
-   { .name = "PBL reserved",
- .offset   = 32 * SZ_1M - 3 * SZ_256K,
- .size =  3 * SZ_256K },
-};
-
 static void ams_delta_write_commit(struct ams_delta_nand *priv)
 {
gpiod_set_value(priv->gpiod_nwe, 0);
@@ -238,6 +213,7 @@ static int ams_delta_init(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
 
nand_set_controller_data(this, priv);
+   nand_set_flash_node(this, pdev->dev.of_node);
 
priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
if (IS_ERR(priv->gpiod_rdy)) {
@@ -315,8 +291,7 @@ static int ams_delta_init(struct platform_device *pdev)
return err;
 
/* Register the partitions */
-   err = mtd_device_register(mtd, partition_info,
- ARRAY_SIZE(partition_info));
+   err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
if (err)
goto err_nand_cleanup;
 
-- 
2.21.0



Re: [PATCH v2] mtd: rawnand: ams-delta: Drop board specific partition info

2019-04-18 Thread Janusz Krzysztofik
Hi Miquèl,

I'm wondering if we could register up a custom mtd partition parser from the 
board file.  It could return a pointer to a statically defined table.  Then we 
could add its name to the list of parsers the driver is going to try if the 
board is enabled in .config.
Would that be acceptable from the MTD subsystem point of view?

Thanks,
Janusz


On Thursday, April 18, 2019 8:49:29 AM CEST Miquel Raynal wrote:
> Hi Janusz,
> 
> Janusz Krzysztofik  wrote on Thu, 18 Apr 2019
> 01:09:59 +0200:
> 
> > Hi Aaro, Tony,
> > 
> > On Wednesday, April 17, 2019 11:40:10 AM CEST Miquel Raynal wrote:
> > > Hi Janusz,
> > > 
> > > Janusz Krzysztofik  wrote on Sun, 24 Mar 2019
> > > 23:33:44 +0100:
> > >   
> > > > After recent modifications, only a hardcoded partition info makes
> > > > the driver device specific.  Other than that, the driver uses GPIO
> > > > exclusively and can be used on any hardware.
> > > > 
> > > > Drop the partition info and use MTD partition parser with default list
> > > > of parser names instead.  For the OF parser to work correctly, pass
> > > > device of_node to mtd.
> > > > 
> > > > Amstrad Delta users should append the following partition info to 
their
> > > > kernel command line, possibly by embedding it in CONFIG_CMDLINE:
> > > > 
> > > > mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-
boot_params),\
> > > > 256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).
> > > > 
> > > > For their convenience, CONFIG_MTD_CMDLINE_PARTS symbol is selected
> > > > automatically from that board Kconfig if this NAND driver is also
> > > > selected.
> > > > 
> > > > Signed-off-by: Janusz Krzysztofik 
> > > > Cc: Tony Lindgren 
> > > > ---  
> > > 
> > > FYI I am okay with the change but I am waiting for acks before applying
> > > it.  
> > 
> > May we have an ack from you?
> > 
> > If still not convinced with my clarifications, I can add a comment to help 
text 
> > in Kconfig, either squashed or in a follow up patch, on the requirement of 
> > appending mtdparts parameter to command line.  What do you think?
> 
> In the same patch I guess that would be fine.
> 
> Thanks,
> Miquèl
> 






Re: [PATCH v2] mtd: rawnand: ams-delta: Drop board specific partition info

2019-04-17 Thread Janusz Krzysztofik
Hi Aaro, Tony,

On Wednesday, April 17, 2019 11:40:10 AM CEST Miquel Raynal wrote:
> Hi Janusz,
> 
> Janusz Krzysztofik  wrote on Sun, 24 Mar 2019
> 23:33:44 +0100:
> 
> > After recent modifications, only a hardcoded partition info makes
> > the driver device specific.  Other than that, the driver uses GPIO
> > exclusively and can be used on any hardware.
> > 
> > Drop the partition info and use MTD partition parser with default list
> > of parser names instead.  For the OF parser to work correctly, pass
> > device of_node to mtd.
> > 
> > Amstrad Delta users should append the following partition info to their
> > kernel command line, possibly by embedding it in CONFIG_CMDLINE:
> > 
> > mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),\
> > 256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).
> > 
> > For their convenience, CONFIG_MTD_CMDLINE_PARTS symbol is selected
> > automatically from that board Kconfig if this NAND driver is also
> > selected.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: Tony Lindgren 
> > ---
> 
> FYI I am okay with the change but I am waiting for acks before applying
> it.

May we have an ack from you?

If still not convinced with my clarifications, I can add a comment to help text 
in Kconfig, either squashed or in a follow up patch, on the requirement of 
appending mtdparts parameter to command line.  What do you think?

Thanks,
Janusz

> 
> Thanks,
> Miquèl
> 






[PATCH 09/14] media: ov6650: Fix incorrect use of JPEG colorspace

2019-04-08 Thread Janusz Krzysztofik
Since its initial submission, the driver selects V4L2_COLORSPACE_JPEG
for supported formats other than V4L2_MBUS_FMT_SBGGR8_1X8.  According
to v4l2-compliance test program, V4L2_COLORSPACE_JPEG applies
exclusively to V4L2_PIX_FMT_JPEG.  Since the sensor does not support
JPEG format, fix it to always select V4L2_COLORSPACE_SRGB.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 07d7a0708cca..dfee07ec976e 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -203,7 +203,6 @@ struct ov6650 {
unsigned long   pclk_max;   /* from resolution and format */
struct v4l2_fract   tpf;/* as requested with 
s_frame_interval */
u32 code;
-   enum v4l2_colorspacecolorspace;
 };
 
 
@@ -534,7 +533,7 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
mf->width   = priv->rect.width >> priv->half_scale;
mf->height  = priv->rect.height >> priv->half_scale;
mf->code= priv->code;
-   mf->colorspace  = priv->colorspace;
+   mf->colorspace  = V4L2_COLORSPACE_SRGB;
mf->field   = V4L2_FIELD_NONE;
 
return 0;
@@ -642,11 +641,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
priv->pclk_max = 800;
}
 
-   if (code == MEDIA_BUS_FMT_SBGGR8_1X8)
-   priv->colorspace = V4L2_COLORSPACE_SRGB;
-   else if (code != 0)
-   priv->colorspace = V4L2_COLORSPACE_JPEG;
-
if (half_scale) {
dev_dbg(&client->dev, "max resolution: QCIF\n");
coma_set |= COMA_QCIF;
@@ -677,7 +671,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct 
v4l2_mbus_framefmt *mf)
ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
 
if (!ret) {
-   mf->colorspace  = priv->colorspace;
mf->width = priv->rect.width >> half_scale;
mf->height = priv->rect.height >> half_scale;
}
@@ -711,6 +704,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
&mf->height, 2, H_CIF, 1, 0);
 
mf->field = V4L2_FIELD_NONE;
+   mf->colorspace = V4L2_COLORSPACE_SRGB;
 
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
@@ -721,13 +715,11 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
case MEDIA_BUS_FMT_YUYV8_2X8:
case MEDIA_BUS_FMT_VYUY8_2X8:
case MEDIA_BUS_FMT_UYVY8_2X8:
-   mf->colorspace = V4L2_COLORSPACE_JPEG;
break;
default:
mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
/* fall through */
case MEDIA_BUS_FMT_SBGGR8_1X8:
-   mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
}
 
@@ -1055,7 +1047,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.height = H_CIF;
priv->half_scale  = false;
priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
-   priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-- 
2.21.0



[PATCH 12/14] media: ov6650: Fix default format not applied on device probe

2019-04-08 Thread Janusz Krzysztofik
It is not clear what pixel format is actually configured in hardware on
reset.  MEDIA_BUS_FMT_YUYV8_2X8, assumed on device probe since the
driver was intiially submitted, is for sure not the one.

Fix it by explicitly applying a known, driver default frame format just
after initial device reset.

Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 drivers/media/i2c/ov6650.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index e72210653f55..8013afea0c02 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -920,6 +920,11 @@ static int ov6650_video_probe(struct v4l2_subdev *sd)
ret = ov6650_reset(client);
if (!ret)
ret = ov6650_prog_dflt(client);
+   if (!ret) {
+   struct v4l2_mbus_framefmt mf = ov6650_def_fmt;
+
+   ret = ov6650_s_fmt(sd, &mf);
+   }
if (!ret)
ret = v4l2_ctrl_handler_setup(&priv->hdl);
 
@@ -1074,8 +1079,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.top= DEF_VSTRT << 1;
priv->rect.width  = W_CIF;
priv->rect.height = H_CIF;
-   priv->half_scale  = false;
-   priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
 
priv->subdev.internal_ops = &ov6650_internal_ops;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-- 
2.21.0



Re: [PATCH] drm/i915: Use drm_dev_unplug()

2019-04-05 Thread Janusz Krzysztofik
On Fri, 2019-04-05 at 09:24 +0100, Chris Wilson wrote:
> Quoting Janusz Krzysztofik (2019-04-05 09:11:54)
> > On Fri, 2019-04-05 at 08:41 +0100, Chris Wilson wrote:
> > > Quoting Janusz Krzysztofik (2019-04-05 08:26:57)
> > > > From: Janusz Krzysztofik 
> > > > 
> > > > The driver does not currently support unbinding from a device
> > > > which
> > > > is
> > > > in use.  Since open file descriptors may still be pointing into
> > > > kernel
> > > > memory where the device structures used to be, entirely correct
> > > > kernel
> > > > panics protect the driver from being unbound as we should not
> > > > be
> > > > unbinding it before those dangling pointers have been made
> > > > safe.
> > > > 
> > > > According to the documentation found inside
> > > > drivers/gpu/drm/drm_drv.c,
> > > > drm_dev_unplug() should be used instead of drm_dev_unregister()
> > > > in
> > > > order to make a device inaccessible to users as soon as it is
> > > > unpluged.
> > > > Follow that advice to make those possibly dangling pointers
> > > > safe,
> > > > protected by DRM layer from a user who is otherwise left
> > > > pointing
> > > > into
> > > > possibly reused kernel memory after the driver has been unbound
> > > > from
> > > > the device.
> > > > 
> > > > Signed-off-by: Janusz Krzysztofik  > > > >
> > > > ---
> > > >  drivers/gpu/drm/i915/i915_drv.c | 2 +-
> > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/i915_drv.c
> > > > b/drivers/gpu/drm/i915/i915_drv.c
> > > > index 9df65d386d11..66163378c481 100644
> > > > --- a/drivers/gpu/drm/i915/i915_drv.c
> > > > +++ b/drivers/gpu/drm/i915/i915_drv.c
> > > > @@ -1596,7 +1596,7 @@ static void i915_driver_unregister(struct
> > > > drm_i915_private *dev_priv)
> > > > i915_pmu_unregister(dev_priv);
> > > >  
> > > > i915_teardown_sysfs(dev_priv);
> > > > -   drm_dev_unregister(&dev_priv->drm);
> > > > +   drm_dev_unplug(&dev_priv->drm);
> > > 
> > > I think we may have our onion inverted here. We want to stop the
> > > users
> > > as the first step, then start removing the entries. (That will
> > > also
> > > nicely invert the order from register, which is what we typically
> > > expect).
> > > 
> > > After calling i915_driver_unregister(); call
> > > i915_gem_set_wedged() to
> > > immediately (give or take external fences) cancel inflight
> > > operations.
> > 
> > OK, thanks.  Do you prefer them squashed or as serparate patches?
> 
> Quite happy to do the s/unregister/unplug/ and move in one go. Have a
> pre-emptive
> Reviewed-by: Chris Wilson 
> on that as that seems to be the right thing to do.
> 
> And there should be no issues in placing a i915_gem_set_wedged()
> immediately after the call to i915_driver_unregister, so if you
> include
> a line of commentary about why, for example
> 
> /*
>  * After unregistering the device to prevent any new users, cancel
>  * all in-flight requests so that we can quickly unbind the active
>  * resources.
>  */
> i915_gem_set_wedged(dev_priv);
> 
> Reviewed-by: Chris Wilson 

I've given it some testing, no side effects with test workloads I've
tried, and looks like it at least helps to prevent from making the
device actually wedged.

With these two patches, plus the one we discussed yesterday, and yet
another one I'm going to submit soon, I'm now able to unbind the driver
from a device while a workload is running on it, unload the module,
reload it and successfully perform basic GEM health checks, all in a
quick succession :-).

Unfortunately, not 100% reproducible, as well as not the case with
device unplug simulated by writing 1 to device/remove sysfs file.
Surely that needs the work you describe below to be done first.

Thanks for your cooperation,
Janusz


> 
> I think overall though, we need to go through i915_driver_unload()
> and
> push the module cleanup operations to i915_driver_release -- that
> will
> take a bit of surgery to separate the different phases that are
> currently smashed together.
> -Chris
> ___
> dri-devel mailing list
> dri-de...@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



[PATCH v3 0/2] media: ov6650: Add V4L2 asynchronous subdevice support

2019-03-29 Thread Janusz Krzysztofik
Janusz Krzysztofik (2):
  media: ov6650: Move v4l2_clk_get() to ov6650_video_probe() helper
  media: ov6650: Register with asynchronous subdevice framework

 ov6650.c |   44 
 1 file changed, 28 insertions(+), 16 deletions(-)

Changelog:
v2->v3:
- use v4l2_i2c_subdev_set_name() - thanks Sakari

v1->v2:
- labels should be outside conditionals - thanks Sakari
- rebased on my former fix so it applied cleanly



[PATCH v3 2/2] media: ov6650: Register with asynchronous subdevice framework

2019-03-29 Thread Janusz Krzysztofik
Register V4L2 subdevice implemented by the driver to the V4L2
asynchronous subdevice framework.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 19 ++-
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index de7d9790f054..7145bb68a9e1 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -804,8 +804,9 @@ static int ov6650_prog_dflt(struct i2c_client *client)
return ret;
 }
 
-static int ov6650_video_probe(struct i2c_client *client)
+static int ov6650_video_probe(struct v4l2_subdev *sd)
 {
+   struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
u8  pidh, pidl, midh, midl;
int ret;
@@ -817,7 +818,7 @@ static int ov6650_video_probe(struct i2c_client *client)
return ret;
}
 
-   ret = ov6650_s_power(&priv->subdev, 1);
+   ret = ov6650_s_power(sd, 1);
if (ret < 0)
goto eclkput;
 
@@ -855,7 +856,7 @@ static int ov6650_video_probe(struct i2c_client *client)
ret = v4l2_ctrl_handler_setup(&priv->hdl);
 
 done:
-   ov6650_s_power(&priv->subdev, 0);
+   ov6650_s_power(sd, 0);
if (!ret)
return 0;
 eclkput:
@@ -943,6 +944,10 @@ static const struct v4l2_subdev_ops ov6650_subdev_ops = {
.pad= &ov6650_pad_ops,
 };
 
+static const struct v4l2_subdev_internal_ops ov6650_internal_ops = {
+   .registered = ov6650_video_probe,
+};
+
 /*
  * i2c_driver function
  */
@@ -1003,7 +1008,11 @@ static int ov6650_probe(struct i2c_client *client,
priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
-   ret = ov6650_video_probe(client);
+   priv->subdev.internal_ops = &ov6650_internal_ops;
+   priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+   v4l2_i2c_subdev_set_name(&priv->subdev, client, NULL, NULL);
+
+   ret = v4l2_async_register_subdev(&priv->subdev);
if (ret)
v4l2_ctrl_handler_free(&priv->hdl);
 
@@ -1015,7 +1024,7 @@ static int ov6650_remove(struct i2c_client *client)
struct ov6650 *priv = to_ov6650(client);
 
v4l2_clk_put(priv->clk);
-   v4l2_device_unregister_subdev(&priv->subdev);
+   v4l2_async_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
 }
-- 
2.19.2



[PATCH v3 1/2] media: ov6650: Move v4l2_clk_get() to ov6650_video_probe() helper

2019-03-29 Thread Janusz Krzysztofik
In preparation for adding asynchronous subdevice support to the driver,
don't acquire v4l2_clk from the driver .probe() callback as that may
fail if the clock is provided by a bridge driver which may be not yet
initialized.  Move the v4l2_clk_get() to ov6650_video_probe() helper
which is going to be converted to v4l2_subdev_internal_ops.registered()
callback, executed only when the bridge driver is ready.

Signed-off-by: Janusz Krzysztofik 
---
 drivers/media/i2c/ov6650.c | 25 ++---
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index f9359b11fa5c..de7d9790f054 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -810,9 +810,16 @@ static int ov6650_video_probe(struct i2c_client *client)
u8  pidh, pidl, midh, midl;
int ret;
 
+   priv->clk = v4l2_clk_get(&client->dev, NULL);
+   if (IS_ERR(priv->clk)) {
+   ret = PTR_ERR(priv->clk);
+   dev_err(&client->dev, "v4l2_clk request err: %d\n", ret);
+   return ret;
+   }
+
ret = ov6650_s_power(&priv->subdev, 1);
if (ret < 0)
-   return ret;
+   goto eclkput;
 
msleep(20);
 
@@ -849,6 +856,11 @@ static int ov6650_video_probe(struct i2c_client *client)
 
 done:
ov6650_s_power(&priv->subdev, 0);
+   if (!ret)
+   return 0;
+eclkput:
+   v4l2_clk_put(priv->clk);
+
return ret;
 }
 
@@ -991,18 +1003,9 @@ static int ov6650_probe(struct i2c_client *client,
priv->code= MEDIA_BUS_FMT_YUYV8_2X8;
priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
-   priv->clk = v4l2_clk_get(&client->dev, NULL);
-   if (IS_ERR(priv->clk)) {
-   ret = PTR_ERR(priv->clk);
-   goto eclkget;
-   }
-
ret = ov6650_video_probe(client);
-   if (ret) {
-   v4l2_clk_put(priv->clk);
-eclkget:
+   if (ret)
v4l2_ctrl_handler_free(&priv->hdl);
-   }
 
return ret;
 }
-- 
2.19.2



[PATCH v2] mtd: rawnand: ams-delta: Drop board specific partition info

2019-03-24 Thread Janusz Krzysztofik
After recent modifications, only a hardcoded partition info makes
the driver device specific.  Other than that, the driver uses GPIO
exclusively and can be used on any hardware.

Drop the partition info and use MTD partition parser with default list
of parser names instead.  For the OF parser to work correctly, pass
device of_node to mtd.

Amstrad Delta users should append the following partition info to their
kernel command line, possibly by embedding it in CONFIG_CMDLINE:

mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),\
256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).

For their convenience, CONFIG_MTD_CMDLINE_PARTS symbol is selected
automatically from that board Kconfig if this NAND driver is also
selected.

Signed-off-by: Janusz Krzysztofik 
Cc: Tony Lindgren 
---
CHangelog:
v1->v2:
- fix a typo poined out by Aaro - thanks!
- fix device_node not passed to OF parser via mtd_info
- commit message reworded and reformatted a bit for better readability

 arch/arm/mach-omap1/Kconfig  |  1 +
 drivers/mtd/nand/raw/ams-delta.c | 29 ++---
 2 files changed, 3 insertions(+), 27 deletions(-)

diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index c4694f26b5c4..62cf20f22828 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -171,6 +171,7 @@ config MACH_AMS_DELTA
select LEDS_GPIO_REGISTER
select REGULATOR
select REGULATOR_FIXED_VOLTAGE
+   select MTD_CMDLINE_PARTS if MTD_NAND_AMS_DELTA
help
  Support for the Amstrad E3 (codename Delta) videophone. Say Y here
  if you have such a device.
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index 8312182088c1..e0f09179bbda 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -41,31 +41,6 @@ struct ams_delta_nand {
booldata_in;
 };
 
-/*
- * Define partitions for flash devices
- */
-
-static const struct mtd_partition partition_info[] = {
-   { .name = "Kernel",
- .offset   = 0,
- .size = 3 * SZ_1M + SZ_512K },
-   { .name = "u-boot",
- .offset   = 3 * SZ_1M + SZ_512K,
- .size = SZ_256K },
-   { .name = "u-boot params",
- .offset   = 3 * SZ_1M + SZ_512K + SZ_256K,
- .size = SZ_256K },
-   { .name = "Amstrad LDR",
- .offset   = 4 * SZ_1M,
- .size = SZ_256K },
-   { .name = "File system",
- .offset   = 4 * SZ_1M + 1 * SZ_256K,
- .size = 27 * SZ_1M },
-   { .name = "PBL reserved",
- .offset   = 32 * SZ_1M - 3 * SZ_256K,
- .size =  3 * SZ_256K },
-};
-
 static void ams_delta_write_commit(struct ams_delta_nand *priv)
 {
gpiod_set_value(priv->gpiod_nwe, 0);
@@ -238,6 +213,7 @@ static int ams_delta_init(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
 
nand_set_controller_data(this, priv);
+   nand_set_flash_node(this, pdev->dev.of_node);
 
priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
if (IS_ERR(priv->gpiod_rdy)) {
@@ -315,8 +291,7 @@ static int ams_delta_init(struct platform_device *pdev)
return err;
 
/* Register the partitions */
-   err = mtd_device_register(mtd, partition_info,
- ARRAY_SIZE(partition_info));
+   err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
if (err)
goto err_nand_cleanup;
 
-- 
2.19.2



Re: [PATCH] mtd: rawnand: ams-delta: Drop board specific partition info

2019-03-24 Thread Janusz Krzysztofik
Hi,

On Sunday, March 24, 2019 8:24:48 PM CET H. Nikolaus Schaller wrote:
> Hi,
> 
> > Am 24.03.2019 um 19:59 schrieb Aaro Koskinen :
> > 
> > Hi,
> > 
> > On Sun, Mar 24, 2019 at 05:48:22PM +0100, Janusz Krzysztofik wrote:
> >> Hi Aaro,
> >> 
> >> Thanks for your review.
> >> 
> >> On Wednesday, March 20, 2019 2:16:30 AM CET Aaro Koskinen wrote:
> >>> On Tue, Mar 19, 2019 at 11:37:18PM +0100, Janusz Krzysztofik wrote:
> >>>> After recent modifications, only a hardcoded partition info makes
> >>>> the driver device specific.  Other than that, the driver uses GPIO
> >>>> exclusively and can be used on any hardware.
> >>>> 
> >>>> Drop the partition info and use MTD partition parser with default
> >>>> list of partition types instead.
> >>>> 
> >>>> Amstrad Delta users should append the followig partition info to their
> >>>
> >>> Should be "following".
> >>> 
> >>>> kernel command line, possibly by embedding it in CONFIG_CMDLINE:
> >>>> mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),
\
> >>>> 256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).  For their
> >>>> convenience, select CONFIG_MTD_CMDLINE_PARTS  symbol from that board
> >>>> Kconfig automatically if this NAND driver is also selected.
> >>>> 
> >>>> Signed-off-by: Janusz Krzysztofik 
> >>>> Cc: Tony Lindgren 
> >>> 
> >>> Could we move the fixed partition setup to the board file
> >>> instead? Otherwise this kind of change is not really nice for the users,
> >>> as it will likely break existing setups. The default partition layout
> >>> should remain the same.
> >> 
> >> I'm wondering if it would be acceptable to pass partition info from a 
.dts 
> >> file.  I think that would be a better, more modern approach than adding a 
new 
> >> header under include/linux/platform_data.
> > 
> > Hmm, I thought there was some generic way to define partitions without
> > adding any new headers. But if that is not possible, then I guess your
> > CMDLINE proposal is the preferred one..
> 
> I am not sure what you exactly need, but partitions can be defined in
> the DTS as children of some NAND drivers. Example:
> arch/arm/boot/dts/omap3-beagle.dts
> So this design pattern could be copied instead of using CMDLINE.

The problem is, OMAP1 has no device tree support.  Other than that, your 
proposed approach already works for me locally with some basic support for 
device tree added to the board file.

Thanks,
Janusz





Re: [PATCH] mtd: rawnand: ams-delta: Drop board specific partition info

2019-03-24 Thread Janusz Krzysztofik
Hi,

On Sunday, March 24, 2019 7:59:32 PM CET Aaro Koskinen wrote:
> Hi,
> 
> On Sun, Mar 24, 2019 at 05:48:22PM +0100, Janusz Krzysztofik wrote:
> > Hi Aaro,
> > 
> > Thanks for your review.
> > 
> > On Wednesday, March 20, 2019 2:16:30 AM CET Aaro Koskinen wrote:
> > > On Tue, Mar 19, 2019 at 11:37:18PM +0100, Janusz Krzysztofik wrote:
> > > > After recent modifications, only a hardcoded partition info makes
> > > > the driver device specific.  Other than that, the driver uses GPIO
> > > > exclusively and can be used on any hardware.
> > > > 
> > > > Drop the partition info and use MTD partition parser with default
> > > > list of partition types instead.
> > > > 
> > > > Amstrad Delta users should append the followig partition info to their
> > > 
> > > Should be "following".
> > > 
> > > > kernel command line, possibly by embedding it in CONFIG_CMDLINE:
> > > > mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-
boot_params),\
> > > > 256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).  For their
> > > > convenience, select CONFIG_MTD_CMDLINE_PARTS  symbol from that board
> > > > Kconfig automatically if this NAND driver is also selected.
> > > > 
> > > > Signed-off-by: Janusz Krzysztofik 
> > > > Cc: Tony Lindgren 
> > > 
> > > Could we move the fixed partition setup to the board file
> > > instead? Otherwise this kind of change is not really nice for the users,
> > > as it will likely break existing setups. The default partition layout
> > > should remain the same.
> > 
> > I'm wondering if it would be acceptable to pass partition info from a .dts 
> > file.  I think that would be a better, more modern approach than adding a 
new 
> > header under include/linux/platform_data.
> 
> Hmm, I thought there was some generic way to define partitions without
> adding any new headers. But if that is not possible, then I guess your
> CMDLINE proposal is the preferred one..

I could for example reuse (or abuse) struct gpio_nand_platdata defined in 
include/linux/mtd/nand-gpio.h for use with drivers/mtd/nand/raw/gpio.c, but 
I'm not sure if hi-jacking a header that belongs to another driver would be an 
elegant solution.

Thanks,
Janusz


> 
> A.
> 






Re: [PATCH] mtd: rawnand: ams-delta: Drop board specific partition info

2019-03-24 Thread Janusz Krzysztofik
Hi Aaro,

Thanks for your review.

On Wednesday, March 20, 2019 2:16:30 AM CET Aaro Koskinen wrote:
> On Tue, Mar 19, 2019 at 11:37:18PM +0100, Janusz Krzysztofik wrote:
> > After recent modifications, only a hardcoded partition info makes
> > the driver device specific.  Other than that, the driver uses GPIO
> > exclusively and can be used on any hardware.
> > 
> > Drop the partition info and use MTD partition parser with default
> > list of partition types instead.
> > 
> > Amstrad Delta users should append the followig partition info to their
> 
> Should be "following".
> 
> > kernel command line, possibly by embedding it in CONFIG_CMDLINE:
> > mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),\
> > 256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).  For their
> > convenience, select CONFIG_MTD_CMDLINE_PARTS  symbol from that board
> > Kconfig automatically if this NAND driver is also selected.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: Tony Lindgren 
> 
> Could we move the fixed partition setup to the board file
> instead? Otherwise this kind of change is not really nice for the users,
> as it will likely break existing setups. The default partition layout
> should remain the same.

I'm wondering if it would be acceptable to pass partition info from a .dts 
file.  I think that would be a better, more modern approach than adding a new 
header under include/linux/platform_data.

The problem with a device tree based implementation is, I know of no u-boot 
version supporting both Amstrad Delta and FDT.  However, I've already tested 
two solutions that work for me.

One uses CONFIG_ARM_APPENDED_DTB and requires a user to manually append the 
blob to zImage and (re)generate uImage.  I'm not sure how much more user-
friendly it looks for you, compared to the command line version I proposed 
initially.

If the above is not acceptable. I can propose still another approach. The blob 
is automagically built and embedded into the kernel with some assembler glue, 
then unflattened from the board init_machine(), somehow similar to the way 
drivers/of/unittest.c does it.

Please advise which approach sounds best to you (platform_data, 
CONFIG_ARM_APPENDED_DTB or unittest like).

Thanks,
Janusz


> 
> A.
> 






[PATCH] mtd: rawnand: ams-delta: Drop board specific partition info

2019-03-19 Thread Janusz Krzysztofik
After recent modifications, only a hardcoded partition info makes
the driver device specific.  Other than that, the driver uses GPIO
exclusively and can be used on any hardware.

Drop the partition info and use MTD partition parser with default
list of partition types instead.

Amstrad Delta users should append the followig partition info to their
kernel command line, possibly by embedding it in CONFIG_CMDLINE:
mtdparts=ams-delta-nand:3584k(Kernel),256k(u-boot),256k(u-boot_params),\
256k(Amstrad_LDR),27m(File_system),768k(PBL_reserved).  For their
convenience, select CONFIG_MTD_CMDLINE_PARTS  symbol from that board
Kconfig automatically if this NAND driver is also selected.

Signed-off-by: Janusz Krzysztofik 
Cc: Tony Lindgren 
---
 arch/arm/mach-omap1/Kconfig  |  1 +
 drivers/mtd/nand/raw/ams-delta.c | 28 +---
 2 files changed, 2 insertions(+), 27 deletions(-)

diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index c4694f26b5c4..62cf20f22828 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -171,6 +171,7 @@ config MACH_AMS_DELTA
select LEDS_GPIO_REGISTER
select REGULATOR
select REGULATOR_FIXED_VOLTAGE
+   select MTD_CMDLINE_PARTS if MTD_NAND_AMS_DELTA
help
  Support for the Amstrad E3 (codename Delta) videophone. Say Y here
  if you have such a device.
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index 8312182088c1..2e8e37ea549a 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -41,31 +41,6 @@ struct ams_delta_nand {
booldata_in;
 };
 
-/*
- * Define partitions for flash devices
- */
-
-static const struct mtd_partition partition_info[] = {
-   { .name = "Kernel",
- .offset   = 0,
- .size = 3 * SZ_1M + SZ_512K },
-   { .name = "u-boot",
- .offset   = 3 * SZ_1M + SZ_512K,
- .size = SZ_256K },
-   { .name = "u-boot params",
- .offset   = 3 * SZ_1M + SZ_512K + SZ_256K,
- .size = SZ_256K },
-   { .name = "Amstrad LDR",
- .offset   = 4 * SZ_1M,
- .size = SZ_256K },
-   { .name = "File system",
- .offset   = 4 * SZ_1M + 1 * SZ_256K,
- .size = 27 * SZ_1M },
-   { .name = "PBL reserved",
- .offset   = 32 * SZ_1M - 3 * SZ_256K,
- .size =  3 * SZ_256K },
-};
-
 static void ams_delta_write_commit(struct ams_delta_nand *priv)
 {
gpiod_set_value(priv->gpiod_nwe, 0);
@@ -315,8 +290,7 @@ static int ams_delta_init(struct platform_device *pdev)
return err;
 
/* Register the partitions */
-   err = mtd_device_register(mtd, partition_info,
- ARRAY_SIZE(partition_info));
+   err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
if (err)
goto err_nand_cleanup;
 
-- 
2.19.2



[PATCH] ARM: OMAP1: ams-delta: Fix broken GPIO ID allocation

2019-03-19 Thread Janusz Krzysztofik
In order to request dynamic allocationn of GPIO IDs, a negative number
should be passed as a base GPIO ID via platform data.  Unfortuntely,
commit 771e53c4d1a1 ("ARM: OMAP1: ams-delta: Drop board specific global
GPIO numbers") didn't follow that rule while switching to dynamically
allocated GPIO IDs for Amstrad Delta latches, making their IDs
overlapping with those already assigned to OMAP GPIO devices.  Fix it.

Fixes: 771e53c4d1a1 ("ARM: OMAP1: ams-delta: Drop board specific global GPIO 
numbers")
Signed-off-by: Janusz Krzysztofik 
Cc: sta...@vger.kernel.org
---
 arch/arm/mach-omap1/board-ams-delta.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index be30c3c061b4..1b15d593837e 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -182,6 +182,7 @@ static struct resource latch1_resources[] = {
 
 static struct bgpio_pdata latch1_pdata = {
.label  = LATCH1_LABEL,
+   .base   = -1,
.ngpio  = LATCH1_NGPIO,
 };
 
@@ -219,6 +220,7 @@ static struct resource latch2_resources[] = {
 
 static struct bgpio_pdata latch2_pdata = {
.label  = LATCH2_LABEL,
+   .base   = -1,
.ngpio  = LATCH2_NGPIO,
 };
 
-- 
2.19.2



Re: [PATCH 2/5 v7] regulator: fixed/gpio: Pull inversion/OD into gpiolib

2018-11-29 Thread Janusz Krzysztofik
Hi Linus,

On Monday, November 19, 2018 8:11:23 AM CET Linus Walleij wrote:
> This pushes the handling of inversion semantics and open drain
> settings to the GPIO descriptor and gpiolib. All affected board
> files are also augmented.
> 
> This is especially nice since we don't have to have any
> confusing flags passed around to the left and right littering
> the fixed and GPIO regulator drivers and the regulator core.
> It is all just very straight-forward: the core asks the GPIO
> line to be asserted or deasserted and gpiolib deals with the
> rest depending on how the platform is configured: if the line
> is active low, it deals with that, if the line is open drain,
> it deals with that too.
> 
> Cc: Janusz Krzysztofik  # OMAP1

Tested-by: Janusz Krzysztofik  #OMAP1 Amstrad Delta

Thanks,
Janusz




[PATCH] ARM: OMAP1: ams-delta: Fix audio permanently muted

2018-11-23 Thread Janusz Krzysztofik
Since commit 1137ceee76ba ("ARM: OMAP1: ams-delta: Don't request unused
GPIOs"), on-board audio has appeared muted.  Believed to be unused GPIO
pin "hookflash1", apparently set high regardless of the corresponding
bit of "latch2" port attempted to be set low during .init_machine(),
has been identified as the reason.

According to Amstrad E3 wiki, the purpose of the pin hasn't been
clearly identified.  Original Amstrad software used to produce a high
pulse on it when the phone was taken off hook or recall was pressed.
With the current finding, we can assume the pin provides a kind of
audio mute function.

Proper resolution of the issue should be done in two steps:
- resolution of an issue with the pin state not reflecting the value
  the corresponding bit of the port was attempted to be initialized
  with,
- extension of on-board audio driver with a new control.

For now, rename the pin to "audio_mute" to reflect its function and,
as a quick fix, hogg it as output low so on-board audio can produce
audible sound again.

Fixes: 1137ceee76ba ("ARM: OMAP1: ams-delta: Don't request unused GPIOs")
Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index 3d191fd52910..1d801f5e8308 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -247,8 +247,8 @@ static struct platform_device latch2_gpio_device = {
 #define LATCH2_PIN_SCARD_CMDVCC11
 #define LATCH2_PIN_MODEM_NRESET12
 #define LATCH2_PIN_MODEM_CODEC 13
-#define LATCH2_PIN_HOOKFLASH1  14
-#define LATCH2_PIN_HOOKFLASH2  15
+#define LATCH2_PIN_AUDIO_MUTE  14
+#define LATCH2_PIN_HOOKFLASH   15
 
 static struct regulator_consumer_supply modem_nreset_consumers[] = {
REGULATOR_SUPPLY("RESET#", "serial8250.1"),
@@ -588,6 +588,8 @@ static int gpiochip_match_by_label(struct gpio_chip *chip, 
void *data)
 static struct gpiod_hog ams_delta_gpio_hogs[] = {
GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_KEYBRD_DATAOUT, "keybrd_dataout",
 GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW),
+   GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_AUDIO_MUTE, "audio_mute",
+GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW),
{},
 };
 
-- 
2.18.1



[PATCH v4 1/4] ARM: OMAP1: ams-delta: Provide GPIO lookup table for NAND data port

2018-11-21 Thread Janusz Krzysztofik
Data port used by Amstrad Delta NAND driver is actually an OMAP MPUIO
device, already under control of gpio-omap driver.  The NAND driver
gets access to the port by ioremapping it and performs read/write
operations.  That is done without any proteciton from other users
legally manipulating the port pins over GPIO API.

The plan is to convert the driver to access the port over GPIO consumer
API.  Before that is implemented, the driver can already obtain
exclusive access to the port by requesting an array of its GPIO
descriptors.

Add respective entries to the NAND GPIO lookup table.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Boris Brezillon 
Reviewed-by: Linus Walleij 
---
 arch/arm/mach-omap1/board-ams-delta.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index 3d191fd52910..30c0d18f372e 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -312,7 +312,8 @@ static struct platform_device ams_delta_nand_device = {
.resource   = ams_delta_nand_resources,
 };
 
-#define OMAP_GPIO_LABEL"gpio-0-15"
+#define OMAP_GPIO_LABEL"gpio-0-15"
+#define OMAP_MPUIO_LABEL   "mpuio"
 
 static struct gpiod_lookup_table ams_delta_nand_gpio_table = {
.table = {
@@ -324,6 +325,14 @@ static struct gpiod_lookup_table ams_delta_nand_gpio_table 
= {
GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_NWE, "nwe", 0),
GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_ALE, "ale", 0),
GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_CLE, "cle", 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 0, "data", 0, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 1, "data", 1, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 2, "data", 2, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 3, "data", 3, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 4, "data", 4, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 5, "data", 5, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 6, "data", 6, 0),
+   GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 7, "data", 7, 0),
{ },
},
 };
-- 
2.18.1



[PATCH v4 3/4] mtd: rawnand: ams-delta: Use GPIO API for data I/O

2018-11-21 Thread Janusz Krzysztofik
Don't readw()/writew() data directly from/to GPIO port which is under
control of gpio-omap driver, use GPIO consumer API instead.

The driver should now work with any 8-bit bidirectional GPIO port, not
only OMAP.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Linus Walleij 
---
 drivers/mtd/nand/raw/ams-delta.c | 109 +--
 1 file changed, 61 insertions(+), 48 deletions(-)

diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index bb50dda05654..8312182088c1 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -18,11 +18,10 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 
 /*
@@ -38,7 +37,7 @@ struct ams_delta_nand {
struct gpio_desc*gpiod_nwe;
struct gpio_desc*gpiod_ale;
struct gpio_desc*gpiod_cle;
-   void __iomem*io_base;
+   struct gpio_descs   *data_gpiods;
booldata_in;
 };
 
@@ -67,42 +66,78 @@ static const struct mtd_partition partition_info[] = {
  .size =  3 * SZ_256K },
 };
 
-static void ams_delta_io_write(struct ams_delta_nand *priv, u8 byte)
+static void ams_delta_write_commit(struct ams_delta_nand *priv)
 {
-   writew(byte, priv->io_base + OMAP_MPUIO_OUTPUT);
gpiod_set_value(priv->gpiod_nwe, 0);
ndelay(40);
gpiod_set_value(priv->gpiod_nwe, 1);
 }
 
+static void ams_delta_io_write(struct ams_delta_nand *priv, u8 byte)
+{
+   struct gpio_descs *data_gpiods = priv->data_gpiods;
+   DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, };
+
+   gpiod_set_raw_array_value(data_gpiods->ndescs, data_gpiods->desc,
+ data_gpiods->info, values);
+
+   ams_delta_write_commit(priv);
+}
+
+static void ams_delta_dir_output(struct ams_delta_nand *priv, u8 byte)
+{
+   struct gpio_descs *data_gpiods = priv->data_gpiods;
+   DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, };
+   int i;
+
+   for (i = 0; i < data_gpiods->ndescs; i++)
+   gpiod_direction_output_raw(data_gpiods->desc[i],
+  test_bit(i, values));
+
+   ams_delta_write_commit(priv);
+
+   priv->data_in = false;
+}
+
 static u8 ams_delta_io_read(struct ams_delta_nand *priv)
 {
u8 res;
+   struct gpio_descs *data_gpiods = priv->data_gpiods;
+   DECLARE_BITMAP(values, BITS_PER_TYPE(res)) = { 0, };
 
gpiod_set_value(priv->gpiod_nre, 0);
ndelay(40);
-   res = readw(priv->io_base + OMAP_MPUIO_INPUT_LATCH);
+
+   gpiod_get_raw_array_value(data_gpiods->ndescs, data_gpiods->desc,
+ data_gpiods->info, values);
+
gpiod_set_value(priv->gpiod_nre, 1);
 
+   res = values[0];
return res;
 }
 
-static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in)
+static void ams_delta_dir_input(struct ams_delta_nand *priv)
 {
-   writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL);
-   priv->data_in = in;
+   struct gpio_descs *data_gpiods = priv->data_gpiods;
+   int i;
+
+   for (i = 0; i < data_gpiods->ndescs; i++)
+   gpiod_direction_input(data_gpiods->desc[i]);
+
+   priv->data_in = true;
 }
 
 static void ams_delta_write_buf(struct ams_delta_nand *priv, const u8 *buf,
int len)
 {
-   int i;
+   int i = 0;
 
-   if (priv->data_in)
-   ams_delta_dir_input(priv, false);
+   if (len > 0 && priv->data_in)
+   ams_delta_dir_output(priv, buf[i++]);
 
-   for (i = 0; i < len; i++)
-   ams_delta_io_write(priv, buf[i]);
+   while (i < len)
+   ams_delta_io_write(priv, buf[i++]);
 }
 
 static void ams_delta_read_buf(struct ams_delta_nand *priv, u8 *buf, int len)
@@ -110,7 +145,7 @@ static void ams_delta_read_buf(struct ams_delta_nand *priv, 
u8 *buf, int len)
int i;
 
if (!priv->data_in)
-   ams_delta_dir_input(priv, true);
+   ams_delta_dir_input(priv);
 
for (i = 0; i < len; i++)
buf[i] = ams_delta_io_read(priv);
@@ -188,14 +223,9 @@ static int ams_delta_init(struct platform_device *pdev)
struct ams_delta_nand *priv;
struct nand_chip *this;
struct mtd_info *mtd;
-   struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   void __iomem *io_base;
struct gpio_descs *data_gpiods;
int err = 0;
 
-   if (!res)
-   return -ENXIO;
-
/* Allocate memory for MTD device structure and private data */
priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand),
GFP_KERNEL);
@@ -207,25 +237,13 @@ static

[PATCH v4 2/4] mtd: rawnand: ams-delta: Request data port GPIO resource

2018-11-21 Thread Janusz Krzysztofik
Data port used by the driver is actually an OMAP MPUIO device, already
under control of gpio-omap driver.  For that reason we used to not
request the memory region of the port as that would fail because the
region is already busy.  Despite that, we are still accessing the port
by just ioremapping it and performing read/write operations.  Moreover,
we are doing that without any proteciton from other users legally
manipulating the port pins over GPIO API.

The plan is to convert the driver to access the port over GPIO consumer
API.  Before that happens, already prevent from other users accessing
the port pins by requesting an array of its GPIO descriptors.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Boris Brezillon 
Reviewed-by: Linus Walleij 
---
 drivers/mtd/nand/raw/ams-delta.c | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index f8eb4a419e77..bb50dda05654 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -190,6 +190,7 @@ static int ams_delta_init(struct platform_device *pdev)
struct mtd_info *mtd;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *io_base;
+   struct gpio_descs *data_gpiods;
int err = 0;
 
if (!res)
@@ -275,8 +276,14 @@ static int ams_delta_init(struct platform_device *pdev)
goto err_unmap;
}
 
-   /* Initialize data port direction to a known state */
-   ams_delta_dir_input(priv, true);
+   /* Request array of data pins, initialize them as input */
+   data_gpiods = devm_gpiod_get_array(&pdev->dev, "data", GPIOD_IN);
+   if (IS_ERR(data_gpiods)) {
+   err = PTR_ERR(data_gpiods);
+   dev_err(&pdev->dev, "data GPIO request failed: %d\n", err);
+   goto err_unmap;
+   }
+   priv->data_in = true;
 
/* Initialize the NAND controller object embedded in ams_delta_nand. */
priv->base.ops = &ams_delta_ops;
-- 
2.18.1



[PATCH v4 4/4] ARM: OMAP1: ams-delta: Drop obsolete NAND resources

2018-11-21 Thread Janusz Krzysztofik
Amstrad Delta NAND driver now uses GPIO API for data I/O so there is no
need to assign memory I/O resource to the device any longer.  Drop it.

Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.c | 11 ---
 1 file changed, 11 deletions(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index 30c0d18f372e..d594f60c3224 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -296,20 +296,9 @@ struct modem_private_data {
 
 static struct modem_private_data modem_priv;
 
-static struct resource ams_delta_nand_resources[] = {
-   [0] = {
-   .start  = OMAP1_MPUIO_BASE,
-   .end= OMAP1_MPUIO_BASE +
-   OMAP_MPUIO_IO_CNTL + sizeof(u32) - 1,
-   .flags  = IORESOURCE_MEM,
-   },
-};
-
 static struct platform_device ams_delta_nand_device = {
.name   = "ams-delta-nand",
.id = -1,
-   .num_resources  = ARRAY_SIZE(ams_delta_nand_resources),
-   .resource   = ams_delta_nand_resources,
 };
 
 #define OMAP_GPIO_LABEL"gpio-0-15"
-- 
2.18.1



Subject: [PATCH v4 0/4] mtd: rawnand: ams-delta: Use GPIO API for data I/O

2018-11-21 Thread Janusz Krzysztofik


Finalize implementation of the idea suggested by Artem Bityutskiy and
Tony Lindgren, described in commit b027274d2e3a ("mtd: ams-delta: fix
request_mem_region() failure"). Use pure GPIO consumer API, as reqested
by Boris Brezillon.

Janusz Krzysztofik (4):
  ARM: OMAP1: ams-delta: Provide GPIO lookup table for NAND data port
  mtd: rawnand: ams-delta: Request data port GPIO resource
  mtd: rawnand: ams-delta: Use GPIO API for data I/O
  ARM: OMAP1: ams-delta: Drop obsolete NAND resources

 arch/arm/mach-omap1/board-ams-delta.c |   22 ++
 drivers/mtd/nand/raw/ams-delta.c  |  120 +++---
 2 files changed, 80 insertions(+), 62 deletions(-)

Performance on Amstrad Delta is now acceptable after recent extensions
to GPIO API and rawnanad enhancements.

Series intented to be merged via mtd tree, should not conflict with
other OMAP1 patches submitted for 4.21.

Changelog:
v4:   
- drop patches 1/7, 2/7, 5/7 6/7 - changes already merged,
- reintroduce postponed PATCH v2 06/12 as 4/4,
- rebase on nand-next for 4.21.

v3:
[PATCH v3 1/7] mtd: rawnand: ams-delta: show parent device in sysfs
- renamed and an explanation added based on other similar patches on
 Marek Vasut request, thanks.
[PATCH v3 2/7] mtd: rawnand: ams-delta: Use private structure
- no changes.
[PATCH v3 3/7] ARM: OMAP1: ams-delta: Provide GPIO lookup table for NAND
 data port
- no changes.
[PATCH v3 4/7] mtd: rawnand: ams-delta: request data port GPIO resource
- no changes.
[PATCH v3 5/7] mtd: rawnand: ams-delta: Set port direction when needed
- modified to set port direction only when needed instead of on each
 transfer as suggested by Boris, thanks, though I kept separate 
 *_next_byte() functions to maximize performance as much as possible,
- moved back in front of "mtd: rawnand: ams-delta: use GPIO API for data
 I/O" with a comment added referring to the planned switch to GPIO API.
[PATCH v3 6/7] mtd: rawnand: ams-delta: Simplify pointer resolution
- moved back in front of "mtd: rawnand: ams-delta: use GPIO API for data 
 I/O" on Boris request, thanks.
[RFC PATCH v3 7/7] mtd: rawnand: ams-delta: use GPIO API for data I/O
- rebased back on top of the two mentioned above,
- not intended to apply it yet due to performance issues on Amstrad Delta.
Removed from the series:
[RFC PATCH v2 09/12] gpiolib: Identify GPIO descriptor arrays with direct
 mapping
[RFC PATCH v2 10/12] gpiolib: Introduce bitmap get/set array API extension
[RFC PATCH v2 11/12] mtd: rawnand: ams-delta: Use GPIO API bitmap extension
[RFC PATCH v2 12/12] gpiolib: Add fast processing path to bitmap API functions
- intended to be still iterated in a follow up series until performance
 issues are resolved.
[RFC PATCH v2 06/12] ARM: OMAP1: ams-delta: drop obsolete NAND resources
- postponed until acceptable performance on Amstrad Delta is achieved.

v2:
[RFC PATCH v2 00/12] mtd: rawnand: ams-delta: Use GPIO API for data I/O
- renamed from former [RFC PATCH 0/8] mtd: rawnand: ams-delta: Use
  gpio-omap accessors for data I/O
[RFC PATCH v2 01/12] mtd: rawnand: ams-delta: Assign mtd->dev.parent,
not mtd->owner
- split out from former [RFC PATCH 1/8] on Boris request, thanks.
[RFC PATCH v2 02/12] mtd: rawnand: ams-delta: Use private structure
- remaining part of the former [RFC PATCH 1/8].
[RFC PATCH v2 03/12] ARM: OMAP1: ams-delta: Provide GPIO lookup table
for NAND data port
- split out from former [RFC PATCH 5/8] on Boris requesst, thanks,
[RFC PATCH v2 04/12] mtd: rawnand: ams-delta: request data port GPIO resource
- remaining part of the former [RFC PATCH 5/8],
[RFC PATCH v2 05/12] mtd: rawnand: ams-delta: use GPIO API for data read/write
- reworked from former [RFC PATCH 8/8] on Boris requesst to use pure
  GPIO API, thanks,
- moved up in front of former [RFC PATCH 3/8] on Boris request, thanks.
[RFC PATCH v2 06/12] ARM: OMAP1: ams-delta: drop obsolete NAND resources
- split out from former [RFC PATCH 8/8].
[RFC PATCH v2 07/12] mtd: rawnand: ams-delta: Set port direction once per
transfer
- reworked from former [RFC PATCH 3/8] on top of [RFC PATCH v2 05/12].
[RFC PATCH v2 08/12] mtd: rawnand: ams-delta: Simplify pointer resolution
on read/write
- reworked from former [RFC PATCH 4/8] on top of [RFC PATCH v2 08/12],
- renamed from 'Optimize' to 'Simplify' on Boris request, thanks.
[RFC PATCH v2 09/12] gpiolib: Identify GPIO descriptor arrays with direct
mapping
- new patch.
[RFC PATCH v2 10/12] gpiolib: Introduce bitmap get/set array API extension
- new patch.
[RFC PATCH v2 11/12] mtd: rawnand: ams-delta: Use GPIO API bitmap extension
- new patch.
[RFC PATCH v2 12/12] gpiolib: Add fast processing path to bitmap API functions
- new patch.
Removed from the series:
[RFC PATCH 2/8] mtd: rawnand: ams-delta: Write protect device during probe
- postponed on Bo

[PATCH] ARM: OMAP1: ams-delta: Fix possible use of uninitialized field

2018-11-07 Thread Janusz Krzysztofik
While playing with initialization order of modem device, it has been
discovered that under some circumstances (early console init, I
believe) its .pm() callback may be called before the
uart_port->private_data pointer is initialized from
plat_serial8250_port->private_data, resulting in NULL pointer
dereference.  Fix it by checking for uninitialized pointer before using
it in modem_pm().

Fixes: aabf31737a6a ("ARM: OMAP1: ams-delta: update the modem to use regulator 
API")
Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index 1947bc63074e..17e0b386e1b2 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -764,6 +764,9 @@ static void modem_pm(struct uart_port *port, unsigned int 
state, unsigned old)
struct modem_private_data *priv = port->private_data;
int ret;
 
+   if (!priv)
+   return;
+
if (IS_ERR(priv->regulator))
return;
 
-- 
2.16.4



[PATCH 2/3] ARM: OMAP1: ams-delta: Drop unused symbols from the board header

2018-11-07 Thread Janusz Krzysztofik
Those bitmap symbols defining pins of latch2 register, used with
read()/write() calls before the latch was converted to a GPIO device,
have been obsoleted by integer symbols defined inside the board file.

Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.h | 4 
 1 file changed, 4 deletions(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.h 
b/arch/arm/mach-omap1/board-ams-delta.h
index 06e4c64a47f8..2c3aff824cf0 100644
--- a/arch/arm/mach-omap1/board-ams-delta.h
+++ b/arch/arm/mach-omap1/board-ams-delta.h
@@ -28,10 +28,6 @@
 
 #if defined (CONFIG_MACH_AMS_DELTA)
 
-#define AMD_DELTA_LATCH2_SCARD_RSTIN   0x0400
-#define AMD_DELTA_LATCH2_SCARD_CMDVCC  0x0800
-#define AMS_DELTA_LATCH2_MODEM_CODEC   0x2000
-
 #define AMS_DELTA_GPIO_PIN_KEYBRD_DATA 0
 #define AMS_DELTA_GPIO_PIN_KEYBRD_CLK  1
 #define AMS_DELTA_GPIO_PIN_MODEM_IRQ   2
-- 
2.16.4



[PATCH 3/3] ARM: OMAP1: ams-delta: Move AMS_DELTA_LATCH2_NGPIO to the board file

2018-11-07 Thread Janusz Krzysztofik
That symbol is not used outside the board file, there is no need to
keep it in the board header.

Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.c | 6 --
 arch/arm/mach-omap1/board-ams-delta.h | 2 --
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index a6986a83a916..1947bc63074e 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -204,11 +204,13 @@ static struct platform_device latch1_gpio_device = {
 #define LATCH1_PIN_DOCKIT1 6
 #define LATCH1_PIN_DOCKIT2 7
 
+#define LATCH2_NGPIO   16
+
 static struct resource latch2_resources[] = {
[0] = {
.name   = "dat",
.start  = LATCH2_PHYS,
-   .end= LATCH2_PHYS + (AMS_DELTA_LATCH2_NGPIO - 1) / 8,
+   .end= LATCH2_PHYS + (LATCH2_NGPIO - 1) / 8,
.flags  = IORESOURCE_MEM,
},
 };
@@ -217,7 +219,7 @@ static struct resource latch2_resources[] = {
 
 static struct bgpio_pdata latch2_pdata = {
.label  = LATCH2_LABEL,
-   .ngpio  = AMS_DELTA_LATCH2_NGPIO,
+   .ngpio  = LATCH2_NGPIO,
 };
 
 static struct platform_device latch2_gpio_device = {
diff --git a/arch/arm/mach-omap1/board-ams-delta.h 
b/arch/arm/mach-omap1/board-ams-delta.h
index 2c3aff824cf0..b5c4a373b905 100644
--- a/arch/arm/mach-omap1/board-ams-delta.h
+++ b/arch/arm/mach-omap1/board-ams-delta.h
@@ -37,8 +37,6 @@
 #define AMS_DELTA_GPIO_PIN_CONFIG  11
 #define AMS_DELTA_GPIO_PIN_NAND_RB 12
 
-#define AMS_DELTA_LATCH2_NGPIO 16
-
 #endif /* CONFIG_MACH_AMS_DELTA */
 
 #endif /* __ASM_ARCH_OMAP_AMS_DELTA_H */
-- 
2.16.4



[PATCH 1/3] ARM: OMAP1: ams-delta: Drop board specific global GPIO numbers

2018-11-07 Thread Janusz Krzysztofik
As all users of the board specific GPIO pins have been converted from
legacy integer-based to descriptor-based interface, there is no longer
a need to maintain statically assigned GPIO pin numbers.  Drop support
for that.

Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.c |  3 ---
 arch/arm/mach-omap1/board-ams-delta.h | 16 
 2 files changed, 19 deletions(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index 19e0c071d675..a6986a83a916 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -167,7 +167,6 @@ static struct omap_usb_config ams_delta_usb_config 
__initdata = {
.pins[0]= 2,
 };
 
-#define LATCH1_GPIO_BASE   232
 #define LATCH1_NGPIO   8
 
 static struct resource latch1_resources[] = {
@@ -183,7 +182,6 @@ static struct resource latch1_resources[] = {
 
 static struct bgpio_pdata latch1_pdata = {
.label  = LATCH1_LABEL,
-   .base   = LATCH1_GPIO_BASE,
.ngpio  = LATCH1_NGPIO,
 };
 
@@ -219,7 +217,6 @@ static struct resource latch2_resources[] = {
 
 static struct bgpio_pdata latch2_pdata = {
.label  = LATCH2_LABEL,
-   .base   = AMS_DELTA_LATCH2_GPIO_BASE,
.ngpio  = AMS_DELTA_LATCH2_NGPIO,
 };
 
diff --git a/arch/arm/mach-omap1/board-ams-delta.h 
b/arch/arm/mach-omap1/board-ams-delta.h
index a74a306d7e77..06e4c64a47f8 100644
--- a/arch/arm/mach-omap1/board-ams-delta.h
+++ b/arch/arm/mach-omap1/board-ams-delta.h
@@ -41,22 +41,6 @@
 #define AMS_DELTA_GPIO_PIN_CONFIG  11
 #define AMS_DELTA_GPIO_PIN_NAND_RB 12
 
-#define AMS_DELTA_GPIO_PIN_LCD_VBLEN   240
-#define AMS_DELTA_GPIO_PIN_LCD_NDISP   241
-#define AMS_DELTA_GPIO_PIN_NAND_NCE242
-#define AMS_DELTA_GPIO_PIN_NAND_NRE243
-#define AMS_DELTA_GPIO_PIN_NAND_NWP244
-#define AMS_DELTA_GPIO_PIN_NAND_NWE245
-#define AMS_DELTA_GPIO_PIN_NAND_ALE246
-#define AMS_DELTA_GPIO_PIN_NAND_CLE247
-#define AMS_DELTA_GPIO_PIN_KEYBRD_PWR  248
-#define AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT  249
-#define AMS_DELTA_GPIO_PIN_SCARD_RSTIN 250
-#define AMS_DELTA_GPIO_PIN_SCARD_CMDVCC251
-#define AMS_DELTA_GPIO_PIN_MODEM_NRESET252
-#define AMS_DELTA_GPIO_PIN_MODEM_CODEC 253
-
-#define AMS_DELTA_LATCH2_GPIO_BASE AMS_DELTA_GPIO_PIN_LCD_VBLEN
 #define AMS_DELTA_LATCH2_NGPIO 16
 
 #endif /* CONFIG_MACH_AMS_DELTA */
-- 
2.16.4



[PATCH 0/3] ARN: OMAP1: ams-delta: Post-GPIO-refresh cleanups

2018-11-07 Thread Janusz Krzysztofik


Janusz Krzysztofik (3):
  ARM: OMAP1: ams-delta: Drop board specific global GPIO numbers
  ARM: OMAP1: ams-delta: Drop unused symbols from the board header
  ARM: OMAP1: ams-delta: Move AMS_DELTA_LATCH2_NGPIO to the board file

 board-ams-delta.c |9 -
 board-ams-delta.h |   22 --
 2 files changed, 4 insertions(+), 27 deletions(-)



[PATCH] ARM: OMAP1: ams-delta: Provide GPIO lookup table for LED device

2018-11-05 Thread Janusz Krzysztofik
Global GPIO numbers no longer have to be passed to leds-gpio driver,
replace their assignment with a lookup table.

Signed-off-by: Janusz Krzysztofik 
---
 arch/arm/mach-omap1/board-ams-delta.c | 95 ++-
 1 file changed, 26 insertions(+), 69 deletions(-)

diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index b8acc9912a58..19e0c071d675 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -371,15 +371,9 @@ static struct gpiod_lookup_table ams_delta_lcd_gpio_table 
= {
},
 };
 
-/*
- * Dynamically allocated GPIO numbers must be obtained fromm GPIO device
- * before they can be put in the gpio_led table.  Before that happens,
- * initialize the table with invalid GPIO numbers, not 0.
- */
 static struct gpio_led gpio_leds[] __initdata = {
[LATCH1_PIN_LED_CAMERA] = {
.name= "camera",
-   .gpio= -EINVAL,
.default_state   = LEDS_GPIO_DEFSTATE_OFF,
 #ifdef CONFIG_LEDS_TRIGGERS
.default_trigger = "ams_delta_camera",
@@ -387,27 +381,22 @@ static struct gpio_led gpio_leds[] __initdata = {
},
[LATCH1_PIN_LED_ADVERT] = {
.name= "advert",
-   .gpio= -EINVAL,
.default_state   = LEDS_GPIO_DEFSTATE_OFF,
},
[LATCH1_PIN_LED_MAIL] = {
.name= "email",
-   .gpio= -EINVAL,
.default_state   = LEDS_GPIO_DEFSTATE_OFF,
},
[LATCH1_PIN_LED_HANDSFREE] = {
.name= "handsfree",
-   .gpio= -EINVAL,
.default_state   = LEDS_GPIO_DEFSTATE_OFF,
},
[LATCH1_PIN_LED_VOICEMAIL] = {
.name= "voicemail",
-   .gpio= -EINVAL,
.default_state   = LEDS_GPIO_DEFSTATE_OFF,
},
[LATCH1_PIN_LED_VOICE] = {
.name= "voice",
-   .gpio= -EINVAL,
.default_state   = LEDS_GPIO_DEFSTATE_OFF,
},
 };
@@ -417,6 +406,24 @@ static const struct gpio_led_platform_data leds_pdata 
__initconst = {
.num_leds   = ARRAY_SIZE(gpio_leds),
 };
 
+static struct gpiod_lookup_table leds_gpio_table = {
+   .table = {
+   GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_CAMERA, NULL,
+   LATCH1_PIN_LED_CAMERA, 0),
+   GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_ADVERT, NULL,
+   LATCH1_PIN_LED_ADVERT, 0),
+   GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_MAIL, NULL,
+   LATCH1_PIN_LED_MAIL, 0),
+   GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_HANDSFREE, NULL,
+   LATCH1_PIN_LED_HANDSFREE, 0),
+   GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_VOICEMAIL, NULL,
+   LATCH1_PIN_LED_VOICEMAIL, 0),
+   GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_VOICE, NULL,
+   LATCH1_PIN_LED_VOICE, 0),
+   { },
+   },
+};
+
 static struct i2c_board_info ams_delta_camera_board_info[] = {
{
I2C_BOARD_INFO("ov6650", 0x60),
@@ -677,6 +684,8 @@ static void __init ams_delta_latch2_init(void)
 
 static void __init ams_delta_init(void)
 {
+   struct platform_device *leds_pdev;
+
/* mux pins for uarts */
omap_cfg_reg(UART1_TX);
omap_cfg_reg(UART1_RTS);
@@ -740,6 +749,12 @@ static void __init ams_delta_init(void)
gpiod_add_lookup_tables(ams_delta_gpio_tables,
ARRAY_SIZE(ams_delta_gpio_tables));
 
+   leds_pdev = gpio_led_register_device(PLATFORM_DEVID_NONE, &leds_pdata);
+   if (!IS_ERR(leds_pdev)) {
+   leds_gpio_table.dev_id = dev_name(&leds_pdev->dev);
+   gpiod_add_lookup_table(&leds_gpio_table);
+   }
+
omap_writew(omap_readw(ARM_RSTCT1) | 0x0004, ARM_RSTCT1);
 
omapfb_set_lcd_config(&ams_delta_lcd_config);
@@ -793,64 +808,6 @@ static struct platform_device ams_delta_modem_device = {
},
 };
 
-/*
- * leds-gpio driver doesn't make use of GPIO lookup tables,
- * it has to be provided with GPIO numbers over platform data
- * if GPIO descriptor info can't be obtained from device tree.
- * We could either define GPIO lookup tables and use them on behalf
- * of the leds-gpio device, or we can use GPIO driver level methods
- * for identification of GPIO numbers as long as we don't support
- * device tree.  Let's do the latter.
- */
-static void __init ams_delta_led_init(struct gpio_chip *chip)
-{
-   struct gpio_desc *gpiod;
-   int i;
-
-   f

[PATCH] ARM: OMAP1: ams-delta: make board header file local to mach-omap1

2018-11-05 Thread Janusz Krzysztofik
Now as the board header file is no longer included by drivers, move it
to the root directory of mach-omap1.

Signed-off-by: Janusz Krzysztofik 
---
Changelog:
v4:
- rebased on top of v4.20-rc1
- resubmitted as a standalone patch, other patches of the series it
  depended on have been already applied

v3:
- rebased on top of v4.19-rc1
- submitted as PATCH v3 3/3

v2:
- resent as PATCH v2 3/3

Initially submitted in series as PATCH 6/6


 arch/arm/mach-omap1/ams-delta-fiq-handler.S  | 2 +-
 arch/arm/mach-omap1/ams-delta-fiq.c  | 3 +--
 arch/arm/mach-omap1/board-ams-delta.c| 2 +-
 arch/arm/mach-omap1/{include/mach => }/board-ams-delta.h | 2 +-
 4 files changed, 4 insertions(+), 5 deletions(-)
 rename arch/arm/mach-omap1/{include/mach => }/board-ams-delta.h (97%)

diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S 
b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index e3faa0274b56..7c9fb7fe0070 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -18,9 +18,9 @@
 #include 
 
 #include 
-#include 
 
 #include "ams-delta-fiq.h"
+#include "board-ams-delta.h"
 #include "iomap.h"
 #include "soc.h"
 
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c 
b/arch/arm/mach-omap1/ams-delta-fiq.c
index b0dc7ddf5877..14c3d3f5255e 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -22,11 +22,10 @@
 #include 
 #include 
 
-#include 
-
 #include 
 
 #include "ams-delta-fiq.h"
+#include "board-ams-delta.h"
 
 static struct fiq_handler fh = {
.name   = "ams-delta-fiq"
diff --git a/arch/arm/mach-omap1/board-ams-delta.c 
b/arch/arm/mach-omap1/board-ams-delta.c
index 3d191fd52910..b8acc9912a58 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -36,7 +36,6 @@
 #include 
 #include 
 
-#include 
 #include 
 #include 
 
@@ -45,6 +44,7 @@
 #include 
 
 #include "ams-delta-fiq.h"
+#include "board-ams-delta.h"
 #include "iomap.h"
 #include "common.h"
 
diff --git a/arch/arm/mach-omap1/include/mach/board-ams-delta.h 
b/arch/arm/mach-omap1/board-ams-delta.h
similarity index 97%
rename from arch/arm/mach-omap1/include/mach/board-ams-delta.h
rename to arch/arm/mach-omap1/board-ams-delta.h
index 3b2d8019238a..a74a306d7e77 100644
--- a/arch/arm/mach-omap1/include/mach/board-ams-delta.h
+++ b/arch/arm/mach-omap1/board-ams-delta.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/board-ams-delta.h
+ * arch/arm/mach-omap1/board-ams-delta.h
  *
  * Copyright (C) 2006 Jonathan McDowell 
  *
-- 
2.16.4



  1   2   3   >