[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-24 Thread Thierry Reding
On Thu, Jul 24, 2014 at 09:57:04AM +0200, Andrzej Hajda wrote:
> On 07/23/2014 03:37 PM, Thierry Reding wrote:
> > On Wed, Jul 23, 2014 at 12:59:46PM +0200, Andrzej Hajda wrote:
> >> On 07/23/2014 09:51 AM, Thierry Reding wrote:
> >>> On Tue, Jul 22, 2014 at 11:33:11AM +0200, Andrzej Hajda wrote:
>  On 07/22/2014 10:12 AM, Thierry Reding wrote:
> > On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
> >> On 07/22/2014 09:12 AM, Thierry Reding wrote:
> >>> From: Thierry Reding 
> >>>
> >>> Currently the mipi_dsi_dcs_write() function requires the DCS command
> >>> byte to be embedded within the write buffer whereas 
> >>> mipi_dsi_dcs_read()
> >>> has a separate parameter. Make them more symmetrical by adding an 
> >>> extra
> >>> command parameter to mipi_dsi_dcs_write().
> >>>
> >>> Also update the S6E8AA0 panel driver (the only user of this API) to
> >>> adapt to this new API.
> >> I do not agree with that. DCS read and write are not symmetrical by 
> >> design:
> >> - write just sends data,
> >> - read sends data then reads response.
> >>
> >> Forcing API to be symmetrical complicates the implementation without 
> >> real gain.
> > Why does it complicate anything?
>  Why? Lets see:
> 
>   drivers/gpu/drm/drm_mipi_dsi.c| 45 
>  ---
>   drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
>   include/drm/drm_mipi_dsi.h|  4 ++--
>   3 files changed, 35 insertions(+), 18 deletions(-)
> 
> 
>  Original function has two vars, one 'if', one 'switch' and one operation
>  call, nothing more.
>  You proposes to add new vars, kmalloc with no memory handling, memcpy,
>  playing with indices, conditional kfree. Isn't it enough to call it more
>  complicated? :)
> >>> It certainly makes the implementation of mipi_dsi_dcs_write() slightly
> >>> more complicated, but the point is that it makes it easier for users of
> >>> the API. So the complexity moves into one central location rather than
> >>> each call site. Ultimately that will reduce overall complexity.
> >> I guess it will increase complexity. If you look at the s6e8aa0 or any
> >> other driver using DCS commands you will see the most DCS commands have
> >> constant arguments, so driver uses small static arrays without copying
> >> them to temporary variables. With your approach every time you will have
> >> to allocate tiny memory bufs, memcpy to them and deallocate them later.
> > Yes, there are certainly additional costs. But they give us more
> > consistency in return. The whole point of having MIPI DCS helpers is so
> > that they can take away some of the work that drivers have to do. This
> > is core code
> >
> >> I terms of drivers code simplicity, current version with proposed macros
> >> do better job.
> > Quite frankly, I think they result in horrible code. The s6e8aa0 driver
> > is currently not much more than a huge set of tables that are dumped to
> > hardware.
> >
> > And of course that's "simple", but it's also completely unreadable and
> > makes it really difficult to factor out common pieces of code. Of course
> > the driver then also goes and uses these macros to execute standard DCS
> > commands instead of doing the right thing and writing proper functions
> > so that other drivers can reuse them. Yes, that's simple for the
> > individual drivers but it doesn't help us at all in the big picture.
> 
> Hmm, I think you look at the wrong driver :) panel-s6e8aa0.c uses only
> four DCS commands:
> s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
> s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
> s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
> I see it rather readable :)

When I was talking about readable I wasn't talking about these. These
are what I said should be generic functions. They aren't s6e8aa0
specific at all, therefore shouldn't be using s6e8aa0 specific
functions.

> The rest of DSI transactions are MCS commands,  completely undocumented
> - I had no access to datasheet for this
> panel/IC driver during driver development.

So did you just guess the right sequences? Somebody must have had access
to the documentation at some point.

> How do you imagine 'proper functions' in such situation?

I agree that that's a problem. However I think we should try really hard
to get access to proper documentation. We require other drivers to avoid
these kinds of magic values, why should panels be different?

While there may be circumstances where it's simply not possible to get
access to the documentation, providing an API that allows to pass in any
arbitrary binary buffer actively encourages this kind of behaviour. I
know that we can't really prevent it by extracting the command into a
separate function argument, but 

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-24 Thread Andrzej Hajda
On 07/23/2014 03:37 PM, Thierry Reding wrote:
> On Wed, Jul 23, 2014 at 12:59:46PM +0200, Andrzej Hajda wrote:
>> On 07/23/2014 09:51 AM, Thierry Reding wrote:
>>> On Tue, Jul 22, 2014 at 11:33:11AM +0200, Andrzej Hajda wrote:
 On 07/22/2014 10:12 AM, Thierry Reding wrote:
> On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
>> On 07/22/2014 09:12 AM, Thierry Reding wrote:
>>> From: Thierry Reding 
>>>
>>> Currently the mipi_dsi_dcs_write() function requires the DCS command
>>> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
>>> has a separate parameter. Make them more symmetrical by adding an extra
>>> command parameter to mipi_dsi_dcs_write().
>>>
>>> Also update the S6E8AA0 panel driver (the only user of this API) to
>>> adapt to this new API.
>> I do not agree with that. DCS read and write are not symmetrical by 
>> design:
>> - write just sends data,
>> - read sends data then reads response.
>>
>> Forcing API to be symmetrical complicates the implementation without 
>> real gain.
> Why does it complicate anything?
 Why? Lets see:

  drivers/gpu/drm/drm_mipi_dsi.c| 45 
 ---
  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
  include/drm/drm_mipi_dsi.h|  4 ++--
  3 files changed, 35 insertions(+), 18 deletions(-)


 Original function has two vars, one 'if', one 'switch' and one operation
 call, nothing more.
 You proposes to add new vars, kmalloc with no memory handling, memcpy,
 playing with indices, conditional kfree. Isn't it enough to call it more
 complicated? :)
>>> It certainly makes the implementation of mipi_dsi_dcs_write() slightly
>>> more complicated, but the point is that it makes it easier for users of
>>> the API. So the complexity moves into one central location rather than
>>> each call site. Ultimately that will reduce overall complexity.
>> I guess it will increase complexity. If you look at the s6e8aa0 or any
>> other driver using DCS commands you will see the most DCS commands have
>> constant arguments, so driver uses small static arrays without copying
>> them to temporary variables. With your approach every time you will have
>> to allocate tiny memory bufs, memcpy to them and deallocate them later.
> Yes, there are certainly additional costs. But they give us more
> consistency in return. The whole point of having MIPI DCS helpers is so
> that they can take away some of the work that drivers have to do. This
> is core code
>
>> I terms of drivers code simplicity, current version with proposed macros
>> do better job.
> Quite frankly, I think they result in horrible code. The s6e8aa0 driver
> is currently not much more than a huge set of tables that are dumped to
> hardware.
>
> And of course that's "simple", but it's also completely unreadable and
> makes it really difficult to factor out common pieces of code. Of course
> the driver then also goes and uses these macros to execute standard DCS
> commands instead of doing the right thing and writing proper functions
> so that other drivers can reuse them. Yes, that's simple for the
> individual drivers but it doesn't help us at all in the big picture.

Hmm, I think you look at the wrong driver :) panel-s6e8aa0.c uses only
four DCS commands:
s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
I see it rather readable :)

The rest of DSI transactions are MCS commands,  completely undocumented
- I had no access to datasheet for this
panel/IC driver during driver development. How do you imagine 'proper
functions' in such situation?

> Some of this could possibly be alleviated by adding separate functions
> for standard commands. But either way, I think having this kind of
> symmetry within an API is always good (it's consistent). By the law of
> least surprise people will actually expect mipi_dsi_dcs_write() to take
> a command as a second parameter.
 As I wrote earlier I do not see symmetry here: dcs-read is in fact write
 and read,
 dcs-write is just write. Hiding this fact in API does not seems to me
 good, but I guess
 it is rather matter of taste.
>>> The symmetry isn't about the physical transfers. It's a logical
>>> symmetry. Each DCS command is identified by a command, whether it's a
>>> read or a write.
>> If you insist on it maybe it will be better to leave my version of
>> mipi_dsi_dcs_write, maybe renamed to mipi_dsi_dcs_write_buf or sth
>> similar and add your version using internally my version. This way
>> you will have your symmetry and I will keep my simplicity :)
> Maybe that would be an alternative. I'll think about it.
>
>>> There's a 

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-23 Thread Thierry Reding
On Wed, Jul 23, 2014 at 12:59:46PM +0200, Andrzej Hajda wrote:
> On 07/23/2014 09:51 AM, Thierry Reding wrote:
> > On Tue, Jul 22, 2014 at 11:33:11AM +0200, Andrzej Hajda wrote:
> >> On 07/22/2014 10:12 AM, Thierry Reding wrote:
> >>> On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
>  On 07/22/2014 09:12 AM, Thierry Reding wrote:
> > From: Thierry Reding 
> >
> > Currently the mipi_dsi_dcs_write() function requires the DCS command
> > byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
> > has a separate parameter. Make them more symmetrical by adding an extra
> > command parameter to mipi_dsi_dcs_write().
> >
> > Also update the S6E8AA0 panel driver (the only user of this API) to
> > adapt to this new API.
>  I do not agree with that. DCS read and write are not symmetrical by 
>  design:
>  - write just sends data,
>  - read sends data then reads response.
> 
>  Forcing API to be symmetrical complicates the implementation without 
>  real gain.
> >>> Why does it complicate anything?
> >>
> >> Why? Lets see:
> >>
> >>  drivers/gpu/drm/drm_mipi_dsi.c| 45 
> >> ---
> >>  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
> >>  include/drm/drm_mipi_dsi.h|  4 ++--
> >>  3 files changed, 35 insertions(+), 18 deletions(-)
> >>
> >>
> >> Original function has two vars, one 'if', one 'switch' and one operation
> >> call, nothing more.
> >> You proposes to add new vars, kmalloc with no memory handling, memcpy,
> >> playing with indices, conditional kfree. Isn't it enough to call it more
> >> complicated? :)
> > 
> > It certainly makes the implementation of mipi_dsi_dcs_write() slightly
> > more complicated, but the point is that it makes it easier for users of
> > the API. So the complexity moves into one central location rather than
> > each call site. Ultimately that will reduce overall complexity.
> 
> I guess it will increase complexity. If you look at the s6e8aa0 or any
> other driver using DCS commands you will see the most DCS commands have
> constant arguments, so driver uses small static arrays without copying
> them to temporary variables. With your approach every time you will have
> to allocate tiny memory bufs, memcpy to them and deallocate them later.

Yes, there are certainly additional costs. But they give us more
consistency in return. The whole point of having MIPI DCS helpers is so
that they can take away some of the work that drivers have to do. This
is core code

> I terms of drivers code simplicity, current version with proposed macros
> do better job.

Quite frankly, I think they result in horrible code. The s6e8aa0 driver
is currently not much more than a huge set of tables that are dumped to
hardware.

And of course that's "simple", but it's also completely unreadable and
makes it really difficult to factor out common pieces of code. Of course
the driver then also goes and uses these macros to execute standard DCS
commands instead of doing the right thing and writing proper functions
so that other drivers can reuse them. Yes, that's simple for the
individual drivers but it doesn't help us at all in the big picture.

> >>> Some of this could possibly be alleviated by adding separate functions
> >>> for standard commands. But either way, I think having this kind of
> >>> symmetry within an API is always good (it's consistent). By the law of
> >>> least surprise people will actually expect mipi_dsi_dcs_write() to take
> >>> a command as a second parameter.
> >>
> >> As I wrote earlier I do not see symmetry here: dcs-read is in fact write
> >> and read,
> >> dcs-write is just write. Hiding this fact in API does not seems to me
> >> good, but I guess
> >> it is rather matter of taste.
> > 
> > The symmetry isn't about the physical transfers. It's a logical
> > symmetry. Each DCS command is identified by a command, whether it's a
> > read or a write.
> 
> If you insist on it maybe it will be better to leave my version of
> mipi_dsi_dcs_write, maybe renamed to mipi_dsi_dcs_write_buf or sth
> similar and add your version using internally my version. This way
> you will have your symmetry and I will keep my simplicity :)

Maybe that would be an alternative. I'll think about it.

> > There's a similar dissymmetry in how the payload length is handled.
> > Currently peripheral drivers need to encode that within the payload
> > buffer, and DSI host drivers need to parse it out of that depending on
> > the type of write. That makes it needlessly difficult for host drivers
> > and I think the interface would be much easier to use if peripheral
> > drivers specified the payload (and its length) only and let drivers
> > obtain the length of writes from the .tx_len field.
> 
> I am not sure if I understand correctly. Where the peripherals encodes
> payload length in payload buffer?

Heh, it's not encoded in the payload buffer, which makes this even
weirder. B

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-23 Thread Andrzej Hajda
On 07/23/2014 09:51 AM, Thierry Reding wrote:
> On Tue, Jul 22, 2014 at 11:33:11AM +0200, Andrzej Hajda wrote:
>> On 07/22/2014 10:12 AM, Thierry Reding wrote:
>>> On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
 On 07/22/2014 09:12 AM, Thierry Reding wrote:
> From: Thierry Reding 
>
> Currently the mipi_dsi_dcs_write() function requires the DCS command
> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
> has a separate parameter. Make them more symmetrical by adding an extra
> command parameter to mipi_dsi_dcs_write().
>
> Also update the S6E8AA0 panel driver (the only user of this API) to
> adapt to this new API.
 I do not agree with that. DCS read and write are not symmetrical by design:
 - write just sends data,
 - read sends data then reads response.

 Forcing API to be symmetrical complicates the implementation without real 
 gain.
>>> Why does it complicate anything?
>>
>> Why? Lets see:
>>
>>  drivers/gpu/drm/drm_mipi_dsi.c| 45 
>> ---
>>  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
>>  include/drm/drm_mipi_dsi.h|  4 ++--
>>  3 files changed, 35 insertions(+), 18 deletions(-)
>>
>>
>> Original function has two vars, one 'if', one 'switch' and one operation
>> call, nothing more.
>> You proposes to add new vars, kmalloc with no memory handling, memcpy,
>> playing with indices, conditional kfree. Isn't it enough to call it more
>> complicated? :)
> 
> It certainly makes the implementation of mipi_dsi_dcs_write() slightly
> more complicated, but the point is that it makes it easier for users of
> the API. So the complexity moves into one central location rather than
> each call site. Ultimately that will reduce overall complexity.

I guess it will increase complexity. If you look at the s6e8aa0 or any
other driver using DCS commands you will see the most DCS commands have
constant arguments, so driver uses small static arrays without copying
them to temporary variables. With your approach every time you will have
to allocate tiny memory bufs, memcpy to them and deallocate them later.

I terms of drivers code simplicity, current version with proposed macros
do better job.

> 
>>>  Granted we need to dynamically allocate
>>> a buffer for each transfer, but it's all hidden away in a common helper
>>> function. The big advantage in using a separate parameter for the
>>> command is that it makes it trivial to implement the majority of DCS
>>> commands, like this:
>>>
>>> const u8 format = 0x77;
>>> const u8 mode = 0x00;
>>>
>>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
>>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, 1);
>>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &mode, 1);
>>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
>>
>> For this I have proposed once more universal macro, sth like this:
>>
>> #define mipi_dsi_dcs_write_seq(dsi, seq...) \
>> ({\
>> const u8 d[] = { seq };\
>> BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
>> mipi_dsi_dcs_write(dsi, d, ARRAY_SIZE(d));\
>> })
>>
>> It makes trivial to implement ALL DCS commands in much more readable manner.
>> Please compare with your examples above:
>> mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SOFT_RESET);
>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x77);
>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, 0);
>> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON);
>>
>> It could be also accompanied by static version, for memory optimization:
>>
>> #define mipi_dsi_dcs_write_seq_static(dsi, seq...) \
>> ({\
>> static const u8 d[] = { seq };\
>> mipi_dsi_dcs_write(dsi, d, ARRAY_SIZE(d));\
>> })
> 
> I've said before why I dislike these macros. One alternative for the
> above would be to add something like a mipi_dsi_dcs_writev() function
> that takes a variable list of arguments,

Few greps in sources shows kernel prefers variadic macros over variadic
functions. Few examples:
#define or51132_writebytes(state, data...)
#define sn9c102_write_const_regs(sn9c102_device, data...)
#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...)
#define media_entity_call(entity, operation, args...)
#define call_memop(vb, op, args...)
#define __pcpu_size_call(stem, variable, ...)
#define rsnd_platform_call(priv, dai, func, param...)
#define send_seq(priv, data...)


> somewhat like this:
> 
>   ssize_t mipi_dsi_dcs_writev(struct mipi_dsi_device *dsi, u8 command,
>   unsigned int count, ...)
>   {
>   ...
>   }
> 
> And the above would become:
> 
>   mipi_dsi_dcs_writev(dsi, MIPI_DCS_SOFT_RESET, 0);
>   mipi_dsi_dcs_writev(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 1, 0x77);
>   ...
> 
> That's still one argument more, but at least it isn't a macro.
> 
> Thierry
> 
>>
>>
>>>
>>> Without the extra parameter, the above beco

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-23 Thread Thierry Reding
On Tue, Jul 22, 2014 at 11:33:11AM +0200, Andrzej Hajda wrote:
> On 07/22/2014 10:12 AM, Thierry Reding wrote:
> > On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
> >> On 07/22/2014 09:12 AM, Thierry Reding wrote:
> >>> From: Thierry Reding 
> >>>
> >>> Currently the mipi_dsi_dcs_write() function requires the DCS command
> >>> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
> >>> has a separate parameter. Make them more symmetrical by adding an extra
> >>> command parameter to mipi_dsi_dcs_write().
> >>>
> >>> Also update the S6E8AA0 panel driver (the only user of this API) to
> >>> adapt to this new API.
> >> I do not agree with that. DCS read and write are not symmetrical by design:
> >> - write just sends data,
> >> - read sends data then reads response.
> >>
> >> Forcing API to be symmetrical complicates the implementation without real 
> >> gain.
> > Why does it complicate anything?
> 
> Why? Lets see:
> 
>  drivers/gpu/drm/drm_mipi_dsi.c| 45 
> ---
>  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
>  include/drm/drm_mipi_dsi.h|  4 ++--
>  3 files changed, 35 insertions(+), 18 deletions(-)
> 
> 
> Original function has two vars, one 'if', one 'switch' and one operation
> call, nothing more.
> You proposes to add new vars, kmalloc with no memory handling, memcpy,
> playing with indices, conditional kfree. Isn't it enough to call it more
> complicated? :)

It certainly makes the implementation of mipi_dsi_dcs_write() slightly
more complicated, but the point is that it makes it easier for users of
the API. So the complexity moves into one central location rather than
each call site. Ultimately that will reduce overall complexity.

> >  Granted we need to dynamically allocate
> > a buffer for each transfer, but it's all hidden away in a common helper
> > function. The big advantage in using a separate parameter for the
> > command is that it makes it trivial to implement the majority of DCS
> > commands, like this:
> >
> > const u8 format = 0x77;
> > const u8 mode = 0x00;
> >
> > mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
> > mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, 1);
> > mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &mode, 1);
> > mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
> 
> For this I have proposed once more universal macro, sth like this:
> 
> #define mipi_dsi_dcs_write_seq(dsi, seq...) \
> ({\
> const u8 d[] = { seq };\
> BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
> mipi_dsi_dcs_write(dsi, d, ARRAY_SIZE(d));\
> })
> 
> It makes trivial to implement ALL DCS commands in much more readable manner.
> Please compare with your examples above:
> mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SOFT_RESET);
> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x77);
> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, 0);
> mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON);
> 
> It could be also accompanied by static version, for memory optimization:
> 
> #define mipi_dsi_dcs_write_seq_static(dsi, seq...) \
> ({\
> static const u8 d[] = { seq };\
> mipi_dsi_dcs_write(dsi, d, ARRAY_SIZE(d));\
> })

I've said before why I dislike these macros. One alternative for the
above would be to add something like a mipi_dsi_dcs_writev() function
that takes a variable list of arguments, somewhat like this:

ssize_t mipi_dsi_dcs_writev(struct mipi_dsi_device *dsi, u8 command,
unsigned int count, ...)
{
...
}

And the above would become:

mipi_dsi_dcs_writev(dsi, MIPI_DCS_SOFT_RESET, 0);
mipi_dsi_dcs_writev(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 1, 0x77);
...

That's still one argument more, but at least it isn't a macro.

Thierry

> 
> 
> >
> > Without the extra parameter, the above becomes:
> >
> > const u8 data[1] = { MIPI_DCS_SOFT_RESET };
> > mipi_dsi_dcs_write(dsi, data, sizeof(data));
> >
> > const u8 data[2] = { MIPI_DCS_SET_PIXEL_FORMAT, 0x77 };
> > mipi_dsi_dcs_write(dsi, data, sizeof(data));
> >
> > const u8 data[2] = { MIPI_DCS_SET_TEAR_ON, 0x00 };
> > mipi_dsi_dcs_write(dsi, data, sizeof(data));
> >
> > const u8 data[1] = { MIPI_DCS_SET_DISPLAY_ON };
> > mipi_dsi_dcs_write(dsi, data, sizeof(data));
> >
> > In this form it looks still rather readable, but if you need to do this
> > within an initialization function, it become fairly cluttered:
> >
> > const u8 soft_reset[1] = { MIPI_DCS_SOFT_RESET };
> > const u8 set_pixel_format[2] = { MIPI_DCS_SET_PIXEL_FORMAT, 0x77 };
> > const u8 set_tear_on[2] = { MIPI_DCS_SET_TEAR_ON, 0x00 };
> > const u8 set_display_on[1] = { MIPI_DCS_SET_DISPLAY_ON };
> >
> > mipi_dsi_dcs_write(dsi, soft_reset, sizeof(soft_reset));
> >
> > mipi_dsi_dcs_write(dsi, set_pixel_format, sizeof(set_pixel_format));
> >
> > mipi_dsi_d

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-23 Thread Andrzej Hajda
On 07/22/2014 01:20 PM, Daniel Vetter wrote:
> On Tue, Jul 22, 2014 at 09:12:20AM +0200, Thierry Reding wrote:
>> From: Thierry Reding 
>>
>> Currently the mipi_dsi_dcs_write() function requires the DCS command
>> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
>> has a separate parameter. Make them more symmetrical by adding an extra
>> command parameter to mipi_dsi_dcs_write().
>>
>> Also update the S6E8AA0 panel driver (the only user of this API) to
>> adapt to this new API.
>>
>> Signed-off-by: Thierry Reding 
> Given the patterns established by other sideband subsystesm like i2c or
> the dp aux helpers we have in drm I think this is going into the right
> direction. Also, this seems to match somewhat the style we have in our
> hand-rolled intel dsi implementation. So I think this makes sense.

Could you point me out the patterns you are referring to.

Regarding intel dsi implementation I have found in intel_dsi_cmd.h:

int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
const u8 *data, int len);
int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel,
u8 dcs_cmd, u8 *buf, int buflen);

This is the same approach as in the current drm mipi, no forced symmetry.

There are also helpers for simple DCS commands: dsi_vc_dcs_write_[01],
but they
are using dsi_vc_dcs_write internally, which seems to me more reasonable.

Regards
Andrzej

>
> Reviewed-by: Daniel Vetter 
>> ---
>>  drivers/gpu/drm/drm_mipi_dsi.c| 45 
>> ---
>>  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
>>  include/drm/drm_mipi_dsi.h|  4 ++--
>>  3 files changed, 35 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
>> index 6aa6a9e95570..bbab06ef80c9 100644
>> --- a/drivers/gpu/drm/drm_mipi_dsi.c
>> +++ b/drivers/gpu/drm/drm_mipi_dsi.c
>> @@ -201,29 +201,41 @@ EXPORT_SYMBOL(mipi_dsi_detach);
>>  /**
>>   * mipi_dsi_dcs_write - send DCS write command
>>   * @dsi: DSI device
>> - * @data: pointer to the command followed by parameters
>> - * @len: length of @data
>> + * @cmd: DCS command
>> + * @data: pointer to the command payload
>> + * @len: payload length
>>   */
>> -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
>> -size_t len)
>> +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
>> +   const void *data, size_t len)
>>  {
>>  const struct mipi_dsi_host_ops *ops = dsi->host->ops;
>> -struct mipi_dsi_msg msg = {
>> -.channel = dsi->channel,
>> -.tx_buf = data,
>> -.tx_len = len
>> -};
>> +struct mipi_dsi_msg msg;
>> +ssize_t err;
>> +u8 *tx;
>>  
>>  if (!ops || !ops->transfer)
>>  return -ENOSYS;
>>  
>> +if (len > 0) {
>> +tx = kmalloc(1 + len, GFP_KERNEL);
>> +if (!tx)
>> +return -ENOMEM;
>> +
>> +tx[0] = cmd;
>> +memcpy(tx + 1, data, len);
>> +} else {
>> +tx = &cmd;
>> +}
>> +
>> +msg.channel = dsi->channel;
>> +msg.tx_len = 1 + len;
>> +msg.tx_buf = tx;
>> +
>>  switch (len) {
>>  case 0:
>> -return -EINVAL;
>> -case 1:
>>  msg.type = MIPI_DSI_DCS_SHORT_WRITE;
>>  break;
>> -case 2:
>> +case 1:
>>  msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
>>  break;
>>  default:
>> @@ -231,14 +243,19 @@ ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device 
>> *dsi, const void *data,
>>  break;
>>  }
>>  
>> -return ops->transfer(dsi->host, &msg);
>> +err = ops->transfer(dsi->host, &msg);
>> +
>> +if (len > 0)
>> +kfree(tx);
>> +
>> +return err;
>>  }
>>  EXPORT_SYMBOL(mipi_dsi_dcs_write);
>>  
>>  /**
>>   * mipi_dsi_dcs_read - send DCS read request command
>>   * @dsi: DSI device
>> - * @cmd: DCS read command
>> + * @cmd: DCS command
>>   * @data: pointer to read buffer
>>   * @len: length of @data
>>   *
>> diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c 
>> b/drivers/gpu/drm/panel/panel-s6e8aa0.c
>> index 5502ef6bc074..d39bee36816c 100644
>> --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c
>> +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
>> @@ -130,7 +130,7 @@ static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
>>  return ret;
>>  }
>>  
>> -static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t 
>> len)
>> +static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const u8 *data, size_t 
>> len)
>>  {
>>  struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
>>  ssize_t ret;
>> @@ -138,7 +138,7 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const 
>> void *data, size_t len)
>>  if (ctx->error < 0)
>>  return;
>>  
>> -ret = mipi_dsi_dcs_write(dsi, data, len);
>> +ret = mipi_dsi_dcs_write(dsi, data[0], data + 1, len - 1);
>> 

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-22 Thread Daniel Vetter
On Tue, Jul 22, 2014 at 09:12:20AM +0200, Thierry Reding wrote:
> From: Thierry Reding 
> 
> Currently the mipi_dsi_dcs_write() function requires the DCS command
> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
> has a separate parameter. Make them more symmetrical by adding an extra
> command parameter to mipi_dsi_dcs_write().
> 
> Also update the S6E8AA0 panel driver (the only user of this API) to
> adapt to this new API.
> 
> Signed-off-by: Thierry Reding 

Given the patterns established by other sideband subsystesm like i2c or
the dp aux helpers we have in drm I think this is going into the right
direction. Also, this seems to match somewhat the style we have in our
hand-rolled intel dsi implementation. So I think this makes sense.

Reviewed-by: Daniel Vetter 
> ---
>  drivers/gpu/drm/drm_mipi_dsi.c| 45 
> ---
>  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
>  include/drm/drm_mipi_dsi.h|  4 ++--
>  3 files changed, 35 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
> index 6aa6a9e95570..bbab06ef80c9 100644
> --- a/drivers/gpu/drm/drm_mipi_dsi.c
> +++ b/drivers/gpu/drm/drm_mipi_dsi.c
> @@ -201,29 +201,41 @@ EXPORT_SYMBOL(mipi_dsi_detach);
>  /**
>   * mipi_dsi_dcs_write - send DCS write command
>   * @dsi: DSI device
> - * @data: pointer to the command followed by parameters
> - * @len: length of @data
> + * @cmd: DCS command
> + * @data: pointer to the command payload
> + * @len: payload length
>   */
> -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
> - size_t len)
> +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
> +const void *data, size_t len)
>  {
>   const struct mipi_dsi_host_ops *ops = dsi->host->ops;
> - struct mipi_dsi_msg msg = {
> - .channel = dsi->channel,
> - .tx_buf = data,
> - .tx_len = len
> - };
> + struct mipi_dsi_msg msg;
> + ssize_t err;
> + u8 *tx;
>  
>   if (!ops || !ops->transfer)
>   return -ENOSYS;
>  
> + if (len > 0) {
> + tx = kmalloc(1 + len, GFP_KERNEL);
> + if (!tx)
> + return -ENOMEM;
> +
> + tx[0] = cmd;
> + memcpy(tx + 1, data, len);
> + } else {
> + tx = &cmd;
> + }
> +
> + msg.channel = dsi->channel;
> + msg.tx_len = 1 + len;
> + msg.tx_buf = tx;
> +
>   switch (len) {
>   case 0:
> - return -EINVAL;
> - case 1:
>   msg.type = MIPI_DSI_DCS_SHORT_WRITE;
>   break;
> - case 2:
> + case 1:
>   msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
>   break;
>   default:
> @@ -231,14 +243,19 @@ ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, 
> const void *data,
>   break;
>   }
>  
> - return ops->transfer(dsi->host, &msg);
> + err = ops->transfer(dsi->host, &msg);
> +
> + if (len > 0)
> + kfree(tx);
> +
> + return err;
>  }
>  EXPORT_SYMBOL(mipi_dsi_dcs_write);
>  
>  /**
>   * mipi_dsi_dcs_read - send DCS read request command
>   * @dsi: DSI device
> - * @cmd: DCS read command
> + * @cmd: DCS command
>   * @data: pointer to read buffer
>   * @len: length of @data
>   *
> diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c 
> b/drivers/gpu/drm/panel/panel-s6e8aa0.c
> index 5502ef6bc074..d39bee36816c 100644
> --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c
> +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
> @@ -130,7 +130,7 @@ static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
>   return ret;
>  }
>  
> -static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t 
> len)
> +static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const u8 *data, size_t 
> len)
>  {
>   struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
>   ssize_t ret;
> @@ -138,7 +138,7 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const 
> void *data, size_t len)
>   if (ctx->error < 0)
>   return;
>  
> - ret = mipi_dsi_dcs_write(dsi, data, len);
> + ret = mipi_dsi_dcs_write(dsi, data[0], data + 1, len - 1);
>   if (ret < 0) {
>   dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len,
>   data);
> diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
> index 7b5e1a9244e1..bea181121e8b 100644
> --- a/include/drm/drm_mipi_dsi.h
> +++ b/include/drm/drm_mipi_dsi.h
> @@ -127,8 +127,8 @@ struct mipi_dsi_device {
>  
>  int mipi_dsi_attach(struct mipi_dsi_device *dsi);
>  int mipi_dsi_detach(struct mipi_dsi_device *dsi);
> -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
> - size_t len);
> +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
> +const void *data, size_t len);

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-22 Thread Andrzej Hajda
On 07/22/2014 10:12 AM, Thierry Reding wrote:
> On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
>> On 07/22/2014 09:12 AM, Thierry Reding wrote:
>>> From: Thierry Reding 
>>>
>>> Currently the mipi_dsi_dcs_write() function requires the DCS command
>>> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
>>> has a separate parameter. Make them more symmetrical by adding an extra
>>> command parameter to mipi_dsi_dcs_write().
>>>
>>> Also update the S6E8AA0 panel driver (the only user of this API) to
>>> adapt to this new API.
>> I do not agree with that. DCS read and write are not symmetrical by design:
>> - write just sends data,
>> - read sends data then reads response.
>>
>> Forcing API to be symmetrical complicates the implementation without real 
>> gain.
> Why does it complicate anything?

Why? Lets see:

 drivers/gpu/drm/drm_mipi_dsi.c| 45 ---
 drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
 include/drm/drm_mipi_dsi.h|  4 ++--
 3 files changed, 35 insertions(+), 18 deletions(-)


Original function has two vars, one 'if', one 'switch' and one operation
call, nothing more.
You proposes to add new vars, kmalloc with no memory handling, memcpy,
playing with indices, conditional kfree. Isn't it enough to call it more
complicated? :)

>  Granted we need to dynamically allocate
> a buffer for each transfer, but it's all hidden away in a common helper
> function. The big advantage in using a separate parameter for the
> command is that it makes it trivial to implement the majority of DCS
> commands, like this:
>
>   const u8 format = 0x77;
>   const u8 mode = 0x00;
>
>   mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
>   mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, 1);
>   mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &mode, 1);
>   mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);

For this I have proposed once more universal macro, sth like this:

#define mipi_dsi_dcs_write_seq(dsi, seq...) \
({\
const u8 d[] = { seq };\
BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
mipi_dsi_dcs_write(dsi, d, ARRAY_SIZE(d));\
})

It makes trivial to implement ALL DCS commands in much more readable manner.
Please compare with your examples above:
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SOFT_RESET);
mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x77);
mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, 0);
mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON);

It could be also accompanied by static version, for memory optimization:

#define mipi_dsi_dcs_write_seq_static(dsi, seq...) \
({\
static const u8 d[] = { seq };\
mipi_dsi_dcs_write(dsi, d, ARRAY_SIZE(d));\
})


>
> Without the extra parameter, the above becomes:
>
>   const u8 data[1] = { MIPI_DCS_SOFT_RESET };
>   mipi_dsi_dcs_write(dsi, data, sizeof(data));
>
>   const u8 data[2] = { MIPI_DCS_SET_PIXEL_FORMAT, 0x77 };
>   mipi_dsi_dcs_write(dsi, data, sizeof(data));
>
>   const u8 data[2] = { MIPI_DCS_SET_TEAR_ON, 0x00 };
>   mipi_dsi_dcs_write(dsi, data, sizeof(data));
>
>   const u8 data[1] = { MIPI_DCS_SET_DISPLAY_ON };
>   mipi_dsi_dcs_write(dsi, data, sizeof(data));
>
> In this form it looks still rather readable, but if you need to do this
> within an initialization function, it become fairly cluttered:
>
>   const u8 soft_reset[1] = { MIPI_DCS_SOFT_RESET };
>   const u8 set_pixel_format[2] = { MIPI_DCS_SET_PIXEL_FORMAT, 0x77 };
>   const u8 set_tear_on[2] = { MIPI_DCS_SET_TEAR_ON, 0x00 };
>   const u8 set_display_on[1] = { MIPI_DCS_SET_DISPLAY_ON };
>
>   mipi_dsi_dcs_write(dsi, soft_reset, sizeof(soft_reset));
>
>   mipi_dsi_dcs_write(dsi, set_pixel_format, sizeof(set_pixel_format));
>
>   mipi_dsi_dcs_write(dsi, set_tear_on, sizeof(set_tear_on));
>
>   mipi_dsi_dcs_write(dsi, set_display_on, sizeof(set_display_on));
>
> I find that really hard to read because it has a potentially large gap
> between the place where the commands are defined and where they're used.

You will have the same gap issue with your approach in case of DCS
commands with arguments.
With 'my' approach it is still readable.

>
> Some of this could possibly be alleviated by adding separate functions
> for standard commands. But either way, I think having this kind of
> symmetry within an API is always good (it's consistent). By the law of
> least surprise people will actually expect mipi_dsi_dcs_write() to take
> a command as a second parameter.

As I wrote earlier I do not see symmetry here: dcs-read is in fact write
and read,
dcs-write is just write. Hiding this fact in API does not seems to me
good, but I guess
it is rather matter of taste.

Regards
Andrzej

>
> Thierry



[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-22 Thread Thierry Reding
On Tue, Jul 22, 2014 at 09:32:58AM +0200, Andrzej Hajda wrote:
> On 07/22/2014 09:12 AM, Thierry Reding wrote:
> > From: Thierry Reding 
> >
> > Currently the mipi_dsi_dcs_write() function requires the DCS command
> > byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
> > has a separate parameter. Make them more symmetrical by adding an extra
> > command parameter to mipi_dsi_dcs_write().
> >
> > Also update the S6E8AA0 panel driver (the only user of this API) to
> > adapt to this new API.
> 
> I do not agree with that. DCS read and write are not symmetrical by design:
> - write just sends data,
> - read sends data then reads response.
> 
> Forcing API to be symmetrical complicates the implementation without real 
> gain.

Why does it complicate anything? Granted we need to dynamically allocate
a buffer for each transfer, but it's all hidden away in a common helper
function. The big advantage in using a separate parameter for the
command is that it makes it trivial to implement the majority of DCS
commands, like this:

const u8 format = 0x77;
const u8 mode = 0x00;

mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, 1);
mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &mode, 1);
mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);

Without the extra parameter, the above becomes:

const u8 data[1] = { MIPI_DCS_SOFT_RESET };
mipi_dsi_dcs_write(dsi, data, sizeof(data));

const u8 data[2] = { MIPI_DCS_SET_PIXEL_FORMAT, 0x77 };
mipi_dsi_dcs_write(dsi, data, sizeof(data));

const u8 data[2] = { MIPI_DCS_SET_TEAR_ON, 0x00 };
mipi_dsi_dcs_write(dsi, data, sizeof(data));

const u8 data[1] = { MIPI_DCS_SET_DISPLAY_ON };
mipi_dsi_dcs_write(dsi, data, sizeof(data));

In this form it looks still rather readable, but if you need to do this
within an initialization function, it become fairly cluttered:

const u8 soft_reset[1] = { MIPI_DCS_SOFT_RESET };
const u8 set_pixel_format[2] = { MIPI_DCS_SET_PIXEL_FORMAT, 0x77 };
const u8 set_tear_on[2] = { MIPI_DCS_SET_TEAR_ON, 0x00 };
const u8 set_display_on[1] = { MIPI_DCS_SET_DISPLAY_ON };

mipi_dsi_dcs_write(dsi, soft_reset, sizeof(soft_reset));

mipi_dsi_dcs_write(dsi, set_pixel_format, sizeof(set_pixel_format));

mipi_dsi_dcs_write(dsi, set_tear_on, sizeof(set_tear_on));

mipi_dsi_dcs_write(dsi, set_display_on, sizeof(set_display_on));

I find that really hard to read because it has a potentially large gap
between the place where the commands are defined and where they're used.

Some of this could possibly be alleviated by adding separate functions
for standard commands. But either way, I think having this kind of
symmetry within an API is always good (it's consistent). By the law of
least surprise people will actually expect mipi_dsi_dcs_write() to take
a command as a second parameter.

Thierry
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: 



[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read, write}() symmetrical

2014-07-22 Thread Andrzej Hajda
On 07/22/2014 09:12 AM, Thierry Reding wrote:
> From: Thierry Reding 
>
> Currently the mipi_dsi_dcs_write() function requires the DCS command
> byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
> has a separate parameter. Make them more symmetrical by adding an extra
> command parameter to mipi_dsi_dcs_write().
>
> Also update the S6E8AA0 panel driver (the only user of this API) to
> adapt to this new API.

I do not agree with that. DCS read and write are not symmetrical by design:
- write just sends data,
- read sends data then reads response.

Forcing API to be symmetrical complicates the implementation without real gain.

Regards
Andrzej



>
> Signed-off-by: Thierry Reding 
> ---
>  drivers/gpu/drm/drm_mipi_dsi.c| 45 
> ---
>  drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
>  include/drm/drm_mipi_dsi.h|  4 ++--
>  3 files changed, 35 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
> index 6aa6a9e95570..bbab06ef80c9 100644
> --- a/drivers/gpu/drm/drm_mipi_dsi.c
> +++ b/drivers/gpu/drm/drm_mipi_dsi.c
> @@ -201,29 +201,41 @@ EXPORT_SYMBOL(mipi_dsi_detach);
>  /**
>   * mipi_dsi_dcs_write - send DCS write command
>   * @dsi: DSI device
> - * @data: pointer to the command followed by parameters
> - * @len: length of @data
> + * @cmd: DCS command
> + * @data: pointer to the command payload
> + * @len: payload length
>   */
> -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
> - size_t len)
> +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
> +const void *data, size_t len)
>  {
>   const struct mipi_dsi_host_ops *ops = dsi->host->ops;
> - struct mipi_dsi_msg msg = {
> - .channel = dsi->channel,
> - .tx_buf = data,
> - .tx_len = len
> - };
> + struct mipi_dsi_msg msg;
> + ssize_t err;
> + u8 *tx;
>  
>   if (!ops || !ops->transfer)
>   return -ENOSYS;
>  
> + if (len > 0) {
> + tx = kmalloc(1 + len, GFP_KERNEL);
> + if (!tx)
> + return -ENOMEM;
> +
> + tx[0] = cmd;
> + memcpy(tx + 1, data, len);
> + } else {
> + tx = &cmd;
> + }
> +
> + msg.channel = dsi->channel;
> + msg.tx_len = 1 + len;
> + msg.tx_buf = tx;
> +
>   switch (len) {
>   case 0:
> - return -EINVAL;
> - case 1:
>   msg.type = MIPI_DSI_DCS_SHORT_WRITE;
>   break;
> - case 2:
> + case 1:
>   msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
>   break;
>   default:
> @@ -231,14 +243,19 @@ ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, 
> const void *data,
>   break;
>   }
>  
> - return ops->transfer(dsi->host, &msg);
> + err = ops->transfer(dsi->host, &msg);
> +
> + if (len > 0)
> + kfree(tx);
> +
> + return err;
>  }
>  EXPORT_SYMBOL(mipi_dsi_dcs_write);
>  
>  /**
>   * mipi_dsi_dcs_read - send DCS read request command
>   * @dsi: DSI device
> - * @cmd: DCS read command
> + * @cmd: DCS command
>   * @data: pointer to read buffer
>   * @len: length of @data
>   *
> diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c 
> b/drivers/gpu/drm/panel/panel-s6e8aa0.c
> index 5502ef6bc074..d39bee36816c 100644
> --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c
> +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
> @@ -130,7 +130,7 @@ static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
>   return ret;
>  }
>  
> -static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t 
> len)
> +static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const u8 *data, size_t 
> len)
>  {
>   struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
>   ssize_t ret;
> @@ -138,7 +138,7 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const 
> void *data, size_t len)
>   if (ctx->error < 0)
>   return;
>  
> - ret = mipi_dsi_dcs_write(dsi, data, len);
> + ret = mipi_dsi_dcs_write(dsi, data[0], data + 1, len - 1);
>   if (ret < 0) {
>   dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len,
>   data);
> diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
> index 7b5e1a9244e1..bea181121e8b 100644
> --- a/include/drm/drm_mipi_dsi.h
> +++ b/include/drm/drm_mipi_dsi.h
> @@ -127,8 +127,8 @@ struct mipi_dsi_device {
>  
>  int mipi_dsi_attach(struct mipi_dsi_device *dsi);
>  int mipi_dsi_detach(struct mipi_dsi_device *dsi);
> -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
> - size_t len);
> +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
> +const void *data, size_t len);
>  ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
>

[PATCH 3/4] drm/dsi: Make mipi_dsi_dcs_{read,write}() symmetrical

2014-07-22 Thread Thierry Reding
From: Thierry Reding 

Currently the mipi_dsi_dcs_write() function requires the DCS command
byte to be embedded within the write buffer whereas mipi_dsi_dcs_read()
has a separate parameter. Make them more symmetrical by adding an extra
command parameter to mipi_dsi_dcs_write().

Also update the S6E8AA0 panel driver (the only user of this API) to
adapt to this new API.

Signed-off-by: Thierry Reding 
---
 drivers/gpu/drm/drm_mipi_dsi.c| 45 ---
 drivers/gpu/drm/panel/panel-s6e8aa0.c |  4 ++--
 include/drm/drm_mipi_dsi.h|  4 ++--
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 6aa6a9e95570..bbab06ef80c9 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -201,29 +201,41 @@ EXPORT_SYMBOL(mipi_dsi_detach);
 /**
  * mipi_dsi_dcs_write - send DCS write command
  * @dsi: DSI device
- * @data: pointer to the command followed by parameters
- * @len: length of @data
+ * @cmd: DCS command
+ * @data: pointer to the command payload
+ * @len: payload length
  */
-ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
-   size_t len)
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+  const void *data, size_t len)
 {
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
-   struct mipi_dsi_msg msg = {
-   .channel = dsi->channel,
-   .tx_buf = data,
-   .tx_len = len
-   };
+   struct mipi_dsi_msg msg;
+   ssize_t err;
+   u8 *tx;

if (!ops || !ops->transfer)
return -ENOSYS;

+   if (len > 0) {
+   tx = kmalloc(1 + len, GFP_KERNEL);
+   if (!tx)
+   return -ENOMEM;
+
+   tx[0] = cmd;
+   memcpy(tx + 1, data, len);
+   } else {
+   tx = &cmd;
+   }
+
+   msg.channel = dsi->channel;
+   msg.tx_len = 1 + len;
+   msg.tx_buf = tx;
+
switch (len) {
case 0:
-   return -EINVAL;
-   case 1:
msg.type = MIPI_DSI_DCS_SHORT_WRITE;
break;
-   case 2:
+   case 1:
msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
break;
default:
@@ -231,14 +243,19 @@ ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, 
const void *data,
break;
}

-   return ops->transfer(dsi->host, &msg);
+   err = ops->transfer(dsi->host, &msg);
+
+   if (len > 0)
+   kfree(tx);
+
+   return err;
 }
 EXPORT_SYMBOL(mipi_dsi_dcs_write);

 /**
  * mipi_dsi_dcs_read - send DCS read request command
  * @dsi: DSI device
- * @cmd: DCS read command
+ * @cmd: DCS command
  * @data: pointer to read buffer
  * @len: length of @data
  *
diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c 
b/drivers/gpu/drm/panel/panel-s6e8aa0.c
index 5502ef6bc074..d39bee36816c 100644
--- a/drivers/gpu/drm/panel/panel-s6e8aa0.c
+++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
@@ -130,7 +130,7 @@ static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
return ret;
 }

-static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t 
len)
+static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const u8 *data, size_t len)
 {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
ssize_t ret;
@@ -138,7 +138,7 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const 
void *data, size_t len)
if (ctx->error < 0)
return;

-   ret = mipi_dsi_dcs_write(dsi, data, len);
+   ret = mipi_dsi_dcs_write(dsi, data[0], data + 1, len - 1);
if (ret < 0) {
dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len,
data);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 7b5e1a9244e1..bea181121e8b 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -127,8 +127,8 @@ struct mipi_dsi_device {

 int mipi_dsi_attach(struct mipi_dsi_device *dsi);
 int mipi_dsi_detach(struct mipi_dsi_device *dsi);
-ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
-   size_t len);
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+  const void *data, size_t len);
 ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
  size_t len);

-- 
2.0.1