Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH 00/33] OMAPDSS: platform_enable/disable callback removal from panel drivers
From: Archit Taneja @ 2013-02-14  7:29 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: tomi.valkeinen, linux-omap, linux-fbdev
In-Reply-To: <20130213164647.GF7144@atomide.com>

Hi,

On Wednesday 13 February 2013 10:16 PM, Tony Lindgren wrote:
> * Archit Taneja <archit@ti.com> [130213 06:26]:
>> init functions in omap board files request panel specific gpios, and provide
>> functions which omapdss panel drivers call to enable or disable them.
>>
>> Instead of the board files requesting these gpios, they should just pass the
>> platform specific data(like the gpio numbers), the panel should retrieve the
>> platform data and request the gpios. Doing this prevents the need of the panel
>> driver calling platform functions in board files.
>>
>> Panel drivers have their own platform data struct, and the board files populate
>> these structs and pass the pointer to the 'data' field of omap_dss_device. This
>> work will make it easier for the panel drivers be more adaptable to the
>> DT model.
>>
>> There is also removal of passing panel reset_gpio numbers through
>> omap_dss_device struct directly, reset gpios are passed through platform data
>> only.
>
> To avoid merge conflicts and dependencies between drivers and core
> Soc code, please break thes kind of patches into following parts:
>
> 1. Any platform_data header changes needed so both I and Tomi
>     can pull it in as needed.
>
> 2. Changes to DSS drivers. Please keep stubs around for the
>     board specific callback functions so omap2plus_defconfig
>     won't break with just #1 merged into arm soc tree.

The build won't break, and the kernel will boot up properly, but the 
panels won't work till the time #3 is also merged,

>
> 3. All the arch/arm/*omap* changes based on #1 above to
>     drop obsolete callback functions and add new pdata if still
>     needed. This needs to build and boot on #1 so I can merge
>     this in via arm soc tree.
>
> 4. Any .dts changes needed.

We don't have any .dts changes for DSS as of now.

I'll split the patches accordingly.

Thanks,
Archit

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Igor Grinberg @ 2013-02-14  8:37 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511C8D8F.9060805@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/14/13 09:09, Tomi Valkeinen wrote:
> On 2013-02-14 08:56, Igor Grinberg wrote:
>> On 02/13/13 17:59, Tomi Valkeinen wrote:
> 
>>> Okay, so I just realized there's an spi backlight driver used here, and
>>> that backlight driver is actually handling the SPI transactions with the
>>> panel, instead of the panel driver. So this looks quite messed up.
>>
>> Yep, it always was.
>> The whole DSS specific panel handling inside the
>> drivers/video/omap2/displays is a mess.
> 
> Well, that's not mess itself, it's just omap specific panel framework.
> But dividing single device handling into two separate places is a mess.

Yes, you are right it is not the mess, but it prevents the panel to
be used on other systems and that is BAD.
At the very least, drivers/video/backlight is a generic place that can be
used not just on OMAP.
And since the toppoly was and is used on other systems, why the hell
should anyone duplicate the driver just to please the OMAP specific
panel framework? The real problem is that this framework should not be
OMAP specific...
Of course I'm aware of the fact that currently there is no generic
panel framework, but forging something OMAP specific which is obviously
used on most of the other architectures/platforms (and I mean
panel<->controller relations), is not a good way to go.
Although, I'm also aware of the fact that most things are done this way:
do several specific drivers/frameworks, find the common stuff, and extract
it into a core driver/framework. So I don't want to blame anyone - that's
just the way how we do things, right?

> 
>> Those panels can be (and are) used not only with OMAP based boards.
> 
> True, but as there's no generic panel framework, that's the best we can
> do. But see CDF (common display framework) discussions if you're
> interested in what's hopefully coming soon.

Yep, I've seen the CDF discussion and I think this is a good way to go.

> 
>>> For a quick solution, can we just set the LCD_EN at boot time (with the
>>> msleep), and not touch it after that?
>>
>> That would be sensible for now, so this series can be merged.
>> As a more appropriate (and long term) solution,
>> I plan on moving the panel reset pin handling to the spi backlight
>> driver itself.
> 
> Well, if you must. But I suggest moving the whole panel handling into a
> (omap specific) panel driver, as it's done for other panels. That way
> you'll have a proper panel driver for it, for omap, and when CDF comes,
> you'll get a platform independent panel driver for it.

You can't just move generic architecture/platform independent stuff
into OMAP specific framework... Just think about this... It's insane.

> 
> Of course, if you have multiple platforms already using that backlight
> driver, the omap specific approach may not be enticing. So perhaps it's
> easier to just do the quick fix and wait for CDF.

That is exactly what I am talking about.
In addition, AFAIR, the reset pin is the property of the toppoly panel
hardware, so that is why I think, we should let the toppoly driver
(currently spi backlight, later hopefully CDF) handle it correctly
along with the spi sequences.

 

- -- 
Regards,
Igor.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJRHKJGAAoJEBDE8YO64EfacksP/j79jaDbnXpFcwT9KlInp8OE
e+XNi5Vt8zbqhj4gHtxZlN/eIQsVRfuivm9CTp5aJSZHBDAJlPNKobmwjFrDLO9V
RtYTwLAcuWyOdnutIQ52xNwXSntQknd8yxm1qJZMEBjEP+mcQxISWXXMsdxlQEiT
emNtU42W16ZOR34kHUoVfYLkV0v02/JVygt3oaU71+mrNBOt+5L6cHcXaQZPKSes
LUOcyz0qJfzKbnmmZnP/+clTIids83u8rVCNZ1/JoIIlR4rvtNcxRM8Apa8KFJx/
PVT38ds62F0L0qbxL3UmI1uJS2KuEHuJyjYo0uDeQqeeSyz7Q3ZG4TwAJYkWZdWQ
TdFbVrsXbK408FT33VIP4rOzDjqO93IK6f5ld0tZoIvL59NLwgXIejJn6jTNNcU4
p25mUXGSDnaZrNU5cC7d/MzSMt60XQx3UiHjEXD3eJAT33yb+DdBaQwloMCXJQOx
vnseFqhuAzgFHd9LEl47LBg7eXudjaSvWYfJOV0SoB9s7QM8m/YUhnmqmtvdCqZL
fKMJcAjCgm0BG2P6ss79sl6P4XDoBF1LOwSwz4dRmocA3TP7vBNkuRoK08vQe6gv
Qi7hJ05ioa8THt77FxMHtf+ZrO34/L6gHxZqrOD++OgPPdL6qtegemyp4IaKKbUg
q3Mpgsr4ODyStdjEXxTC
=lIHm
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Tomi Valkeinen @ 2013-02-14  9:09 UTC (permalink / raw)
  To: Igor Grinberg; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511CA247.80606@compulab.co.il>

[-- Attachment #1: Type: text/plain, Size: 4247 bytes --]

On 2013-02-14 10:37, Igor Grinberg wrote:
> On 02/14/13 09:09, Tomi Valkeinen wrote:
>> On 2013-02-14 08:56, Igor Grinberg wrote:
>>> On 02/13/13 17:59, Tomi Valkeinen wrote:
> 
>>>> Okay, so I just realized there's an spi backlight driver used here, and
>>>> that backlight driver is actually handling the SPI transactions with the
>>>> panel, instead of the panel driver. So this looks quite messed up.
>>>
>>> Yep, it always was.
>>> The whole DSS specific panel handling inside the
>>> drivers/video/omap2/displays is a mess.
> 
>> Well, that's not mess itself, it's just omap specific panel framework.
>> But dividing single device handling into two separate places is a mess.
> 
> Yes, you are right it is not the mess, but it prevents the panel to
> be used on other systems and that is BAD.
> At the very least, drivers/video/backlight is a generic place that can be
> used not just on OMAP.

True, it's generic, but does it work reliably? The panel hardware is now
partly handled in the backlight driver, and partly in the omap's panel
driver (and wherever on other platforms).

At least currently there's a dependency between the two, as the LCD_EN
gpio is handled by the panel driver, which affects the functioning of
the backlight driver. Is it ensured that the panel driver does not
disable the panel when the backlight driver does spi transactions?

That's what I meant with the mess, it's difficult to make it work
reliably. I know that for some panels such a two-driver approach would
not work at all. Although I guess it's working well enough for you for
this panel.

Thinking about it, if you do move the gpio handling to the backlight
driver, the panel driver will only handle the DPI video stream. Then it
should not have any effect on the SPI side (presuming the panel doesn't
use the pixel clock as func clock), although there's probably still
possibility for display artifacts on enable and disable, if the order of
operations goes the wrong way.

> And since the toppoly was and is used on other systems, why the hell
> should anyone duplicate the driver just to please the OMAP specific
> panel framework? The real problem is that this framework should not be

Not to please. To make it reliable.

> OMAP specific...
> Of course I'm aware of the fact that currently there is no generic
> panel framework, but forging something OMAP specific which is obviously
> used on most of the other architectures/platforms (and I mean
> panel<->controller relations), is not a good way to go.

Well, if duplicating the code gives us reliable drivers, versus
unreliable without duplicating, then... I don't see it as that bad.

> Although, I'm also aware of the fact that most things are done this way:
> do several specific drivers/frameworks, find the common stuff, and extract
> it into a core driver/framework. So I don't want to blame anyone - that's
> just the way how we do things, right?

If it was easy, somebody would've done it.

>>>> For a quick solution, can we just set the LCD_EN at boot time (with the
>>>> msleep), and not touch it after that?
>>>
>>> That would be sensible for now, so this series can be merged.
>>> As a more appropriate (and long term) solution,
>>> I plan on moving the panel reset pin handling to the spi backlight
>>> driver itself.
> 
>> Well, if you must. But I suggest moving the whole panel handling into a
>> (omap specific) panel driver, as it's done for other panels. That way
>> you'll have a proper panel driver for it, for omap, and when CDF comes,
>> you'll get a platform independent panel driver for it.
> 
> You can't just move generic architecture/platform independent stuff
> into OMAP specific framework... Just think about this... It's insane.

As I said, reliable vs unreliable. That's not insane.

But again, if you can handle this particular panel reliably with the
two-driver approach, I'm fine with it.

> In addition, AFAIR, the reset pin is the property of the toppoly panel
> hardware, so that is why I think, we should let the toppoly driver
> (currently spi backlight, later hopefully CDF) handle it correctly
> along with the spi sequences.

Yes, that sounds ok.

 Tomi


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* Re: [PATCH v2 0/1] OMAP4: DSS: Add panel for Blaze Tablet boards
From: Tomi Valkeinen @ 2013-02-14  9:24 UTC (permalink / raw)
  To: Ruslan Bilovol
  Cc: andi, FlorianSchandinat, linux-fbdev, linux-kernel, linux-omap
In-Reply-To: <CAB=otbSX_O-zbHZuPWPSEU0D1s3uKfZfeatoguoRiwogS5tVHQ@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1332 bytes --]

On 2013-02-14 02:07, Ruslan Bilovol wrote:

> This patch is exactly a part of mainlining of the BlazeTablet board support :)
> The goal is to have as much as possible support of this board in the
> 'vanilla' kernel.
> The BlazeTablet mainlining is already ongoing (
> https://patchwork.kernel.org/patch/2118281/ )
> and I hope we will have some support of this board in near future.
> The BlazeTablet's LCD panel support is very important thing for us to
> have it in mainline because
> without it the BlazeTablet becomes a 'black brick' and it is painful
> for us to port this
> driver against each new version of kernel.

Ok, good to hear you're pushing it to mainline. However, you should
mentally prepare for it being a black brick =(.

Tony said he's not adding new board files, only DT from now on. The
display subsystem driver and the panel drivers do not work with DT yet,
and it will still take some time for that to realize.

Thus adding this driver would help nothing, as it couldn't be used. And
after the DSS and the panel drivers are made to work with DT (which is a
big job, needing large rewrites of the drivers), there's a rework that
has to be done with this driver to make it compatible with the new DSS
model.

So, I'm still inclined to say that we shouldn't merge this.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Igor Grinberg @ 2013-02-14  9:43 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511CA9B3.70401@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/14/13 11:09, Tomi Valkeinen wrote:
> On 2013-02-14 10:37, Igor Grinberg wrote:
>> On 02/14/13 09:09, Tomi Valkeinen wrote:
>>> On 2013-02-14 08:56, Igor Grinberg wrote:
>>>> On 02/13/13 17:59, Tomi Valkeinen wrote:
>>
>>>>> Okay, so I just realized there's an spi backlight driver used here, and
>>>>> that backlight driver is actually handling the SPI transactions with the
>>>>> panel, instead of the panel driver. So this looks quite messed up.
>>>>
>>>> Yep, it always was.
>>>> The whole DSS specific panel handling inside the
>>>> drivers/video/omap2/displays is a mess.
>>
>>> Well, that's not mess itself, it's just omap specific panel framework.
>>> But dividing single device handling into two separate places is a mess.
>>
>> Yes, you are right it is not the mess, but it prevents the panel to
>> be used on other systems and that is BAD.
>> At the very least, drivers/video/backlight is a generic place that can be
>> used not just on OMAP.
> 
> True, it's generic, but does it work reliably? The panel hardware is now
> partly handled in the backlight driver, and partly in the omap's panel
> driver (and wherever on other platforms).

It works reliably on other platforms, but not on OMAP - because
we need to cope with the OMAP specific framework...

> 
> At least currently there's a dependency between the two, as the LCD_EN
> gpio is handled by the panel driver, which affects the functioning of
> the backlight driver. Is it ensured that the panel driver does not
> disable the panel when the backlight driver does spi transactions?
> 
> That's what I meant with the mess, it's difficult to make it work
> reliably. I know that for some panels such a two-driver approach would
> not work at all. Although I guess it's working well enough for you for
> this panel.

Yep, that is correct - this is the mess.

> 
> Thinking about it, if you do move the gpio handling to the backlight
> driver, the panel driver will only handle the DPI video stream. Then it
> should not have any effect on the SPI side (presuming the panel doesn't
> use the pixel clock as func clock), although there's probably still
> possibility for display artifacts on enable and disable, if the order of
> operations goes the wrong way.

Yep, again, that is correct.

> 
>> And since the toppoly was and is used on other systems, why the hell
>> should anyone duplicate the driver just to please the OMAP specific
>> panel framework? The real problem is that this framework should not be
> 
> Not to please. To make it reliable.

Well, there are multiple ways to make it reliable.
And I don't think that the best would be: make it OMAP specific.

> 
>> OMAP specific...
>> Of course I'm aware of the fact that currently there is no generic
>> panel framework, but forging something OMAP specific which is obviously
>> used on most of the other architectures/platforms (and I mean
>> panel<->controller relations), is not a good way to go.
> 
> Well, if duplicating the code gives us reliable drivers, versus
> unreliable without duplicating, then... I don't see it as that bad.

Hmmm... I don't think this fits the mainline (upstream) philosophy.
This can be also extrapolated into: let's make our own Linux ARM fork
so it will be more reliable...
This is the way how vendor specific kernel releases work.

> 
>> Although, I'm also aware of the fact that most things are done this way:
>> do several specific drivers/frameworks, find the common stuff, and extract
>> it into a core driver/framework. So I don't want to blame anyone - that's
>> just the way how we do things, right?
> 
> If it was easy, somebody would've done it.

In fact this is done all the time on multiple drivers and frameworks.
Also, I don't say this is easy, but I also don't think this too hard.
It is also a function of resources (time/will/experience/etc.).

> 
>>>>> For a quick solution, can we just set the LCD_EN at boot time (with the
>>>>> msleep), and not touch it after that?
>>>>
>>>> That would be sensible for now, so this series can be merged.
>>>> As a more appropriate (and long term) solution,
>>>> I plan on moving the panel reset pin handling to the spi backlight
>>>> driver itself.
>>
>>> Well, if you must. But I suggest moving the whole panel handling into a
>>> (omap specific) panel driver, as it's done for other panels. That way
>>> you'll have a proper panel driver for it, for omap, and when CDF comes,
>>> you'll get a platform independent panel driver for it.
>>
>> You can't just move generic architecture/platform independent stuff
>> into OMAP specific framework... Just think about this... It's insane.
> 
> As I said, reliable vs unreliable. That's not insane.
> 
> But again, if you can handle this particular panel reliably with the
> two-driver approach, I'm fine with it.

Again, it works reliably on other platforms,
why would OMAP be an exception?

> 
>> In addition, AFAIR, the reset pin is the property of the toppoly panel
>> hardware, so that is why I think, we should let the toppoly driver
>> (currently spi backlight, later hopefully CDF) handle it correctly
>> along with the spi sequences.
> 
> Yes, that sounds ok.
> 
>  Tomi
> 

- -- 
Regards,
Igor.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJRHLGzAAoJEBDE8YO64EfaOJMP/AtR9IkN+eWwdbt0R1Vu9vKH
mFgSCENqErAjYi3zM0YScj+E2zSby4rfXCY14Goh46DBCBXjRWYms6P/nZgGSLYT
lIup5YljWxWJxM0nvrykok872Atx+TSJukx3nD5foWieu4tNRRvhqN7+ckBO7R4D
J1D5uy3wH8Ea3SZ/foPrzewTeajnOeZxzhprfodLdmKIuqxInVE0KrWqrcefspNI
TvWAjLCHtoM4LDCZRaiHs3mN03QMdcJc1BfWeJe1eVx6YXSBqNTTG6mSgUegQyOG
PnC1T3kzS5Vuhmk9NfUmL19LInAljPVDoQomUqG6N140M6jol4ru+A5yE/NZ/tSl
j/8vz5pE8JXp0ueQt1X1vkAGL+Lgzbyrf38xQTxnjSLggO3OFHOv6AzlY453Lfem
gz6Xpjq+2Kcqxghfndd4yXnOjdlyWDN6dvYBthBBixmt34c6nNtdoXmakAXyw8wW
qSyT3sO6WgE53ROZRh9W2FCiLXdJ1rHYMBRRY4nbKNhOhtC/vSF4UVsFBUuAaqul
a6QToMggpugY8n3lm/SZ6LFWJDaHjnkUAVXxq3/GiclJSFwBnHqsOT1bfjsF5OfC
YnaldNBbH0WvmFN89Ds/inW1MLcFc/yWirB0Utj7ysb5AL4vH4QLs1dokzjxnTyK
WJmOMyQi7Jk+ocUSBgu2
=G6lL
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Tomi Valkeinen @ 2013-02-14 10:59 UTC (permalink / raw)
  To: Igor Grinberg; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511CB1B3.80605@compulab.co.il>

[-- Attachment #1: Type: text/plain, Size: 3173 bytes --]

On 2013-02-14 11:43, Igor Grinberg wrote:

>> True, it's generic, but does it work reliably? The panel hardware is now
>> partly handled in the backlight driver, and partly in the omap's panel
>> driver (and wherever on other platforms).
> 
> It works reliably on other platforms, but not on OMAP - because
> we need to cope with the OMAP specific framework...

How do you handle the gpios on other platform? Those are the ones
causing the issues here, right?

Or is there something else with OMAP DSS that you need to specifically
cope with?

>> Thinking about it, if you do move the gpio handling to the backlight
>> driver, the panel driver will only handle the DPI video stream. Then it
>> should not have any effect on the SPI side (presuming the panel doesn't
>> use the pixel clock as func clock), although there's probably still
>> possibility for display artifacts on enable and disable, if the order of
>> operations goes the wrong way.
> 
> Yep, again, that is correct.

It's correct that there may be artifacts? How do you manage the ordering
of the operations on other platforms?

>>> And since the toppoly was and is used on other systems, why the hell
>>> should anyone duplicate the driver just to please the OMAP specific
>>> panel framework? The real problem is that this framework should not be
> 
>> Not to please. To make it reliable.
> 
> Well, there are multiple ways to make it reliable.
> And I don't think that the best would be: make it OMAP specific.

I'm not saying it's the best option. I'm saying it's a realistic option
to get it working.

>> Well, if duplicating the code gives us reliable drivers, versus
>> unreliable without duplicating, then... I don't see it as that bad.
> 
> Hmmm... I don't think this fits the mainline (upstream) philosophy.
> This can be also extrapolated into: let's make our own Linux ARM fork
> so it will be more reliable...
> This is the way how vendor specific kernel releases work.

Well, we are talking about a smallish driver here. Not an arch fork. If
the options are a) platform specific driver that works, or b) generic
driver that's not reliable, or c) no driver at all, I can't really see
why a) would be such a horrible option for the time being.

But this discussion is getting a bit out of hand. It sounds to me that
for this panel in question we can manage with the current approach, so
this whole line of discussion doesn't matter for this specific problem.

>> If it was easy, somebody would've done it.
> 
> In fact this is done all the time on multiple drivers and frameworks.
> Also, I don't say this is easy, but I also don't think this too hard.
> It is also a function of resources (time/will/experience/etc.).

I think the CDF discussions have already proven that it is quite hard.
But feel free to contribute.

And I've talked about a common display framework already years ago, and
I've tried to design OMAP DSS panels from start in such a way that they
try to depend on OMAP DSS features as little as possible, to make it
easier to generalize them. Just to prove I'm not indifferent about the
issue =).

 Tomi


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Igor Grinberg @ 2013-02-14 12:37 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511CC37C.3020706@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/14/13 12:59, Tomi Valkeinen wrote:
> On 2013-02-14 11:43, Igor Grinberg wrote:
> 
>>> True, it's generic, but does it work reliably? The panel hardware is now
>>> partly handled in the backlight driver, and partly in the omap's panel
>>> driver (and wherever on other platforms).
>>
>> It works reliably on other platforms, but not on OMAP - because
>> we need to cope with the OMAP specific framework...
> 
> How do you handle the gpios on other platform? Those are the ones
> causing the issues here, right?

Well, I'm also talking about something that is a history already.
Remember, we had multiple panel drivers inside the
video/omap2/displays and then they were consolidated into the
"generic dpi/dsi/whatever".

And yes you are right, on the platforms I'm aware of, the GPIO is not
handled. Apparently its hardware default (pull resistor) is always on...

> 
> Or is there something else with OMAP DSS that you need to specifically
> cope with?

The fact there is a need to create a OMAP specific driver.
I'm not talking about the generic driver which only needs to have the
controller specific data (e.g. porches, pixel clock, bus width).
The generic driver was one of the good ways to go.

> 
>>> Thinking about it, if you do move the gpio handling to the backlight
>>> driver, the panel driver will only handle the DPI video stream. Then it
>>> should not have any effect on the SPI side (presuming the panel doesn't
>>> use the pixel clock as func clock), although there's probably still
>>> possibility for display artifacts on enable and disable, if the order of
>>> operations goes the wrong way.
>>
>> Yep, again, that is correct.
> 
> It's correct that there may be artifacts? How do you manage the ordering
> of the operations on other platforms?

Yep, there might be artifacts if the ordering is incorrect.
The ordering is something that should be solved by the CDF.

> 
>>>> And since the toppoly was and is used on other systems, why the hell
>>>> should anyone duplicate the driver just to please the OMAP specific
>>>> panel framework? The real problem is that this framework should not be
>>
>>> Not to please. To make it reliable.
>>
>> Well, there are multiple ways to make it reliable.
>> And I don't think that the best would be: make it OMAP specific.
> 
> I'm not saying it's the best option. I'm saying it's a realistic option
> to get it working.
> 
>>> Well, if duplicating the code gives us reliable drivers, versus
>>> unreliable without duplicating, then... I don't see it as that bad.
>>
>> Hmmm... I don't think this fits the mainline (upstream) philosophy.
>> This can be also extrapolated into: let's make our own Linux ARM fork
>> so it will be more reliable...
>> This is the way how vendor specific kernel releases work.
> 
> Well, we are talking about a smallish driver here. Not an arch fork. If
> the options are a) platform specific driver that works, or b) generic
> driver that's not reliable, or c) no driver at all, I can't really see
> why a) would be such a horrible option for the time being.

I think there is b.5) where the driver is both generic and reliable,
but I haven't looked into this deep enough.

> 
> But this discussion is getting a bit out of hand. It sounds to me that
> for this panel in question we can manage with the current approach, so
> this whole line of discussion doesn't matter for this specific problem.
> 
>>> If it was easy, somebody would've done it.
>>
>> In fact this is done all the time on multiple drivers and frameworks.
>> Also, I don't say this is easy, but I also don't think this too hard.
>> It is also a function of resources (time/will/experience/etc.).
> 
> I think the CDF discussions have already proven that it is quite hard.
> But feel free to contribute.

I will contribute as much as I can in terms of my paid work.
I always do...

> 
> And I've talked about a common display framework already years ago, and
> I've tried to design OMAP DSS panels from start in such a way that they
> try to depend on OMAP DSS features as little as possible, to make it
> easier to generalize them. Just to prove I'm not indifferent about the
> issue =).

Yep, your work was fruitful and no one can take it from you!
That's why I said that I'm not trying to blame or accuse anyone.
That is more of a wish that the CDF will come as quickly as it can.
Because currently it is clear that there are cases where we don't
have a proper support...


- -- 
Regards,
Igor.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJRHNqRAAoJEBDE8YO64Efac08QAKBgU7xFkdBHU0ekAgRIafhO
kd0EgPXwPZDvuAaoj5pzdMI65alRSuoQxp5ohHyz0aFfGRk0Q66f6/zXzTsGXPLP
pRTkqGGTHD5Qtv2IvhHPvLMRGW+87QiuK0NU0BJqV/1JRPz1UyKMJrwc5U3Acf4J
B7bQnWLlIcPftIt2zHwuvZZMYZUL8f5/dXGWMhxmTF7rse7YcTjCwQO4eabTIX5r
/GUanF+qlwKJzk7nxQR1DFQdN+7Vv8vdumJi38sq9fouLgXlhmzOgXvxMgT7lq8T
l+7Bg7l+E9yrHaXmWf3zjZBAk6/wBnzzrmmK5V6Gjg2PiEh6Rs5ARWPrdc/FQCpt
4bXTKEktLonHj2rya8intrPLw7lP4AQN81QsQOLeRIPGoSCcDsi4RGAFrWdXR0Xt
Du9ea/liAD3+qiNIErQcTlR5zDKAIhMvWycG+ZFj0kVFUFb6p/F1TKcqVy0O7HAG
SLSsrCyO8jA/UxAKQifhiUU2Hoq9a3VhQi507lbXiN0NTsk686mp/W8YJPB/di+v
44wayaE5Kyw5iawLj9WUyTpw29sOysiewp+z7XuaF3fM5lWeMy2e0/mNbe4iCcCG
LYMl0NWcQn0S7okkQz5HHmCJp3L3/Se5sMfGKJRzpG0vK1DR+m8nJh0MGbEu/14C
B9+3VrImRZS8te/wnPqE
ºnK
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: [PATCH 27/33] OMAPDSS: n8x0 panel: handle gpio data in panel driver
From: Aaro Koskinen @ 2013-02-14 12:45 UTC (permalink / raw)
  To: Archit Taneja; +Cc: tomi.valkeinen, linux-omap, linux-fbdev
In-Reply-To: <511C8578.1070907@ti.com>

On Thu, Feb 14, 2013 at 12:04:32PM +0530, Archit Taneja wrote:
> On Wednesday 13 February 2013 11:05 PM, Aaro Koskinen wrote:
> >On Wed, Feb 13, 2013 at 07:52:19PM +0530, Archit Taneja wrote:
> >>@@ -444,6 +445,20 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
> >>  	dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
> >>  	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
> >>
> >>+	if (gpio_is_valid(bdata->panel_reset)) {
> >>+		r = devm_gpio_request_one(&dssdev->dev, bdata->panel_reset,
> >>+				GPIOF_OUT_INIT_LOW, "PANEL RESET");
> >>+		if (r)
> >>+			return r;
> >>+	}
> >>+
> >>+	if (gpio_is_valid(bdata->ctrl_pwrdown)) {
> >>+		r = devm_gpio_request_one(&dssdev->dev, bdata->ctrl_pwrdown,
> >>+				GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN");
> >>+		if (r)
> >>+			return r;
> >>+	}
> >>+
> >
> >In the error case, the other GPIO is not freed. Also maybe you should
> >free them on module removal, because now the module owns the GPIOs.
> 
> Wouldn't the usage of devm_* functions take care of this? If the
> device isn't registered successfully, then all allocations/requests
> done using devm_* functions will be free'd automatically.

Sorry, I didn't realized they are devm_* now. You are right.

A.

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Tomi Valkeinen @ 2013-02-14 12:52 UTC (permalink / raw)
  To: Igor Grinberg; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511CDA91.1050300@compulab.co.il>

[-- Attachment #1: Type: text/plain, Size: 2409 bytes --]

On 2013-02-14 14:37, Igor Grinberg wrote:
> On 02/14/13 12:59, Tomi Valkeinen wrote:
>> On 2013-02-14 11:43, Igor Grinberg wrote:
> 
>>>> True, it's generic, but does it work reliably? The panel hardware is now
>>>> partly handled in the backlight driver, and partly in the omap's panel
>>>> driver (and wherever on other platforms).
>>>
>>> It works reliably on other platforms, but not on OMAP - because
>>> we need to cope with the OMAP specific framework...
> 
>> How do you handle the gpios on other platform? Those are the ones
>> causing the issues here, right?
> 
> Well, I'm also talking about something that is a history already.
> Remember, we had multiple panel drivers inside the
> video/omap2/displays and then they were consolidated into the
> "generic dpi/dsi/whatever".

Sorry, I miss the point. Was that a bad thing? Didn't it simplify the
task for you with simple panels? It could've been taken even further,
though (see below).

> And yes you are right, on the platforms I'm aware of, the GPIO is not
> handled. Apparently its hardware default (pull resistor) is always on...

Ok, so the simple fix of setting the GPIOs only in the board file is
acceptable for now.

Can the LCD_BL_GPIO be handled by the omap panel driver? Otherwise the
backlight will supposedly be always on. Is it just a simple switch for
the BL power, which does not affect the SPI in any way?

>> Or is there something else with OMAP DSS that you need to specifically
>> cope with?
> 
> The fact there is a need to create a OMAP specific driver.
> I'm not talking about the generic driver which only needs to have the
> controller specific data (e.g. porches, pixel clock, bus width).
> The generic driver was one of the good ways to go.

Well, we could also have an even more generic driver that takes the
video timings from the board file as platform data. Then all you would
need to do is to define the timings in the board file, as I think is
done for other platforms also.

I'm not very fond of that idea, as I think hardcoded device specific
data should not be given as parameters, but they should be handled by
the device driver internally, as it should know that device specific
data already.

But, in practice, making this kind of even more generic panel driver
will probably make life easier for everyone, so I think we'll have one
with CDF.

 Tomi


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* Re: [PATCH 05/33] arm: omap: board-cm-t35: use generic dpi panel's gpio handling
From: Igor Grinberg @ 2013-02-14 13:51 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev, Tony Lindgren
In-Reply-To: <511CDE12.60701@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/14/13 14:52, Tomi Valkeinen wrote:
> On 2013-02-14 14:37, Igor Grinberg wrote:
>> On 02/14/13 12:59, Tomi Valkeinen wrote:
>>> On 2013-02-14 11:43, Igor Grinberg wrote:
>>
>>>>> True, it's generic, but does it work reliably? The panel hardware is now
>>>>> partly handled in the backlight driver, and partly in the omap's panel
>>>>> driver (and wherever on other platforms).
>>>>
>>>> It works reliably on other platforms, but not on OMAP - because
>>>> we need to cope with the OMAP specific framework...
>>
>>> How do you handle the gpios on other platform? Those are the ones
>>> causing the issues here, right?
>>
>> Well, I'm also talking about something that is a history already.
>> Remember, we had multiple panel drivers inside the
>> video/omap2/displays and then they were consolidated into the
>> "generic dpi/dsi/whatever".
> 
> Sorry, I miss the point. Was that a bad thing? Didn't it simplify the
> task for you with simple panels? It could've been taken even further,
> though (see below).

Yes it was a good thing (I have already told this below).

> 
>> And yes you are right, on the platforms I'm aware of, the GPIO is not
>> handled. Apparently its hardware default (pull resistor) is always on...
> 
> Ok, so the simple fix of setting the GPIOs only in the board file is
> acceptable for now.

Yep. I also told this already in one of the previous emails.

> 
> Can the LCD_BL_GPIO be handled by the omap panel driver? Otherwise the
> backlight will supposedly be always on. Is it just a simple switch for
> the BL power, which does not affect the SPI in any way?

Yes, it can for now.
Also, I think we should also take into account the backlight framework,
including PMW.

> 
>>> Or is there something else with OMAP DSS that you need to specifically
>>> cope with?
>>
>> The fact there is a need to create a OMAP specific driver.
>> I'm not talking about the generic driver which only needs to have the
>> controller specific data (e.g. porches, pixel clock, bus width).
>> The generic driver was one of the good ways to go.
> 
> Well, we could also have an even more generic driver that takes the
> video timings from the board file as platform data. Then all you would
> need to do is to define the timings in the board file, as I think is
> done for other platforms also.

Yep. That sounds reasonable also for cases where the bus width is the
hardware (board) property.

> 
> I'm not very fond of that idea, as I think hardcoded device specific
> data should not be given as parameters, but they should be handled by
> the device driver internally, as it should know that device specific
> data already.

Yes, that is why I think the generic driver for "simple" panels
was a good idea. There was some flexibility missing though.
For example the resolution setting which in turn drags another set
of timings and pixel clock.
There are panels that support more than one resolution.

> 
> But, in practice, making this kind of even more generic panel driver
> will probably make life easier for everyone, so I think we'll have one
> with CDF.

I'm looking forward to see it happening!

- -- 
Regards,
Igor.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJRHOvEAAoJEBDE8YO64EfaCZ0P/32SYC7MZRJMfUVrnzZtJZpn
9BKzrvO0h/GKZMbKoKKNFwmvlTxEocELLkljF35ipbc51C/dpD45ZmMBvu4s8owE
6bopGw6ssTahTKk0zY5PekTamZT7UlY86hI9ZcZBxSzY8xaj7UCSPnJ3qzY2ZGzA
4heJW01mlHr9i1qkOzxz0IHA2CdQmQltAsW12NFCWYBRpDfhrYtECwhlnvLXHEzy
nqXNpRHOnrL/hqvJwor1X+D/O1JlyxUiVr6+7sAZqXxvv/iMX8Nc1XeTObgGbse6
1bpipPD57etqISsN1g9ur1tU5f6KvoR4IA35RaCCkBFINIXMEBl7kr5X9Bcg3giE
3pz23k91KRloOcXJ0OvLHp7RnSrwswU/4C3Cse+95cY0wyChaVlwJtySEnfGALWV
aiuw89v6DXaC5WDQq55UtTc3qjc23Ehut8i184PAv5HKrDHLLjVg4HqgGjC9uGEn
JKOxOnfMTstqyKC2whW+Pep3g4npJAHsn/0QmpdSJQ/vEwm7CmXBZeR6DwcTSLAT
xR1SUWwHav2HqpYUz4y7TgIPuwsR+VNKn/mSOTbhbLB4s9bowPMxMiqz2AQn3ige
YyMTo7KnObivXZydrVrx0/e/DJC4ENGpE3macVQytr0BpjJhK1+XiNMHa17+Mymm
U45VDKrUgaYcYXW2L4JN
=xeSz
-----END PGP SIGNATURE-----

^ permalink raw reply

* [GIT PULL] omapdss fixes for 3.8
From: Tomi Valkeinen @ 2013-02-14 17:27 UTC (permalink / raw)
  To: Linus Torvalds, linux-omap, linux-fbdev

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

Hi Linus,

It'd be great if these two late fixes would still make it into 3.8. The other
one fixes ARM kernel compilation when using 'allyesconfig', and the other makes
DPI displays function again on OMAP3630 boards.

 Tomi

The following changes since commit 836dc9e3fbbab0c30aa6e664417225f5c1fb1c39:

  Linux 3.8-rc7 (2013-02-09 08:20:39 +1100)

are available in the git repository at:

  git://gitorious.org/linux-omap-dss2/linux.git tags/omapdss-for-3.8-rc8

for you to fetch changes up to 91e83ffd6d3ba4de21202b4f541777a7a8db02c8:

  omapdrm: fix the dependency to omapdss (2013-02-14 13:08:29 +0200)

----------------------------------------------------------------
* Fix ARM compilation with "allyesconfig" (omapdrm: fix the dependency to
  omapdss)

* fix DPI displays on OMAP3630 (OMAPDSS: add FEAT_DPI_USES_VDDS_DSI to
  omap3630_dss_feat_list)

----------------------------------------------------------------
NeilBrown (1):
      OMAPDSS: add FEAT_DPI_USES_VDDS_DSI to omap3630_dss_feat_list

Tomi Valkeinen (1):
      omapdrm: fix the dependency to omapdss

 drivers/staging/omapdrm/Kconfig        |    2 +-
 drivers/video/omap2/dss/dss_features.c |    1 +
 2 files changed, 2 insertions(+), 1 deletion(-)


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* [PATCH/RFC] mfd: as3711: add OF support
From: Guennadi Liakhovetski @ 2013-02-15 10:07 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Samuel Ortiz,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Mark Brown,
	Magnus Damm, Simon Horman, Richard Purdie, Andrew Morton,
	Liam Girdwood

Add device-tree bindings to the AS3711 regulator and backlight drivers.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---

As usual - comments to the new bindings are very welcome!

 Documentation/devicetree/bindings/mfd/as3711.txt |   73 +++++++++++++
 drivers/mfd/as3711.c                             |   30 +++++-
 drivers/regulator/as3711-regulator.c             |   69 ++++++++++++-
 drivers/video/backlight/as3711_bl.c              |  118 +++++++++++++++++++++-
 4 files changed, 282 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/as3711.txt

diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt
new file mode 100644
index 0000000..d98cf18
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/as3711.txt
@@ -0,0 +1,73 @@
+AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power
+supplies, a battery charger and an RTC. So far only bindings for the two stepup
+DCDC converters are defined. Other DCDC and LDO supplies are configured, using
+standard regulator properties, they must belong to a sub-node, called
+"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter
+configuration should be placed in a subnode, called "backlight."
+
+Compulsory properties:
+- compatible		: must be "ams,as3711"
+- reg			: specifies the I2C address
+
+To use the SU1 converter as a backlight source the following two properties must
+be provided:
+- su1-dev		: framebuffer phandle
+- su1-max-uA		: maximum current
+
+To use the SU2 converter as a backlight source the following two properties must
+be provided:
+- su2-dev		: framebuffer phandle
+- su1-max-uA		: maximum current
+
+Additionally one of these properties must be provided to select the type of
+feedback used:
+- su2-feedback-voltage	: voltage feedback is used
+- su2-feedback-curr1	: CURR1 input used for current feedback
+- su2-feedback-curr2	: CURR2 input used for current feedback
+- su2-feedback-curr3	: CURR3 input used for current feedback
+- su2-feedback-curr-auto: automatic current feedback selection
+
+and one of these to select the over-voltage protection pin
+- su2-fbprot-lx-sd4	: LX_SD4 is used for over-voltage protection
+- su2-fbprot-gpio2	: GPIO2 is used for over-voltage protection
+- su2-fbprot-gpio3	: GPIO3 is used for over-voltage protection
+- su2-fbprot-gpio4	: GPIO4 is used for over-voltage protection
+
+If "su2-feedback-curr-auto" is selected, one or more of the following properties
+have to be specified:
+- su2-auto-curr1	: use CURR1 input for current feedback
+- su2-auto-curr2	: use CURR2 input for current feedback
+- su2-auto-curr3	: use CURR3 input for current feedback
+
+Example:
+
+as3711@40 {
+	compatible = "ams,as3711";
+	reg = <0x40>;
+
+	regulators {
+		sd4 {
+			regulator-name = "1.215V";
+			regulator-min-microvolt = <1215000>;
+			regulator-max-microvolt = <1235000>;
+		};
+		ldo2 {
+			regulator-name = "2.8V CPU";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			regulator-always-on;
+			regulator-boot-on;
+		};
+	};
+
+	backlight {
+		compatible = "ams,as3711-bl";
+		su2-dev = <&lcdc>;
+		su2-max-uA = <36000>;
+		su2-feedback-curr-auto;
+		su2-fbprot-gpio4;
+		su2-auto-curr1;
+		su2-auto-curr2;
+		su2-auto-curr3;
+	};
+};
diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c
index e994c96..5e0e8b3 100644
--- a/drivers/mfd/as3711.c
+++ b/drivers/mfd/as3711.c
@@ -112,16 +112,37 @@ static const struct regmap_config as3711_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+#ifdef CONFIG_OF
+static struct of_device_id as3711_of_match[] = {
+	{.compatible = "ams,as3711",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, as3711_of_match);
+#endif
+
 static int as3711_i2c_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
 	struct as3711 *as3711;
-	struct as3711_platform_data *pdata = client->dev.platform_data;
+	struct as3711_platform_data *pdata;
 	unsigned int id1, id2;
 	int ret;
 
-	if (!pdata)
-		dev_dbg(&client->dev, "Platform data not found\n");
+	if (!client->dev.of_node) {
+		pdata = client->dev.platform_data;
+		if (!pdata)
+			dev_dbg(&client->dev, "Platform data not found\n");
+	} else {
+		if (!of_device_is_available(client->dev.of_node))
+			return -ENODEV;
+
+		pdata = devm_kzalloc(&client->dev,
+				     sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "Failed to allocate pdata\n");
+			return -ENOMEM;
+		}
+	}
 
 	as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
 	if (!as3711) {
@@ -193,7 +214,8 @@ static struct i2c_driver as3711_i2c_driver = {
 	.driver = {
 		   .name = "as3711",
 		   .owner = THIS_MODULE,
-		   },
+		   .of_match_table = of_match_ptr(as3711_of_match),
+	},
 	.probe = as3711_i2c_probe,
 	.remove = as3711_i2c_remove,
 	.id_table = as3711_i2c_id,
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index f0ba8c4..cf145fc 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -13,9 +13,11 @@
 #include <linux/init.h>
 #include <linux/mfd/as3711.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/slab.h>
 
 struct as3711_regulator_info {
@@ -276,6 +278,57 @@ static struct as3711_regulator_info as3711_reg_info[] = {
 
 #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info)
 
+static const char *as3711_regulator_of_names[AS3711_REGULATOR_NUM] = {
+	[AS3711_REGULATOR_SD_1] = "sd1",
+	[AS3711_REGULATOR_SD_2] = "sd2",
+	[AS3711_REGULATOR_SD_3] = "sd3",
+	[AS3711_REGULATOR_SD_4] = "sd4",
+	[AS3711_REGULATOR_LDO_1] = "ldo1",
+	[AS3711_REGULATOR_LDO_2] = "ldo2",
+	[AS3711_REGULATOR_LDO_3] = "ldo3",
+	[AS3711_REGULATOR_LDO_4] = "ldo4",
+	[AS3711_REGULATOR_LDO_5] = "ldo5",
+	[AS3711_REGULATOR_LDO_6] = "ldo6",
+	[AS3711_REGULATOR_LDO_7] = "ldo7",
+	[AS3711_REGULATOR_LDO_8] = "ldo8",
+};
+
+static int as3711_regulator_parse_dt(struct device *dev)
+{
+	struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
+	struct device_node *regulators +		of_find_node_by_name(dev->parent->of_node, "regulators");
+	struct of_regulator_match *matches, *match;
+	const int count = AS3711_REGULATOR_NUM;
+	int ret, i;
+
+	if (!regulators) {
+		dev_err(dev, "regulator node not found\n");
+		return -ENODEV;
+	}
+
+	matches = devm_kzalloc(dev, sizeof(*matches) * count, GFP_KERNEL);
+	if (!matches)
+		return -ENOMEM;
+
+	for (i = 0, match = matches; i < count; i++, match++) {
+		match->name = as3711_regulator_of_names[i];
+		match->driver_data = as3711_reg_info + i;
+	}
+
+	ret = of_regulator_match(dev->parent, regulators, matches, count);
+	if (ret < 0) {
+		dev_err(dev, "Error parsing regulator init data: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0, match = matches; i < count; i++, match++)
+		if (match->of_node)
+			pdata->init_data[i] = match->init_data;
+
+	return 0;
+}
+
 static int as3711_regulator_probe(struct platform_device *pdev)
 {
 	struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -289,8 +342,18 @@ static int as3711_regulator_probe(struct platform_device *pdev)
 	int ret;
 	int id;
 
-	if (!pdata)
-		dev_dbg(&pdev->dev, "No platform data...\n");
+	if (!pdata) {
+		dev_err(&pdev->dev, "No platform data...\n");
+		return -ENODEV;
+	}
+
+	if (pdev->dev.parent->of_node) {
+		ret = as3711_regulator_parse_dt(&pdev->dev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
+			return ret;
+		}
+	}
 
 	regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
 			sizeof(struct as3711_regulator), GFP_KERNEL);
@@ -300,7 +363,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
 	}
 
 	for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
-		reg_data = pdata ? pdata->init_data[id] : NULL;
+		reg_data = pdata->init_data[id];
 
 		/* No need to register if there is no regulator data */
 		if (!reg_data)
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
index c6bc65d..90c9208 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -257,6 +257,109 @@ static int as3711_bl_register(struct platform_device *pdev,
 	return 0;
 }
 
+static int as3711_backlight_parse_dt(struct device *dev)
+{
+	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
+	struct device_node *bl +		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
+	int ret;
+
+	if (!bl) {
+		dev_dbg(dev, "backlight node not found\n");
+		return -ENODEV;
+	}
+
+	fb = of_parse_phandle(bl, "su1-dev", 0);
+	if (fb) {
+		pdata->su1_fb = fb->full_name;
+
+		ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
+		if (pdata->su1_max_uA <= 0)
+			ret = -EINVAL;
+		if (ret < 0)
+			return ret;
+	}
+
+	fb = of_parse_phandle(bl, "su2-dev", 0);
+	if (fb) {
+		int count = 0;
+
+		pdata->su2_fb = fb->full_name;
+
+		ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
+		if (pdata->su2_max_uA <= 0)
+			ret = -EINVAL;
+		if (ret < 0)
+			return ret;
+
+		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr1", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR1;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr2", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR2;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr3", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR3;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
+			count++;
+		}
+		if (count != 1)
+			return -EINVAL;
+
+		count = 0;
+		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_LX_SD4;
+			count++;
+		}
+		if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_GPIO2;
+			count++;
+		}
+		if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_GPIO3;
+			count++;
+		}
+		if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_GPIO4;
+			count++;
+		}
+		if (count != 1)
+			return -EINVAL;
+
+		count = 0;
+		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
+			pdata->su2_auto_curr1 = true;
+			count++;
+		}
+		if (of_find_property(bl, "su2-auto-curr2", NULL)) {
+			pdata->su2_auto_curr2 = true;
+			count++;
+		}
+		if (of_find_property(bl, "su2-auto-curr3", NULL)) {
+			pdata->su2_auto_curr3 = true;
+			count++;
+		}
+
+		/*
+		 * At least one su2-auto-curr* must be specified iff
+		 * AS3711_SU2_CURR_AUTO is used
+		 */
+		if (!count ^ pdata->su2_feedback != AS3711_SU2_CURR_AUTO)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int as3711_backlight_probe(struct platform_device *pdev)
 {
 	struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -266,11 +369,24 @@ static int as3711_backlight_probe(struct platform_device *pdev)
 	unsigned int max_brightness;
 	int ret;
 
-	if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) {
+	if (!pdata) {
 		dev_err(&pdev->dev, "No platform data, exiting...\n");
 		return -ENODEV;
 	}
 
+	if (pdev->dev.parent->of_node) {
+		ret = as3711_backlight_parse_dt(&pdev->dev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (!pdata->su1_fb && !pdata->su2_fb) {
+		dev_err(&pdev->dev, "No framebuffer specified\n");
+		return -EINVAL;
+	}
+
 	/*
 	 * Due to possible hardware damage I chose to block all modes,
 	 * unsupported on my hardware. Anyone, wishing to use any of those modes
-- 
1.7.2.5


^ permalink raw reply related

* [RFC] ARM: shmobile: add framebuffer and backlight support to kzm9g-reference
From: Guennadi Liakhovetski @ 2013-02-15 10:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Magnus Damm, Simon Horman, devicetree-discuss, Samuel Ortiz,
	Mark Brown, Liam Girdwood, Richard Purdie, Andrew Morton,
	linux-fbdev
In-Reply-To: <Pine.LNX.4.64.1302151101140.7446@axis700.grange>

This adds support for the framebuffer and an AS3711 PMIC, used for supplying
power to the CPU, some peripherals and the backlight.

not-Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---

As is clear from the not-Sob line and the RFC in the subject, this is not 
for mainline. This is just an illustration how the recently submitted 
"mfd: as3711: add OF support" patch can be used with the kzm9g board. I 
had to add the framebuffer support to kzm9g, because without it the 
backlight would just be turned on with no image on the LCD, which doesn't 
look pretty. In the future, if needed, we could first only apply the 
regulator part of the .dts, leaving the backlight disabled.

 arch/arm/boot/dts/sh73a0-kzm9g-reference.dts   |   90 ++++++++++++++++++++++++
 arch/arm/mach-shmobile/board-kzm9g-reference.c |   73 +++++++++++++++++++-
 2 files changed, 162 insertions(+), 1 deletions(-)

diff --git a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
index b93b16a..a5810fc 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
@@ -99,6 +99,12 @@
 		toshiba,mmc-wrprotect-disable;
 		toshiba,mmc-has-idle-wait;
 	};
+
+	/* A dummy LCDC DT node for now */
+	lcdc: lcdc@0xfe940000 {
+		compatible = "renesas,sh-mobile-lcdc";
+		reg = <0xfe940000 0x4000>;
+	};
 };
 
 &i2c3 {
@@ -106,6 +112,90 @@
 	pinctrl-0 = <&i2c3_pins>;
 };
 
+&i2c0 {
+	as3711@40 {
+		compatible = "ams,as3711";
+		reg = <0x40>;
+
+		regulators {
+			sd1 {
+				regulator-name = "1.315V CPU";
+				regulator-min-microvolt = <1315000>;
+				regulator-max-microvolt = <1335000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			sd2 {
+				regulator-name = "1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			sd4 {
+				regulator-name = "1.215V";
+				regulator-min-microvolt = <1215000>;
+				regulator-max-microvolt = <1235000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo2 {
+				regulator-name = "2.8V CPU";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo3 {
+				regulator-name = "3.0V CPU";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo4 {
+				regulator-name = "2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo5 {
+				regulator-name = "2.8V #2";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo7 {
+				regulator-name = "1.15V CPU";
+				regulator-min-microvolt = <1150000>;
+				regulator-max-microvolt = <1150000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+			ldo8 {
+				regulator-name = "1.15V CPU #2";
+				regulator-min-microvolt = <1150000>;
+				regulator-max-microvolt = <1150000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+		};
+
+		backlight {
+			compatible = "ams,as3711-bl";
+			su2-dev = <&lcdc>;
+			su2-max-uA = <36000>;
+			su2-feedback-curr-auto;
+			su2-fbprot-gpio4;
+			su2-auto-curr1;
+			su2-auto-curr2;
+			su2-auto-curr3;
+		};
+	};
+};
+
 &gpio {
 	sdhi0_pins: pfc_sdhi0_pins {
 		renesas,pins = "sdhi0_data4", "sdhi0_ctrl", "sdhi0_wp", "sdhi0_cd";
diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c
index 1490246..9d520ca 100644
--- a/arch/arm/mach-shmobile/board-kzm9g-reference.c
+++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c
@@ -31,6 +31,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
+#include <linux/videodev2.h>
 
 #include <mach/irqs.h>
 #include <mach/sh73a0.h>
@@ -39,6 +40,62 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include <video/sh_mobile_lcdc.h>
+
+/* LCDC */
+static struct fb_videomode kzm_lcdc_mode = {
+	.name		= "WVGA Panel",
+	.xres		= 800,
+	.yres		= 480,
+	.left_margin	= 220,
+	.right_margin	= 110,
+	.hsync_len	= 70,
+	.upper_margin	= 20,
+	.lower_margin	= 5,
+	.vsync_len	= 5,
+	.sync		= 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc_info = {
+	.clock_source = LCDC_CLK_BUS,
+	.ch[0] = {
+		.chan		= LCDC_CHAN_MAINLCD,
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.interface_type	= RGB24,
+		.lcd_modes	= &kzm_lcdc_mode,
+		.num_modes	= 1,
+		.clock_divider	= 5,
+		.flags		= 0,
+		.panel_cfg = {
+			.width	= 152,
+			.height	= 91,
+		},
+	}
+};
+
+static struct resource lcdc_resources[] = {
+	[0] = {
+		.name	= "LCDC",
+		.start	= 0xfe940000,
+		.end	= 0xfe943fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x580),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device lcdc_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(lcdc_resources),
+	.resource	= lcdc_resources,
+	.dev	= {
+		.platform_data	= &lcdc_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
 /* Dummy supplies, where voltage doesn't matter */
 static struct regulator_consumer_supply dummy_supplies[] = {
 	REGULATOR_SUPPLY("vddvario", "smsc911x"),
@@ -79,6 +136,15 @@ static const struct pinctrl_map kzm_pinctrl_map[] = {
 				  "scifa4_data", "scifa4"),
 	PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.4", "e6050000.pfc",
 				  "scifa4_ctrl", "scifa4"),
+	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_lcdc_fb.0", "e6050000.pfc",
+				  "lcd_data24", "lcd"),
+	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_lcdc_fb.0", "e6050000.pfc",
+				  "lcd_sync", "lcd"),
+};
+
+static struct platform_device *kzm_devices[] __initdata = {
+	&smsc_device,
+	&lcdc_device,
 };
 
 static void __init kzm_init(void)
@@ -88,7 +154,10 @@ static void __init kzm_init(void)
 	pinctrl_register_mappings(kzm_pinctrl_map, ARRAY_SIZE(kzm_pinctrl_map));
 
 	regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies));
-	platform_device_register(&smsc_device);
+
+	/* LCDC */
+	gpio_request_one(222, GPIOF_OUT_INIT_HIGH, NULL); /* LCDCDON */
+	gpio_request_one(226, GPIOF_OUT_INIT_HIGH, NULL); /* SC */
 
 	/*
 	 * Enable SD: this is a pseudo-GPIO, it actually only sets bit 28 in
@@ -101,6 +170,8 @@ static void __init kzm_init(void)
 	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
 	l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
 #endif
+
+	platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
 }
 
 static void kzm9g_restart(char mode, const char *cmd)
-- 
1.7.2.5


^ permalink raw reply related

* [PATCH RFC] video: Add Hyper-V Synthetic Video Frame Buffer Driver
From: Haiyang Zhang @ 2013-02-15 18:48 UTC (permalink / raw)
  To: FlorianSchandinat, linux-fbdev
  Cc: haiyangz, kys, olaf, jasowang, linux-kernel, devel

This is the driver for the Hyper-V Synthetic Video, which supports screen
resolution up to Full HD 1920x1080 on Windows Server 2012 host, and 1600x1200
on  Windows Server 2008 R2 or earlier.
It also solves the double mouse cursor issue of the emulated video mode.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
---
 drivers/video/Kconfig     |   11 +
 drivers/video/Makefile    |    1 +
 drivers/video/hyperv_fb.c |  983 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/video/vesafb.c    |   48 +++
 include/linux/hyperv.h    |   11 +
 5 files changed, 1054 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/hyperv_fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1e2f2d8..7d2a721 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2449,6 +2449,17 @@ config FB_PUV3_UNIGFX
 	  Choose this option if you want to use the Unigfx device as a
 	  framebuffer device. Without the support of PCI & AGP.
 
+config HYPERV_FB
+	tristate "Microsoft Hyper-V Synthetic Video support"
+	depends on FB && HYPERV
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	select FB_DEFERRED_IO
+	help
+	  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
+
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 136af7d..dd1c6da 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -148,6 +148,7 @@ obj-$(CONFIG_FB_MSM)              += msm/
 obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
 obj-$(CONFIG_FB_JZ4740)		  += jz4740_fb.o
 obj-$(CONFIG_FB_PUV3_UNIGFX)      += fb-puv3.o
+obj-$(CONFIG_HYPERV_FB)		  += hyperv_fb.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
new file mode 100644
index 0000000..d7c660f
--- /dev/null
+++ b/drivers/video/hyperv_fb.c
@@ -0,0 +1,983 @@
+/*
+ * Copyright (c) 2012, Microsoft Corporation.
+ *
+ * Author:
+ *   Haiyang Zhang <haiyangz@microsoft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Hyper-V Synthetic Video Frame Buffer Driver
+ *
+ * This is the driver for the Hyper-V Synthetic Video, which supports
+ * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows
+ * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2
+ * or earlier.
+ *
+ * It also solves the double mouse cursor issue of the emulated video mode.
+ *
+ * The default screen resolution is 1152x864, which may be changed by a
+ * kernel parameter:
+ *     video=hyperv_fb:<width>x<height>
+ *     For example: video=hyperv_fb:1280x1024
+ *
+ * Portrait orientation is also supported:
+ *     For example: video=hyperv_fb:864x1152
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/fb.h>
+
+#include <linux/hyperv.h>
+
+
+/* Hyper-V Synthetic Video Protocol definitions and structures */
+#define MAX_VMBUS_PKT_SIZE 0x4000
+
+#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
+#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
+#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+
+#define SYNTHVID_DEPTH_WIN7 16
+#define SYNTHVID_DEPTH_WIN8 32
+
+#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024)
+#define SYNTHVID_WIDTH_MAX_WIN7 1600
+#define SYNTHVID_HEIGHT_MAX_WIN7 1200
+
+#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
+
+
+enum pipe_msg_type {
+	PIPE_MSG_INVALID,
+	PIPE_MSG_DATA,
+	PIPE_MSG_MAX
+};
+
+struct pipe_msg_hdr {
+	u32 type;
+	u32 size; /* size of message after this field */
+} __packed;
+
+
+enum synthvid_msg_type {
+	SYNTHVID_ERROR			= 0,
+	SYNTHVID_VERSION_REQUEST	= 1,
+	SYNTHVID_VERSION_RESPONSE	= 2,
+	SYNTHVID_VRAM_LOCATION		= 3,
+	SYNTHVID_VRAM_LOCATION_ACK	= 4,
+	SYNTHVID_SITUATION_UPDATE	= 5,
+	SYNTHVID_SITUATION_UPDATE_ACK	= 6,
+	SYNTHVID_POINTER_POSITION	= 7,
+	SYNTHVID_POINTER_SHAPE		= 8,
+	SYNTHVID_FEATURE_CHANGE		= 9,
+	SYNTHVID_DIRT			= 10,
+
+	SYNTHVID_MAX			= 11
+};
+
+struct synthvid_msg_hdr {
+	u32 type;
+	u32 size;  /* size of this header + payload after this field*/
+} __packed;
+
+
+struct synthvid_version_req {
+	u32 version;
+} __packed;
+
+struct synthvid_version_resp {
+	u32 version;
+	u8 is_accepted;
+	u8 max_video_outputs;
+} __packed;
+
+struct synthvid_vram_location {
+	u64 user_ctx;
+	u8 is_vram_gpa_specified;
+	u64 vram_gpa;
+} __packed;
+
+struct synthvid_vram_location_ack {
+	u64 user_ctx;
+} __packed;
+
+struct video_output_situation {
+	u8 active;
+	u32 vram_offset;
+	u8 depth_bits;
+	u32 width_pixels;
+	u32 height_pixels;
+	u32 pitch_bytes;
+} __packed;
+
+struct synthvid_situation_update {
+	u64 user_ctx;
+	u8 video_output_count;
+	struct video_output_situation video_output[1];
+} __packed;
+
+struct synthvid_situation_update_ack {
+	u64 user_ctx;
+} __packed;
+
+struct synthvid_pointer_position {
+	u8 is_visible;
+	u8 video_output;
+	s32 image_x;
+	s32 image_y;
+} __packed;
+
+
+#define CURSOR_MAX_X 96
+#define CURSOR_MAX_Y 96
+#define CURSOR_ARGB_PIXEL_SIZE 4
+#define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE)
+#define CURSOR_COMPLETE (-1)
+
+struct synthvid_pointer_shape {
+	u8 part_idx;
+	u8 is_argb;
+	u32 width; /* CURSOR_MAX_X at most */
+	u32 height; /* CURSOR_MAX_Y at most */
+	u32 hot_x; /* hotspot relative to upper-left of pointer image */
+	u32 hot_y;
+	u8 data[4];
+} __packed;
+
+struct synthvid_feature_change {
+	u8 is_dirt_needed;
+	u8 is_ptr_pos_needed;
+	u8 is_ptr_shape_needed;
+	u8 is_situ_needed;
+} __packed;
+
+struct rect {
+	s32 x1, y1; /* top left corner */
+	s32 x2, y2; /* bottom right corner, exclusive */
+} __packed;
+
+struct synthvid_dirt {
+	u8 video_output;
+	u8 dirt_count;
+	struct rect rect[1];
+} __packed;
+
+struct synthvid_msg {
+	struct pipe_msg_hdr pipe_hdr;
+	struct synthvid_msg_hdr vid_hdr;
+	union {
+		struct synthvid_version_req ver_req;
+		struct synthvid_version_resp ver_resp;
+		struct synthvid_vram_location vram;
+		struct synthvid_vram_location_ack vram_ack;
+		struct synthvid_situation_update situ;
+		struct synthvid_situation_update_ack situ_ack;
+		struct synthvid_pointer_position ptr_pos;
+		struct synthvid_pointer_shape ptr_shape;
+		struct synthvid_feature_change feature_chg;
+		struct synthvid_dirt dirt;
+	};
+} __packed;
+
+
+
+/* FB driver definitions and structures */
+#define HVFB_WIDTH 1152 /* default screen width */
+#define HVFB_HEIGHT 864 /* default screen height */
+#define HVFB_WIDTH_MIN 640
+#define HVFB_HEIGHT_MIN 480
+
+#define RING_BUFSIZE (256 * 1024)
+#define VSP_TIMEOUT (10 * HZ)
+#define HVFB_UPDATE_DELAY (HZ / 30)
+
+struct hvfb_par {
+	struct fb_info *info;
+	bool info_ready; /* info and its fields are set up */
+	struct completion wait;
+	u32 synthvid_version;
+
+	struct delayed_work dwork;
+	spinlock_t area_lock; /* protect changed area */
+	int x1, y1, x2, y2; /* changed rectangle area */
+
+	u32 pseudo_palette[16];
+	u8 init_buf[MAX_VMBUS_PKT_SIZE];
+	u8 recv_buf[MAX_VMBUS_PKT_SIZE];
+};
+
+static uint screen_width = HVFB_WIDTH;
+static uint screen_height = HVFB_HEIGHT;
+static uint screen_depth;
+static uint screen_fb_size;
+
+/* Send message to Hyper-V host */
+static inline int synthvid_send(struct hv_device *hdev,
+				struct synthvid_msg *msg)
+{
+	static atomic64_t request_id = ATOMIC64_INIT(0);
+	int ret;
+
+	msg->pipe_hdr.type = PIPE_MSG_DATA;
+	msg->pipe_hdr.size = msg->vid_hdr.size;
+
+	ret = vmbus_sendpacket(hdev->channel, msg,
+			       msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
+			       atomic64_inc_return(&request_id),
+			       VM_PKT_DATA_INBAND, 0);
+
+	if (ret)
+		pr_err("Unable to send packet via vmbus\n");
+
+	return ret;
+}
+
+
+/* Send screen resolution info to host */
+static int synthvid_send_situ(struct hv_device *hdev)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par;
+	struct synthvid_msg msg;
+
+	if (!info)
+		return -ENODEV;
+
+	par = info->par;
+	if (!par->info_ready)
+		return -ENODEV;
+
+	memset(&msg, 0, sizeof(struct synthvid_msg));
+
+	msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
+	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_situation_update);
+	msg.situ.user_ctx = 0;
+	msg.situ.video_output_count = 1;
+	msg.situ.video_output[0].active = 1;
+	msg.situ.video_output[0].vram_offset = 0;
+	msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel;
+	msg.situ.video_output[0].width_pixels = info->var.xres;
+	msg.situ.video_output[0].height_pixels = info->var.yres;
+	msg.situ.video_output[0].pitch_bytes = info->fix.line_length;
+
+	synthvid_send(hdev, &msg);
+
+	return 0;
+}
+
+/* Send mouse pointer info to host */
+static int synthvid_send_ptr(struct hv_device *hdev)
+{
+	struct synthvid_msg msg;
+
+	memset(&msg, 0, sizeof(struct synthvid_msg));
+	msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
+	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_pointer_position);
+	msg.ptr_pos.is_visible = 1;
+	msg.ptr_pos.video_output = 0;
+	msg.ptr_pos.image_x = 0;
+	msg.ptr_pos.image_y = 0;
+	synthvid_send(hdev, &msg);
+
+	memset(&msg, 0, sizeof(struct synthvid_msg));
+	msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
+	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_pointer_shape);
+	msg.ptr_shape.part_idx = CURSOR_COMPLETE;
+	msg.ptr_shape.is_argb = 1;
+	msg.ptr_shape.width = 1;
+	msg.ptr_shape.height = 1;
+	msg.ptr_shape.hot_x = 0;
+	msg.ptr_shape.hot_y = 0;
+	msg.ptr_shape.data[0] = 0;
+	msg.ptr_shape.data[1] = 1;
+	msg.ptr_shape.data[2] = 1;
+	msg.ptr_shape.data[3] = 1;
+	synthvid_send(hdev, &msg);
+
+	return 0;
+}
+
+/* Send updated screen area (dirty rectangle) location to host */
+static int synthvid_update(struct fb_info *info, int x1, int y1,
+			   int x2, int y2)
+{
+	struct hv_device *hdev = device_to_hv_device(info->device);
+	struct synthvid_msg msg;
+
+	memset(&msg, 0, sizeof(struct synthvid_msg));
+
+	msg.vid_hdr.type = SYNTHVID_DIRT;
+	msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_dirt);
+	msg.dirt.video_output = 0;
+	msg.dirt.dirt_count = 1;
+	msg.dirt.rect[0].x1 = x1;
+	msg.dirt.rect[0].y1 = y1;
+	msg.dirt.rect[0].x2 = x2;
+	msg.dirt.rect[0].y2 = y2;
+
+	synthvid_send(hdev, &msg);
+
+	return 0;
+}
+
+
+/*
+ * Actions on received messages from host:
+ * Complete the wait event.
+ * Or, reply with screen and cursor info.
+ */
+static void synthvid_recv_sub(struct hv_device *hdev)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par;
+	struct synthvid_msg *msg;
+
+	if (!info)
+		return;
+
+	par = info->par;
+	msg = (struct synthvid_msg *)par->recv_buf;
+
+	/* Complete the wait event */
+	if (msg->vid_hdr.type = SYNTHVID_VERSION_RESPONSE ||
+	    msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION_ACK) {
+		memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
+		complete(&par->wait);
+		return;
+	}
+
+	/* Reply with screen and cursor info */
+	if (msg->vid_hdr.type = SYNTHVID_FEATURE_CHANGE) {
+		synthvid_send_situ(hdev);
+		synthvid_send_ptr(hdev);
+	}
+
+}
+
+/* Receive callback for messages from the host */
+static void synthvid_receive(void *ctx)
+{
+	struct hv_device *hdev = ctx;
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par;
+	struct synthvid_msg *recv_buf;
+	u32 bytes_recvd;
+	u64 req_id;
+	int ret;
+
+	if (!info)
+		return;
+
+	par = info->par;
+	recv_buf = (struct synthvid_msg *)par->recv_buf;
+
+	do {
+		ret = vmbus_recvpacket(hdev->channel, recv_buf,
+				       MAX_VMBUS_PKT_SIZE,
+				       &bytes_recvd, &req_id);
+		if (bytes_recvd > 0 &&
+		    recv_buf->pipe_hdr.type = PIPE_MSG_DATA)
+			synthvid_recv_sub(hdev);
+	} while (bytes_recvd > 0 && ret = 0);
+}
+
+/* Check synthetic video protocol version with the host */
+static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par = info->par;
+	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+	int t, ret = 0;
+
+	memset(msg, 0, sizeof(struct synthvid_msg));
+	msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
+	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_version_req);
+	msg->ver_req.version = ver;
+	synthvid_send(hdev, msg);
+
+	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+	if (!t) {
+		pr_err("Time out on waiting version response\n");
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+	if (!msg->ver_resp.is_accepted) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	par->synthvid_version = ver;
+
+out:
+	return ret;
+}
+
+/* Connect to VSP (Virtual Service Provider) on host */
+static int synthvid_connect_vsp(struct hv_device *hdev)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par = info->par;
+	int ret;
+
+	ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
+			 NULL, 0, synthvid_receive, hdev);
+	if (ret) {
+		pr_err("Unable to open vmbus channel\n");
+		return ret;
+	}
+
+	/* Negotiate the protocol version with host */
+	if (vmbus_proto_version = VERSION_WS2008 ||
+	    vmbus_proto_version = VERSION_WIN7)
+		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
+	else
+		ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
+
+	if (ret) {
+		pr_err("Synthetic video device version not accepted\n");
+		goto error;
+	}
+
+	if (par->synthvid_version = SYNTHVID_VERSION_WIN7) {
+		screen_depth = SYNTHVID_DEPTH_WIN7;
+		screen_fb_size = SYNTHVID_FB_SIZE_WIN7;
+	} else {
+		screen_depth = SYNTHVID_DEPTH_WIN8;
+		screen_fb_size = SYNTHVID_FB_SIZE_WIN8;
+	}
+
+	return 0;
+
+error:
+	vmbus_close(hdev->channel);
+	return ret;
+}
+
+/* Send VRAM and Situation messages to the host */
+static int synthvid_send_config(struct hv_device *hdev)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	struct hvfb_par *par = info->par;
+	struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+	int t, ret = 0;
+
+	/* Send VRAM location */
+	memset(msg, 0, sizeof(struct synthvid_msg));
+	msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
+	msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+		sizeof(struct synthvid_vram_location);
+	msg->vram.user_ctx = msg->vram.vram_gpa +		virt_to_phys(info->screen_base);
+	msg->vram.is_vram_gpa_specified = 1;
+	synthvid_send(hdev, msg);
+
+	t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+	if (!t) {
+		pr_err("Time out on waiting vram location ack\n");
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+	if (msg->vram_ack.user_ctx != virt_to_phys(info->screen_base)) {
+		pr_err("Unable to set VRAM location\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	/* Send situation and pointer update */
+	synthvid_send_situ(hdev);
+	synthvid_send_ptr(hdev);
+
+	return 0;
+
+error:
+	return ret;
+}
+
+
+static inline void hvfb_init_rect(struct hvfb_par *par)
+{
+	par->x1 = par->y1 = INT_MAX;
+	par->x2 = par->y2 = 0;
+}
+
+/*
+ * Delayed work callback:
+ * It is called at HVFB_UPDATE_DELAY or longer time interval to process
+ * screen updates from non-deferred I/O, such as imageblit, which can happen
+ * at high frequency.
+ */
+static void hvfb_update_work(struct work_struct *w)
+{
+	struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
+	struct fb_info *info = par->info;
+	int x1, y1, x2, y2;
+	ulong flags;
+
+	spin_lock_irqsave(&par->area_lock, flags);
+
+	x1 = par->x1;
+	y1 = par->y1;
+	x2 = par->x2;
+	y2 = par->y2;
+
+	hvfb_init_rect(par);
+
+	spin_unlock_irqrestore(&par->area_lock, flags);
+
+	if (x1 = INT_MAX)
+		return;
+
+	synthvid_update(info, x1, y1, x2, y2);
+}
+
+/*
+ * Record the updated screen area, and schedule the delayed work.
+ * If the work is still on the queue, schedule_delayed_work() will
+ * automatically ignore the new request. But the updated area is
+ * always recorded, and will be handled by the queued work.
+ */
+static void hvfb_add_rect(struct fb_info *info, int x1, int y1,
+			  int x2, int y2)
+{
+	struct hvfb_par *par = info->par;
+	ulong flags;
+
+	spin_lock_irqsave(&par->area_lock, flags);
+
+	if (x1 < par->x1)
+		par->x1 = x1;
+	if (y1 < par->y1)
+		par->y1 = y1;
+
+	if (x2 > par->x2)
+		par->x2 = x2;
+	if (y2 > par->y2)
+		par->y2 = y2;
+
+	spin_unlock_irqrestore(&par->area_lock, flags);
+
+	schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
+}
+
+
+
+/* Framebuffer operation handlers */
+
+static ssize_t hvfb_write(struct fb_info *info, const char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+
+	ret = fb_sys_write(info, buf, count, ppos);
+
+	hvfb_add_rect(info, 0, 0,
+		      info->var.xres, info->var.yres);
+
+	return ret;
+}
+
+
+static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN ||
+	    var->xres > screen_width || var->yres >  screen_height ||
+	    var->bits_per_pixel != screen_depth)
+		return -EINVAL;
+
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	return 0;
+}
+
+static int hvfb_set_par(struct fb_info *info)
+{
+	struct hv_device *hdev = device_to_hv_device(info->device);
+
+	return synthvid_send_situ(hdev);
+}
+
+
+static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
+{
+	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned transp, struct fb_info *info)
+{
+	u32 *pal = info->pseudo_palette;
+
+	if (regno > 15)
+		return -EINVAL;
+
+	pal[regno] = chan_to_field(red, &info->var.red)
+		| chan_to_field(green, &info->var.green)
+		| chan_to_field(blue, &info->var.blue);
+
+	return 0;
+}
+
+static void hvfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	sys_fillrect(info, rect);
+
+	hvfb_add_rect(info, rect->dx, rect->dy,
+		      rect->dx + rect->width, rect->dy + rect->height);
+}
+
+static void hvfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	sys_copyarea(info, area);
+
+	hvfb_add_rect(info, area->dx, area->dy,
+		      area->dx + area->width, area->dy + area->height);
+}
+
+static void hvfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	sys_imageblit(info, image);
+
+	hvfb_add_rect(info, image->dx, image->dy,
+		      image->dx + image->width, image->dy + image->height);
+}
+
+static struct fb_ops hvfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_read = fb_sys_read,
+	.fb_write = hvfb_write,
+	.fb_check_var = hvfb_check_var,
+	.fb_set_par = hvfb_set_par,
+	.fb_setcolreg = hvfb_setcolreg,
+	.fb_fillrect = hvfb_fillrect,
+	.fb_copyarea = hvfb_copyarea,
+	.fb_imageblit = hvfb_imageblit,
+};
+
+
+/*
+ * Callback for the deferred I/O.
+ * Applications, such as X-Window, use deferred I/O mechanism to put screen
+ * updates in batches, and send to fb driver periodically.
+ */
+static void hvfb_deferred_io(struct fb_info *info, struct list_head *pl)
+{
+	struct page *page;
+	ulong pa, pb, min = ULONG_MAX, max = 0;
+	int ymin, ymax;
+
+	list_for_each_entry(page, pl, lru) {
+		pa = page->index << PAGE_SHIFT;
+		pb = pa + PAGE_SIZE - 1;
+		if (pa < min)
+			min = pa;
+		if (pb > max)
+			max = pb;
+	}
+
+	if (max = 0)
+		return;
+
+	ymin = min / info->fix.line_length;
+	ymax = max / info->fix.line_length + 1;
+	if (ymax > info->var.yres)
+		ymax = info->var.yres;
+
+	synthvid_update(info, 0, ymin, info->var.xres, ymax);
+}
+
+static struct fb_deferred_io hvfb_defio = {
+	.delay = HVFB_UPDATE_DELAY,
+	.deferred_io = hvfb_deferred_io,
+};
+
+
+/* Get options from kernel paramenter "video=" */
+static void hvfb_get_option(struct fb_info *info)
+{
+	struct hvfb_par *par = info->par;
+	char *opt = NULL, *p;
+	uint x = 0, y = 0;
+
+	if (fb_get_options("hyperv_fb", &opt) || !opt || !*opt)
+		return;
+
+	p = strsep(&opt, "x");
+	if (!*p || kstrtouint(p, 0, &x) ||
+	    !opt || !*opt || kstrtouint(opt, 0, &y)) {
+		pr_err("Screen option is invalid: skipped\n");
+		return;
+	}
+
+	if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
+	    (par->synthvid_version = SYNTHVID_VERSION_WIN8 &&
+	     x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
+	    (par->synthvid_version = SYNTHVID_VERSION_WIN7 &&
+	     (x > SYNTHVID_WIDTH_MAX_WIN7 || y > SYNTHVID_HEIGHT_MAX_WIN7))) {
+		pr_err("Screen resolution option is out of range: skipped\n");
+		return;
+	}
+
+	screen_width = x;
+	screen_height = y;
+	return;
+}
+
+
+/* Allocate framebuffer memory */
+#define FOUR_MEGA (4*1024*1024)
+#define NALLOC 10
+static void *hvfb_getmem(void)
+{
+	ulong *p;
+	int i, j;
+	ulong ret = 0;
+
+	if (screen_fb_size = FOUR_MEGA) {
+		ret = __get_free_pages(GFP_KERNEL|__GFP_ZERO,
+				       get_order(FOUR_MEGA));
+		goto out1;
+	}
+
+	if (screen_fb_size != FOUR_MEGA * 2)
+		return NULL;
+
+	/*
+	 * Windows 2012 requires frame buffer size to be 8MB, which exceeds
+	 * the limit of __get_free_pages(). So, we allocate multiple 4MB
+	 * chunks, and find out two adjacent ones.
+	 */
+	p = kmalloc(NALLOC * sizeof(ulong), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	for (i = 0; i < NALLOC; i++)
+		p[i] = __get_free_pages(GFP_KERNEL|__GFP_ZERO,
+					get_order(FOUR_MEGA));
+
+	for (i = 0; i < NALLOC; i++)
+		for (j = 0; j < NALLOC; j++) {
+			if (p[j] && p[i] && virt_to_phys((void *)p[j]) -
+			    virt_to_phys((void *)p[i]) = FOUR_MEGA &&
+			    p[j] - p[i] = FOUR_MEGA) {
+				ret = p[i];
+				goto out;
+			}
+		}
+
+out:
+	for (i = 0; i < NALLOC; i++)
+		if (p[i] && !(ret && (p[i] = ret || p[i] = ret + FOUR_MEGA)))
+			free_pages(p[i], get_order(FOUR_MEGA));
+
+	kfree(p);
+
+out1:
+	if (!ret)
+		return NULL;
+
+	/* Get an extra ref-count to prevent page error when x-window exits */
+	for (i = 0; i < screen_fb_size; i += PAGE_SIZE)
+		atomic_inc(&virt_to_page((void *)ret + i)->_count);
+
+	return (void *)ret;
+}
+
+/* Free the frame buffer */
+static void hvfb_putmem(void *p)
+{
+	int i;
+
+	if (!p)
+		return;
+
+	for (i = 0; i < screen_fb_size; i += PAGE_SIZE)
+		atomic_dec(&virt_to_page(p + i)->_count);
+
+	free_pages((ulong)p, get_order(FOUR_MEGA));
+
+	if (screen_fb_size = FOUR_MEGA * 2)
+		free_pages((ulong)p + FOUR_MEGA, get_order(FOUR_MEGA));
+}
+
+
+static int hvfb_probe(struct hv_device *hdev,
+		      const struct hv_vmbus_device_id *dev_id)
+{
+	struct fb_info *info;
+	void *fb = NULL;
+	struct hvfb_par *par;
+	int ret = 0;
+
+	info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
+	if (!info) {
+		pr_err("No memory for framebuffer info\n");
+		return -ENOMEM;
+	}
+
+	par = info->par;
+	par->info = info;
+	par->info_ready = false;
+	init_completion(&par->wait);
+
+	/* Connect to VSP */
+	hv_set_drvdata(hdev, info);
+	ret = synthvid_connect_vsp(hdev);
+	if (ret) {
+		pr_err("Unable to connect to VSP\n");
+		goto error1;
+	}
+
+	fb = hvfb_getmem();
+	if (!fb) {
+		pr_err("No memory for framebuffer\n");
+		ret = -ENOMEM;
+		goto error2;
+	}
+
+	hvfb_get_option(info);
+	pr_info("Screen resolution: %dx%d, Color depth: %d\n",
+		screen_width, screen_height, screen_depth);
+
+
+	/* Set up fb_info */
+	info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB;
+
+	info->var.xres_virtual = info->var.xres = screen_width;
+	info->var.yres_virtual = info->var.yres = screen_height;
+	info->var.bits_per_pixel = screen_depth;
+
+	if (info->var.bits_per_pixel = 16) {
+		info->var.red = (struct fb_bitfield){11, 5, 0};
+		info->var.green = (struct fb_bitfield){5, 6, 0};
+		info->var.blue = (struct fb_bitfield){0, 5, 0};
+
+	} else {
+		info->var.red = (struct fb_bitfield){16, 8, 0};
+		info->var.green = (struct fb_bitfield){8, 8, 0};
+		info->var.blue = (struct fb_bitfield){0, 8, 0};
+	}
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.height = -1;
+	info->var.width = -1;
+	info->var.vmode = FB_VMODE_NONINTERLACED;
+
+	strcpy(info->fix.id, "hyperv");
+	info->fix.smem_start = virt_to_phys(fb);
+	info->fix.smem_len = screen_width * screen_height * screen_depth / 8;
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = screen_width * screen_depth / 8;
+	info->fix.accel = FB_ACCEL_NONE;
+
+	info->fbops = &hvfb_ops;
+	info->screen_base = fb;
+	info->pseudo_palette = par->pseudo_palette;
+
+	par->info_ready = true;
+
+	/* Send config to host */
+	ret = synthvid_send_config(hdev);
+	if (ret)
+		goto error2;
+
+	info->fbdefio = &hvfb_defio;
+	fb_deferred_io_init(info);
+
+	INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
+	spin_lock_init(&par->area_lock);
+	hvfb_init_rect(par);
+	ret = register_framebuffer(info);
+	if (ret) {
+		pr_err("Unable to register framebuffer\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	cancel_delayed_work_sync(&par->dwork);
+	fb_deferred_io_cleanup(info);
+error2:
+	vmbus_close(hdev->channel);
+error1:
+	hv_set_drvdata(hdev, NULL);
+	framebuffer_release(info);
+	hvfb_putmem(fb);
+	return ret;
+}
+
+
+static int hvfb_remove(struct hv_device *hdev)
+{
+	struct fb_info *info = hv_get_drvdata(hdev);
+	void *fb = info->screen_base;
+	struct hvfb_par *par = info->par;
+
+	fb_deferred_io_cleanup(info);
+	unregister_framebuffer(info);
+	cancel_delayed_work_sync(&par->dwork);
+
+	vmbus_close(hdev->channel);
+	hv_set_drvdata(hdev, NULL);
+
+	framebuffer_release(info);
+	hvfb_putmem(fb);
+
+	return 0;
+}
+
+
+static const struct hv_vmbus_device_id id_table[] = {
+	/* Synthetic Video Device GUID */
+	{HV_SYNTHVID_GUID},
+	{}
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
+static struct hv_driver hvfb_drv = {
+	.name = KBUILD_MODNAME,
+	.id_table = id_table,
+	.probe = hvfb_probe,
+	.remove = hvfb_remove,
+};
+
+
+static int __init hvfb_drv_init(void)
+{
+	return vmbus_driver_register(&hvfb_drv);
+}
+
+static void __exit hvfb_drv_exit(void)
+{
+	vmbus_driver_unregister(&hvfb_drv);
+}
+
+module_init(hvfb_drv_init);
+module_exit(hvfb_drv_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 501b340..34b82075 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
+#include <linux/dmi.h>
 
 #include <video/vga.h>
 #include <asm/io.h>
@@ -495,6 +496,41 @@ err:
 	return err;
 }
 
+
+#if IS_ENABLED(CONFIG_HYPERV_FB)
+static struct dmi_system_id __initdata hyperv_dmi[] = {
+	{
+		.ident = "Microsoft Virtual PC",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
+		},
+	},
+
+	{
+		.ident = "Microsoft Hyper-V",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+		},
+	},
+
+	{}
+};
+
+/* Check if we are running on Microsoft Hyper-V platform */
+static bool __init is_hyperv(void)
+{
+	/*
+	 * If the first match is "Microsoft Hyper-V", it means we are not
+	 * running on the MS Virtual PC or other platforms, but on Hyper-V.
+	 */
+	return dmi_first_match(hyperv_dmi) = hyperv_dmi + 1;
+}
+#endif
+
+
 static struct platform_driver vesafb_driver = {
 	.driver	= {
 		.name	= "vesafb",
@@ -508,6 +544,18 @@ static int __init vesafb_init(void)
 	int ret;
 	char *option = NULL;
 
+#if IS_ENABLED(CONFIG_HYPERV_FB)
+	/*
+	 * On Hyper-V both the emulated and synthetic video devices are
+	 * available. To avoid conflicts, we disable vesafb for the emulated
+	 * video if hyperv_fb is configured.
+	 */
+	if (is_hyperv()) {
+		pr_info("Disabled vesafb on Hyper-V.\n");
+		return -ENODEV;
+	}
+#endif
+
 	/* ignore error return of fb_get_options */
 	fb_get_options("vesafb", &option);
 	vesafb_setup(option);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index df77ba9..a460ee4 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1253,6 +1253,17 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
 		}
 
 /*
+ * Synthetic Video GUID
+ * {DA0A7802-E377-4aac-8E77-0558EB1073F8}
+ */
+#define HV_SYNTHVID_GUID \
+	.guid = { \
+			0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \
+			0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
+		}
+
+
+/*
  * Common header for Hyper-V ICs
  */
 
-- 
1.7.4.1


^ permalink raw reply related

* Re: [PATCH v2] fbdev: Add Renesas vdc4 framebuffer driver
From: Simon Horman @ 2013-02-16  2:04 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1347267372-22949-1-git-send-email-phil.edworthy@renesas.com>

On Fri, Oct 05, 2012 at 05:34:54PM +0100, phil.edworthy@renesas.com wrote:
> Hi,
> 
> Any news on this patch?

Phil, did this patch get merged in the end?

> 
> Thanks
> Phil
> 
> > From: Jingoo Han <jg1.han@samsung.com>
> > To: "'Phil Edworthy'" <phil.edworthy@renesas.com>, 
> > Cc: "'Florian Tobias Schandinat'" <FlorianSchandinat@gmx.de>, linux-
> > fbdev@vger.kernel.org, linux-sh@vger.kernel.org, "'Jingoo Han'" 
> > <jg1.han@samsung.com>
> > Date: 11/09/2012 03:31
> > Subject: Re: [PATCH v2] fbdev: Add Renesas vdc4 framebuffer driver
> > 
> > On Monday, September 10, 2012 5:56 PM Phil Edworthy wrote
> > > 
> > > The vdc4 display hardware is found on the sh7269 device.
> > > 
> > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > 
> > 
> > Reviewed-by: Jingoo Han <jg1.han@samsung.com>
> > 
> > Best regards,
> > Jingoo Han
> > 
> > 
> > > ---
> > > v2:
> > >  * Use devm_ variants of clk_get, ioremap_nocache, request_irq.
> > >  * Replace spaces with tabs.
> > >  * Check ren_vdc4_start return value.
> > >  * Fix headers used.
> > > 
> > >  drivers/video/Kconfig      |   10 +
> > >  drivers/video/Makefile     |    1 +
> > >  drivers/video/ren_vdc4fb.c |  641 +++++++++++++++++++++++++++++++
> > +++++++++++++
> > >  include/video/ren_vdc4fb.h |   19 ++
> > >  4 files changed, 671 insertions(+), 0 deletions(-)
> > >  create mode 100644 drivers/video/ren_vdc4fb.c
> > >  create mode 100644 include/video/ren_vdc4fb.h
> > 
> > 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* Re: [PATCH/RFC] mfd: as3711: add OF support
From: Simon Horman @ 2013-02-16  2:26 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: linux-kernel, Magnus Damm, devicetree-discuss, Samuel Ortiz,
	Mark Brown, Liam Girdwood, Richard Purdie, Andrew Morton,
	linux-fbdev
In-Reply-To: <Pine.LNX.4.64.1302151101140.7446@axis700.grange>

On Fri, Feb 15, 2013 at 11:07:16AM +0100, Guennadi Liakhovetski wrote:
> Add device-tree bindings to the AS3711 regulator and backlight drivers.

Hi,

at this stage I do not expect this code to go through the renesas tree.
However, in order to provide a basis for work on renesas SoCs I have added
this patch to the topic/backlight topic branch in the reneas tree on
kernel.org and merged it into topic/all+next.

In other words, I am not picking this patch up to merge it or add it to
linux-next, rather I am storing it for reference.

> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> 
> As usual - comments to the new bindings are very welcome!
> 
>  Documentation/devicetree/bindings/mfd/as3711.txt |   73 +++++++++++++
>  drivers/mfd/as3711.c                             |   30 +++++-
>  drivers/regulator/as3711-regulator.c             |   69 ++++++++++++-
>  drivers/video/backlight/as3711_bl.c              |  118 +++++++++++++++++++++-
>  4 files changed, 282 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mfd/as3711.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt
> new file mode 100644
> index 0000000..d98cf18
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/as3711.txt
> @@ -0,0 +1,73 @@
> +AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power
> +supplies, a battery charger and an RTC. So far only bindings for the two stepup
> +DCDC converters are defined. Other DCDC and LDO supplies are configured, using
> +standard regulator properties, they must belong to a sub-node, called
> +"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter
> +configuration should be placed in a subnode, called "backlight."
> +
> +Compulsory properties:
> +- compatible		: must be "ams,as3711"
> +- reg			: specifies the I2C address
> +
> +To use the SU1 converter as a backlight source the following two properties must
> +be provided:
> +- su1-dev		: framebuffer phandle
> +- su1-max-uA		: maximum current
> +
> +To use the SU2 converter as a backlight source the following two properties must
> +be provided:
> +- su2-dev		: framebuffer phandle
> +- su1-max-uA		: maximum current
> +
> +Additionally one of these properties must be provided to select the type of
> +feedback used:
> +- su2-feedback-voltage	: voltage feedback is used
> +- su2-feedback-curr1	: CURR1 input used for current feedback
> +- su2-feedback-curr2	: CURR2 input used for current feedback
> +- su2-feedback-curr3	: CURR3 input used for current feedback
> +- su2-feedback-curr-auto: automatic current feedback selection
> +
> +and one of these to select the over-voltage protection pin
> +- su2-fbprot-lx-sd4	: LX_SD4 is used for over-voltage protection
> +- su2-fbprot-gpio2	: GPIO2 is used for over-voltage protection
> +- su2-fbprot-gpio3	: GPIO3 is used for over-voltage protection
> +- su2-fbprot-gpio4	: GPIO4 is used for over-voltage protection
> +
> +If "su2-feedback-curr-auto" is selected, one or more of the following properties
> +have to be specified:
> +- su2-auto-curr1	: use CURR1 input for current feedback
> +- su2-auto-curr2	: use CURR2 input for current feedback
> +- su2-auto-curr3	: use CURR3 input for current feedback
> +
> +Example:
> +
> +as3711@40 {
> +	compatible = "ams,as3711";
> +	reg = <0x40>;
> +
> +	regulators {
> +		sd4 {
> +			regulator-name = "1.215V";
> +			regulator-min-microvolt = <1215000>;
> +			regulator-max-microvolt = <1235000>;
> +		};
> +		ldo2 {
> +			regulator-name = "2.8V CPU";
> +			regulator-min-microvolt = <2800000>;
> +			regulator-max-microvolt = <2800000>;
> +			regulator-always-on;
> +			regulator-boot-on;
> +		};
> +	};
> +
> +	backlight {
> +		compatible = "ams,as3711-bl";
> +		su2-dev = <&lcdc>;
> +		su2-max-uA = <36000>;
> +		su2-feedback-curr-auto;
> +		su2-fbprot-gpio4;
> +		su2-auto-curr1;
> +		su2-auto-curr2;
> +		su2-auto-curr3;
> +	};
> +};
> diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c
> index e994c96..5e0e8b3 100644
> --- a/drivers/mfd/as3711.c
> +++ b/drivers/mfd/as3711.c
> @@ -112,16 +112,37 @@ static const struct regmap_config as3711_regmap_config = {
>  	.cache_type = REGCACHE_RBTREE,
>  };
>  
> +#ifdef CONFIG_OF
> +static struct of_device_id as3711_of_match[] = {
> +	{.compatible = "ams,as3711",},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, as3711_of_match);
> +#endif
> +
>  static int as3711_i2c_probe(struct i2c_client *client,
>  			    const struct i2c_device_id *id)
>  {
>  	struct as3711 *as3711;
> -	struct as3711_platform_data *pdata = client->dev.platform_data;
> +	struct as3711_platform_data *pdata;
>  	unsigned int id1, id2;
>  	int ret;
>  
> -	if (!pdata)
> -		dev_dbg(&client->dev, "Platform data not found\n");
> +	if (!client->dev.of_node) {
> +		pdata = client->dev.platform_data;
> +		if (!pdata)
> +			dev_dbg(&client->dev, "Platform data not found\n");
> +	} else {
> +		if (!of_device_is_available(client->dev.of_node))
> +			return -ENODEV;
> +
> +		pdata = devm_kzalloc(&client->dev,
> +				     sizeof(*pdata), GFP_KERNEL);
> +		if (!pdata) {
> +			dev_err(&client->dev, "Failed to allocate pdata\n");
> +			return -ENOMEM;
> +		}
> +	}
>  
>  	as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
>  	if (!as3711) {
> @@ -193,7 +214,8 @@ static struct i2c_driver as3711_i2c_driver = {
>  	.driver = {
>  		   .name = "as3711",
>  		   .owner = THIS_MODULE,
> -		   },
> +		   .of_match_table = of_match_ptr(as3711_of_match),
> +	},
>  	.probe = as3711_i2c_probe,
>  	.remove = as3711_i2c_remove,
>  	.id_table = as3711_i2c_id,
> diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
> index f0ba8c4..cf145fc 100644
> --- a/drivers/regulator/as3711-regulator.c
> +++ b/drivers/regulator/as3711-regulator.c
> @@ -13,9 +13,11 @@
>  #include <linux/init.h>
>  #include <linux/mfd/as3711.h>
>  #include <linux/module.h>
> +#include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/regmap.h>
>  #include <linux/regulator/driver.h>
> +#include <linux/regulator/of_regulator.h>
>  #include <linux/slab.h>
>  
>  struct as3711_regulator_info {
> @@ -276,6 +278,57 @@ static struct as3711_regulator_info as3711_reg_info[] = {
>  
>  #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info)
>  
> +static const char *as3711_regulator_of_names[AS3711_REGULATOR_NUM] = {
> +	[AS3711_REGULATOR_SD_1] = "sd1",
> +	[AS3711_REGULATOR_SD_2] = "sd2",
> +	[AS3711_REGULATOR_SD_3] = "sd3",
> +	[AS3711_REGULATOR_SD_4] = "sd4",
> +	[AS3711_REGULATOR_LDO_1] = "ldo1",
> +	[AS3711_REGULATOR_LDO_2] = "ldo2",
> +	[AS3711_REGULATOR_LDO_3] = "ldo3",
> +	[AS3711_REGULATOR_LDO_4] = "ldo4",
> +	[AS3711_REGULATOR_LDO_5] = "ldo5",
> +	[AS3711_REGULATOR_LDO_6] = "ldo6",
> +	[AS3711_REGULATOR_LDO_7] = "ldo7",
> +	[AS3711_REGULATOR_LDO_8] = "ldo8",
> +};
> +
> +static int as3711_regulator_parse_dt(struct device *dev)
> +{
> +	struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
> +	struct device_node *regulators > +		of_find_node_by_name(dev->parent->of_node, "regulators");
> +	struct of_regulator_match *matches, *match;
> +	const int count = AS3711_REGULATOR_NUM;
> +	int ret, i;
> +
> +	if (!regulators) {
> +		dev_err(dev, "regulator node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	matches = devm_kzalloc(dev, sizeof(*matches) * count, GFP_KERNEL);
> +	if (!matches)
> +		return -ENOMEM;
> +
> +	for (i = 0, match = matches; i < count; i++, match++) {
> +		match->name = as3711_regulator_of_names[i];
> +		match->driver_data = as3711_reg_info + i;
> +	}
> +
> +	ret = of_regulator_match(dev->parent, regulators, matches, count);
> +	if (ret < 0) {
> +		dev_err(dev, "Error parsing regulator init data: %d\n", ret);
> +		return ret;
> +	}
> +
> +	for (i = 0, match = matches; i < count; i++, match++)
> +		if (match->of_node)
> +			pdata->init_data[i] = match->init_data;
> +
> +	return 0;
> +}
> +
>  static int as3711_regulator_probe(struct platform_device *pdev)
>  {
>  	struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
> @@ -289,8 +342,18 @@ static int as3711_regulator_probe(struct platform_device *pdev)
>  	int ret;
>  	int id;
>  
> -	if (!pdata)
> -		dev_dbg(&pdev->dev, "No platform data...\n");
> +	if (!pdata) {
> +		dev_err(&pdev->dev, "No platform data...\n");
> +		return -ENODEV;
> +	}
> +
> +	if (pdev->dev.parent->of_node) {
> +		ret = as3711_regulator_parse_dt(&pdev->dev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
> +			return ret;
> +		}
> +	}
>  
>  	regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
>  			sizeof(struct as3711_regulator), GFP_KERNEL);
> @@ -300,7 +363,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
>  	}
>  
>  	for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
> -		reg_data = pdata ? pdata->init_data[id] : NULL;
> +		reg_data = pdata->init_data[id];
>  
>  		/* No need to register if there is no regulator data */
>  		if (!reg_data)
> diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
> index c6bc65d..90c9208 100644
> --- a/drivers/video/backlight/as3711_bl.c
> +++ b/drivers/video/backlight/as3711_bl.c
> @@ -257,6 +257,109 @@ static int as3711_bl_register(struct platform_device *pdev,
>  	return 0;
>  }
>  
> +static int as3711_backlight_parse_dt(struct device *dev)
> +{
> +	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
> +	struct device_node *bl > +		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
> +	int ret;
> +
> +	if (!bl) {
> +		dev_dbg(dev, "backlight node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	fb = of_parse_phandle(bl, "su1-dev", 0);
> +	if (fb) {
> +		pdata->su1_fb = fb->full_name;
> +
> +		ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
> +		if (pdata->su1_max_uA <= 0)
> +			ret = -EINVAL;
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	fb = of_parse_phandle(bl, "su2-dev", 0);
> +	if (fb) {
> +		int count = 0;
> +
> +		pdata->su2_fb = fb->full_name;
> +
> +		ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
> +		if (pdata->su2_max_uA <= 0)
> +			ret = -EINVAL;
> +		if (ret < 0)
> +			return ret;
> +
> +		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr1", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR1;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr2", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR2;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr3", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR3;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
> +			count++;
> +		}
> +		if (count != 1)
> +			return -EINVAL;
> +
> +		count = 0;
> +		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_LX_SD4;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_GPIO2;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_GPIO3;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_GPIO4;
> +			count++;
> +		}
> +		if (count != 1)
> +			return -EINVAL;
> +
> +		count = 0;
> +		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
> +			pdata->su2_auto_curr1 = true;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-auto-curr2", NULL)) {
> +			pdata->su2_auto_curr2 = true;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-auto-curr3", NULL)) {
> +			pdata->su2_auto_curr3 = true;
> +			count++;
> +		}
> +
> +		/*
> +		 * At least one su2-auto-curr* must be specified iff
> +		 * AS3711_SU2_CURR_AUTO is used
> +		 */
> +		if (!count ^ pdata->su2_feedback != AS3711_SU2_CURR_AUTO)
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int as3711_backlight_probe(struct platform_device *pdev)
>  {
>  	struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev);
> @@ -266,11 +369,24 @@ static int as3711_backlight_probe(struct platform_device *pdev)
>  	unsigned int max_brightness;
>  	int ret;
>  
> -	if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) {
> +	if (!pdata) {
>  		dev_err(&pdev->dev, "No platform data, exiting...\n");
>  		return -ENODEV;
>  	}
>  
> +	if (pdev->dev.parent->of_node) {
> +		ret = as3711_backlight_parse_dt(&pdev->dev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	if (!pdata->su1_fb && !pdata->su2_fb) {
> +		dev_err(&pdev->dev, "No framebuffer specified\n");
> +		return -EINVAL;
> +	}
> +
>  	/*
>  	 * Due to possible hardware damage I chose to block all modes,
>  	 * unsupported on my hardware. Anyone, wishing to use any of those modes
> -- 
> 1.7.2.5
> 

^ permalink raw reply

* Re: [PATCH/RFC] mfd: as3711: add OF support
From: Simon Horman @ 2013-02-16  5:54 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Samuel Ortiz,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Mark Brown,
	Magnus Damm, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Richard Purdie,
	Andrew Morton, Liam Girdwood
In-Reply-To: <Pine.LNX.4.64.1302151101140.7446-0199iw4Nj15frtckUFj5Ag@public.gmane.org>

On Fri, Feb 15, 2013 at 11:07:16AM +0100, Guennadi Liakhovetski wrote:
> Add device-tree bindings to the AS3711 regulator and backlight drivers.
> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> 
> As usual - comments to the new bindings are very welcome!
> 
>  Documentation/devicetree/bindings/mfd/as3711.txt |   73 +++++++++++++
>  drivers/mfd/as3711.c                             |   30 +++++-
>  drivers/regulator/as3711-regulator.c             |   69 ++++++++++++-
>  drivers/video/backlight/as3711_bl.c              |  118 +++++++++++++++++++++-
>  4 files changed, 282 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mfd/as3711.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt
> new file mode 100644
> index 0000000..d98cf18
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/as3711.txt
> @@ -0,0 +1,73 @@
> +AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power
> +supplies, a battery charger and an RTC. So far only bindings for the two stepup
> +DCDC converters are defined. Other DCDC and LDO supplies are configured, using
> +standard regulator properties, they must belong to a sub-node, called
> +"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter
> +configuration should be placed in a subnode, called "backlight."
> +
> +Compulsory properties:
> +- compatible		: must be "ams,as3711"
> +- reg			: specifies the I2C address
> +
> +To use the SU1 converter as a backlight source the following two properties must
> +be provided:
> +- su1-dev		: framebuffer phandle
> +- su1-max-uA		: maximum current
> +
> +To use the SU2 converter as a backlight source the following two properties must
> +be provided:
> +- su2-dev		: framebuffer phandle
> +- su1-max-uA		: maximum current
> +
> +Additionally one of these properties must be provided to select the type of
> +feedback used:
> +- su2-feedback-voltage	: voltage feedback is used
> +- su2-feedback-curr1	: CURR1 input used for current feedback
> +- su2-feedback-curr2	: CURR2 input used for current feedback
> +- su2-feedback-curr3	: CURR3 input used for current feedback
> +- su2-feedback-curr-auto: automatic current feedback selection
> +
> +and one of these to select the over-voltage protection pin
> +- su2-fbprot-lx-sd4	: LX_SD4 is used for over-voltage protection
> +- su2-fbprot-gpio2	: GPIO2 is used for over-voltage protection
> +- su2-fbprot-gpio3	: GPIO3 is used for over-voltage protection
> +- su2-fbprot-gpio4	: GPIO4 is used for over-voltage protection
> +
> +If "su2-feedback-curr-auto" is selected, one or more of the following properties
> +have to be specified:
> +- su2-auto-curr1	: use CURR1 input for current feedback
> +- su2-auto-curr2	: use CURR2 input for current feedback
> +- su2-auto-curr3	: use CURR3 input for current feedback
> +
> +Example:
> +
> +as3711@40 {
> +	compatible = "ams,as3711";
> +	reg = <0x40>;
> +
> +	regulators {
> +		sd4 {
> +			regulator-name = "1.215V";
> +			regulator-min-microvolt = <1215000>;
> +			regulator-max-microvolt = <1235000>;
> +		};
> +		ldo2 {
> +			regulator-name = "2.8V CPU";
> +			regulator-min-microvolt = <2800000>;
> +			regulator-max-microvolt = <2800000>;
> +			regulator-always-on;
> +			regulator-boot-on;
> +		};
> +	};
> +
> +	backlight {
> +		compatible = "ams,as3711-bl";
> +		su2-dev = <&lcdc>;
> +		su2-max-uA = <36000>;
> +		su2-feedback-curr-auto;
> +		su2-fbprot-gpio4;
> +		su2-auto-curr1;
> +		su2-auto-curr2;
> +		su2-auto-curr3;
> +	};
> +};
> diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c
> index e994c96..5e0e8b3 100644
> --- a/drivers/mfd/as3711.c
> +++ b/drivers/mfd/as3711.c
> @@ -112,16 +112,37 @@ static const struct regmap_config as3711_regmap_config = {
>  	.cache_type = REGCACHE_RBTREE,
>  };
>  
> +#ifdef CONFIG_OF
> +static struct of_device_id as3711_of_match[] = {
> +	{.compatible = "ams,as3711",},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, as3711_of_match);
> +#endif
> +
>  static int as3711_i2c_probe(struct i2c_client *client,
>  			    const struct i2c_device_id *id)
>  {
>  	struct as3711 *as3711;
> -	struct as3711_platform_data *pdata = client->dev.platform_data;
> +	struct as3711_platform_data *pdata;
>  	unsigned int id1, id2;
>  	int ret;
>  
> -	if (!pdata)
> -		dev_dbg(&client->dev, "Platform data not found\n");
> +	if (!client->dev.of_node) {
> +		pdata = client->dev.platform_data;
> +		if (!pdata)
> +			dev_dbg(&client->dev, "Platform data not found\n");
> +	} else {
> +		if (!of_device_is_available(client->dev.of_node))
> +			return -ENODEV;

The wonder that is kbuild tells me that the above call to
of_device_is_available() may cause a build-time error.
Perhaps it or this entire else clause should be guarded by CONFIG_OF?

> +
> +		pdata = devm_kzalloc(&client->dev,
> +				     sizeof(*pdata), GFP_KERNEL);
> +		if (!pdata) {
> +			dev_err(&client->dev, "Failed to allocate pdata\n");
> +			return -ENOMEM;
> +		}
> +	}
>  
>  	as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
>  	if (!as3711) {
> @@ -193,7 +214,8 @@ static struct i2c_driver as3711_i2c_driver = {
>  	.driver = {
>  		   .name = "as3711",
>  		   .owner = THIS_MODULE,
> -		   },
> +		   .of_match_table = of_match_ptr(as3711_of_match),
> +	},
>  	.probe = as3711_i2c_probe,
>  	.remove = as3711_i2c_remove,
>  	.id_table = as3711_i2c_id,
> diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
> index f0ba8c4..cf145fc 100644
> --- a/drivers/regulator/as3711-regulator.c
> +++ b/drivers/regulator/as3711-regulator.c
> @@ -13,9 +13,11 @@
>  #include <linux/init.h>
>  #include <linux/mfd/as3711.h>
>  #include <linux/module.h>
> +#include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/regmap.h>
>  #include <linux/regulator/driver.h>
> +#include <linux/regulator/of_regulator.h>
>  #include <linux/slab.h>
>  
>  struct as3711_regulator_info {
> @@ -276,6 +278,57 @@ static struct as3711_regulator_info as3711_reg_info[] = {
>  
>  #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info)
>  
> +static const char *as3711_regulator_of_names[AS3711_REGULATOR_NUM] = {
> +	[AS3711_REGULATOR_SD_1] = "sd1",
> +	[AS3711_REGULATOR_SD_2] = "sd2",
> +	[AS3711_REGULATOR_SD_3] = "sd3",
> +	[AS3711_REGULATOR_SD_4] = "sd4",
> +	[AS3711_REGULATOR_LDO_1] = "ldo1",
> +	[AS3711_REGULATOR_LDO_2] = "ldo2",
> +	[AS3711_REGULATOR_LDO_3] = "ldo3",
> +	[AS3711_REGULATOR_LDO_4] = "ldo4",
> +	[AS3711_REGULATOR_LDO_5] = "ldo5",
> +	[AS3711_REGULATOR_LDO_6] = "ldo6",
> +	[AS3711_REGULATOR_LDO_7] = "ldo7",
> +	[AS3711_REGULATOR_LDO_8] = "ldo8",
> +};
> +
> +static int as3711_regulator_parse_dt(struct device *dev)
> +{
> +	struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
> +	struct device_node *regulators > +		of_find_node_by_name(dev->parent->of_node, "regulators");
> +	struct of_regulator_match *matches, *match;
> +	const int count = AS3711_REGULATOR_NUM;
> +	int ret, i;
> +
> +	if (!regulators) {
> +		dev_err(dev, "regulator node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	matches = devm_kzalloc(dev, sizeof(*matches) * count, GFP_KERNEL);
> +	if (!matches)
> +		return -ENOMEM;
> +
> +	for (i = 0, match = matches; i < count; i++, match++) {
> +		match->name = as3711_regulator_of_names[i];
> +		match->driver_data = as3711_reg_info + i;
> +	}
> +
> +	ret = of_regulator_match(dev->parent, regulators, matches, count);
> +	if (ret < 0) {
> +		dev_err(dev, "Error parsing regulator init data: %d\n", ret);
> +		return ret;
> +	}
> +
> +	for (i = 0, match = matches; i < count; i++, match++)
> +		if (match->of_node)
> +			pdata->init_data[i] = match->init_data;
> +
> +	return 0;
> +}
> +
>  static int as3711_regulator_probe(struct platform_device *pdev)
>  {
>  	struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
> @@ -289,8 +342,18 @@ static int as3711_regulator_probe(struct platform_device *pdev)
>  	int ret;
>  	int id;
>  
> -	if (!pdata)
> -		dev_dbg(&pdev->dev, "No platform data...\n");
> +	if (!pdata) {
> +		dev_err(&pdev->dev, "No platform data...\n");
> +		return -ENODEV;
> +	}
> +
> +	if (pdev->dev.parent->of_node) {
> +		ret = as3711_regulator_parse_dt(&pdev->dev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
> +			return ret;
> +		}
> +	}
>  
>  	regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
>  			sizeof(struct as3711_regulator), GFP_KERNEL);
> @@ -300,7 +363,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
>  	}
>  
>  	for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
> -		reg_data = pdata ? pdata->init_data[id] : NULL;
> +		reg_data = pdata->init_data[id];
>  
>  		/* No need to register if there is no regulator data */
>  		if (!reg_data)
> diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
> index c6bc65d..90c9208 100644
> --- a/drivers/video/backlight/as3711_bl.c
> +++ b/drivers/video/backlight/as3711_bl.c
> @@ -257,6 +257,109 @@ static int as3711_bl_register(struct platform_device *pdev,
>  	return 0;
>  }
>  
> +static int as3711_backlight_parse_dt(struct device *dev)
> +{
> +	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
> +	struct device_node *bl > +		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
> +	int ret;
> +
> +	if (!bl) {
> +		dev_dbg(dev, "backlight node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	fb = of_parse_phandle(bl, "su1-dev", 0);
> +	if (fb) {
> +		pdata->su1_fb = fb->full_name;
> +
> +		ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
> +		if (pdata->su1_max_uA <= 0)
> +			ret = -EINVAL;
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	fb = of_parse_phandle(bl, "su2-dev", 0);
> +	if (fb) {
> +		int count = 0;
> +
> +		pdata->su2_fb = fb->full_name;
> +
> +		ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
> +		if (pdata->su2_max_uA <= 0)
> +			ret = -EINVAL;
> +		if (ret < 0)
> +			return ret;
> +
> +		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr1", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR1;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr2", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR2;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr3", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR3;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) {
> +			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
> +			count++;
> +		}
> +		if (count != 1)
> +			return -EINVAL;
> +
> +		count = 0;
> +		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_LX_SD4;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_GPIO2;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_GPIO3;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) {
> +			pdata->su2_fbprot = AS3711_SU2_GPIO4;
> +			count++;
> +		}
> +		if (count != 1)
> +			return -EINVAL;
> +
> +		count = 0;
> +		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
> +			pdata->su2_auto_curr1 = true;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-auto-curr2", NULL)) {
> +			pdata->su2_auto_curr2 = true;
> +			count++;
> +		}
> +		if (of_find_property(bl, "su2-auto-curr3", NULL)) {
> +			pdata->su2_auto_curr3 = true;
> +			count++;
> +		}
> +
> +		/*
> +		 * At least one su2-auto-curr* must be specified iff
> +		 * AS3711_SU2_CURR_AUTO is used
> +		 */
> +		if (!count ^ pdata->su2_feedback != AS3711_SU2_CURR_AUTO)
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int as3711_backlight_probe(struct platform_device *pdev)
>  {
>  	struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev);
> @@ -266,11 +369,24 @@ static int as3711_backlight_probe(struct platform_device *pdev)
>  	unsigned int max_brightness;
>  	int ret;
>  
> -	if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) {
> +	if (!pdata) {
>  		dev_err(&pdev->dev, "No platform data, exiting...\n");
>  		return -ENODEV;
>  	}
>  
> +	if (pdev->dev.parent->of_node) {
> +		ret = as3711_backlight_parse_dt(&pdev->dev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	if (!pdata->su1_fb && !pdata->su2_fb) {
> +		dev_err(&pdev->dev, "No framebuffer specified\n");
> +		return -EINVAL;
> +	}
> +
>  	/*
>  	 * Due to possible hardware damage I chose to block all modes,
>  	 * unsupported on my hardware. Anyone, wishing to use any of those modes
> -- 
> 1.7.2.5
> 

^ permalink raw reply

* Re: [PATCH/RFC] mfd: as3711: add OF support
From: Simon Horman @ 2013-02-16  6:13 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Samuel Ortiz,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Mark Brown,
	Magnus Damm, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Richard Purdie,
	Andrew Morton, Liam Girdwood
In-Reply-To: <20130216022630.GA11628-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org>

On Sat, Feb 16, 2013 at 11:26:30AM +0900, Simon Horman wrote:
> On Fri, Feb 15, 2013 at 11:07:16AM +0100, Guennadi Liakhovetski wrote:
> > Add device-tree bindings to the AS3711 regulator and backlight drivers.
> 
> Hi,
> 
> at this stage I do not expect this code to go through the renesas tree.
> However, in order to provide a basis for work on renesas SoCs I have added
> this patch to the topic/backlight topic branch in the reneas tree on
> kernel.org and merged it into topic/all+next.
> 
> In other words, I am not picking this patch up to merge it or add it to
> linux-next, rather I am storing it for reference.

I have dropped this patch due to the of_device_is_available build error
reported by kbuild and reported in another sub-thread.

^ permalink raw reply

* [PATCH] OMAPDSS: tpo-td043 panel: fix data passing between SPI/DSS parts
From: Grazvydas Ignotas @ 2013-02-17  0:43 UTC (permalink / raw)
  To: linux-fbdev; +Cc: linux-omap, Tomi Valkeinen, Archit Taneja, Grazvydas Ignotas

This driver uses omap_dss_device that it gets from a board file through
SPI platfrom_data pointer to pass data from SPI to DSS portion of the
driver by using dev_set_drvdata(). However this trick no longer works,
as DSS core no longer uses omap_dss_device from a board file to create
the real device, so use a global pointer to accomplish this instead,
like other SPI panel drivers do.

Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
---
 .../video/omap2/displays/panel-tpo-td043mtea1.c    |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index 6b66439..048c983 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -63,6 +63,9 @@ struct tpo_td043_device {
 	u32 power_on_resume:1;
 };
 
+/* used to pass spi_device from SPI to DSS portion of the driver */
+static struct tpo_td043_device *g_tpo_td043;
+
 static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
 {
 	struct spi_message	m;
@@ -403,7 +406,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
 
 static int tpo_td043_probe(struct omap_dss_device *dssdev)
 {
-	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+	struct tpo_td043_device *tpo_td043 = g_tpo_td043;
 	int nreset_gpio = dssdev->reset_gpio;
 	int ret = 0;
 
@@ -440,6 +443,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
 	if (ret)
 		dev_warn(&dssdev->dev, "failed to create sysfs files\n");
 
+	dev_set_drvdata(&dssdev->dev, tpo_td043);
+
 	return 0;
 
 fail_gpio_req:
@@ -505,6 +510,9 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
 		return -ENODEV;
 	}
 
+	if (g_tpo_td043 != NULL)
+		return -EBUSY;
+
 	spi->bits_per_word = 16;
 	spi->mode = SPI_MODE_0;
 
@@ -521,7 +529,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
 	tpo_td043->spi = spi;
 	tpo_td043->nreset_gpio = dssdev->reset_gpio;
 	dev_set_drvdata(&spi->dev, tpo_td043);
-	dev_set_drvdata(&dssdev->dev, tpo_td043);
+	g_tpo_td043 = tpo_td043;
 
 	omap_dss_register_driver(&tpo_td043_driver);
 
@@ -534,6 +542,7 @@ static int tpo_td043_spi_remove(struct spi_device *spi)
 
 	omap_dss_unregister_driver(&tpo_td043_driver);
 	kfree(tpo_td043);
+	g_tpo_td043 = NULL;
 
 	return 0;
 }
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH v2 1/1] OMAP4: DSS: Add panel for Blaze Tablet boards
From: Andi Shyti @ 2013-02-17 14:17 UTC (permalink / raw)
  To: Ruslan Bilovol
  Cc: Andi Shyti, tomi.valkeinen, FlorianSchandinat, linux-fbdev,
	linux-kernel, linux-omap
In-Reply-To: <CAB=otbSpspZ9Z_fOpBvE1mPtt+JwZydZrgcR2LdkD_4CrGa_eg@mail.gmail.com>

> >> +     char name[30];
> >> +     char buf[50];
> >> +
> >> +     if (size >= sizeof(buf))
> >> +             size = sizeof(buf);
> >
> > what's the point of this?
> 
> This is a way to limit copied from userspace data by available buffer size,
> widely used in current kernel sources. Are you implying there is some
> better (more graceful) way?

No indeed :)
There is no other way, sorry for polluting the review :)

> >> +     if ((pins[2] & 1) || (pins[3] & 1)) {
> >> +             lanes |= (1 << 1);
> >> +             ret |= tc358765_write_register(dssdev, PPI_D0S_CLRSIPOCOUNT,
> >> +                                                     board_data->clrsipo);
> >> +     }
> >> +     if ((pins[4] & 1) || (pins[5] & 1)) {
> >> +             lanes |= (1 << 2);
> >> +             ret |= tc358765_write_register(dssdev, PPI_D1S_CLRSIPOCOUNT,
> >> +                                                     board_data->clrsipo);
> >> +     }
> >> +     if ((pins[6] & 1) || (pins[7] & 1)) {
> >> +             lanes |= (1 << 3);
> >> +             ret |= tc358765_write_register(dssdev, PPI_D2S_CLRSIPOCOUNT,
> >> +                                                     board_data->clrsipo);
> >> +     }
> >> +     if ((pins[8] & 1) || (pins[9] & 1)) {
> >> +             lanes |= (1 << 4);
> >> +             ret |= tc358765_write_register(dssdev, PPI_D3S_CLRSIPOCOUNT,
> >> +                                                     board_data->clrsipo);
> >> +     }
> >
> > Can't this be done in one single multiwrighting command since
> > this registers are consecutive?
> >
> > You build once the array to write and you send it at once.
> 
> In this particular case I disagree. Yes, it will be a little bit
> faster, however:
> 1) we write this for panel initialization only (so no impact in other cases)
> 2) multiwriting of array will make code reading more difficult
> 
> So I would like to leave it as-is
> Same is for next your similar comment.

If the hw is providing us some ways for simplifying the code I
would use it. In this case we are talking about the i2c feature
of multiwriting and multireading.

Let's assume that we want to write on 8 different consecutive
registers. In my opinion this aproach is quite "heavy":

  uX register;

  register = value1;
  i2c_write(REG1, register);

  register = value2;
  i2c_write(REG2, register);

  ...

Usually what I do is this:

  uX register[8];

  for (i = 0; i < 8; i++)
    register |= valuei << i; (or register[i] = valuei or whatever)

  i2c_multi_write(REG, register, 8);

of course this is a simplified example in pseudocode. I think
it's more readable and we are making a better use of the i2c
protocol.

In your case you have some if statement that are making the multi
writing more difficult, but still is not impossible.

At the end it's still a matter of taste, so that you are free to
choose whatever you prefer :)

Andi

^ permalink raw reply

* Re: [PATCH RFC] video: Add Hyper-V Synthetic Video Frame Buffer Driver
From: Olaf Hering @ 2013-02-17 14:32 UTC (permalink / raw)
  To: Haiyang Zhang
  Cc: FlorianSchandinat, linux-fbdev, kys, jasowang, linux-kernel,
	devel
In-Reply-To: <1360955396-14183-1-git-send-email-haiyangz@microsoft.com>

On Fri, Feb 15, Haiyang Zhang wrote:

> +config HYPERV_FB

This should probably be FB_HYPERB to follow the naming of all other
drivers.

Olaf

^ permalink raw reply

* Re: [PATCH v2 1/1] OMAP4: DSS: Add panel for Blaze Tablet boards
From: Andi Shyti @ 2013-02-17 14:46 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1360338220-12753-2-git-send-email-ruslan.bilovol@ti.com>

Ops, sorry, I have to resend the e-mail since I used a mail
address which is not subscribed to the lkml.

Andi

On Sun, Feb 17, 2013 at 03:17:57PM +0100, Andi Shyti wrote:
> > >> +     char name[30];
> > >> +     char buf[50];
> > >> +
> > >> +     if (size >= sizeof(buf))
> > >> +             size = sizeof(buf);
> > >
> > > what's the point of this?
> > 
> > This is a way to limit copied from userspace data by available buffer size,
> > widely used in current kernel sources. Are you implying there is some
> > better (more graceful) way?
> 
> No indeed :)
> There is no other way, sorry for polluting the review :)
> 
> > >> +     if ((pins[2] & 1) || (pins[3] & 1)) {
> > >> +             lanes |= (1 << 1);
> > >> +             ret |= tc358765_write_register(dssdev, PPI_D0S_CLRSIPOCOUNT,
> > >> +                                                     board_data->clrsipo);
> > >> +     }
> > >> +     if ((pins[4] & 1) || (pins[5] & 1)) {
> > >> +             lanes |= (1 << 2);
> > >> +             ret |= tc358765_write_register(dssdev, PPI_D1S_CLRSIPOCOUNT,
> > >> +                                                     board_data->clrsipo);
> > >> +     }
> > >> +     if ((pins[6] & 1) || (pins[7] & 1)) {
> > >> +             lanes |= (1 << 3);
> > >> +             ret |= tc358765_write_register(dssdev, PPI_D2S_CLRSIPOCOUNT,
> > >> +                                                     board_data->clrsipo);
> > >> +     }
> > >> +     if ((pins[8] & 1) || (pins[9] & 1)) {
> > >> +             lanes |= (1 << 4);
> > >> +             ret |= tc358765_write_register(dssdev, PPI_D3S_CLRSIPOCOUNT,
> > >> +                                                     board_data->clrsipo);
> > >> +     }
> > >
> > > Can't this be done in one single multiwrighting command since
> > > this registers are consecutive?
> > >
> > > You build once the array to write and you send it at once.
> > 
> > In this particular case I disagree. Yes, it will be a little bit
> > faster, however:
> > 1) we write this for panel initialization only (so no impact in other cases)
> > 2) multiwriting of array will make code reading more difficult
> > 
> > So I would like to leave it as-is
> > Same is for next your similar comment.
> 
> If the hw is providing us some ways for simplifying the code I
> would use it. In this case we are talking about the i2c feature
> of multiwriting and multireading.
> 
> Let's assume that we want to write on 8 different consecutive
> registers. In my opinion this aproach is quite "heavy":
> 
>   uX register;
> 
>   register = value1;
>   i2c_write(REG1, register);
> 
>   register = value2;
>   i2c_write(REG2, register);
> 
>   ...
> 
> Usually what I do is this:
> 
>   uX register[8];
> 
>   for (i = 0; i < 8; i++)
>     register |= valuei << i; (or register[i] = valuei or whatever)
> 
>   i2c_multi_write(REG, register, 8);
> 
> of course this is a simplified example in pseudocode. I think
> it's more readable and we are making a better use of the i2c
> protocol.
> 
> In your case you have some if statement that are making the multi
> writing more difficult, but still is not impossible.
> 
> At the end it's still a matter of taste, so that you are free to
> choose whatever you prefer :)
> 
> Andi
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* [PATCH 0/9] System Framebuffer Bus (sysfb)
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann

Hi

This series tries to fix the mess with global system framebuffer access in
device drivers. Currently, architecture initialization sets the "screen_info"
object according to the system framebuffer that was detected during boot. The
device driver that can map VMEM first gets access to it. There is no way to give
a specific driver access to the device and no _proper_ way to revoke access
again. In fact, some drivers don't even check whether they mapped the VMEM
successfully, letting multiple drivers to access the system framebuffer at the
same time.

This series introduces a new bus in patch #1. Global system framebuffers are
added as devices to this bus and drivers can register as bus drivers. Via sysfs
we can now bind/unbind the drivers. This guarantees that only one driver has
access to a single system-framebuffer at a time. But we can also easily control
which driver gets loaded (and extend this logic at a central place if we want).

If a real hardware drivers gets loaded via another bus that actually provides
the system-framebuffer (like pci-bus), these drivers can use a special BUS
function to claim the system framebuffer and unload all other drivers from this
device. This can be used by _real_ DRM drivers that want to kill all other
generic framebuffer drivers.

This series adds a SYSFB_VBE (VESA/VBE) framebuffer type as example, but the bus
can be used with any other system-framebuffer type. Any other architecture can
add their own type like SYSFB_VBE. Patch #3 is currently a HACK to provide the
VBE framebuffer on all architectures. However, the platform-device for
system-framebuffers should instead be provided by architecture code.


Why a new BUS type?
We need a way to allow transition from a generic driver to a real hardware
driver (like most DRM drivers or special fbdev drivers). We could implement this
logic separately, but the BUS driver-core code is available, anyway. So lets use
it and save a lot of .text space.
Additionally, we get some extra features like driver binding/unbinding via sysfs
for free (which is really handy for debugging).
The new bus is actually implemented in <200 lines of code. I don't think we can
get a smaller implementation when not using the bus-core code.


Patch #4 fixes vesafb.c to be hotplug-capable. It doesn't depend on this new bus
so it would be nice if it could get applied right away. It allows vesafb to be
compiled as a module.

Patch #5 makes vesafb.c register as new bus driver on the system-framebuffer
bus.

Patch #6-#9 introduce DVBE. It's a DRM driver based on VBE/VESA. It also uses
the new system-framebuffer bus and provides merely the same functionality as
vesafb.c but with a sane user-space API and without any fbdev dependency.


What needs to be done?
All drivers that use screen_info currently don't _have_ to be converted to the
new bus as the request_memory() calls protect the drivers from interfering. So
this new bus works even if no other driver gets converted. However, we really
_should_ convert the drivers. I will do that if a maintainer agrees to take the
bus code through their tree. But I hope to avoid converting all drivers if no
maintainer thinks this bus is a good idea.
The DVBE and vesafb drivers show how it is done.

I also like to see the system-framebuffer platform-devices being registered
during architecture initialization. I haven't worked much there so any comments
are welcome. Otherwise, I will keep the HACK to add the devices during sysfb
module-init.


Regards
David

David Herrmann (9):
  video: introduce system framebuffer bus
  video: sysfb: new vbefb device type
  video: sysfb: always provide vbefb device
  video: vesafb: allow building as module
  video: vesafb: use sysfb bus
  drm: new sysfb DRM bus module
  drm: new VESA BIOS Extension DRM driver stub
  drm: dvbe: implement VBE/VESA blitting backend
  drm: dvbe: add optional fbdev frontend

 drivers/gpu/drm/Kconfig           |   7 +
 drivers/gpu/drm/Makefile          |   2 +
 drivers/gpu/drm/drm_sysfb.c       | 145 +++++++++++++
 drivers/gpu/drm/dvbe/Kconfig      |  47 +++++
 drivers/gpu/drm/dvbe/Makefile     |   5 +
 drivers/gpu/drm/dvbe/dvbe.h       | 121 +++++++++++
 drivers/gpu/drm/dvbe/dvbe_drv.c   | 104 +++++++++
 drivers/gpu/drm/dvbe/dvbe_fbdev.c | 235 +++++++++++++++++++++
 drivers/gpu/drm/dvbe/dvbe_main.c  | 432 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/dvbe/dvbe_mem.c   | 269 ++++++++++++++++++++++++
 drivers/gpu/drm/dvbe/dvbe_vesa.c  | 263 +++++++++++++++++++++++
 drivers/video/Kconfig             |  20 +-
 drivers/video/Makefile            |   1 +
 drivers/video/sysfb.c             | 315 +++++++++++++++++++++++++++
 drivers/video/vesafb.c            | 105 ++++-----
 include/drm/drmP.h                |   4 +
 include/drm/drm_sysfb.h           |  35 +++
 include/linux/sysfb.h             | 137 ++++++++++++
 18 files changed, 2197 insertions(+), 50 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_sysfb.c
 create mode 100644 drivers/gpu/drm/dvbe/Kconfig
 create mode 100644 drivers/gpu/drm/dvbe/Makefile
 create mode 100644 drivers/gpu/drm/dvbe/dvbe.h
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_drv.c
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_fbdev.c
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_main.c
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_mem.c
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_vesa.c
 create mode 100644 drivers/video/sysfb.c
 create mode 100644 include/drm/drm_sysfb.h
 create mode 100644 include/linux/sysfb.h

-- 
1.8.1.3


^ permalink raw reply

* [PATCH 1/9] video: introduce system framebuffer bus
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

From: David Herrmann <dh.herrmann@googlemail.com>

For a long time now we have the problem that there are multiple drivers
available that try to use system framebuffers (like EFI, VESA/VBE, ...).
There is no way to control which driver gets access to the devices, but
instead works on a first-come-first-serve basis.

Furthermore, hardware drivers (eg., gpu/drm/*) that get loaded on the
real hardware bus (eg., pci-bus) of the framebuffer devices have a hard
time unloading other drivers that currently use system framebuffers.

This introduces a new bus-type: sysfb (system framebuffer bus)

Any available system framebuffer gets registered as a device on this bus.
A bus-driver can then pick up the device and use it. Standard sysfs
bind/unbind interfaces can be used to change drivers on-the-fly.

There are actually two types of drivers: generic and real drivers

Generic drivers use the generic framebuffer interface exclusively. They
are often used as a fallback interface where no real driver for the
hardware is available. Generic drivers register as sysfb drivers to the
sysfb bus and will get loaded dynamically. User-space can bind/unbind them
via sysfs to control which driver should get access.
Only one driver can be active per device. During probe the driver can
retrieve additional information via a screen_info object of the device.
Generic drivers include: efifb, (u)vesafb, vgacon, ...

Real drivers work differently. Instead of being loaded via sysfb, they
register as drivers on the real bus (eg., pci-bus). During probe they
should verify whether their real device provides a system-framebuffer. If
it does, they call sysfb_claim() to claim exclusive access to the device.
This guarantees that any generic driver gets unloaded and the real
hardware driver can gain access. This also guarantees that a real hardware
driver always takes precedence over generic fallback drivers.
Real drivers include: i915, radeon, nouveau, ...

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/video/Kconfig  |  17 ++++
 drivers/video/Makefile |   1 +
 drivers/video/sysfb.c  | 230 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sysfb.h  | 134 ++++++++++++++++++++++++++++
 4 files changed, 382 insertions(+)
 create mode 100644 drivers/video/sysfb.c
 create mode 100644 include/linux/sysfb.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d08d799..eac56ef 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -27,6 +27,23 @@ config VGASTATE
        tristate
        default n
 
+config SYSFB
+	tristate "System Framebuffer Bus"
+	help
+	  Framebuffers like VGA, VESA/VBE, EFI and others can be handled by many
+	  different drivers. This bus provides an infrastructure for drivers to
+	  register themselves and then get bound/unbound to these system-wide
+	  framebuffers.
+	  This bus prevents framebuffers from being used by multiple drivers
+	  simultaneously and also provides a sysfs API to bind/rebind different
+	  drivers to each device from userspace.
+
+	  Chipset-specific drivers (like real GPU drivers) will always take
+	  precedence over generic framebuffer drivers.
+
+	  A driver should normally select this bus-option automatically. Enable
+	  it only if you need out-of-tree builds.
+
 config VIDEO_OUTPUT_CONTROL
 	tristate "Lowlevel video output switch controls"
 	help
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 23e948e..f0eb006 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_VGASTATE)            += vgastate.o
+obj-$(CONFIG_SYSFB)		  += sysfb.o
 obj-y                             += fb_notify.o
 obj-$(CONFIG_FB)                  += fb.o
 fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
new file mode 100644
index 0000000..8249006
--- /dev/null
+++ b/drivers/video/sysfb.c
@@ -0,0 +1,230 @@
+/*
+ * System framebuffer bus
+ * Copyright (c) 2013 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * The system framebuffer bus (sysfb) provides a way to register global system
+ * framebuffers and load different drivers for it. This includes VESA/VBE and
+ * EFI framebuffers.
+ * Platform code is responsible of adding the framebuffer devices to the system
+ * platform bus. The sysfb bus will pick up known devices and provide them via
+ * the sysfb bus to system drivers. This guarantees that only one driver uses
+ * a single system framebuffer at a time.
+ *
+ * Drivers that can make use of the generic interfaces of system framebuffers
+ * should register as a sysfb driver. They will get notified via probe/remove
+ * callbacks just like any other hotpluggable driver. Users can load/unload
+ * drivers via the sysfs bus interface so drivers must be hotplug capable.
+ *
+ * Drivers that cannot make use of the generic interfaces but instead control
+ * the real hardware should instead claim the device. These drivers normally
+ * register through PCI or platform devices and control the device via another
+ * interface.
+ * By claiming a device, all other generic drivers are unregistered and no more
+ * drivers will be probed unless the device is released again.
+ *
+ * Only _real_ hardware drivers should claim devices as there is always another
+ * mechanism to control which real hardware driver gets loaded (eg. pci-bus).
+ * Generic drivers which aren't controlled via another bus should use this
+ * generic sysfb driver interface instead of claiming a device.
+ *
+ * All drivers must make sure that after they get unloaded or release a device,
+ * the device is reset to a usable state. If the driver cannot guarantee that,
+ * it should taint the device so other drivers will notice it and can
+ * optionally recover the device.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/sysfb.h>
+
+static DEFINE_SPINLOCK(sysfb_lock);
+static unsigned int claimed_types;
+
+static int sysfb_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct sysfb_device *sdev = to_sysfb_device(dev);
+	struct sysfb_driver *sdrv = to_sysfb_driver(drv);
+
+	return (sdrv->type_mask & sdev->type) &&
+	       (sdrv->allow_tainted || !sdev->tainted);
+}
+
+static int sysfb_bus_probe(struct device *dev)
+{
+	struct sysfb_device *sdev = to_sysfb_device(dev);
+	struct sysfb_driver *sdrv = to_sysfb_driver(dev->driver);
+	unsigned long flags;
+	int ret;
+
+	if (!(sdrv->type_mask & sdev->type))
+		return -ENODEV;
+	if (!sdrv->allow_tainted && sdev->tainted)
+		return -ENODEV;
+
+	spin_lock_irqsave(&sysfb_lock, flags);
+	if ((claimed_types & sdev->type)) {
+		spin_unlock_irqrestore(&sysfb_lock, flags);
+		return -ENODEV;
+	}
+	spin_unlock_irqrestore(&sysfb_lock, flags);
+
+	if (sdrv->probe) {
+		ret = sdrv->probe(sdev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int sysfb_bus_remove(struct device *dev)
+{
+	struct sysfb_device *sdev = to_sysfb_device(dev);
+	struct sysfb_driver *sdrv = to_sysfb_driver(dev->driver);
+
+	if (sdrv->remove)
+		sdrv->remove(sdev);
+
+	return 0;
+}
+
+static struct bus_type sysfb_bus_type = {
+	.name = "sysfb",
+	.match = sysfb_bus_match,
+	.probe = sysfb_bus_probe,
+	.remove = sysfb_bus_remove,
+};
+
+int sysfb_register_driver(struct sysfb_driver *drv)
+{
+	int ret;
+
+	drv->driver.bus = &sysfb_bus_type;
+
+	ret = driver_register(&drv->driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(sysfb_register_driver);
+
+void sysfb_unregister_driver(struct sysfb_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(sysfb_unregister_driver);
+
+static int __sysfb_rescan(struct device *dev, void *data)
+{
+	return device_attach(dev);
+}
+
+static void sysfb_rescan(void)
+{
+	bus_for_each_dev(&sysfb_bus_type, NULL, NULL, __sysfb_rescan);
+}
+
+static int __sysfb_claim(struct device *dev, void *data)
+{
+	struct sysfb_device *sdev = to_sysfb_device(dev);
+	unsigned int claim = (long)data;
+
+	if (!(sdev->type & claim))
+		return 0;
+
+	device_release_driver(dev);
+	return 0;
+}
+
+int sysfb_claim(unsigned int types)
+{
+	unsigned long flags;
+	int ret;
+
+	if (!(types & SYSFB_TYPES))
+		return -EINVAL;
+
+	spin_lock_irqsave(&sysfb_lock, flags);
+	if ((claimed_types & types)) {
+		spin_unlock_irqrestore(&sysfb_lock, flags);
+		return -EALREADY;
+	}
+	claimed_types |= types;
+	spin_unlock_irqrestore(&sysfb_lock, flags);
+
+	ret = bus_for_each_dev(&sysfb_bus_type, NULL, (void*)(long)types,
+			       __sysfb_claim);
+	if (ret)
+		goto err_restore;
+
+	return 0;
+
+err_restore:
+	spin_lock_irqsave(&sysfb_lock, flags);
+	claimed_types &= ~types;
+	spin_unlock_irqrestore(&sysfb_lock, flags);
+
+	sysfb_rescan();
+	return ret;
+}
+EXPORT_SYMBOL(sysfb_claim);
+
+void sysfb_release(unsigned int types)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sysfb_lock, flags);
+	claimed_types &= ~types;
+	spin_unlock_irqrestore(&sysfb_lock, flags);
+
+	sysfb_rescan();
+}
+EXPORT_SYMBOL(sysfb_release);
+
+void sysfb_taint(struct sysfb_device *sdev, bool set)
+{
+	sdev->tainted = set;
+}
+EXPORT_SYMBOL(sysfb_taint);
+
+static int __init sysfb_init(void)
+{
+	int ret;
+
+	ret = bus_register(&sysfb_bus_type);
+	if (ret) {
+		pr_err("cannot register sysfb bus\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit sysfb_exit(void)
+{
+	bus_unregister(&sysfb_bus_type);
+}
+
+module_init(sysfb_init);
+module_exit(sysfb_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("System framebuffer bus");
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
new file mode 100644
index 0000000..6cd3c24
--- /dev/null
+++ b/include/linux/sysfb.h
@@ -0,0 +1,134 @@
+#ifndef __LINUX_SYSFB_H_
+#define __LINUX_SYSFB_H_
+
+/*
+ * System framebuffer bus
+ * Copyright (c) 2013 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/screen_info.h>
+#include <linux/types.h>
+
+/**
+ * sysfb_type
+ *
+ * Different types of available framebuffer devices. Only one device of each
+ * type can be available at a time. In most systems there even is only one
+ * device at all.
+ *
+ * Use the sysfb_device->screen pointer to get information about the framebuffer
+ * devices.
+ */
+enum sysfb_type {
+	SYSFB_TYPES = 0,
+};
+
+/**
+ * sysfb_device
+ * @tainted: whether the device was tainted or not
+ * @type: type of the fb device (@sysfb_type)
+ * @screen: pointer to supplemental screen-info object
+ * @dev: device object
+ *
+ * Each framebuffer device is represented by a sysfb_device object. The sysfb
+ * core manages them and they cannot be registered from the outside.
+ */
+struct sysfb_device {
+	bool tainted;
+	unsigned int type;
+	struct screen_info *screen;
+	struct device dev;
+};
+
+#define to_sysfb_device(_dev) container_of((_dev), struct sysfb_device, dev)
+
+/**
+ * sysfb_driver
+ * @type_mask: mask of device-types that are supported (@sysfb_type)
+ * @allow_tainted: whether the driver can be bound to tainted devices
+ * @driver: driver object
+ * @probe: probe callback
+ * @remove: remove callback
+ *
+ * Each generic framebuffer driver must provide this structure when registering
+ * to the sysfb core. The @driver field must also be provided by the caller
+ * except for the 'driver.bus' field which is initialized by the core.
+ */
+struct sysfb_driver {
+	unsigned int type_mask;
+	bool allow_tainted;
+	struct device_driver driver;
+
+	int (*probe) (struct sysfb_device *dev);
+	void (*remove) (struct sysfb_device *dev);
+};
+
+#define to_sysfb_driver(_drv) container_of((_drv), struct sysfb_driver, driver)
+
+/**
+ * sysfb_register_driver
+ * @drv: Driver object
+ *
+ * Register a new driver on the sysfb bus.
+ */
+int sysfb_register_driver(struct sysfb_driver *drv);
+
+/**
+ * sysfb_unregister_driver
+ * @drv: Driver object
+ *
+ * Remove a driver from the sysfb bus.
+ */
+void sysfb_unregister_driver(struct sysfb_driver *drv);
+
+/**
+ * sysfb_claim
+ * @types: Bitmask of sysfb_type flags
+ *
+ * Unbind all drivers from all devices matching the given types and prevent
+ * further drivers to get loaded on these types of devices. This allows real
+ * hardware drivers that are loaded by other bus-types (eg. pci-bus) to prevent
+ * any generic driver from using the given framebuffer types.
+ *
+ * Return 0 if the types could be claimed, otherwise a negative error code
+ * is returned.
+ */
+int sysfb_claim(unsigned int types);
+
+/**
+ * sysfb_release
+ * @types: Bitmask of sysfb_type flags
+ *
+ * Releases the given previously claimed types. See sysfb_claim(). This does
+ * not check whether the types are actually claimed or who claimed them. So make
+ * sure to call this only when you really claimed these types previously.
+ */
+void sysfb_release(unsigned int types);
+
+/**
+ * sysfb_taint
+ * @sdev: sysfb device
+ * @set: whether to taint or untaint
+ *
+ * This taints a given sysfb device. This should be done by all drivers if they
+ * change the framebuffer device in a way that other generic drivers might not
+ * be able to detect afterwards.
+ * This includes changing the resolution or properties of a framebuffer without
+ * adjusting the screen_info object.
+ * This can be reset to 'false' after all the changes have been undone.
+ *
+ * This is an unlocked function. You must call it from within your probe/remove
+ * callbacks in the driver.
+ */
+void sysfb_taint(struct sysfb_device *sdev, bool set);
+
+#endif /* __LINUX_SYSFB_H_ */
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 2/9] video: sysfb: new vbefb device type
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

From: David Herrmann <dh.herrmann@googlemail.com>

This adds the VESA BIOS Extension (VBE) device type. Platform code needs
to provide the "vbefb" platform-device with a screen_info structure as
platform code.

All drivers that depend on VBE can now register as bus drivers and bind
to SYSFB_VBE devices. There is no distinction between graphics
framebuffers or plain text VGA. Drivers ought to inspect the screen_info
and return -ENODEV during probe() is they cannot make use of the device.

Only one framebuffer of type SYSFB_VBE is available on a system at a time.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/video/sysfb.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sysfb.h |  5 +++-
 2 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
index 8249006..5b47a9a 100644
--- a/drivers/video/sysfb.c
+++ b/drivers/video/sysfb.c
@@ -205,6 +205,72 @@ void sysfb_taint(struct sysfb_device *sdev, bool set)
 }
 EXPORT_SYMBOL(sysfb_taint);
 
+static void sysfb_dev_release(struct device *dev)
+{
+	struct sysfb_device *sdev = to_sysfb_device(dev);
+
+	kfree(sdev);
+}
+
+static struct sysfb_device *sysfb_dev_new(struct device *parent)
+{
+	struct sysfb_device *sdev;
+
+	sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+	if (!sdev)
+		return NULL;
+
+	device_initialize(&sdev->dev);
+	sdev->dev.release = sysfb_dev_release;
+	sdev->dev.bus = &sysfb_bus_type;
+	sdev->dev.parent = parent;
+
+	return sdev;
+}
+
+static int sysfb_vbe_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sysfb_device *sdev;
+
+	sdev = sysfb_dev_new(&pdev->dev);
+	if (!sdev)
+		return -ENOMEM;
+
+	dev_set_name(&sdev->dev, "vbefb");
+	sdev->type = SYSFB_VBE;
+	sdev->screen = pdev->dev.platform_data;
+
+	ret = device_add(&sdev->dev);
+	if (ret)
+		goto err_free;
+
+	platform_set_drvdata(pdev, sdev);
+	return 0;
+
+err_free:
+	put_device(&sdev->dev);
+	return ret;
+}
+
+static int sysfb_vbe_remove(struct platform_device *pdev)
+{
+	struct sysfb_device *sdev = platform_get_drvdata(pdev);
+
+	device_del(&sdev->dev);
+	put_device(&sdev->dev);
+	return 0;
+}
+
+static struct platform_driver sysfb_vbe_driver = {
+	.driver = {
+		.name = "vbefb",
+		.owner = THIS_MODULE,
+	},
+	.probe = sysfb_vbe_probe,
+	.remove = sysfb_vbe_remove,
+};
+
 static int __init sysfb_init(void)
 {
 	int ret;
@@ -215,11 +281,22 @@ static int __init sysfb_init(void)
 		return ret;
 	}
 
+	ret = platform_driver_register(&sysfb_vbe_driver);
+	if (ret) {
+		pr_err("cannot register VBE framebuffer driver\n");
+		goto err_bus;
+	}
+
 	return 0;
+
+err_bus:
+	bus_unregister(&sysfb_bus_type);
+	return ret;
 }
 
 static void __exit sysfb_exit(void)
 {
+	platform_driver_unregister(&sysfb_vbe_driver);
 	bus_unregister(&sysfb_bus_type);
 }
 
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index 6cd3c24..1796c1e 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -20,6 +20,7 @@
 
 /**
  * sysfb_type
+ * @SYSFB_VBE: VESA BIOS Extension compatible device (includes VGA devices)
  *
  * Different types of available framebuffer devices. Only one device of each
  * type can be available at a time. In most systems there even is only one
@@ -29,7 +30,9 @@
  * devices.
  */
 enum sysfb_type {
-	SYSFB_TYPES = 0,
+	SYSFB_VBE = 0x01,
+
+	SYSFB_TYPES = SYSFB_VBE,
 };
 
 /**
-- 
1.8.1.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox