Commit 1d2add28 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'imx-drm-next-2015-03-31' of git://git.pengutronix.de/git/pza/linux into drm-next

imx-drm changes to use media bus formats and LDB drm_panel support

- Add media bus formats needed by imx-drm
- Switch to use media bus formats to describe the pixel format
  on the internal parallel bus between display interface and
  encoders
- Some preparations for TV Output via TVEv2 on i.MX5
- Add drm_panel support to the i.MX LVDS driver, allow to
  determine the bus pixel format from the panel descriptor.

* tag 'imx-drm-next-2015-03-31' of git://git.pengutronix.de/git/pza/linux:
  drm/imx: imx-ldb: allow to determine bus format from the connected panel
  drm/imx: imx-ldb: reset display clock input when disabling LVDS
  drm/imx: imx-ldb: add drm_panel support
  drm/imx: consolidate bus format variable names
  drm/imx: switch to use media bus formats
  Add RGB666_1X24_CPADHI media bus format
  Add YUV8_1X24 media bus format
  Add BGR888_1X24 and GBR888_1X24 media bus formats
  Add LVDS RGB media bus formats
  Add RGB444_1X12 and RGB565_1X16 media bus formats
  drm/imx: ipuv3-crtc: Allow to divide DI clock from TVEv2
  drm/imx: Add support for interlaced scanout
parents bb1dc08c 5e501ed7
...@@ -91,7 +91,9 @@ see <xref linkend="colorspaces" />.</entry> ...@@ -91,7 +91,9 @@ see <xref linkend="colorspaces" />.</entry>
<listitem><para>For formats where the total number of bits per pixel is smaller <listitem><para>For formats where the total number of bits per pixel is smaller
than the number of bus samples per pixel times the bus width, a padding than the number of bus samples per pixel times the bus width, a padding
value stating if the bytes are padded in their most high order bits value stating if the bytes are padded in their most high order bits
(PADHI) or low order bits (PADLO).</para></listitem> (PADHI) or low order bits (PADLO). A "C" prefix is used for component-wise
padding in the most high order bits (CPADHI) or low order bits (CPADLO)
of each separate component.</para></listitem>
<listitem><para>For formats where the number of bus samples per pixel is larger <listitem><para>For formats where the number of bus samples per pixel is larger
than 1, an endianness value stating if the pixel is transferred MSB first than 1, an endianness value stating if the pixel is transferred MSB first
(BE) or LSB first (LE).</para></listitem> (BE) or LSB first (LE).</para></listitem>
...@@ -192,6 +194,24 @@ see <xref linkend="colorspaces" />.</entry> ...@@ -192,6 +194,24 @@ see <xref linkend="colorspaces" />.</entry>
</row> </row>
</thead> </thead>
<tbody valign="top"> <tbody valign="top">
<row id="MEDIA-BUS-FMT-RGB444-1X12">
<entry>MEDIA_BUS_FMT_RGB444_1X12</entry>
<entry>0x100e</entry>
<entry></entry>
&dash-ent-20;
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-BE"> <row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-BE">
<entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE</entry> <entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE</entry>
<entry>0x1001</entry> <entry>0x1001</entry>
...@@ -304,6 +324,28 @@ see <xref linkend="colorspaces" />.</entry> ...@@ -304,6 +324,28 @@ see <xref linkend="colorspaces" />.</entry>
<entry>g<subscript>4</subscript></entry> <entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry> <entry>g<subscript>3</subscript></entry>
</row> </row>
<row id="MEDIA-BUS-FMT-RGB565-1X16">
<entry>MEDIA_BUS_FMT_RGB565_1X16</entry>
<entry>0x100f</entry>
<entry></entry>
&dash-ent-16;
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-BGR565-2X8-BE"> <row id="MEDIA-BUS-FMT-BGR565-2X8-BE">
<entry>MEDIA_BUS_FMT_BGR565_2X8_BE</entry> <entry>MEDIA_BUS_FMT_BGR565_2X8_BE</entry>
<entry>0x1005</entry> <entry>0x1005</entry>
...@@ -440,6 +482,96 @@ see <xref linkend="colorspaces" />.</entry> ...@@ -440,6 +482,96 @@ see <xref linkend="colorspaces" />.</entry>
<entry>b<subscript>1</subscript></entry> <entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry> <entry>b<subscript>0</subscript></entry>
</row> </row>
<row id="MEDIA-BUS-FMT-RGB666-1X24_CPADHI">
<entry>MEDIA_BUS_FMT_RGB666_1X24_CPADHI</entry>
<entry>0x1015</entry>
<entry></entry>
&dash-ent-8;
<entry>0</entry>
<entry>0</entry>
<entry>r<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
<entry>0</entry>
<entry>0</entry>
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
<entry>0</entry>
<entry>0</entry>
<entry>b<subscript>5</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-BGR888-1X24">
<entry>MEDIA_BUS_FMT_BGR888_1X24</entry>
<entry>0x1013</entry>
<entry></entry>
&dash-ent-8;
<entry>b<subscript>7</subscript></entry>
<entry>b<subscript>6</subscript></entry>
<entry>b<subscript>5</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
<entry>g<subscript>7</subscript></entry>
<entry>g<subscript>6</subscript></entry>
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
<entry>r<subscript>7</subscript></entry>
<entry>r<subscript>6</subscript></entry>
<entry>r<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-GBR888-1X24">
<entry>MEDIA_BUS_FMT_GBR888_1X24</entry>
<entry>0x1014</entry>
<entry></entry>
&dash-ent-8;
<entry>g<subscript>7</subscript></entry>
<entry>g<subscript>6</subscript></entry>
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
<entry>b<subscript>7</subscript></entry>
<entry>b<subscript>6</subscript></entry>
<entry>b<subscript>5</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
<entry>r<subscript>7</subscript></entry>
<entry>r<subscript>6</subscript></entry>
<entry>r<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-RGB888-1X24"> <row id="MEDIA-BUS-FMT-RGB888-1X24">
<entry>MEDIA_BUS_FMT_RGB888_1X24</entry> <entry>MEDIA_BUS_FMT_RGB888_1X24</entry>
<entry>0x100a</entry> <entry>0x100a</entry>
...@@ -582,6 +714,261 @@ see <xref linkend="colorspaces" />.</entry> ...@@ -582,6 +714,261 @@ see <xref linkend="colorspaces" />.</entry>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
<para>On LVDS buses, usually each sample is transferred serialized in
seven time slots per pixel clock, on three (18-bit) or four (24-bit)
differential data pairs at the same time. The remaining bits are used for
control signals as defined by SPWG/PSWG/VESA or JEIDA standards.
The 24-bit RGB format serialized in seven time slots on four lanes using
JEIDA defined bit mapping will be named
<constant>MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA</constant>, for example.
</para>
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb-lvds">
<title>LVDS RGB formats</title>
<tgroup cols="8">
<colspec colname="id" align="left" />
<colspec colname="code" align="center" />
<colspec colname="slot" align="center" />
<colspec colname="lane" />
<colspec colnum="5" colname="l03" align="center" />
<colspec colnum="6" colname="l02" align="center" />
<colspec colnum="7" colname="l01" align="center" />
<colspec colnum="8" colname="l00" align="center" />
<spanspec namest="l03" nameend="l00" spanname="l0" />
<thead>
<row>
<entry>Identifier</entry>
<entry>Code</entry>
<entry></entry>
<entry></entry>
<entry spanname="l0">Data organization</entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>Timeslot</entry>
<entry>Lane</entry>
<entry>3</entry>
<entry>2</entry>
<entry>1</entry>
<entry>0</entry>
</row>
</thead>
<tbody valign="top">
<row id="MEDIA-BUS-FMT-RGB666-1X7X3-SPWG">
<entry>MEDIA_BUS_FMT_RGB666_1X7X3_SPWG</entry>
<entry>0x1010</entry>
<entry>0</entry>
<entry></entry>
<entry>-</entry>
<entry>d</entry>
<entry>b<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>1</entry>
<entry></entry>
<entry>-</entry>
<entry>d</entry>
<entry>b<subscript>0</subscript></entry>
<entry>r<subscript>5</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>2</entry>
<entry></entry>
<entry>-</entry>
<entry>d</entry>
<entry>g<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>3</entry>
<entry></entry>
<entry>-</entry>
<entry>b<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>4</entry>
<entry></entry>
<entry>-</entry>
<entry>b<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>5</entry>
<entry></entry>
<entry>-</entry>
<entry>b<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>6</entry>
<entry></entry>
<entry>-</entry>
<entry>b<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-RGB888-1X7X4-SPWG">
<entry>MEDIA_BUS_FMT_RGB888_1X7X4_SPWG</entry>
<entry>0x1011</entry>
<entry>0</entry>
<entry></entry>
<entry>d</entry>
<entry>d</entry>
<entry>b<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>1</entry>
<entry></entry>
<entry>b<subscript>7</subscript></entry>
<entry>d</entry>
<entry>b<subscript>0</subscript></entry>
<entry>r<subscript>5</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>2</entry>
<entry></entry>
<entry>b<subscript>6</subscript></entry>
<entry>d</entry>
<entry>g<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>3</entry>
<entry></entry>
<entry>g<subscript>7</subscript></entry>
<entry>b<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>4</entry>
<entry></entry>
<entry>g<subscript>6</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>5</entry>
<entry></entry>
<entry>r<subscript>7</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>r<subscript>1</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>6</entry>
<entry></entry>
<entry>r<subscript>6</subscript></entry>
<entry>b<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-RGB888-1X7X4-JEIDA">
<entry>MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA</entry>
<entry>0x1012</entry>
<entry>0</entry>
<entry></entry>
<entry>d</entry>
<entry>d</entry>
<entry>b<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>1</entry>
<entry></entry>
<entry>b<subscript>1</subscript></entry>
<entry>d</entry>
<entry>b<subscript>2</subscript></entry>
<entry>r<subscript>7</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>2</entry>
<entry></entry>
<entry>b<subscript>0</subscript></entry>
<entry>d</entry>
<entry>g<subscript>7</subscript></entry>
<entry>r<subscript>6</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>3</entry>
<entry></entry>
<entry>g<subscript>1</subscript></entry>
<entry>b<subscript>7</subscript></entry>
<entry>g<subscript>6</subscript></entry>
<entry>r<subscript>5</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>4</entry>
<entry></entry>
<entry>g<subscript>0</subscript></entry>
<entry>b<subscript>6</subscript></entry>
<entry>g<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>5</entry>
<entry></entry>
<entry>r<subscript>1</subscript></entry>
<entry>b<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>6</entry>
<entry></entry>
<entry>r<subscript>0</subscript></entry>
<entry>b<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
</row>
</tbody>
</tgroup>
</table>
</section> </section>
<section> <section>
...@@ -2660,6 +3047,43 @@ see <xref linkend="colorspaces" />.</entry> ...@@ -2660,6 +3047,43 @@ see <xref linkend="colorspaces" />.</entry>
<entry>u<subscript>1</subscript></entry> <entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry> <entry>u<subscript>0</subscript></entry>
</row> </row>
<row id="MEDIA-BUS-FMT-YUV8-1X24">
<entry>MEDIA_BUS_FMT_YUV8_1X24</entry>
<entry>0x2024</entry>
<entry></entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
<entry>y<subscript>6</subscript></entry>
<entry>y<subscript>5</subscript></entry>
<entry>y<subscript>4</subscript></entry>
<entry>y<subscript>3</subscript></entry>
<entry>y<subscript>2</subscript></entry>
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
<entry>u<subscript>7</subscript></entry>
<entry>u<subscript>6</subscript></entry>
<entry>u<subscript>5</subscript></entry>
<entry>u<subscript>4</subscript></entry>
<entry>u<subscript>3</subscript></entry>
<entry>u<subscript>2</subscript></entry>
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
<entry>v<subscript>7</subscript></entry>
<entry>v<subscript>6</subscript></entry>
<entry>v<subscript>5</subscript></entry>
<entry>v<subscript>4</subscript></entry>
<entry>v<subscript>3</subscript></entry>
<entry>v<subscript>2</subscript></entry>
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
<row id="MEDIA-BUS-FMT-YUV10-1X30"> <row id="MEDIA-BUS-FMT-YUV10-1X30">
<entry>MEDIA_BUS_FMT_YUV10_1X30</entry> <entry>MEDIA_BUS_FMT_YUV10_1X30</entry>
<entry>0x2016</entry> <entry>0x2016</entry>
......
...@@ -44,23 +44,30 @@ Optional properties: ...@@ -44,23 +44,30 @@ Optional properties:
LVDS Channel LVDS Channel
============ ============
Each LVDS Channel has to contain a display-timings node that describes the Each LVDS Channel has to contain either an of graph link to a panel device node
video timings for the connected LVDS display. For detailed information, also or a display-timings node that describes the video timings for the connected
have a look at Documentation/devicetree/bindings/video/display-timing.txt. LVDS display as well as the fsl,data-mapping and fsl,data-width properties.
Required properties: Required properties:
- reg : should be <0> or <1> - reg : should be <0> or <1>
- port: Input and output port nodes with endpoint definitions as defined in
Documentation/devicetree/bindings/graph.txt.
On i.MX5, the internal two-input-multiplexer is used. Due to hardware
limitations, only one input port (port@[0,1]) can be used for each channel
(lvds-channel@[0,1], respectively).
On i.MX6, there should be four input ports (port@[0-3]) that correspond
to the four LVDS multiplexer inputs.
A single output port (port@2 on i.MX5, port@4 on i.MX6) must be connected
to a panel input port. Optionally, the output port can be left out if
display-timings are used instead.
Optional properties (required if display-timings are used):
- display-timings : A node that describes the display timings as defined in
Documentation/devicetree/bindings/video/display-timing.txt.
- fsl,data-mapping : should be "spwg" or "jeida" - fsl,data-mapping : should be "spwg" or "jeida"
This describes how the color bits are laid out in the This describes how the color bits are laid out in the
serialized LVDS signal. serialized LVDS signal.
- fsl,data-width : should be <18> or <24> - fsl,data-width : should be <18> or <24>
- port: A port node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt.
On i.MX5, the internal two-input-multiplexer is used.
Due to hardware limitations, only one port (port@[0,1])
can be used for each channel (lvds-channel@[0,1], respectively)
On i.MX6, there should be four ports (port@[0-3]) that correspond
to the four LVDS multiplexer inputs.
example: example:
...@@ -73,23 +80,21 @@ ldb: ldb@53fa8008 { ...@@ -73,23 +80,21 @@ ldb: ldb@53fa8008 {
#size-cells = <0>; #size-cells = <0>;
compatible = "fsl,imx53-ldb"; compatible = "fsl,imx53-ldb";
gpr = <&gpr>; gpr = <&gpr>;
clocks = <&clks 122>, <&clks 120>, clocks = <&clks IMX5_CLK_LDB_DI0_SEL>,
<&clks 115>, <&clks 116>, <&clks IMX5_CLK_LDB_DI1_SEL>,
<&clks 123>, <&clks 85>; <&clks IMX5_CLK_IPU_DI0_SEL>,
<&clks IMX5_CLK_IPU_DI1_SEL>,
<&clks IMX5_CLK_LDB_DI0_GATE>,
<&clks IMX5_CLK_LDB_DI1_GATE>;
clock-names = "di0_pll", "di1_pll", clock-names = "di0_pll", "di1_pll",
"di0_sel", "di1_sel", "di0_sel", "di1_sel",
"di0", "di1"; "di0", "di1";
/* Using an of-graph endpoint link to connect the panel */
lvds-channel@0 { lvds-channel@0 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
reg = <0>; reg = <0>;
fsl,data-mapping = "spwg";
fsl,data-width = <24>;
display-timings {
/* ... */
};
port@0 { port@0 {
reg = <0>; reg = <0>;
...@@ -98,8 +103,17 @@ ldb: ldb@53fa8008 { ...@@ -98,8 +103,17 @@ ldb: ldb@53fa8008 {
remote-endpoint = <&ipu_di0_lvds0>; remote-endpoint = <&ipu_di0_lvds0>;
}; };
}; };
port@2 {
reg = <2>;
lvds0_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
}; };
/* Using display-timings and fsl,data-mapping/width instead */
lvds-channel@1 { lvds-channel@1 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
...@@ -120,3 +134,13 @@ ldb: ldb@53fa8008 { ...@@ -120,3 +134,13 @@ ldb: ldb@53fa8008 {
}; };
}; };
}; };
panel: lvds-panel {
/* ... */
port {
panel_in: endpoint {
remote-endpoint = <&lvds0_out>;
};
};
};
...@@ -36,6 +36,7 @@ config DRM_IMX_TVE ...@@ -36,6 +36,7 @@ config DRM_IMX_TVE
config DRM_IMX_LDB config DRM_IMX_LDB
tristate "Support for LVDS displays" tristate "Support for LVDS displays"
depends on DRM_IMX && MFD_SYSCON depends on DRM_IMX && MFD_SYSCON
select DRM_PANEL
help help
Choose this to enable the internal LVDS Display Bridge (LDB) Choose this to enable the internal LVDS Display Bridge (LDB)
found on i.MX53 and i.MX6 processors. found on i.MX53 and i.MX6 processors.
......
...@@ -123,7 +123,7 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder) ...@@ -123,7 +123,7 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder)
static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder) static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
{ {
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24);
} }
static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
......
...@@ -103,8 +103,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) ...@@ -103,8 +103,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
return NULL; return NULL;
} }
int imx_drm_panel_format_pins(struct drm_encoder *encoder, int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin) int hsync_pin, int vsync_pin)
{ {
struct imx_drm_crtc_helper_funcs *helper; struct imx_drm_crtc_helper_funcs *helper;
struct imx_drm_crtc *imx_crtc; struct imx_drm_crtc *imx_crtc;
...@@ -116,16 +116,16 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder, ...@@ -116,16 +116,16 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
helper = &imx_crtc->imx_drm_helper_funcs; helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt) if (helper->set_interface_pix_fmt)
return helper->set_interface_pix_fmt(encoder->crtc, return helper->set_interface_pix_fmt(encoder->crtc,
interface_pix_fmt, hsync_pin, vsync_pin); bus_format, hsync_pin, vsync_pin);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins);
int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format)
{ {
return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3);
} }
EXPORT_SYMBOL_GPL(imx_drm_panel_format); EXPORT_SYMBOL_GPL(imx_drm_set_bus_format);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{ {
......
...@@ -18,7 +18,7 @@ struct imx_drm_crtc_helper_funcs { ...@@ -18,7 +18,7 @@ struct imx_drm_crtc_helper_funcs {
int (*enable_vblank)(struct drm_crtc *crtc); int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc);
int (*set_interface_pix_fmt)(struct drm_crtc *crtc, int (*set_interface_pix_fmt)(struct drm_crtc *crtc,
u32 pix_fmt, int hsync_pin, int vsync_pin); u32 bus_format, int hsync_pin, int vsync_pin);
const struct drm_crtc_helper_funcs *crtc_helper_funcs; const struct drm_crtc_helper_funcs *crtc_helper_funcs;
const struct drm_crtc_funcs *crtc_funcs; const struct drm_crtc_funcs *crtc_funcs;
}; };
...@@ -40,10 +40,10 @@ void imx_drm_mode_config_init(struct drm_device *drm); ...@@ -40,10 +40,10 @@ void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
int imx_drm_panel_format_pins(struct drm_encoder *encoder, int imx_drm_set_bus_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin); u32 bus_format, int hsync_pin, int vsync_pin);
int imx_drm_panel_format(struct drm_encoder *encoder, int imx_drm_set_bus_format(struct drm_encoder *encoder,
u32 interface_pix_fmt); u32 bus_format);
int imx_drm_encoder_get_mux_id(struct device_node *node, int imx_drm_encoder_get_mux_id(struct device_node *node,
struct drm_encoder *encoder); struct drm_encoder *encoder);
......
...@@ -19,10 +19,11 @@ ...@@ -19,10 +19,11 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_panel.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_graph.h>
#include <video/of_videomode.h> #include <video/of_videomode.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
...@@ -55,12 +56,14 @@ struct imx_ldb_channel { ...@@ -55,12 +56,14 @@ struct imx_ldb_channel {
struct imx_ldb *ldb; struct imx_ldb *ldb;
struct drm_connector connector; struct drm_connector connector;
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_panel *panel;
struct device_node *child; struct device_node *child;
int chno; int chno;
void *edid; void *edid;
int edid_len; int edid_len;
struct drm_display_mode mode; struct drm_display_mode mode;
int mode_valid; int mode_valid;
int bus_format;
}; };
struct bus_mux { struct bus_mux {
...@@ -75,6 +78,7 @@ struct imx_ldb { ...@@ -75,6 +78,7 @@ struct imx_ldb {
struct imx_ldb_channel channel[2]; struct imx_ldb_channel channel[2];
struct clk *clk[2]; /* our own clock */ struct clk *clk[2]; /* our own clock */
struct clk *clk_sel[4]; /* parent of display clock */ struct clk *clk_sel[4]; /* parent of display clock */
struct clk *clk_parent[4]; /* original parent of clk_sel */
struct clk *clk_pll[2]; /* upstream clock we can adjust */ struct clk *clk_pll[2]; /* upstream clock we can adjust */
u32 ldb_ctrl; u32 ldb_ctrl;
const struct bus_mux *lvds_mux; const struct bus_mux *lvds_mux;
...@@ -91,6 +95,17 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) ...@@ -91,6 +95,17 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
int num_modes = 0; int num_modes = 0;
if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
imx_ldb_ch->panel->funcs->get_modes) {
struct drm_display_info *di = &connector->display_info;
num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
if (!imx_ldb_ch->bus_format && di->num_bus_formats)
imx_ldb_ch->bus_format = di->bus_formats[0];
if (num_modes > 0)
return num_modes;
}
if (imx_ldb_ch->edid) { if (imx_ldb_ch->edid) {
drm_mode_connector_update_edid_property(connector, drm_mode_connector_update_edid_property(connector,
imx_ldb_ch->edid); imx_ldb_ch->edid);
...@@ -163,24 +178,36 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) ...@@ -163,24 +178,36 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
{ {
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb; struct imx_ldb *ldb = imx_ldb_ch->ldb;
u32 pixel_fmt; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
u32 bus_format;
switch (imx_ldb_ch->chno) { switch (imx_ldb_ch->bus_format) {
case 0: default:
pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? dev_warn(ldb->dev,
V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; "could not determine data mapping, default to 18-bit \"spwg\"\n");
/* fallthrough */
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
bus_format = MEDIA_BUS_FMT_RGB666_1X18;
break; break;
case 1: case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? bus_format = MEDIA_BUS_FMT_RGB888_1X24;
V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; if (imx_ldb_ch->chno == 0 || dual)
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
if (imx_ldb_ch->chno == 1 || dual)
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
if (imx_ldb_ch->chno == 0 || dual)
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
LDB_BIT_MAP_CH0_JEIDA;
if (imx_ldb_ch->chno == 1 || dual)
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
LDB_BIT_MAP_CH1_JEIDA;
break; break;
default:
dev_err(ldb->dev, "unable to config di%d panel format\n",
imx_ldb_ch->chno);
pixel_fmt = V4L2_PIX_FMT_RGB24;
} }
imx_drm_panel_format(encoder, pixel_fmt); imx_drm_set_bus_format(encoder, bus_format);
} }
static void imx_ldb_encoder_commit(struct drm_encoder *encoder) static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
...@@ -190,6 +217,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) ...@@ -190,6 +217,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
drm_panel_prepare(imx_ldb_ch->panel);
if (dual) { if (dual) {
clk_prepare_enable(ldb->clk[0]); clk_prepare_enable(ldb->clk[0]);
clk_prepare_enable(ldb->clk[1]); clk_prepare_enable(ldb->clk[1]);
...@@ -223,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) ...@@ -223,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
} }
regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
drm_panel_enable(imx_ldb_ch->panel);
} }
static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
...@@ -274,6 +305,7 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) ...@@ -274,6 +305,7 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
{ {
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb; struct imx_ldb *ldb = imx_ldb_ch->ldb;
int mux, ret;
/* /*
* imx_ldb_encoder_disable is called by * imx_ldb_encoder_disable is called by
...@@ -287,6 +319,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) ...@@ -287,6 +319,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
(ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
return; return;
drm_panel_disable(imx_ldb_ch->panel);
if (imx_ldb_ch == &ldb->channel[0]) if (imx_ldb_ch == &ldb->channel[0])
ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
else if (imx_ldb_ch == &ldb->channel[1]) else if (imx_ldb_ch == &ldb->channel[1])
...@@ -298,6 +332,30 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) ...@@ -298,6 +332,30 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
clk_disable_unprepare(ldb->clk[0]); clk_disable_unprepare(ldb->clk[0]);
clk_disable_unprepare(ldb->clk[1]); clk_disable_unprepare(ldb->clk[1]);
} }
if (ldb->lvds_mux) {
const struct bus_mux *lvds_mux = NULL;
if (imx_ldb_ch == &ldb->channel[0])
lvds_mux = &ldb->lvds_mux[0];
else if (imx_ldb_ch == &ldb->channel[1])
lvds_mux = &ldb->lvds_mux[1];
regmap_read(ldb->regmap, lvds_mux->reg, &mux);
mux &= lvds_mux->mask;
mux >>= lvds_mux->shift;
} else {
mux = (imx_ldb_ch == &ldb->channel[0]) ? 0 : 1;
}
/* set display clock mux back to original input clock */
ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk_parent[mux]);
if (ret)
dev_err(ldb->dev,
"unable to set di%d parent clock to original parent\n",
mux);
drm_panel_unprepare(imx_ldb_ch->panel);
} }
static struct drm_connector_funcs imx_ldb_connector_funcs = { static struct drm_connector_funcs imx_ldb_connector_funcs = {
...@@ -371,6 +429,9 @@ static int imx_ldb_register(struct drm_device *drm, ...@@ -371,6 +429,9 @@ static int imx_ldb_register(struct drm_device *drm,
drm_connector_init(drm, &imx_ldb_ch->connector, drm_connector_init(drm, &imx_ldb_ch->connector,
&imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
if (imx_ldb_ch->panel)
drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector);
drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
&imx_ldb_ch->encoder); &imx_ldb_ch->encoder);
...@@ -382,25 +443,39 @@ enum { ...@@ -382,25 +443,39 @@ enum {
LVDS_BIT_MAP_JEIDA LVDS_BIT_MAP_JEIDA
}; };
static const char * const imx_ldb_bit_mappings[] = { struct imx_ldb_bit_mapping {
[LVDS_BIT_MAP_SPWG] = "spwg", u32 bus_format;
[LVDS_BIT_MAP_JEIDA] = "jeida", u32 datawidth;
const char * const mapping;
};
static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = {
{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, "spwg" },
{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, "spwg" },
{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
}; };
static const int of_get_data_mapping(struct device_node *np) static u32 of_get_bus_format(struct device *dev, struct device_node *np)
{ {
const char *bm; const char *bm;
u32 datawidth = 0;
int ret, i; int ret, i;
ret = of_property_read_string(np, "fsl,data-mapping", &bm); ret = of_property_read_string(np, "fsl,data-mapping", &bm);
if (ret < 0) if (ret < 0)
return ret; return ret;
for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) of_property_read_u32(np, "fsl,data-width", &datawidth);
if (!strcasecmp(bm, imx_ldb_bit_mappings[i]))
return i;
return -EINVAL; for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) {
if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) &&
datawidth == imx_ldb_bit_mappings[i].datawidth)
return imx_ldb_bit_mappings[i].bus_format;
}
dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm);
return -ENOENT;
} }
static struct bus_mux imx6q_lvds_mux[2] = { static struct bus_mux imx6q_lvds_mux[2] = {
...@@ -437,8 +512,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -437,8 +512,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
struct device_node *child; struct device_node *child;
const u8 *edidp; const u8 *edidp;
struct imx_ldb *imx_ldb; struct imx_ldb *imx_ldb;
int datawidth;
int mapping;
int dual; int dual;
int ret; int ret;
int i; int i;
...@@ -479,12 +552,15 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -479,12 +552,15 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
imx_ldb->clk_sel[i] = NULL; imx_ldb->clk_sel[i] = NULL;
break; break;
} }
imx_ldb->clk_parent[i] = clk_get_parent(imx_ldb->clk_sel[i]);
} }
if (i == 0) if (i == 0)
return ret; return ret;
for_each_child_of_node(np, child) { for_each_child_of_node(np, child) {
struct imx_ldb_channel *channel; struct imx_ldb_channel *channel;
struct device_node *port;
ret = of_property_read_u32(child, "reg", &i); ret = of_property_read_u32(child, "reg", &i);
if (ret || i < 0 || i > 1) if (ret || i < 0 || i > 1)
...@@ -503,49 +579,53 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -503,49 +579,53 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
channel->chno = i; channel->chno = i;
channel->child = child; channel->child = child;
/*
* The output port is port@4 with an external 4-port mux or
* port@2 with the internal 2-port mux.
*/
port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2);
if (port) {
struct device_node *endpoint, *remote;
endpoint = of_get_child_by_name(port, "endpoint");
if (endpoint) {
remote = of_graph_get_remote_port_parent(endpoint);
if (remote)
channel->panel = of_drm_find_panel(remote);
else
return -EPROBE_DEFER;
if (!channel->panel) {
dev_err(dev, "panel not found: %s\n",
remote->full_name);
return -EPROBE_DEFER;
}
}
}
edidp = of_get_property(child, "edid", &channel->edid_len); edidp = of_get_property(child, "edid", &channel->edid_len);
if (edidp) { if (edidp) {
channel->edid = kmemdup(edidp, channel->edid_len, channel->edid = kmemdup(edidp, channel->edid_len,
GFP_KERNEL); GFP_KERNEL);
} else { } else if (!channel->panel) {
ret = of_get_drm_display_mode(child, &channel->mode, 0); ret = of_get_drm_display_mode(child, &channel->mode, 0);
if (!ret) if (!ret)
channel->mode_valid = 1; channel->mode_valid = 1;
} }
ret = of_property_read_u32(child, "fsl,data-width", &datawidth); channel->bus_format = of_get_bus_format(dev, child);
if (ret) if (channel->bus_format == -EINVAL) {
datawidth = 0; /*
else if (datawidth != 18 && datawidth != 24) * If no bus format was specified in the device tree,
return -EINVAL; * we can still get it from the connected panel later.
*/
mapping = of_get_data_mapping(child); if (channel->panel && channel->panel->funcs &&
switch (mapping) { channel->panel->funcs->get_modes)
case LVDS_BIT_MAP_SPWG: channel->bus_format = 0;
if (datawidth == 24) {
if (i == 0 || dual)
imx_ldb->ldb_ctrl |=
LDB_DATA_WIDTH_CH0_24;
if (i == 1 || dual)
imx_ldb->ldb_ctrl |=
LDB_DATA_WIDTH_CH1_24;
}
break;
case LVDS_BIT_MAP_JEIDA:
if (datawidth == 18) {
dev_err(dev, "JEIDA standard only supported in 24 bit\n");
return -EINVAL;
} }
if (i == 0 || dual) if (channel->bus_format < 0) {
imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | dev_err(dev, "could not determine data mapping: %d\n",
LDB_BIT_MAP_CH0_JEIDA; channel->bus_format);
if (i == 1 || dual) return channel->bus_format;
imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
LDB_BIT_MAP_CH1_JEIDA;
break;
default:
dev_err(dev, "data mapping not specified or invalid\n");
return -EINVAL;
} }
ret = imx_ldb_register(drm, channel); ret = imx_ldb_register(drm, channel);
......
...@@ -301,11 +301,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) ...@@ -301,11 +301,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
switch (tve->mode) { switch (tve->mode) {
case TVE_MODE_VGA: case TVE_MODE_VGA:
imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24, imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24,
tve->hsync_pin, tve->vsync_pin); tve->hsync_pin, tve->vsync_pin);
break; break;
case TVE_MODE_TVOUT: case TVE_MODE_TVOUT:
imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444); imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24);
break; break;
} }
} }
......
...@@ -45,7 +45,7 @@ struct ipu_crtc { ...@@ -45,7 +45,7 @@ struct ipu_crtc {
struct drm_pending_vblank_event *page_flip_event; struct drm_pending_vblank_event *page_flip_event;
struct drm_framebuffer *newfb; struct drm_framebuffer *newfb;
int irq; int irq;
u32 interface_pix_fmt; u32 bus_format;
int di_hsync_pin; int di_hsync_pin;
int di_vsync_pin; int di_vsync_pin;
}; };
...@@ -145,7 +145,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ...@@ -145,7 +145,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
struct ipu_di_signal_cfg sig_cfg = {}; struct ipu_di_signal_cfg sig_cfg = {};
unsigned long encoder_types = 0; unsigned long encoder_types = 0;
u32 out_pixel_fmt;
int ret; int ret;
dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
...@@ -161,21 +160,21 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ...@@ -161,21 +160,21 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
__func__, encoder_types); __func__, encoder_types);
/* /*
* If we have DAC, TVDAC or LDB, then we need the IPU DI clock * If we have DAC or LDB, then we need the IPU DI clock to be
* to be the same as the LDB DI clock. * the same as the LDB DI clock. For TVDAC, derive the IPU DI
* clock from 27 MHz TVE_DI clock, but allow to divide it.
*/ */
if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
BIT(DRM_MODE_ENCODER_TVDAC) |
BIT(DRM_MODE_ENCODER_LVDS))) BIT(DRM_MODE_ENCODER_LVDS)))
sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC))
sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;
else else
sig_cfg.clkflags = 0; sig_cfg.clkflags = 0;
out_pixel_fmt = ipu_crtc->interface_pix_fmt;
sig_cfg.enable_pol = 1; sig_cfg.enable_pol = 1;
sig_cfg.clk_pol = 0; sig_cfg.clk_pol = 0;
sig_cfg.pixel_fmt = out_pixel_fmt; sig_cfg.bus_format = ipu_crtc->bus_format;
sig_cfg.v_to_h_sync = 0; sig_cfg.v_to_h_sync = 0;
sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
...@@ -184,7 +183,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ...@@ -184,7 +183,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
mode->flags & DRM_MODE_FLAG_INTERLACE, mode->flags & DRM_MODE_FLAG_INTERLACE,
out_pixel_fmt, mode->hdisplay); ipu_crtc->bus_format, mode->hdisplay);
if (ret) { if (ret) {
dev_err(ipu_crtc->dev, dev_err(ipu_crtc->dev,
"initializing display controller failed with %d\n", "initializing display controller failed with %d\n",
...@@ -202,7 +201,8 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ...@@ -202,7 +201,8 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode,
crtc->primary->fb, crtc->primary->fb,
0, 0, mode->hdisplay, mode->vdisplay, 0, 0, mode->hdisplay, mode->vdisplay,
x, y, mode->hdisplay, mode->vdisplay); x, y, mode->hdisplay, mode->vdisplay,
mode->flags & DRM_MODE_FLAG_INTERLACE);
} }
static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
...@@ -291,11 +291,11 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) ...@@ -291,11 +291,11 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
} }
static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
u32 pixfmt, int hsync_pin, int vsync_pin) u32 bus_format, int hsync_pin, int vsync_pin)
{ {
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
ipu_crtc->interface_pix_fmt = pixfmt; ipu_crtc->bus_format = bus_format;
ipu_crtc->di_hsync_pin = hsync_pin; ipu_crtc->di_hsync_pin = hsync_pin;
ipu_crtc->di_vsync_pin = vsync_pin; ipu_crtc->di_vsync_pin = vsync_pin;
......
...@@ -99,7 +99,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, ...@@ -99,7 +99,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y, struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h, unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y, uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h) uint32_t src_w, uint32_t src_h, bool interlaced)
{ {
struct device *dev = ipu_plane->base.dev->dev; struct device *dev = ipu_plane->base.dev->dev;
int ret; int ret;
...@@ -213,6 +213,8 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, ...@@ -213,6 +213,8 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y); ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (interlaced)
ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
ipu_plane->w = src_w; ipu_plane->w = src_w;
ipu_plane->h = src_h; ipu_plane->h = src_h;
...@@ -312,7 +314,8 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -312,7 +314,8 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb, ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
crtc_x, crtc_y, crtc_w, crtc_h, crtc_x, crtc_y, crtc_w, crtc_h,
src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16); src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
false);
if (ret < 0) { if (ret < 0) {
ipu_plane_put_resources(ipu_plane); ipu_plane_put_resources(ipu_plane);
return ret; return ret;
......
...@@ -42,7 +42,7 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, ...@@ -42,7 +42,7 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y, struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h, unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_x, uint32_t src_y, uint32_t src_w,
uint32_t src_h); uint32_t src_h, bool interlaced);
void ipu_plane_enable(struct ipu_plane *plane); void ipu_plane_enable(struct ipu_plane *plane);
void ipu_plane_disable(struct ipu_plane *plane); void ipu_plane_disable(struct ipu_plane *plane);
......
...@@ -33,7 +33,7 @@ struct imx_parallel_display { ...@@ -33,7 +33,7 @@ struct imx_parallel_display {
struct device *dev; struct device *dev;
void *edid; void *edid;
int edid_len; int edid_len;
u32 interface_pix_fmt; u32 bus_format;
int mode_valid; int mode_valid;
struct drm_display_mode mode; struct drm_display_mode mode;
struct drm_panel *panel; struct drm_panel *panel;
...@@ -118,7 +118,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder) ...@@ -118,7 +118,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
{ {
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
imx_drm_panel_format(encoder, imxpd->interface_pix_fmt); imx_drm_set_bus_format(encoder, imxpd->bus_format);
} }
static void imx_pd_encoder_commit(struct drm_encoder *encoder) static void imx_pd_encoder_commit(struct drm_encoder *encoder)
...@@ -225,14 +225,13 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -225,14 +225,13 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
ret = of_property_read_string(np, "interface-pix-fmt", &fmt); ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
if (!ret) { if (!ret) {
if (!strcmp(fmt, "rgb24")) if (!strcmp(fmt, "rgb24"))
imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24; imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
else if (!strcmp(fmt, "rgb565")) else if (!strcmp(fmt, "rgb565"))
imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16;
else if (!strcmp(fmt, "bgr666")) else if (!strcmp(fmt, "bgr666"))
imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
else if (!strcmp(fmt, "lvds666")) else if (!strcmp(fmt, "lvds666"))
imxpd->interface_pix_fmt = imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
v4l2_fourcc('L', 'V', 'D', '6');
} }
panel_node = of_parse_phandle(np, "fsl,panel", 0); panel_node = of_parse_phandle(np, "fsl,panel", 0);
......
...@@ -147,20 +147,20 @@ static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand, ...@@ -147,20 +147,20 @@ static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
writel(reg2, priv->dc_tmpl_reg + word * 8 + 4); writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
} }
static int ipu_pixfmt_to_map(u32 fmt) static int ipu_bus_format_to_map(u32 fmt)
{ {
switch (fmt) { switch (fmt) {
case V4L2_PIX_FMT_RGB24: case MEDIA_BUS_FMT_RGB888_1X24:
return IPU_DC_MAP_RGB24; return IPU_DC_MAP_RGB24;
case V4L2_PIX_FMT_RGB565: case MEDIA_BUS_FMT_RGB565_1X16:
return IPU_DC_MAP_RGB565; return IPU_DC_MAP_RGB565;
case IPU_PIX_FMT_GBR24: case MEDIA_BUS_FMT_GBR888_1X24:
return IPU_DC_MAP_GBR24; return IPU_DC_MAP_GBR24;
case V4L2_PIX_FMT_BGR666: case MEDIA_BUS_FMT_RGB666_1X18:
return IPU_DC_MAP_BGR666; return IPU_DC_MAP_BGR666;
case v4l2_fourcc('L', 'V', 'D', '6'): case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
return IPU_DC_MAP_LVDS666; return IPU_DC_MAP_LVDS666;
case V4L2_PIX_FMT_BGR24: case MEDIA_BUS_FMT_BGR888_1X24:
return IPU_DC_MAP_BGR24; return IPU_DC_MAP_BGR24;
default: default:
return -EINVAL; return -EINVAL;
...@@ -168,7 +168,7 @@ static int ipu_pixfmt_to_map(u32 fmt) ...@@ -168,7 +168,7 @@ static int ipu_pixfmt_to_map(u32 fmt)
} }
int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
u32 pixel_fmt, u32 width) u32 bus_format, u32 width)
{ {
struct ipu_dc_priv *priv = dc->priv; struct ipu_dc_priv *priv = dc->priv;
u32 reg = 0; u32 reg = 0;
...@@ -176,7 +176,7 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, ...@@ -176,7 +176,7 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
dc->di = ipu_di_get_num(di); dc->di = ipu_di_get_num(di);
map = ipu_pixfmt_to_map(pixel_fmt); map = ipu_bus_format_to_map(bus_format);
if (map < 0) { if (map < 0) {
dev_dbg(priv->dev, "IPU_DISP: No MAP\n"); dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
return map; return map;
......
...@@ -33,22 +33,30 @@ ...@@ -33,22 +33,30 @@
#define MEDIA_BUS_FMT_FIXED 0x0001 #define MEDIA_BUS_FMT_FIXED 0x0001
/* RGB - next is 0x100e */ /* RGB - next is 0x1016 */
#define MEDIA_BUS_FMT_RGB444_1X12 0x100e
#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001
#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002
#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003
#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004
#define MEDIA_BUS_FMT_RGB565_1X16 0x100f
#define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 #define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005
#define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 #define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006
#define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007
#define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008
#define MEDIA_BUS_FMT_RGB666_1X18 0x1009 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009
#define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015
#define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010
#define MEDIA_BUS_FMT_BGR888_1X24 0x1013
#define MEDIA_BUS_FMT_GBR888_1X24 0x1014
#define MEDIA_BUS_FMT_RGB888_1X24 0x100a #define MEDIA_BUS_FMT_RGB888_1X24 0x100a
#define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b
#define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c #define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c
#define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG 0x1011
#define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012
#define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d
/* YUV (including grey) - next is 0x2024 */ /* YUV (including grey) - next is 0x2025 */
#define MEDIA_BUS_FMT_Y8_1X8 0x2001 #define MEDIA_BUS_FMT_Y8_1X8 0x2001
#define MEDIA_BUS_FMT_UV8_1X8 0x2015 #define MEDIA_BUS_FMT_UV8_1X8 0x2015
#define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 #define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002
...@@ -74,6 +82,7 @@ ...@@ -74,6 +82,7 @@
#define MEDIA_BUS_FMT_VYUY10_1X20 0x201b #define MEDIA_BUS_FMT_VYUY10_1X20 0x201b
#define MEDIA_BUS_FMT_YUYV10_1X20 0x200d #define MEDIA_BUS_FMT_YUYV10_1X20 0x200d
#define MEDIA_BUS_FMT_YVYU10_1X20 0x200e #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e
#define MEDIA_BUS_FMT_YUV8_1X24 0x2024
#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 #define MEDIA_BUS_FMT_YUV10_1X30 0x2016
#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 #define MEDIA_BUS_FMT_AYUV8_1X32 0x2017
#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c #define MEDIA_BUS_FMT_UYVY12_2X12 0x201c
......
...@@ -39,7 +39,7 @@ struct ipu_di_signal_cfg { ...@@ -39,7 +39,7 @@ struct ipu_di_signal_cfg {
struct videomode mode; struct videomode mode;
u32 pixel_fmt; u32 bus_format;
u32 v_to_h_sync; u32 v_to_h_sync;
#define IPU_DI_CLKMODE_SYNC (1 << 0) #define IPU_DI_CLKMODE_SYNC (1 << 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment