提交 14aa0244 编写于 作者: L Linus Torvalds

Merge branch 'drm-next-merged' of git://people.freedesktop.org/~airlied/linux

Pull drm updates from Dave Airlie:
 "Highlights:

  Core:
   - Virtual GEM layer merged, this has been around for a long time, and
     it provides a software backed device that allows userspace to use
     it as a GEM shared memory handler.  This makes it a lot easier to
     do certain things when you have no GPU but still have to deal with
     DRI expectations.
   - atomic helper updates.
   - framebuffer modifier interface added.
   - i2c over auxch displayport fixes.
   - fb width/height confusion fixes.
   - new driver for ps8622/ps8625 bridge chips
   - lots of new panels

  i915:
   - more plane atomic conversion
   - vGPU guest support for XenGT
   - Skylake workarounds and fixes
   - Y-tiling support
   - work on dynamic pagetable allocation
   - EU count report param for gen9+
   - CHV fixes (no longer prelim)
   - remove ilk rc6
   - frontbuffer tracking for fbc
   - Displayport link rate refactoring
   - sprite colorkey refactor

  radeon:
   - Displayport MST support (not enabled by default)
   - non-ATOM native hw auxch support (DCE5+)
   - output csc support
   - new queries for userspace debug support
   - new VCE packet

  nouveau:
   - gk20a iommu support
   - gm107 graphics support
   - more gm20x bringup (waiting on signed nvidia fw).

  amdkfd:
   - multiple kgd instance support
   - use 64-bit time accessors

  msm:
   - stolen memory support
   - DSI and dual-DSI support
   - snapdragon 410 support

  exynos:
   - cleanups for atomic and pageflip

  imx-drm:
   - more media-bus formats
   - TV output prep
   - drm panel support

  tegra:
   - hw vblank counter using host1x syncpoints

  omap:
   - universal plane support
   - prep work for atomic modesetting

  rcar-du:
   - ported to atomic modesetting

  atmel-hlcdc:
   - ported to atomic modesetting
   - added suspend/resume support

  sti:
   - ported to atomic modesetting

  dwhdmi:
   - more compliant audio support
   - update rockchip phy support

  tda998x:
   - DT probing for attached crtcs
   - simplified EDID reading

  rockchip:
   - fixes

  adv7511:
   - fixes"

* 'drm-next-merged' of git://people.freedesktop.org/~airlied/linux: (689 commits)
  media-bus: Fixup RGB444_1X12, RGB565_1X16, and YUV8_1X24 media bus format
  drm/i915: Dont enable CS_PARSER_ERROR interrupts at all
  drm/i915: Move drm_framebuffer_unreference out of struct_mutex for takeover
  drm: fix trivial typo mistake
  drm: Make integer overflow checking cover universal cursor updates (v2)
  drm/nouveau/bios: fix fetching from acpi on certain systems
  drm/nouveau/gr/gm206: initial init+ctx code
  drm/nouveau/ce/gm206: enable support via gm204 code
  drm/nouveau/fifo/gm206: enable support via gm204 code
  drm/nouveau/gr/gm204: initial init+ctx code
  drm/nouveau: support for buffer moves via MaxwellDmaCopyA
  drm/nouveau/ce/gm204: initial support
  drm/nouveau: add support for gm20x fifo channels
  drm/nouveau/fifo/gm204: initial support
  drm/nouveau/gr/gk104-: prevent reading non-existent regs in intr handler
  drm/nouveau/gr/gm107: very slightly demagic part of attrib cb setup
  drm/nouveau/gr/gk104-: correct crop/zrop num_active_fbps setting
  drm/nouveau/gr/gf100-: add symbolic names for classes
  drm/nouveau/gr/gm107: support tpc "strand" ctxsw in gpccs ucode
  drm/nouveau/gr/gf100-: support mmio access with gpc offset from gpccs ucode
  ...
...@@ -3979,6 +3979,11 @@ int num_ioctls;</synopsis> ...@@ -3979,6 +3979,11 @@ int num_ioctls;</synopsis>
!Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
!Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
</sect2> </sect2>
<sect2>
<title>Intel GVT-g Guest Support(vGPU)</title>
!Pdrivers/gpu/drm/i915/i915_vgpu.c Intel GVT-g guest support
!Idrivers/gpu/drm/i915/i915_vgpu.c
</sect2>
</sect1> </sect1>
<sect1> <sect1>
<title>Display Hardware Handling</title> <title>Display Hardware Handling</title>
...@@ -4046,6 +4051,17 @@ int num_ioctls;</synopsis> ...@@ -4046,6 +4051,17 @@ int num_ioctls;</synopsis>
<title>Frame Buffer Compression (FBC)</title> <title>Frame Buffer Compression (FBC)</title>
!Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC) !Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC)
!Idrivers/gpu/drm/i915/intel_fbc.c !Idrivers/gpu/drm/i915/intel_fbc.c
</sect2>
<sect2>
<title>Display Refresh Rate Switching (DRRS)</title>
!Pdrivers/gpu/drm/i915/intel_dp.c Display Refresh Rate Switching (DRRS)
!Fdrivers/gpu/drm/i915/intel_dp.c intel_dp_set_drrs_state
!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_enable
!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_disable
!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_invalidate
!Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_flush
!Fdrivers/gpu/drm/i915/intel_dp.c intel_dp_drrs_init
</sect2> </sect2>
<sect2> <sect2>
<title>DPIO</title> <title>DPIO</title>
...@@ -4168,7 +4184,7 @@ int num_ioctls;</synopsis> ...@@ -4168,7 +4184,7 @@ int num_ioctls;</synopsis>
<sect2> <sect2>
<title>Buffer Object Eviction</title> <title>Buffer Object Eviction</title>
<para> <para>
This section documents the interface function for evicting buffer This section documents the interface functions for evicting buffer
objects to make space available in the virtual gpu address spaces. objects to make space available in the virtual gpu address spaces.
Note that this is mostly orthogonal to shrinking buffer objects Note that this is mostly orthogonal to shrinking buffer objects
caches, which has the goal to make main memory (shared with the gpu caches, which has the goal to make main memory (shared with the gpu
...@@ -4176,6 +4192,17 @@ int num_ioctls;</synopsis> ...@@ -4176,6 +4192,17 @@ int num_ioctls;</synopsis>
</para> </para>
!Idrivers/gpu/drm/i915/i915_gem_evict.c !Idrivers/gpu/drm/i915/i915_gem_evict.c
</sect2> </sect2>
<sect2>
<title>Buffer Object Memory Shrinking</title>
<para>
This section documents the interface function for shrinking memory
usage of buffer object caches. Shrinking is used to make main memory
available. Note that this is mostly orthogonal to evicting buffer
objects, which has the goal to make space in gpu virtual address
spaces.
</para>
!Idrivers/gpu/drm/i915/i915_gem_shrinker.c
</sect2>
</sect1> </sect1>
<sect1> <sect1>
......
...@@ -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>0x1016</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>0x1017</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>0x2025</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>;
};
};
};
Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
Required properties:
- compatible: should be "ampire,am800480r3tmqwa1h"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
AU Optronics Corporation 10.1" WSVGA TFT LCD panel
Required properties:
- compatible: should be "auo,b101ean01"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Innolux AT043TN24 4.3" WQVGA TFT LCD panel
Required properties:
- compatible: should be "innolux,at043tn24"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
Required properties:
- compatible: should be "innolux,zj070na-01p"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
Required properties:
- compatible: should be "ortustech,com43h4m85ulc"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
Required properties:
- compatible: should be "samsung,ltn140at29-301"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
Required properties:
- compatible: should be "shelly,sca07010-bfn-lnn"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
...@@ -17,6 +17,7 @@ altr Altera Corp. ...@@ -17,6 +17,7 @@ altr Altera Corp.
amcc Applied Micro Circuits Corporation (APM, formally AMCC) amcc Applied Micro Circuits Corporation (APM, formally AMCC)
amd Advanced Micro Devices (AMD), Inc. amd Advanced Micro Devices (AMD), Inc.
amlogic Amlogic, Inc. amlogic Amlogic, Inc.
ampire Ampire Co., Ltd.
ams AMS AG ams AMS AG
amstaos AMS-Taos Inc. amstaos AMS-Taos Inc.
apm Applied Micro Circuits Corporation (APM) apm Applied Micro Circuits Corporation (APM)
...@@ -135,6 +136,7 @@ nvidia NVIDIA ...@@ -135,6 +136,7 @@ nvidia NVIDIA
nxp NXP Semiconductors nxp NXP Semiconductors
onnn ON Semiconductor Corp. onnn ON Semiconductor Corp.
opencores OpenCores.org opencores OpenCores.org
ortustech Ortus Technology Co., Ltd.
ovti OmniVision Technologies ovti OmniVision Technologies
panasonic Panasonic Corporation panasonic Panasonic Corporation
parade Parade Technologies Inc. parade Parade Technologies Inc.
......
...@@ -3417,7 +3417,6 @@ T: git git://people.freedesktop.org/~airlied/linux ...@@ -3417,7 +3417,6 @@ T: git git://people.freedesktop.org/~airlied/linux
S: Supported S: Supported
F: drivers/gpu/drm/rcar-du/ F: drivers/gpu/drm/rcar-du/
F: drivers/gpu/drm/shmobile/ F: drivers/gpu/drm/shmobile/
F: include/linux/platform_data/rcar-du.h
F: include/linux/platform_data/shmob_drm.h F: include/linux/platform_data/shmob_drm.h
DSBR100 USB FM RADIO DRIVER DSBR100 USB FM RADIO DRIVER
......
...@@ -165,6 +165,15 @@ config DRM_SAVAGE ...@@ -165,6 +165,15 @@ config DRM_SAVAGE
Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
chipset. If M is selected the module will be called savage. chipset. If M is selected the module will be called savage.
config DRM_VGEM
tristate "Virtual GEM provider"
depends on DRM
help
Choose this option to get a virtual graphics memory manager,
as used by Mesa's software renderer for enhanced performance.
If M is selected the module will be called vgem.
source "drivers/gpu/drm/exynos/Kconfig" source "drivers/gpu/drm/exynos/Kconfig"
source "drivers/gpu/drm/rockchip/Kconfig" source "drivers/gpu/drm/rockchip/Kconfig"
......
...@@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_SIS) += sis/ ...@@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_SIS) += sis/
obj-$(CONFIG_DRM_SAVAGE)+= savage/ obj-$(CONFIG_DRM_SAVAGE)+= savage/
obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
obj-$(CONFIG_DRM_VIA) +=via/ obj-$(CONFIG_DRM_VIA) +=via/
obj-$(CONFIG_DRM_VGEM) += vgem/
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
obj-$(CONFIG_DRM_EXYNOS) +=exynos/ obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
......
...@@ -435,21 +435,22 @@ static int kfd_ioctl_get_clock_counters(struct file *filep, ...@@ -435,21 +435,22 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
{ {
struct kfd_ioctl_get_clock_counters_args *args = data; struct kfd_ioctl_get_clock_counters_args *args = data;
struct kfd_dev *dev; struct kfd_dev *dev;
struct timespec time; struct timespec64 time;
dev = kfd_device_by_id(args->gpu_id); dev = kfd_device_by_id(args->gpu_id);
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
/* Reading GPU clock counter from KGD */ /* Reading GPU clock counter from KGD */
args->gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd); args->gpu_clock_counter =
dev->kfd2kgd->get_gpu_clock_counter(dev->kgd);
/* No access to rdtsc. Using raw monotonic time */ /* No access to rdtsc. Using raw monotonic time */
getrawmonotonic(&time); getrawmonotonic64(&time);
args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time); args->cpu_clock_counter = (uint64_t)timespec64_to_ns(&time);
get_monotonic_boottime(&time); get_monotonic_boottime64(&time);
args->system_clock_counter = (uint64_t)timespec_to_ns(&time); args->system_clock_counter = (uint64_t)timespec64_to_ns(&time);
/* Since the counter is in nano-seconds we use 1GHz frequency */ /* Since the counter is in nano-seconds we use 1GHz frequency */
args->system_clock_freq = 1000000000; args->system_clock_freq = 1000000000;
......
...@@ -94,7 +94,8 @@ static const struct kfd_device_info *lookup_device_info(unsigned short did) ...@@ -94,7 +94,8 @@ static const struct kfd_device_info *lookup_device_info(unsigned short did)
return NULL; return NULL;
} }
struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev) struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
struct pci_dev *pdev, const struct kfd2kgd_calls *f2g)
{ {
struct kfd_dev *kfd; struct kfd_dev *kfd;
...@@ -112,6 +113,11 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev) ...@@ -112,6 +113,11 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
kfd->device_info = device_info; kfd->device_info = device_info;
kfd->pdev = pdev; kfd->pdev = pdev;
kfd->init_complete = false; kfd->init_complete = false;
kfd->kfd2kgd = f2g;
mutex_init(&kfd->doorbell_mutex);
memset(&kfd->doorbell_available_index, 0,
sizeof(kfd->doorbell_available_index));
return kfd; return kfd;
} }
...@@ -200,8 +206,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, ...@@ -200,8 +206,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
/* add another 512KB for all other allocations on gart (HPD, fences) */ /* add another 512KB for all other allocations on gart (HPD, fences) */
size += 512 * 1024; size += 512 * 1024;
if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem, if (kfd->kfd2kgd->init_gtt_mem_allocation(
&kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) { kfd->kgd, size, &kfd->gtt_mem,
&kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)){
dev_err(kfd_device, dev_err(kfd_device,
"Could not allocate %d bytes for device (%x:%x)\n", "Could not allocate %d bytes for device (%x:%x)\n",
size, kfd->pdev->vendor, kfd->pdev->device); size, kfd->pdev->vendor, kfd->pdev->device);
...@@ -270,7 +277,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, ...@@ -270,7 +277,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
kfd_topology_add_device_error: kfd_topology_add_device_error:
kfd_gtt_sa_fini(kfd); kfd_gtt_sa_fini(kfd);
kfd_gtt_sa_init_error: kfd_gtt_sa_init_error:
kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem); kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
dev_err(kfd_device, dev_err(kfd_device,
"device (%x:%x) NOT added due to errors\n", "device (%x:%x) NOT added due to errors\n",
kfd->pdev->vendor, kfd->pdev->device); kfd->pdev->vendor, kfd->pdev->device);
...@@ -285,7 +292,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) ...@@ -285,7 +292,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
amd_iommu_free_device(kfd->pdev); amd_iommu_free_device(kfd->pdev);
kfd_topology_remove_device(kfd); kfd_topology_remove_device(kfd);
kfd_gtt_sa_fini(kfd); kfd_gtt_sa_fini(kfd);
kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem); kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
} }
kfree(kfd); kfree(kfd);
......
...@@ -82,7 +82,8 @@ static inline unsigned int get_pipes_num_cpsch(void) ...@@ -82,7 +82,8 @@ static inline unsigned int get_pipes_num_cpsch(void)
void program_sh_mem_settings(struct device_queue_manager *dqm, void program_sh_mem_settings(struct device_queue_manager *dqm,
struct qcm_process_device *qpd) struct qcm_process_device *qpd)
{ {
return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid, return dqm->dev->kfd2kgd->program_sh_mem_settings(
dqm->dev->kgd, qpd->vmid,
qpd->sh_mem_config, qpd->sh_mem_config,
qpd->sh_mem_ape1_base, qpd->sh_mem_ape1_base,
qpd->sh_mem_ape1_limit, qpd->sh_mem_ape1_limit,
...@@ -457,9 +458,12 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid, ...@@ -457,9 +458,12 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
{ {
uint32_t pasid_mapping; uint32_t pasid_mapping;
pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid | pasid_mapping = (pasid == 0) ? 0 :
ATC_VMID_PASID_MAPPING_VALID; (uint32_t)pasid |
return kfd2kgd->set_pasid_vmid_mapping(dqm->dev->kgd, pasid_mapping, ATC_VMID_PASID_MAPPING_VALID;
return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
dqm->dev->kgd, pasid_mapping,
vmid); vmid);
} }
...@@ -511,7 +515,7 @@ int init_pipelines(struct device_queue_manager *dqm, ...@@ -511,7 +515,7 @@ int init_pipelines(struct device_queue_manager *dqm,
pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES; pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES;
pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr); pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr);
/* = log2(bytes/4)-1 */ /* = log2(bytes/4)-1 */
kfd2kgd->init_pipeline(dqm->dev->kgd, inx, dqm->dev->kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr); CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr);
} }
...@@ -905,7 +909,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, ...@@ -905,7 +909,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
return retval; return retval;
} }
static int fence_wait_timeout(unsigned int *fence_addr, static int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
unsigned int fence_value, unsigned int fence_value,
unsigned long timeout) unsigned long timeout)
{ {
...@@ -961,7 +965,7 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock) ...@@ -961,7 +965,7 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
pm_send_query_status(&dqm->packets, dqm->fence_gpu_addr, pm_send_query_status(&dqm->packets, dqm->fence_gpu_addr,
KFD_FENCE_COMPLETED); KFD_FENCE_COMPLETED);
/* should be timed out */ /* should be timed out */
fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED, amdkfd_fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS); QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS);
pm_release_ib(&dqm->packets); pm_release_ib(&dqm->packets);
dqm->active_runlist = false; dqm->active_runlist = false;
......
...@@ -32,9 +32,6 @@ ...@@ -32,9 +32,6 @@
* and that's assures that any user process won't get access to the * and that's assures that any user process won't get access to the
* kernel doorbells page * kernel doorbells page
*/ */
static DEFINE_MUTEX(doorbell_mutex);
static unsigned long doorbell_available_index[
DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)] = { 0 };
#define KERNEL_DOORBELL_PASID 1 #define KERNEL_DOORBELL_PASID 1
#define KFD_SIZE_OF_DOORBELL_IN_BYTES 4 #define KFD_SIZE_OF_DOORBELL_IN_BYTES 4
...@@ -170,12 +167,12 @@ u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd, ...@@ -170,12 +167,12 @@ u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
BUG_ON(!kfd || !doorbell_off); BUG_ON(!kfd || !doorbell_off);
mutex_lock(&doorbell_mutex); mutex_lock(&kfd->doorbell_mutex);
inx = find_first_zero_bit(doorbell_available_index, inx = find_first_zero_bit(kfd->doorbell_available_index,
KFD_MAX_NUM_OF_QUEUES_PER_PROCESS); KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
__set_bit(inx, doorbell_available_index); __set_bit(inx, kfd->doorbell_available_index);
mutex_unlock(&doorbell_mutex); mutex_unlock(&kfd->doorbell_mutex);
if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
return NULL; return NULL;
...@@ -203,9 +200,9 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr) ...@@ -203,9 +200,9 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr)
inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr); inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr);
mutex_lock(&doorbell_mutex); mutex_lock(&kfd->doorbell_mutex);
__clear_bit(inx, doorbell_available_index); __clear_bit(inx, kfd->doorbell_available_index);
mutex_unlock(&doorbell_mutex); mutex_unlock(&kfd->doorbell_mutex);
} }
inline void write_kernel_doorbell(u32 __iomem *db, u32 value) inline void write_kernel_doorbell(u32 __iomem *db, u32 value)
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#define KFD_DRIVER_MINOR 7 #define KFD_DRIVER_MINOR 7
#define KFD_DRIVER_PATCHLEVEL 1 #define KFD_DRIVER_PATCHLEVEL 1
const struct kfd2kgd_calls *kfd2kgd;
static const struct kgd2kfd_calls kgd2kfd = { static const struct kgd2kfd_calls kgd2kfd = {
.exit = kgd2kfd_exit, .exit = kgd2kfd_exit,
.probe = kgd2kfd_probe, .probe = kgd2kfd_probe,
...@@ -55,9 +54,7 @@ module_param(max_num_of_queues_per_device, int, 0444); ...@@ -55,9 +54,7 @@ module_param(max_num_of_queues_per_device, int, 0444);
MODULE_PARM_DESC(max_num_of_queues_per_device, MODULE_PARM_DESC(max_num_of_queues_per_device,
"Maximum number of supported queues per device (1 = Minimum, 4096 = default)"); "Maximum number of supported queues per device (1 = Minimum, 4096 = default)");
bool kgd2kfd_init(unsigned interface_version, bool kgd2kfd_init(unsigned interface_version, const struct kgd2kfd_calls **g2f)
const struct kfd2kgd_calls *f2g,
const struct kgd2kfd_calls **g2f)
{ {
/* /*
* Only one interface version is supported, * Only one interface version is supported,
...@@ -66,11 +63,6 @@ bool kgd2kfd_init(unsigned interface_version, ...@@ -66,11 +63,6 @@ bool kgd2kfd_init(unsigned interface_version,
if (interface_version != KFD_INTERFACE_VERSION) if (interface_version != KFD_INTERFACE_VERSION)
return false; return false;
/* Protection against multiple amd kgd loads */
if (kfd2kgd)
return true;
kfd2kgd = f2g;
*g2f = &kgd2kfd; *g2f = &kgd2kfd;
return true; return true;
...@@ -85,8 +77,6 @@ static int __init kfd_module_init(void) ...@@ -85,8 +77,6 @@ static int __init kfd_module_init(void)
{ {
int err; int err;
kfd2kgd = NULL;
/* Verify module parameters */ /* Verify module parameters */
if ((sched_policy < KFD_SCHED_POLICY_HWS) || if ((sched_policy < KFD_SCHED_POLICY_HWS) ||
(sched_policy > KFD_SCHED_POLICY_NO_HWS)) { (sched_policy > KFD_SCHED_POLICY_NO_HWS)) {
......
...@@ -151,14 +151,15 @@ static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd, ...@@ -151,14 +151,15 @@ static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id, static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr) uint32_t queue_id, uint32_t __user *wptr)
{ {
return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr); return mm->dev->kfd2kgd->hqd_load
(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
} }
static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
uint32_t pipe_id, uint32_t queue_id, uint32_t pipe_id, uint32_t queue_id,
uint32_t __user *wptr) uint32_t __user *wptr)
{ {
return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd); return mm->dev->kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
} }
static int update_mqd(struct mqd_manager *mm, void *mqd, static int update_mqd(struct mqd_manager *mm, void *mqd,
...@@ -245,7 +246,7 @@ static int destroy_mqd(struct mqd_manager *mm, void *mqd, ...@@ -245,7 +246,7 @@ static int destroy_mqd(struct mqd_manager *mm, void *mqd,
unsigned int timeout, uint32_t pipe_id, unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id) uint32_t queue_id)
{ {
return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout, return mm->dev->kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
pipe_id, queue_id); pipe_id, queue_id);
} }
...@@ -258,7 +259,7 @@ static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd, ...@@ -258,7 +259,7 @@ static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
unsigned int timeout, uint32_t pipe_id, unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id) uint32_t queue_id)
{ {
return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout); return mm->dev->kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
} }
static bool is_occupied(struct mqd_manager *mm, void *mqd, static bool is_occupied(struct mqd_manager *mm, void *mqd,
...@@ -266,7 +267,7 @@ static bool is_occupied(struct mqd_manager *mm, void *mqd, ...@@ -266,7 +267,7 @@ static bool is_occupied(struct mqd_manager *mm, void *mqd,
uint32_t queue_id) uint32_t queue_id)
{ {
return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address, return mm->dev->kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
pipe_id, queue_id); pipe_id, queue_id);
} }
...@@ -275,7 +276,7 @@ static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd, ...@@ -275,7 +276,7 @@ static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
uint64_t queue_address, uint32_t pipe_id, uint64_t queue_address, uint32_t pipe_id,
uint32_t queue_id) uint32_t queue_id)
{ {
return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd); return mm->dev->kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
} }
/* /*
......
...@@ -148,6 +148,11 @@ struct kfd_dev { ...@@ -148,6 +148,11 @@ struct kfd_dev {
struct kgd2kfd_shared_resources shared_resources; struct kgd2kfd_shared_resources shared_resources;
const struct kfd2kgd_calls *kfd2kgd;
struct mutex doorbell_mutex;
unsigned long doorbell_available_index[DIV_ROUND_UP(
KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)];
void *gtt_mem; void *gtt_mem;
uint64_t gtt_start_gpu_addr; uint64_t gtt_start_gpu_addr;
void *gtt_start_cpu_ptr; void *gtt_start_cpu_ptr;
...@@ -164,13 +169,12 @@ struct kfd_dev { ...@@ -164,13 +169,12 @@ struct kfd_dev {
/* KGD2KFD callbacks */ /* KGD2KFD callbacks */
void kgd2kfd_exit(void); void kgd2kfd_exit(void);
struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev); struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
struct pci_dev *pdev, const struct kfd2kgd_calls *f2g);
bool kgd2kfd_device_init(struct kfd_dev *kfd, bool kgd2kfd_device_init(struct kfd_dev *kfd,
const struct kgd2kfd_shared_resources *gpu_resources); const struct kgd2kfd_shared_resources *gpu_resources);
void kgd2kfd_device_exit(struct kfd_dev *kfd); void kgd2kfd_device_exit(struct kfd_dev *kfd);
extern const struct kfd2kgd_calls *kfd2kgd;
enum kfd_mempool { enum kfd_mempool {
KFD_MEMPOOL_SYSTEM_CACHEABLE = 1, KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2, KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
...@@ -378,8 +382,6 @@ struct qcm_process_device { ...@@ -378,8 +382,6 @@ struct qcm_process_device {
/* The Device Queue Manager that owns this data */ /* The Device Queue Manager that owns this data */
struct device_queue_manager *dqm; struct device_queue_manager *dqm;
struct process_queue_manager *pqm; struct process_queue_manager *pqm;
/* Device Queue Manager lock */
struct mutex *lock;
/* Queues list */ /* Queues list */
struct list_head queues_list; struct list_head queues_list;
struct list_head priv_queue_list; struct list_head priv_queue_list;
......
...@@ -162,10 +162,16 @@ static void kfd_process_wq_release(struct work_struct *work) ...@@ -162,10 +162,16 @@ static void kfd_process_wq_release(struct work_struct *work)
p = my_work->p; p = my_work->p;
pr_debug("Releasing process (pasid %d) in workqueue\n",
p->pasid);
mutex_lock(&p->mutex); mutex_lock(&p->mutex);
list_for_each_entry_safe(pdd, temp, &p->per_device_data, list_for_each_entry_safe(pdd, temp, &p->per_device_data,
per_device_list) { per_device_list) {
pr_debug("Releasing pdd (topology id %d) for process (pasid %d) in workqueue\n",
pdd->dev->id, p->pasid);
amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid); amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
list_del(&pdd->per_device_list); list_del(&pdd->per_device_list);
......
...@@ -726,13 +726,14 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, ...@@ -726,13 +726,14 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
} }
sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute", sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
kfd2kgd->get_max_engine_clock_in_mhz( dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz(
dev->gpu->kgd)); dev->gpu->kgd));
sysfs_show_64bit_prop(buffer, "local_mem_size", sysfs_show_64bit_prop(buffer, "local_mem_size",
kfd2kgd->get_vmem_size(dev->gpu->kgd)); dev->gpu->kfd2kgd->get_vmem_size(
dev->gpu->kgd));
sysfs_show_32bit_prop(buffer, "fw_version", sysfs_show_32bit_prop(buffer, "fw_version",
kfd2kgd->get_fw_version( dev->gpu->kfd2kgd->get_fw_version(
dev->gpu->kgd, dev->gpu->kgd,
KGD_ENGINE_MEC1)); KGD_ENGINE_MEC1));
} }
...@@ -1099,8 +1100,9 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu) ...@@ -1099,8 +1100,9 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
buf[2] = gpu->pdev->subsystem_device; buf[2] = gpu->pdev->subsystem_device;
buf[3] = gpu->pdev->device; buf[3] = gpu->pdev->device;
buf[4] = gpu->pdev->bus->number; buf[4] = gpu->pdev->bus->number;
buf[5] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) & 0xffffffff); buf[5] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd)
buf[6] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) >> 32); & 0xffffffff);
buf[6] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
for (i = 0, hashout = 0; i < 7; i++) for (i = 0, hashout = 0; i < 7; i++)
hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH); hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH);
......
...@@ -76,37 +76,6 @@ struct kgd2kfd_shared_resources { ...@@ -76,37 +76,6 @@ struct kgd2kfd_shared_resources {
size_t doorbell_start_offset; size_t doorbell_start_offset;
}; };
/**
* struct kgd2kfd_calls
*
* @exit: Notifies amdkfd that kgd module is unloaded
*
* @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
*
* @device_init: Initialize the newly probed device (if it is a device that
* amdkfd supports)
*
* @device_exit: Notifies amdkfd about a removal of a kgd device
*
* @suspend: Notifies amdkfd about a suspend action done to a kgd device
*
* @resume: Notifies amdkfd about a resume action done to a kgd device
*
* This structure contains function callback pointers so the kgd driver
* will notify to the amdkfd about certain status changes.
*
*/
struct kgd2kfd_calls {
void (*exit)(void);
struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev);
bool (*device_init)(struct kfd_dev *kfd,
const struct kgd2kfd_shared_resources *gpu_resources);
void (*device_exit)(struct kfd_dev *kfd);
void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
void (*suspend)(struct kfd_dev *kfd);
int (*resume)(struct kfd_dev *kfd);
};
/** /**
* struct kfd2kgd_calls * struct kfd2kgd_calls
* *
...@@ -196,8 +165,39 @@ struct kfd2kgd_calls { ...@@ -196,8 +165,39 @@ struct kfd2kgd_calls {
enum kgd_engine_type type); enum kgd_engine_type type);
}; };
/**
* struct kgd2kfd_calls
*
* @exit: Notifies amdkfd that kgd module is unloaded
*
* @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
*
* @device_init: Initialize the newly probed device (if it is a device that
* amdkfd supports)
*
* @device_exit: Notifies amdkfd about a removal of a kgd device
*
* @suspend: Notifies amdkfd about a suspend action done to a kgd device
*
* @resume: Notifies amdkfd about a resume action done to a kgd device
*
* This structure contains function callback pointers so the kgd driver
* will notify to the amdkfd about certain status changes.
*
*/
struct kgd2kfd_calls {
void (*exit)(void);
struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev,
const struct kfd2kgd_calls *f2g);
bool (*device_init)(struct kfd_dev *kfd,
const struct kgd2kfd_shared_resources *gpu_resources);
void (*device_exit)(struct kfd_dev *kfd);
void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
void (*suspend)(struct kfd_dev *kfd);
int (*resume)(struct kfd_dev *kfd);
};
bool kgd2kfd_init(unsigned interface_version, bool kgd2kfd_init(unsigned interface_version,
const struct kfd2kgd_calls *f2g,
const struct kgd2kfd_calls **g2f); const struct kgd2kfd_calls **g2f);
#endif /* KGD_KFD_INTERFACE_H_INCLUDED */ #endif /* KGD_KFD_INTERFACE_H_INCLUDED */
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#define ARMADA_CONNETOR_H #define ARMADA_CONNETOR_H
#define encoder_helper_funcs(encoder) \ #define encoder_helper_funcs(encoder) \
((struct drm_encoder_helper_funcs *)encoder->helper_private) ((const struct drm_encoder_helper_funcs *)encoder->helper_private)
struct armada_output_type { struct armada_output_type {
int connector_type; int connector_type;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
...@@ -37,14 +38,14 @@ ...@@ -37,14 +38,14 @@
* @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
* @event: pointer to the current page flip event * @event: pointer to the current page flip event
* @id: CRTC id (returned by drm_crtc_index) * @id: CRTC id (returned by drm_crtc_index)
* @dpms: DPMS mode * @enabled: CRTC state
*/ */
struct atmel_hlcdc_crtc { struct atmel_hlcdc_crtc {
struct drm_crtc base; struct drm_crtc base;
struct atmel_hlcdc_dc *dc; struct atmel_hlcdc_dc *dc;
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
int id; int id;
int dpms; bool enabled;
}; };
static inline struct atmel_hlcdc_crtc * static inline struct atmel_hlcdc_crtc *
...@@ -53,86 +54,17 @@ drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc) ...@@ -53,86 +54,17 @@ drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
return container_of(crtc, struct atmel_hlcdc_crtc, base); return container_of(crtc, struct atmel_hlcdc_crtc, base);
} }
static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode) static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
{
struct drm_device *dev = c->dev;
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap;
unsigned int status;
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (crtc->dpms == mode)
return;
pm_runtime_get_sync(dev->dev);
if (mode != DRM_MODE_DPMS_ON) {
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_DISP))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_SYNC))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_PIXEL_CLK))
cpu_relax();
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
pm_runtime_allow(dev->dev);
} else {
pm_runtime_forbid(dev->dev);
clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_PIXEL_CLK))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_SYNC))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_DISP))
cpu_relax();
}
pm_runtime_put_sync(dev->dev);
crtc->dpms = mode;
}
static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
struct drm_display_mode *mode,
struct drm_display_mode *adj,
int x, int y,
struct drm_framebuffer *old_fb)
{ {
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap; struct regmap *regmap = crtc->dc->hlcdc->regmap;
struct drm_plane *plane = c->primary; struct drm_display_mode *adj = &c->state->adjusted_mode;
struct drm_framebuffer *fb;
unsigned long mode_rate; unsigned long mode_rate;
struct videomode vm; struct videomode vm;
unsigned long prate; unsigned long prate;
unsigned int cfg; unsigned int cfg;
int div; int div;
if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
return -EINVAL;
vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start; vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
...@@ -156,7 +88,7 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, ...@@ -156,7 +88,7 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
cfg = 0; cfg = 0;
prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
mode_rate = mode->crtc_clock * 1000; mode_rate = adj->crtc_clock * 1000;
if ((prate / 2) < mode_rate) { if ((prate / 2) < mode_rate) {
prate *= 2; prate *= 2;
cfg |= ATMEL_HLCDC_CLKSEL; cfg |= ATMEL_HLCDC_CLKSEL;
...@@ -174,10 +106,10 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, ...@@ -174,10 +106,10 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
cfg = 0; cfg = 0;
if (mode->flags & DRM_MODE_FLAG_NVSYNC) if (adj->flags & DRM_MODE_FLAG_NVSYNC)
cfg |= ATMEL_HLCDC_VSPOL; cfg |= ATMEL_HLCDC_VSPOL;
if (mode->flags & DRM_MODE_FLAG_NHSYNC) if (adj->flags & DRM_MODE_FLAG_NHSYNC)
cfg |= ATMEL_HLCDC_HSPOL; cfg |= ATMEL_HLCDC_HSPOL;
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5), regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
...@@ -187,77 +119,155 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, ...@@ -187,77 +119,155 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
ATMEL_HLCDC_GUARDTIME_MASK, ATMEL_HLCDC_GUARDTIME_MASK,
cfg); cfg);
}
static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void atmel_hlcdc_crtc_disable(struct drm_crtc *c)
{
struct drm_device *dev = c->dev;
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap;
unsigned int status;
if (!crtc->enabled)
return;
drm_crtc_vblank_off(c);
pm_runtime_get_sync(dev->dev);
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_DISP))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_SYNC))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
(status & ATMEL_HLCDC_PIXEL_CLK))
cpu_relax();
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
pinctrl_pm_select_sleep_state(dev->dev);
pm_runtime_allow(dev->dev);
fb = plane->fb; pm_runtime_put_sync(dev->dev);
plane->fb = old_fb;
return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0, crtc->enabled = false;
adj->hdisplay, adj->vdisplay,
x << 16, y << 16,
adj->hdisplay << 16,
adj->vdisplay << 16,
adj);
} }
int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y, static void atmel_hlcdc_crtc_enable(struct drm_crtc *c)
struct drm_framebuffer *old_fb)
{ {
struct drm_plane *plane = c->primary; struct drm_device *dev = c->dev;
struct drm_framebuffer *fb = plane->fb; struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct drm_display_mode *mode = &c->hwmode; struct regmap *regmap = crtc->dc->hlcdc->regmap;
unsigned int status;
plane->fb = old_fb;
if (crtc->enabled)
return plane->funcs->update_plane(plane, c, fb, return;
0, 0,
mode->hdisplay, pm_runtime_get_sync(dev->dev);
mode->vdisplay,
x << 16, y << 16, pm_runtime_forbid(dev->dev);
mode->hdisplay << 16,
mode->vdisplay << 16); pinctrl_pm_select_default_state(dev->dev);
clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_PIXEL_CLK))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_SYNC))
cpu_relax();
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
!(status & ATMEL_HLCDC_DISP))
cpu_relax();
pm_runtime_put_sync(dev->dev);
drm_crtc_vblank_on(c);
crtc->enabled = true;
} }
static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc) void atmel_hlcdc_crtc_suspend(struct drm_crtc *c)
{ {
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
if (crtc->enabled) {
atmel_hlcdc_crtc_disable(c);
/* save enable state for resume */
crtc->enabled = true;
}
} }
static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc) void atmel_hlcdc_crtc_resume(struct drm_crtc *c)
{ {
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON); struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
if (crtc->enabled) {
crtc->enabled = false;
atmel_hlcdc_crtc_enable(c);
}
} }
static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc, static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
const struct drm_display_mode *mode, struct drm_crtc_state *s)
struct drm_display_mode *adjusted_mode)
{ {
return true; struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
if (atmel_hlcdc_dc_mode_valid(crtc->dc, &s->adjusted_mode) != MODE_OK)
return -EINVAL;
return atmel_hlcdc_plane_prepare_disc_area(s);
} }
static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc) static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c)
{ {
struct drm_plane *plane; struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); if (c->state->event) {
crtc->primary->funcs->disable_plane(crtc->primary); c->state->event->pipe = drm_crtc_index(c);
drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { WARN_ON(drm_crtc_vblank_get(c) != 0);
if (plane->crtc != crtc)
continue;
plane->funcs->disable_plane(crtc->primary); crtc->event = c->state->event;
plane->crtc = NULL; c->state->event = NULL;
} }
} }
static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc)
{
/* TODO: write common plane control register if available */
}
static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
.mode_fixup = atmel_hlcdc_crtc_mode_fixup, .mode_fixup = atmel_hlcdc_crtc_mode_fixup,
.dpms = atmel_hlcdc_crtc_dpms, .mode_set = drm_helper_crtc_mode_set,
.mode_set = atmel_hlcdc_crtc_mode_set, .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
.mode_set_base = atmel_hlcdc_crtc_mode_set_base, .mode_set_base = drm_helper_crtc_mode_set_base,
.prepare = atmel_hlcdc_crtc_prepare,
.commit = atmel_hlcdc_crtc_commit,
.disable = atmel_hlcdc_crtc_disable, .disable = atmel_hlcdc_crtc_disable,
.enable = atmel_hlcdc_crtc_enable,
.atomic_check = atmel_hlcdc_crtc_atomic_check,
.atomic_begin = atmel_hlcdc_crtc_atomic_begin,
.atomic_flush = atmel_hlcdc_crtc_atomic_flush,
}; };
static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c) static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
...@@ -306,61 +316,13 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c) ...@@ -306,61 +316,13 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c)); atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
} }
static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct atmel_hlcdc_plane_update_req req;
struct drm_plane *plane = c->primary;
struct drm_device *dev = c->dev;
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&dev->event_lock, flags);
if (crtc->event)
ret = -EBUSY;
spin_unlock_irqrestore(&dev->event_lock, flags);
if (ret)
return ret;
memset(&req, 0, sizeof(req));
req.crtc_x = 0;
req.crtc_y = 0;
req.crtc_h = c->mode.crtc_vdisplay;
req.crtc_w = c->mode.crtc_hdisplay;
req.src_x = c->x << 16;
req.src_y = c->y << 16;
req.src_w = req.crtc_w << 16;
req.src_h = req.crtc_h << 16;
req.fb = fb;
ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode);
if (ret)
return ret;
if (event) {
drm_vblank_get(c->dev, crtc->id);
spin_lock_irqsave(&dev->event_lock, flags);
crtc->event = event;
spin_unlock_irqrestore(&dev->event_lock, flags);
}
ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
if (ret)
crtc->event = NULL;
else
plane->fb = fb;
return ret;
}
static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
.page_flip = atmel_hlcdc_crtc_page_flip, .page_flip = drm_atomic_helper_page_flip,
.set_config = drm_crtc_helper_set_config, .set_config = drm_atomic_helper_set_config,
.destroy = atmel_hlcdc_crtc_destroy, .destroy = atmel_hlcdc_crtc_destroy,
.reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
}; };
int atmel_hlcdc_crtc_create(struct drm_device *dev) int atmel_hlcdc_crtc_create(struct drm_device *dev)
...@@ -375,7 +337,6 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev) ...@@ -375,7 +337,6 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
if (!crtc) if (!crtc)
return -ENOMEM; return -ENOMEM;
crtc->dpms = DRM_MODE_DPMS_OFF;
crtc->dc = dc; crtc->dc = dc;
ret = drm_crtc_init_with_planes(dev, &crtc->base, ret = drm_crtc_init_with_planes(dev, &crtc->base,
......
...@@ -222,6 +222,8 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev) ...@@ -222,6 +222,8 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
static const struct drm_mode_config_funcs mode_config_funcs = { static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = atmel_hlcdc_fb_create, .fb_create = atmel_hlcdc_fb_create,
.output_poll_changed = atmel_hlcdc_fb_output_poll_changed, .output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
}; };
static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
...@@ -317,6 +319,8 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) ...@@ -317,6 +319,8 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
goto err_periph_clk_disable; goto err_periph_clk_disable;
} }
drm_mode_config_reset(dev);
ret = drm_vblank_init(dev, 1); ret = drm_vblank_init(dev, 1);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n"); dev_err(dev->dev, "failed to initialize vblank\n");
...@@ -555,6 +559,41 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev) ...@@ -555,6 +559,41 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct drm_crtc *crtc;
if (pm_runtime_suspended(dev))
return 0;
drm_modeset_lock_all(drm_dev);
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
atmel_hlcdc_crtc_suspend(crtc);
drm_modeset_unlock_all(drm_dev);
return 0;
}
static int atmel_hlcdc_dc_drm_resume(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct drm_crtc *crtc;
if (pm_runtime_suspended(dev))
return 0;
drm_modeset_lock_all(drm_dev);
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
atmel_hlcdc_crtc_resume(crtc);
drm_modeset_unlock_all(drm_dev);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
atmel_hlcdc_dc_drm_suspend, atmel_hlcdc_dc_drm_resume);
static const struct of_device_id atmel_hlcdc_dc_of_match[] = { static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
{ .compatible = "atmel,hlcdc-display-controller" }, { .compatible = "atmel,hlcdc-display-controller" },
{ }, { },
...@@ -565,6 +604,7 @@ static struct platform_driver atmel_hlcdc_dc_platform_driver = { ...@@ -565,6 +604,7 @@ static struct platform_driver atmel_hlcdc_dc_platform_driver = {
.remove = atmel_hlcdc_dc_drm_remove, .remove = atmel_hlcdc_dc_drm_remove,
.driver = { .driver = {
.name = "atmel-hlcdc-display-controller", .name = "atmel-hlcdc-display-controller",
.pm = &atmel_hlcdc_dc_drm_pm_ops,
.of_match_table = atmel_hlcdc_dc_of_match, .of_match_table = atmel_hlcdc_dc_of_match,
}, },
}; };
......
...@@ -26,11 +26,14 @@ ...@@ -26,11 +26,14 @@
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/pwm.h> #include <linux/pwm.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include <drm/drm_plane_helper.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include "atmel_hlcdc_layer.h" #include "atmel_hlcdc_layer.h"
...@@ -69,7 +72,6 @@ struct atmel_hlcdc_dc_desc { ...@@ -69,7 +72,6 @@ struct atmel_hlcdc_dc_desc {
*/ */
struct atmel_hlcdc_plane_properties { struct atmel_hlcdc_plane_properties {
struct drm_property *alpha; struct drm_property *alpha;
struct drm_property *rotation;
}; };
/** /**
...@@ -84,7 +86,6 @@ struct atmel_hlcdc_plane { ...@@ -84,7 +86,6 @@ struct atmel_hlcdc_plane {
struct drm_plane base; struct drm_plane base;
struct atmel_hlcdc_layer layer; struct atmel_hlcdc_layer layer;
struct atmel_hlcdc_plane_properties *properties; struct atmel_hlcdc_plane_properties *properties;
unsigned int rotation;
}; };
static inline struct atmel_hlcdc_plane * static inline struct atmel_hlcdc_plane *
...@@ -99,43 +100,6 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l) ...@@ -99,43 +100,6 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
return container_of(l, struct atmel_hlcdc_plane, layer); return container_of(l, struct atmel_hlcdc_plane, layer);
} }
/**
* Atmel HLCDC Plane update request structure.
*
* @crtc_x: x position of the plane relative to the CRTC
* @crtc_y: y position of the plane relative to the CRTC
* @crtc_w: visible width of the plane
* @crtc_h: visible height of the plane
* @src_x: x buffer position
* @src_y: y buffer position
* @src_w: buffer width
* @src_h: buffer height
* @fb: framebuffer object object
* @bpp: bytes per pixel deduced from pixel_format
* @offsets: offsets to apply to the GEM buffers
* @xstride: value to add to the pixel pointer between each line
* @pstride: value to add to the pixel pointer between each pixel
* @nplanes: number of planes (deduced from pixel_format)
*/
struct atmel_hlcdc_plane_update_req {
int crtc_x;
int crtc_y;
unsigned int crtc_w;
unsigned int crtc_h;
uint32_t src_x;
uint32_t src_y;
uint32_t src_w;
uint32_t src_h;
struct drm_framebuffer *fb;
/* These fields are private and should not be touched */
int bpp[ATMEL_HLCDC_MAX_PLANES];
unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
int xstride[ATMEL_HLCDC_MAX_PLANES];
int pstride[ATMEL_HLCDC_MAX_PLANES];
int nplanes;
};
/** /**
* Atmel HLCDC Planes. * Atmel HLCDC Planes.
* *
...@@ -184,28 +148,16 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc, ...@@ -184,28 +148,16 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
struct atmel_hlcdc_planes * struct atmel_hlcdc_planes *
atmel_hlcdc_create_planes(struct drm_device *dev); atmel_hlcdc_create_planes(struct drm_device *dev);
int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p, int atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state);
struct atmel_hlcdc_plane_update_req *req,
const struct drm_display_mode *mode);
int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
struct atmel_hlcdc_plane_update_req *req);
int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w,
unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h,
const struct drm_display_mode *mode);
void atmel_hlcdc_crtc_irq(struct drm_crtc *c); void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc, void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
struct drm_file *file); struct drm_file *file);
void atmel_hlcdc_crtc_suspend(struct drm_crtc *crtc);
void atmel_hlcdc_crtc_resume(struct drm_crtc *crtc);
int atmel_hlcdc_crtc_create(struct drm_device *dev); int atmel_hlcdc_crtc_create(struct drm_device *dev);
int atmel_hlcdc_create_outputs(struct drm_device *dev); int atmel_hlcdc_create_outputs(struct drm_device *dev);
......
...@@ -298,7 +298,7 @@ void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer) ...@@ -298,7 +298,7 @@ void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
spin_unlock_irqrestore(&layer->lock, flags); spin_unlock_irqrestore(&layer->lock, flags);
} }
int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer) void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
{ {
struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma; struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
struct atmel_hlcdc_layer_update *upd = &layer->update; struct atmel_hlcdc_layer_update *upd = &layer->update;
...@@ -341,8 +341,6 @@ int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer) ...@@ -341,8 +341,6 @@ int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
dma->status = ATMEL_HLCDC_LAYER_DISABLED; dma->status = ATMEL_HLCDC_LAYER_DISABLED;
spin_unlock_irqrestore(&layer->lock, flags); spin_unlock_irqrestore(&layer->lock, flags);
return 0;
} }
int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer) int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
......
...@@ -120,6 +120,7 @@ ...@@ -120,6 +120,7 @@
#define ATMEL_HLCDC_LAYER_DISCEN BIT(11) #define ATMEL_HLCDC_LAYER_DISCEN BIT(11)
#define ATMEL_HLCDC_LAYER_GA_SHIFT 16 #define ATMEL_HLCDC_LAYER_GA_SHIFT 16
#define ATMEL_HLCDC_LAYER_GA_MASK GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT) #define ATMEL_HLCDC_LAYER_GA_MASK GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT)
#define ATMEL_HLCDC_LAYER_GA(x) ((x) << ATMEL_HLCDC_LAYER_GA_SHIFT)
#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o) #define ATMEL_HLCDC_LAYER_CSC_CFG(p, o) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
...@@ -376,7 +377,7 @@ int atmel_hlcdc_layer_init(struct drm_device *dev, ...@@ -376,7 +377,7 @@ int atmel_hlcdc_layer_init(struct drm_device *dev,
void atmel_hlcdc_layer_cleanup(struct drm_device *dev, void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
struct atmel_hlcdc_layer *layer); struct atmel_hlcdc_layer *layer);
int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer); void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer); int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
......
...@@ -86,25 +86,22 @@ atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output) ...@@ -86,25 +86,22 @@ atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output)
return container_of(output, struct atmel_hlcdc_panel, base); return container_of(output, struct atmel_hlcdc_panel, base);
} }
static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder, static void atmel_hlcdc_panel_encoder_enable(struct drm_encoder *encoder)
int mode)
{ {
struct atmel_hlcdc_rgb_output *rgb = struct atmel_hlcdc_rgb_output *rgb =
drm_encoder_to_atmel_hlcdc_rgb_output(encoder); drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
if (mode != DRM_MODE_DPMS_ON) drm_panel_enable(panel->panel);
mode = DRM_MODE_DPMS_OFF; }
if (mode == rgb->dpms)
return;
if (mode != DRM_MODE_DPMS_ON) static void atmel_hlcdc_panel_encoder_disable(struct drm_encoder *encoder)
drm_panel_disable(panel->panel); {
else struct atmel_hlcdc_rgb_output *rgb =
drm_panel_enable(panel->panel); drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
rgb->dpms = mode; drm_panel_disable(panel->panel);
} }
static bool static bool
...@@ -115,16 +112,6 @@ atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder, ...@@ -115,16 +112,6 @@ atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
return true; return true;
} }
static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
{
atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
}
static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
{
atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
static void static void
atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
...@@ -156,11 +143,10 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, ...@@ -156,11 +143,10 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
} }
static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = { static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
.dpms = atmel_hlcdc_panel_encoder_dpms,
.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup, .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
.prepare = atmel_hlcdc_panel_encoder_prepare,
.commit = atmel_hlcdc_panel_encoder_commit,
.mode_set = atmel_hlcdc_rgb_encoder_mode_set, .mode_set = atmel_hlcdc_rgb_encoder_mode_set,
.disable = atmel_hlcdc_panel_encoder_disable,
.enable = atmel_hlcdc_panel_encoder_enable,
}; };
static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder) static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder)
...@@ -226,10 +212,13 @@ atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector) ...@@ -226,10 +212,13 @@ atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
} }
static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = {
.dpms = drm_helper_connector_dpms, .dpms = drm_atomic_helper_connector_dpms,
.detect = atmel_hlcdc_panel_connector_detect, .detect = atmel_hlcdc_panel_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.destroy = atmel_hlcdc_panel_connector_destroy, .destroy = atmel_hlcdc_panel_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
}; };
static int atmel_hlcdc_create_panel_output(struct drm_device *dev, static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
......
...@@ -164,6 +164,7 @@ void bochs_hw_setmode(struct bochs_device *bochs, ...@@ -164,6 +164,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 0);
bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp);
bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres); bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres);
bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres); bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres);
......
...@@ -11,3 +11,14 @@ config DRM_PTN3460 ...@@ -11,3 +11,14 @@ config DRM_PTN3460
select DRM_PANEL select DRM_PANEL
---help--- ---help---
ptn3460 eDP-LVDS bridge chip driver. ptn3460 eDP-LVDS bridge chip driver.
config DRM_PS8622
tristate "Parade eDP/LVDS bridge"
depends on DRM
depends on OF
select DRM_PANEL
select DRM_KMS_HELPER
select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
---help---
parade eDP-LVDS bridge chip driver.
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PS8622) += ps8622.o
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/mutex.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
...@@ -126,6 +127,7 @@ struct dw_hdmi { ...@@ -126,6 +127,7 @@ struct dw_hdmi {
struct i2c_adapter *ddc; struct i2c_adapter *ddc;
void __iomem *regs; void __iomem *regs;
struct mutex audio_mutex;
unsigned int sample_rate; unsigned int sample_rate;
int ratio; int ratio;
...@@ -177,26 +179,23 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, ...@@ -177,26 +179,23 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
hdmi_modb(hdmi, data << shift, mask, reg); hdmi_modb(hdmi, data << shift, mask, reg);
} }
static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi, static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
unsigned int value) unsigned int n)
{ {
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); /* Must be set/cleared first */
hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
/* nshift factor = 0 */ /* nshift factor = 0 */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3);
hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1);
} }
static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
...@@ -355,18 +354,21 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, ...@@ -355,18 +354,21 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
__func__, hdmi->sample_rate, hdmi->ratio, __func__, hdmi->sample_rate, hdmi->ratio,
pixel_clk, clk_n, clk_cts); pixel_clk, clk_n, clk_cts);
hdmi_set_clock_regenerator_n(hdmi, clk_n); hdmi_set_cts_n(hdmi, clk_cts, clk_n);
hdmi_regenerate_cts(hdmi, clk_cts);
} }
static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{ {
mutex_lock(&hdmi->audio_mutex);
hdmi_set_clk_regenerator(hdmi, 74250000); hdmi_set_clk_regenerator(hdmi, 74250000);
mutex_unlock(&hdmi->audio_mutex);
} }
static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{ {
mutex_lock(&hdmi->audio_mutex);
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
mutex_unlock(&hdmi->audio_mutex);
} }
/* /*
...@@ -753,10 +755,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, ...@@ -753,10 +755,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
{ {
unsigned res_idx, i; unsigned res_idx, i;
u8 val, msec; u8 val, msec;
const struct dw_hdmi_mpll_config *mpll_config = const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data;
hdmi->plat_data->mpll_cfg; const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr; const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr;
const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term; const struct dw_hdmi_phy_config *phy_config = plat_data->phy_config;
if (prep) if (prep)
return -EINVAL; return -EINVAL;
...@@ -827,18 +829,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, ...@@ -827,18 +829,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
for (i = 0; sym_term[i].mpixelclock != (~0UL); i++) for (i = 0; phy_config[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <= if (hdmi->hdmi_data.video_mode.mpixelclock <=
sym_term[i].mpixelclock) phy_config[i].mpixelclock)
break; break;
/* RESISTANCE TERM 133Ohm Cfg */ /* RESISTANCE TERM 133Ohm Cfg */
hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */ hdmi_phy_i2c_write(hdmi, phy_config[i].term, 0x19); /* TXTERM */
/* PREEMP Cgf 0.00 */ /* PREEMP Cgf 0.00 */
hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */ hdmi_phy_i2c_write(hdmi, phy_config[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
/* TX/CK LVL 10 */ /* TX/CK LVL 10 */
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ hdmi_phy_i2c_write(hdmi, phy_config[i].vlev_ctr, 0x0E); /* VLEVCTRL */
/* REMOVE CLK TERM */ /* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
...@@ -1569,6 +1571,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master, ...@@ -1569,6 +1571,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->ratio = 100; hdmi->ratio = 100;
hdmi->encoder = encoder; hdmi->encoder = encoder;
mutex_init(&hdmi->audio_mutex);
of_property_read_u32(np, "reg-io-width", &val); of_property_read_u32(np, "reg-io-width", &val);
switch (val) { switch (val) {
......
/*
* Parade PS8622 eDP/LVDS bridge driver
*
* Copyright (C) 2014 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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. See the
* GNU General Public License for more details.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_panel.h>
#include "drmP.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
/* Brightness scale on the Parade chip */
#define PS8622_MAX_BRIGHTNESS 0xff
/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
#define PS8622_POWER_RISE_T1_MIN_US 10
#define PS8622_POWER_RISE_T1_MAX_US 10000
#define PS8622_RST_HIGH_T2_MIN_US 3000
#define PS8622_RST_HIGH_T2_MAX_US 30000
#define PS8622_PWMO_END_T12_MS 200
#define PS8622_POWER_FALL_T16_MAX_US 10000
#define PS8622_POWER_OFF_T17_MS 500
#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
(PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
#error "T2.min + T1.max must be less than T2.max + T1.min"
#endif
struct ps8622_bridge {
struct drm_connector connector;
struct i2c_client *client;
struct drm_bridge bridge;
struct drm_panel *panel;
struct regulator *v12;
struct backlight_device *bl;
struct gpio_desc *gpio_slp;
struct gpio_desc *gpio_rst;
u32 max_lane_count;
u32 lane_count;
bool enabled;
};
static inline struct ps8622_bridge *
bridge_to_ps8622(struct drm_bridge *bridge)
{
return container_of(bridge, struct ps8622_bridge, bridge);
}
static inline struct ps8622_bridge *
connector_to_ps8622(struct drm_connector *connector)
{
return container_of(connector, struct ps8622_bridge, connector);
}
static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
{
int ret;
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg;
u8 data[] = {reg, val};
msg.addr = client->addr + page;
msg.flags = 0;
msg.len = sizeof(data);
msg.buf = data;
ret = i2c_transfer(adap, &msg, 1);
if (ret != 1)
pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
client->addr + page, reg, val, ret);
return !(ret == 1);
}
static int ps8622_send_config(struct ps8622_bridge *ps8622)
{
struct i2c_client *cl = ps8622->client;
int err = 0;
/* HPD low */
err = ps8622_set(cl, 0x02, 0xa1, 0x01);
if (err)
goto error;
/* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
err = ps8622_set(cl, 0x04, 0x14, 0x01);
if (err)
goto error;
/* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
err = ps8622_set(cl, 0x04, 0xe3, 0x20);
if (err)
goto error;
/* [7] RCO SS enable */
err = ps8622_set(cl, 0x04, 0xe2, 0x80);
if (err)
goto error;
/* RPHY Setting
* [3:2] CDR tune wait cycle before measure for fine tune
* b00: 1us b01: 0.5us b10:2us, b11: 4us
*/
err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
if (err)
goto error;
/* [3] RFD always on */
err = ps8622_set(cl, 0x04, 0x89, 0x08);
if (err)
goto error;
/* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
err = ps8622_set(cl, 0x04, 0x71, 0x2d);
if (err)
goto error;
/* 2.7G CDR settings: NOF=40LSB for HBR CDR setting */
err = ps8622_set(cl, 0x04, 0x7d, 0x07);
if (err)
goto error;
/* [1:0] Fmin=+4bands */
err = ps8622_set(cl, 0x04, 0x7b, 0x00);
if (err)
goto error;
/* [7:5] DCO_FTRNG=+-40% */
err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
if (err)
goto error;
/* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
err = ps8622_set(cl, 0x04, 0xc0, 0x12);
if (err)
goto error;
/* Gitune=-37% */
err = ps8622_set(cl, 0x04, 0xc1, 0x92);
if (err)
goto error;
/* Fbstep=100% */
err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
if (err)
goto error;
/* [7] LOS signal disable */
err = ps8622_set(cl, 0x04, 0x32, 0x80);
if (err)
goto error;
/* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
err = ps8622_set(cl, 0x04, 0x00, 0xb0);
if (err)
goto error;
/* [7:6] Right-bar GPIO output strength is 8mA */
err = ps8622_set(cl, 0x04, 0x15, 0x40);
if (err)
goto error;
/* EQ Training State Machine Setting, RCO calibration start */
err = ps8622_set(cl, 0x04, 0x54, 0x10);
if (err)
goto error;
/* Logic, needs more than 10 I2C command */
/* [4:0] MAX_LANE_COUNT set to max supported lanes */
err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
if (err)
goto error;
/* [4:0] LANE_COUNT_SET set to chosen lane count */
err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
if (err)
goto error;
err = ps8622_set(cl, 0x00, 0x52, 0x20);
if (err)
goto error;
/* HPD CP toggle enable */
err = ps8622_set(cl, 0x00, 0xf1, 0x03);
if (err)
goto error;
err = ps8622_set(cl, 0x00, 0x62, 0x41);
if (err)
goto error;
/* Counter number, add 1ms counter delay */
err = ps8622_set(cl, 0x00, 0xf6, 0x01);
if (err)
goto error;
/* [6]PWM function control by DPCD0040f[7], default is PWM block */
err = ps8622_set(cl, 0x00, 0x77, 0x06);
if (err)
goto error;
/* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
err = ps8622_set(cl, 0x00, 0x4c, 0x04);
if (err)
goto error;
/* DPCD00400='h00, Parade OUI ='h001cf8 */
err = ps8622_set(cl, 0x01, 0xc0, 0x00);
if (err)
goto error;
/* DPCD00401='h1c */
err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
if (err)
goto error;
/* DPCD00402='hf8 */
err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
if (err)
goto error;
/* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
err = ps8622_set(cl, 0x01, 0xc3, 0x44);
if (err)
goto error;
/* DPCD404 */
err = ps8622_set(cl, 0x01, 0xc4, 0x32);
if (err)
goto error;
/* DPCD405 */
err = ps8622_set(cl, 0x01, 0xc5, 0x53);
if (err)
goto error;
/* DPCD406 */
err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
if (err)
goto error;
/* DPCD407 */
err = ps8622_set(cl, 0x01, 0xc7, 0x56);
if (err)
goto error;
/* DPCD408 */
err = ps8622_set(cl, 0x01, 0xc8, 0x35);
if (err)
goto error;
/* DPCD40A, Initial Code major revision '01' */
err = ps8622_set(cl, 0x01, 0xca, 0x01);
if (err)
goto error;
/* DPCD40B, Initial Code minor revision '05' */
err = ps8622_set(cl, 0x01, 0xcb, 0x05);
if (err)
goto error;
if (ps8622->bl) {
/* DPCD720, internal PWM */
err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
if (err)
goto error;
/* FFh for 100% brightness, 0h for 0% brightness */
err = ps8622_set(cl, 0x01, 0xa7,
ps8622->bl->props.brightness);
if (err)
goto error;
} else {
/* DPCD720, external PWM */
err = ps8622_set(cl, 0x01, 0xa5, 0x80);
if (err)
goto error;
}
/* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
err = ps8622_set(cl, 0x01, 0xcc, 0x13);
if (err)
goto error;
/* Enable SSC set by register */
err = ps8622_set(cl, 0x02, 0xb1, 0x20);
if (err)
goto error;
/* Set SSC enabled and +/-1% central spreading */
err = ps8622_set(cl, 0x04, 0x10, 0x16);
if (err)
goto error;
/* Logic end */
/* MPU Clock source: LC => RCO */
err = ps8622_set(cl, 0x04, 0x59, 0x60);
if (err)
goto error;
/* LC -> RCO */
err = ps8622_set(cl, 0x04, 0x54, 0x14);
if (err)
goto error;
/* HPD high */
err = ps8622_set(cl, 0x02, 0xa1, 0x91);
error:
return err ? -EIO : 0;
}
static int ps8622_backlight_update(struct backlight_device *bl)
{
struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
int ret, brightness = bl->props.brightness;
if (bl->props.power != FB_BLANK_UNBLANK ||
bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
brightness = 0;
if (!ps8622->enabled)
return -EINVAL;
ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
return ret;
}
static const struct backlight_ops ps8622_backlight_ops = {
.update_status = ps8622_backlight_update,
};
static void ps8622_pre_enable(struct drm_bridge *bridge)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
int ret;
if (ps8622->enabled)
return;
gpiod_set_value(ps8622->gpio_rst, 0);
if (ps8622->v12) {
ret = regulator_enable(ps8622->v12);
if (ret)
DRM_ERROR("fails to enable ps8622->v12");
}
if (drm_panel_prepare(ps8622->panel)) {
DRM_ERROR("failed to prepare panel\n");
return;
}
gpiod_set_value(ps8622->gpio_slp, 1);
/*
* T1 is the range of time that it takes for the power to rise after we
* enable the lcd/ps8622 fet. T2 is the range of time in which the
* data sheet specifies we should deassert the reset pin.
*
* If it takes T1.max for the power to rise, we need to wait atleast
* T2.min before deasserting the reset pin. If it takes T1.min for the
* power to rise, we need to wait at most T2.max before deasserting the
* reset pin.
*/
usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
gpiod_set_value(ps8622->gpio_rst, 1);
/* wait 20ms after RST high */
usleep_range(20000, 30000);
ret = ps8622_send_config(ps8622);
if (ret) {
DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
return;
}
ps8622->enabled = true;
}
static void ps8622_enable(struct drm_bridge *bridge)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
if (drm_panel_enable(ps8622->panel)) {
DRM_ERROR("failed to enable panel\n");
return;
}
}
static void ps8622_disable(struct drm_bridge *bridge)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
if (drm_panel_disable(ps8622->panel)) {
DRM_ERROR("failed to disable panel\n");
return;
}
msleep(PS8622_PWMO_END_T12_MS);
}
static void ps8622_post_disable(struct drm_bridge *bridge)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
if (!ps8622->enabled)
return;
ps8622->enabled = false;
/*
* This doesn't matter if the regulators are turned off, but something
* else might keep them on. In that case, we want to assert the slp gpio
* to lower power.
*/
gpiod_set_value(ps8622->gpio_slp, 0);
if (drm_panel_unprepare(ps8622->panel)) {
DRM_ERROR("failed to unprepare panel\n");
return;
}
if (ps8622->v12)
regulator_disable(ps8622->v12);
/*
* Sleep for at least the amount of time that it takes the power rail to
* fall to prevent asserting the rst gpio from doing anything.
*/
usleep_range(PS8622_POWER_FALL_T16_MAX_US,
2 * PS8622_POWER_FALL_T16_MAX_US);
gpiod_set_value(ps8622->gpio_rst, 0);
msleep(PS8622_POWER_OFF_T17_MS);
}
static int ps8622_get_modes(struct drm_connector *connector)
{
struct ps8622_bridge *ps8622;
ps8622 = connector_to_ps8622(connector);
return drm_panel_get_modes(ps8622->panel);
}
static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
{
struct ps8622_bridge *ps8622;
ps8622 = connector_to_ps8622(connector);
return ps8622->bridge.encoder;
}
static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
.get_modes = ps8622_get_modes,
.best_encoder = ps8622_best_encoder,
};
static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
bool force)
{
return connector_status_connected;
}
static void ps8622_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}
static const struct drm_connector_funcs ps8622_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ps8622_detect,
.destroy = ps8622_connector_destroy,
};
static int ps8622_attach(struct drm_bridge *bridge)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
int ret;
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
return -ENODEV;
}
ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(bridge->dev, &ps8622->connector,
&ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
return ret;
}
drm_connector_helper_add(&ps8622->connector,
&ps8622_connector_helper_funcs);
drm_connector_register(&ps8622->connector);
drm_mode_connector_attach_encoder(&ps8622->connector,
bridge->encoder);
if (ps8622->panel)
drm_panel_attach(ps8622->panel, &ps8622->connector);
drm_helper_hpd_irq_event(ps8622->connector.dev);
return ret;
}
static const struct drm_bridge_funcs ps8622_bridge_funcs = {
.pre_enable = ps8622_pre_enable,
.enable = ps8622_enable,
.disable = ps8622_disable,
.post_disable = ps8622_post_disable,
.attach = ps8622_attach,
};
static const struct of_device_id ps8622_devices[] = {
{.compatible = "parade,ps8622",},
{.compatible = "parade,ps8625",},
{}
};
MODULE_DEVICE_TABLE(of, ps8622_devices);
static int ps8622_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *endpoint, *panel_node;
struct ps8622_bridge *ps8622;
int ret;
ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
if (!ps8622)
return -ENOMEM;
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
if (endpoint) {
panel_node = of_graph_get_remote_port_parent(endpoint);
if (panel_node) {
ps8622->panel = of_drm_find_panel(panel_node);
of_node_put(panel_node);
if (!ps8622->panel)
return -EPROBE_DEFER;
}
}
ps8622->client = client;
ps8622->v12 = devm_regulator_get(dev, "vdd12");
if (IS_ERR(ps8622->v12)) {
dev_info(dev, "no 1.2v regulator found for PS8622\n");
ps8622->v12 = NULL;
}
ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
if (IS_ERR(ps8622->gpio_slp)) {
ret = PTR_ERR(ps8622->gpio_slp);
dev_err(dev, "cannot get gpio_slp %d\n", ret);
return ret;
}
ret = gpiod_direction_output(ps8622->gpio_slp, 1);
if (ret) {
dev_err(dev, "cannot configure gpio_slp\n");
return ret;
}
ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
if (IS_ERR(ps8622->gpio_rst)) {
ret = PTR_ERR(ps8622->gpio_rst);
dev_err(dev, "cannot get gpio_rst %d\n", ret);
return ret;
}
/*
* Assert the reset pin high to avoid the bridge being
* initialized prematurely
*/
ret = gpiod_direction_output(ps8622->gpio_rst, 1);
if (ret) {
dev_err(dev, "cannot configure gpio_rst\n");
return ret;
}
ps8622->max_lane_count = id->driver_data;
if (of_property_read_u32(dev->of_node, "lane-count",
&ps8622->lane_count)) {
ps8622->lane_count = ps8622->max_lane_count;
} else if (ps8622->lane_count > ps8622->max_lane_count) {
dev_info(dev, "lane-count property is too high,"
"using max_lane_count\n");
ps8622->lane_count = ps8622->max_lane_count;
}
if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
ps8622->bl = backlight_device_register("ps8622-backlight",
dev, ps8622, &ps8622_backlight_ops,
NULL);
if (IS_ERR(ps8622->bl)) {
DRM_ERROR("failed to register backlight\n");
ret = PTR_ERR(ps8622->bl);
ps8622->bl = NULL;
return ret;
}
ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
}
ps8622->bridge.funcs = &ps8622_bridge_funcs;
ps8622->bridge.of_node = dev->of_node;
ret = drm_bridge_add(&ps8622->bridge);
if (ret) {
DRM_ERROR("Failed to add bridge\n");
return ret;
}
i2c_set_clientdata(client, ps8622);
return 0;
}
static int ps8622_remove(struct i2c_client *client)
{
struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
if (ps8622->bl)
backlight_device_unregister(ps8622->bl);
drm_bridge_remove(&ps8622->bridge);
return 0;
}
static const struct i2c_device_id ps8622_i2c_table[] = {
/* Device type, max_lane_count */
{"ps8622", 1},
{"ps8625", 2},
{},
};
MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
static struct i2c_driver ps8622_driver = {
.id_table = ps8622_i2c_table,
.probe = ps8622_probe,
.remove = ps8622_remove,
.driver = {
.name = "ps8622",
.owner = THIS_MODULE,
.of_match_table = ps8622_devices,
},
};
module_i2c_driver(ps8622_driver);
MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
MODULE_LICENSE("GPL v2");
...@@ -265,7 +265,7 @@ static struct drm_connector_funcs ptn3460_connector_funcs = { ...@@ -265,7 +265,7 @@ static struct drm_connector_funcs ptn3460_connector_funcs = {
.destroy = ptn3460_connector_destroy, .destroy = ptn3460_connector_destroy,
}; };
int ptn3460_bridge_attach(struct drm_bridge *bridge) static int ptn3460_bridge_attach(struct drm_bridge *bridge)
{ {
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
int ret; int ret;
......
...@@ -92,7 +92,7 @@ drm_atomic_state_alloc(struct drm_device *dev) ...@@ -92,7 +92,7 @@ drm_atomic_state_alloc(struct drm_device *dev)
state->dev = dev; state->dev = dev;
DRM_DEBUG_KMS("Allocate atomic state %p\n", state); DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state);
return state; return state;
fail: fail:
...@@ -122,7 +122,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -122,7 +122,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
struct drm_mode_config *config = &dev->mode_config; struct drm_mode_config *config = &dev->mode_config;
int i; int i;
DRM_DEBUG_KMS("Clearing atomic state %p\n", state); DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
for (i = 0; i < state->num_connector; i++) { for (i = 0; i < state->num_connector; i++) {
struct drm_connector *connector = state->connectors[i]; struct drm_connector *connector = state->connectors[i];
...@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
connector->funcs->atomic_destroy_state(connector, connector->funcs->atomic_destroy_state(connector,
state->connector_states[i]); state->connector_states[i]);
state->connectors[i] = NULL;
state->connector_states[i] = NULL; state->connector_states[i] = NULL;
} }
...@@ -145,6 +146,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -145,6 +146,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
crtc->funcs->atomic_destroy_state(crtc, crtc->funcs->atomic_destroy_state(crtc,
state->crtc_states[i]); state->crtc_states[i]);
state->crtcs[i] = NULL;
state->crtc_states[i] = NULL; state->crtc_states[i] = NULL;
} }
...@@ -156,6 +158,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -156,6 +158,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
plane->funcs->atomic_destroy_state(plane, plane->funcs->atomic_destroy_state(plane,
state->plane_states[i]); state->plane_states[i]);
state->planes[i] = NULL;
state->plane_states[i] = NULL; state->plane_states[i] = NULL;
} }
} }
...@@ -170,9 +173,12 @@ EXPORT_SYMBOL(drm_atomic_state_clear); ...@@ -170,9 +173,12 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
*/ */
void drm_atomic_state_free(struct drm_atomic_state *state) void drm_atomic_state_free(struct drm_atomic_state *state)
{ {
if (!state)
return;
drm_atomic_state_clear(state); drm_atomic_state_clear(state);
DRM_DEBUG_KMS("Freeing atomic state %p\n", state); DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
kfree_state(state); kfree_state(state);
} }
...@@ -217,8 +223,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, ...@@ -217,8 +223,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
state->crtcs[index] = crtc; state->crtcs[index] = crtc;
crtc_state->state = state; crtc_state->state = state;
DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n", DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n",
crtc->base.id, crtc_state, state); crtc->base.id, crtc_state, state);
return crtc_state; return crtc_state;
} }
...@@ -248,11 +254,14 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ...@@ -248,11 +254,14 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
struct drm_mode_config *config = &dev->mode_config; struct drm_mode_config *config = &dev->mode_config;
/* FIXME: Mode prop is missing, which also controls ->enable. */ /* FIXME: Mode prop is missing, which also controls ->enable. */
if (property == config->prop_active) { if (property == config->prop_active)
state->active = val; state->active = val;
} else if (crtc->funcs->atomic_set_property) else if (crtc->funcs->atomic_set_property)
return crtc->funcs->atomic_set_property(crtc, state, property, val); return crtc->funcs->atomic_set_property(crtc, state, property, val);
return -EINVAL; else
return -EINVAL;
return 0;
} }
EXPORT_SYMBOL(drm_atomic_crtc_set_property); EXPORT_SYMBOL(drm_atomic_crtc_set_property);
...@@ -266,9 +275,17 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc, ...@@ -266,9 +275,17 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
const struct drm_crtc_state *state, const struct drm_crtc_state *state,
struct drm_property *property, uint64_t *val) struct drm_property *property, uint64_t *val)
{ {
if (crtc->funcs->atomic_get_property) struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
if (property == config->prop_active)
*val = state->active;
else if (crtc->funcs->atomic_get_property)
return crtc->funcs->atomic_get_property(crtc, state, property, val); return crtc->funcs->atomic_get_property(crtc, state, property, val);
return -EINVAL; else
return -EINVAL;
return 0;
} }
/** /**
...@@ -293,8 +310,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, ...@@ -293,8 +310,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
*/ */
if (state->active && !state->enable) { if (state->active && !state->enable) {
DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n", DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n",
crtc->base.id); crtc->base.id);
return -EINVAL; return -EINVAL;
} }
...@@ -340,8 +357,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, ...@@ -340,8 +357,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
state->planes[index] = plane; state->planes[index] = plane;
plane_state->state = state; plane_state->state = state;
DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n", DRM_DEBUG_ATOMIC("Added [PLANE:%d] %p state to %p\n",
plane->base.id, plane_state, state); plane->base.id, plane_state, state);
if (plane_state->crtc) { if (plane_state->crtc) {
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
...@@ -450,6 +467,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane, ...@@ -450,6 +467,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
*val = state->src_w; *val = state->src_w;
} else if (property == config->prop_src_h) { } else if (property == config->prop_src_h) {
*val = state->src_h; *val = state->src_h;
} else if (property == config->rotation_property) {
*val = state->rotation;
} else if (plane->funcs->atomic_get_property) { } else if (plane->funcs->atomic_get_property) {
return plane->funcs->atomic_get_property(plane, state, property, val); return plane->funcs->atomic_get_property(plane, state, property, val);
} else { } else {
...@@ -473,14 +492,14 @@ static int drm_atomic_plane_check(struct drm_plane *plane, ...@@ -473,14 +492,14 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
unsigned int fb_width, fb_height; unsigned int fb_width, fb_height;
unsigned int i; int ret;
/* either *both* CRTC and FB must be set, or neither */ /* either *both* CRTC and FB must be set, or neither */
if (WARN_ON(state->crtc && !state->fb)) { if (WARN_ON(state->crtc && !state->fb)) {
DRM_DEBUG_KMS("CRTC set but no FB\n"); DRM_DEBUG_ATOMIC("CRTC set but no FB\n");
return -EINVAL; return -EINVAL;
} else if (WARN_ON(state->fb && !state->crtc)) { } else if (WARN_ON(state->fb && !state->crtc)) {
DRM_DEBUG_KMS("FB set but no CRTC\n"); DRM_DEBUG_ATOMIC("FB set but no CRTC\n");
return -EINVAL; return -EINVAL;
} }
...@@ -490,18 +509,16 @@ static int drm_atomic_plane_check(struct drm_plane *plane, ...@@ -490,18 +509,16 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
/* Check whether this plane is usable on this CRTC */ /* Check whether this plane is usable on this CRTC */
if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) {
DRM_DEBUG_KMS("Invalid crtc for plane\n"); DRM_DEBUG_ATOMIC("Invalid crtc for plane\n");
return -EINVAL; return -EINVAL;
} }
/* Check whether this plane supports the fb pixel format. */ /* Check whether this plane supports the fb pixel format. */
for (i = 0; i < plane->format_count; i++) ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format);
if (state->fb->pixel_format == plane->format_types[i]) if (ret) {
break; DRM_DEBUG_ATOMIC("Invalid pixel format %s\n",
if (i == plane->format_count) { drm_get_format_name(state->fb->pixel_format));
DRM_DEBUG_KMS("Invalid pixel format %s\n", return ret;
drm_get_format_name(state->fb->pixel_format));
return -EINVAL;
} }
/* Give drivers some help against integer overflows */ /* Give drivers some help against integer overflows */
...@@ -509,9 +526,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane, ...@@ -509,9 +526,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
state->crtc_x > INT_MAX - (int32_t) state->crtc_w || state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
state->crtc_h > INT_MAX || state->crtc_h > INT_MAX ||
state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", DRM_DEBUG_ATOMIC("Invalid CRTC coordinates %ux%u+%d+%d\n",
state->crtc_w, state->crtc_h, state->crtc_w, state->crtc_h,
state->crtc_x, state->crtc_y); state->crtc_x, state->crtc_y);
return -ERANGE; return -ERANGE;
} }
...@@ -523,12 +540,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane, ...@@ -523,12 +540,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
state->src_x > fb_width - state->src_w || state->src_x > fb_width - state->src_w ||
state->src_h > fb_height || state->src_h > fb_height ||
state->src_y > fb_height - state->src_h) { state->src_y > fb_height - state->src_h) {
DRM_DEBUG_KMS("Invalid source coordinates " DRM_DEBUG_ATOMIC("Invalid source coordinates "
"%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
return -ENOSPC; return -ENOSPC;
} }
...@@ -575,7 +592,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, ...@@ -575,7 +592,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
* at most the array is a bit too large. * at most the array is a bit too large.
*/ */
if (index >= state->num_connector) { if (index >= state->num_connector) {
DRM_DEBUG_KMS("Hot-added connector would overflow state array, restarting\n"); DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n");
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
} }
...@@ -590,8 +607,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, ...@@ -590,8 +607,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
state->connectors[index] = connector; state->connectors[index] = connector;
connector_state->state = state; connector_state->state = state;
DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n", DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d] %p state to %p\n",
connector->base.id, connector_state, state); connector->base.id, connector_state, state);
if (connector_state->crtc) { if (connector_state->crtc) {
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
...@@ -752,17 +769,18 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, ...@@ -752,17 +769,18 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
} }
if (crtc) if (crtc)
DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n", DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d]\n",
plane_state, crtc->base.id); plane_state, crtc->base.id);
else else
DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state); DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n",
plane_state);
return 0; return 0;
} }
EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane); EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
/** /**
* drm_atomic_set_fb_for_plane - set crtc for plane * drm_atomic_set_fb_for_plane - set framebuffer for plane
* @plane_state: atomic state object for the plane * @plane_state: atomic state object for the plane
* @fb: fb to use for the plane * @fb: fb to use for the plane
* *
...@@ -782,10 +800,11 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, ...@@ -782,10 +800,11 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
plane_state->fb = fb; plane_state->fb = fb;
if (fb) if (fb)
DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n", DRM_DEBUG_ATOMIC("Set [FB:%d] for plane state %p\n",
fb->base.id, plane_state); fb->base.id, plane_state);
else else
DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state); DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n",
plane_state);
} }
EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
...@@ -818,11 +837,11 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, ...@@ -818,11 +837,11 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
conn_state->crtc = crtc; conn_state->crtc = crtc;
if (crtc) if (crtc)
DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n", DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d]\n",
conn_state, crtc->base.id); conn_state, crtc->base.id);
else else
DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n", DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n",
conn_state); conn_state);
return 0; return 0;
} }
...@@ -858,8 +877,8 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, ...@@ -858,8 +877,8 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
if (ret) if (ret)
return ret; return ret;
DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n", DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d] to %p\n",
crtc->base.id, state); crtc->base.id, state);
/* /*
* Changed connectors are already in @state, so only need to look at the * Changed connectors are already in @state, so only need to look at the
...@@ -890,19 +909,18 @@ int ...@@ -890,19 +909,18 @@ int
drm_atomic_connectors_for_crtc(struct drm_atomic_state *state, drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
struct drm_crtc *crtc) struct drm_crtc *crtc)
{ {
int i, num_connected_connectors = 0; struct drm_connector *connector;
struct drm_connector_state *conn_state;
for (i = 0; i < state->num_connector; i++) {
struct drm_connector_state *conn_state;
conn_state = state->connector_states[i]; int i, num_connected_connectors = 0;
if (conn_state && conn_state->crtc == crtc) for_each_connector_in_state(state, connector, conn_state, i) {
if (conn_state->crtc == crtc)
num_connected_connectors++; num_connected_connectors++;
} }
DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n", DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n",
state, num_connected_connectors, crtc->base.id); state, num_connected_connectors, crtc->base.id);
return num_connected_connectors; return num_connected_connectors;
} }
...@@ -914,7 +932,7 @@ EXPORT_SYMBOL(drm_atomic_connectors_for_crtc); ...@@ -914,7 +932,7 @@ EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
* *
* This function should be used by legacy entry points which don't understand * This function should be used by legacy entry points which don't understand
* -EDEADLK semantics. For simplicity this one will grab all modeset locks after * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
* the slowpath completed. * the slowpath completed.
*/ */
void drm_atomic_legacy_backoff(struct drm_atomic_state *state) void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
{ {
...@@ -949,36 +967,28 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ...@@ -949,36 +967,28 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
{ {
struct drm_device *dev = state->dev; struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config; struct drm_mode_config *config = &dev->mode_config;
int nplanes = config->num_total_plane; struct drm_plane *plane;
int ncrtcs = config->num_crtc; struct drm_plane_state *plane_state;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
int i, ret = 0; int i, ret = 0;
DRM_DEBUG_KMS("checking %p\n", state); DRM_DEBUG_ATOMIC("checking %p\n", state);
for (i = 0; i < nplanes; i++) {
struct drm_plane *plane = state->planes[i];
if (!plane) for_each_plane_in_state(state, plane, plane_state, i) {
continue; ret = drm_atomic_plane_check(plane, plane_state);
ret = drm_atomic_plane_check(plane, state->plane_states[i]);
if (ret) { if (ret) {
DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n", DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n",
plane->base.id); plane->base.id);
return ret; return ret;
} }
} }
for (i = 0; i < ncrtcs; i++) { for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct drm_crtc *crtc = state->crtcs[i]; ret = drm_atomic_crtc_check(crtc, crtc_state);
if (!crtc)
continue;
ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]);
if (ret) { if (ret) {
DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n", DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n",
crtc->base.id); crtc->base.id);
return ret; return ret;
} }
} }
...@@ -987,17 +997,11 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ...@@ -987,17 +997,11 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
ret = config->funcs->atomic_check(state->dev, state); ret = config->funcs->atomic_check(state->dev, state);
if (!state->allow_modeset) { if (!state->allow_modeset) {
for (i = 0; i < ncrtcs; i++) { for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct drm_crtc *crtc = state->crtcs[i];
struct drm_crtc_state *crtc_state = state->crtc_states[i];
if (!crtc)
continue;
if (crtc_state->mode_changed || if (crtc_state->mode_changed ||
crtc_state->active_changed) { crtc_state->active_changed) {
DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n",
crtc->base.id); crtc->base.id);
return -EINVAL; return -EINVAL;
} }
} }
...@@ -1032,7 +1036,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) ...@@ -1032,7 +1036,7 @@ int drm_atomic_commit(struct drm_atomic_state *state)
if (ret) if (ret)
return ret; return ret;
DRM_DEBUG_KMS("commiting %p\n", state); DRM_DEBUG_ATOMIC("commiting %p\n", state);
return config->funcs->atomic_commit(state->dev, state, false); return config->funcs->atomic_commit(state->dev, state, false);
} }
...@@ -1063,7 +1067,7 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) ...@@ -1063,7 +1067,7 @@ int drm_atomic_async_commit(struct drm_atomic_state *state)
if (ret) if (ret)
return ret; return ret;
DRM_DEBUG_KMS("commiting %p asynchronously\n", state); DRM_DEBUG_ATOMIC("commiting %p asynchronously\n", state);
return config->funcs->atomic_commit(state->dev, state, true); return config->funcs->atomic_commit(state->dev, state, true);
} }
...@@ -1191,6 +1195,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ...@@ -1191,6 +1195,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
struct drm_atomic_state *state; struct drm_atomic_state *state;
struct drm_modeset_acquire_ctx ctx; struct drm_modeset_acquire_ctx ctx;
struct drm_plane *plane; struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
unsigned plane_mask = 0; unsigned plane_mask = 0;
int ret = 0; int ret = 0;
unsigned int i, j; unsigned int i, j;
...@@ -1294,15 +1300,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ...@@ -1294,15 +1300,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
} }
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
int ncrtcs = dev->mode_config.num_crtc; for_each_crtc_in_state(state, crtc, crtc_state, i) {
for (i = 0; i < ncrtcs; i++) {
struct drm_crtc_state *crtc_state = state->crtc_states[i];
struct drm_pending_vblank_event *e; struct drm_pending_vblank_event *e;
if (!crtc_state)
continue;
e = create_vblank_event(dev, file_priv, arg->user_data); e = create_vblank_event(dev, file_priv, arg->user_data);
if (!e) { if (!e) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -1354,14 +1354,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ...@@ -1354,14 +1354,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
goto backoff; goto backoff;
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
int ncrtcs = dev->mode_config.num_crtc; for_each_crtc_in_state(state, crtc, crtc_state, i) {
for (i = 0; i < ncrtcs; i++) {
struct drm_crtc_state *crtc_state = state->crtc_states[i];
if (!crtc_state)
continue;
destroy_vblank_event(dev, file_priv, crtc_state->event); destroy_vblank_event(dev, file_priv, crtc_state->event);
crtc_state->event = NULL; crtc_state->event = NULL;
} }
......
此差异已折叠。
...@@ -49,7 +49,7 @@ void drm_bridge_remove(struct drm_bridge *bridge) ...@@ -49,7 +49,7 @@ void drm_bridge_remove(struct drm_bridge *bridge)
} }
EXPORT_SYMBOL(drm_bridge_remove); EXPORT_SYMBOL(drm_bridge_remove);
extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge) int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
{ {
if (!dev || !bridge) if (!dev || !bridge)
return -EINVAL; return -EINVAL;
......
...@@ -660,6 +660,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, ...@@ -660,6 +660,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_mode_config *config = &dev->mode_config; struct drm_mode_config *config = &dev->mode_config;
int ret; int ret;
WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
crtc->dev = dev; crtc->dev = dev;
crtc->funcs = funcs; crtc->funcs = funcs;
crtc->invert_dimensions = false; crtc->invert_dimensions = false;
...@@ -1999,21 +2002,32 @@ int drm_mode_getcrtc(struct drm_device *dev, ...@@ -1999,21 +2002,32 @@ int drm_mode_getcrtc(struct drm_device *dev,
return -ENOENT; return -ENOENT;
drm_modeset_lock_crtc(crtc, crtc->primary); drm_modeset_lock_crtc(crtc, crtc->primary);
crtc_resp->x = crtc->x;
crtc_resp->y = crtc->y;
crtc_resp->gamma_size = crtc->gamma_size; crtc_resp->gamma_size = crtc->gamma_size;
if (crtc->primary->fb) if (crtc->primary->fb)
crtc_resp->fb_id = crtc->primary->fb->base.id; crtc_resp->fb_id = crtc->primary->fb->base.id;
else else
crtc_resp->fb_id = 0; crtc_resp->fb_id = 0;
if (crtc->enabled) { if (crtc->state) {
crtc_resp->x = crtc->primary->state->src_x >> 16;
drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); crtc_resp->y = crtc->primary->state->src_y >> 16;
crtc_resp->mode_valid = 1; if (crtc->state->enable) {
drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
crtc_resp->mode_valid = 1;
} else {
crtc_resp->mode_valid = 0;
}
} else { } else {
crtc_resp->mode_valid = 0; crtc_resp->x = crtc->x;
crtc_resp->y = crtc->y;
if (crtc->enabled) {
drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
crtc_resp->mode_valid = 1;
} else {
crtc_resp->mode_valid = 0;
}
} }
drm_modeset_unlock_crtc(crtc); drm_modeset_unlock_crtc(crtc);
...@@ -2266,8 +2280,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, ...@@ -2266,8 +2280,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
crtc = drm_encoder_get_crtc(encoder); crtc = drm_encoder_get_crtc(encoder);
if (crtc) if (crtc)
enc_resp->crtc_id = crtc->base.id; enc_resp->crtc_id = crtc->base.id;
else if (encoder->crtc)
enc_resp->crtc_id = encoder->crtc->base.id;
else else
enc_resp->crtc_id = 0; enc_resp->crtc_id = 0;
drm_modeset_unlock(&dev->mode_config.connection_mutex); drm_modeset_unlock(&dev->mode_config.connection_mutex);
...@@ -2402,6 +2414,27 @@ int drm_mode_getplane(struct drm_device *dev, void *data, ...@@ -2402,6 +2414,27 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
return 0; return 0;
} }
/**
* drm_plane_check_pixel_format - Check if the plane supports the pixel format
* @plane: plane to check for format support
* @format: the pixel format
*
* Returns:
* Zero of @plane has @format in its list of supported pixel formats, -EINVAL
* otherwise.
*/
int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
{
unsigned int i;
for (i = 0; i < plane->format_count; i++) {
if (format == plane->format_types[i])
return 0;
}
return -EINVAL;
}
/* /*
* setplane_internal - setplane handler for internal callers * setplane_internal - setplane handler for internal callers
* *
...@@ -2422,7 +2455,6 @@ static int __setplane_internal(struct drm_plane *plane, ...@@ -2422,7 +2455,6 @@ static int __setplane_internal(struct drm_plane *plane,
{ {
int ret = 0; int ret = 0;
unsigned int fb_width, fb_height; unsigned int fb_width, fb_height;
unsigned int i;
/* No fb means shut it down */ /* No fb means shut it down */
if (!fb) { if (!fb) {
...@@ -2445,16 +2477,24 @@ static int __setplane_internal(struct drm_plane *plane, ...@@ -2445,16 +2477,24 @@ static int __setplane_internal(struct drm_plane *plane,
} }
/* Check whether this plane supports the fb pixel format. */ /* Check whether this plane supports the fb pixel format. */
for (i = 0; i < plane->format_count; i++) ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
if (fb->pixel_format == plane->format_types[i]) if (ret) {
break;
if (i == plane->format_count) {
DRM_DEBUG_KMS("Invalid pixel format %s\n", DRM_DEBUG_KMS("Invalid pixel format %s\n",
drm_get_format_name(fb->pixel_format)); drm_get_format_name(fb->pixel_format));
ret = -EINVAL;
goto out; goto out;
} }
/* Give drivers some help against integer overflows */
if (crtc_w > INT_MAX ||
crtc_x > INT_MAX - (int32_t) crtc_w ||
crtc_h > INT_MAX ||
crtc_y > INT_MAX - (int32_t) crtc_h) {
DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
crtc_w, crtc_h, crtc_x, crtc_y);
return -ERANGE;
}
fb_width = fb->width << 16; fb_width = fb->width << 16;
fb_height = fb->height << 16; fb_height = fb->height << 16;
...@@ -2539,17 +2579,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, ...@@ -2539,17 +2579,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL; return -EINVAL;
/* Give drivers some help against integer overflows */
if (plane_req->crtc_w > INT_MAX ||
plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
plane_req->crtc_h > INT_MAX ||
plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
plane_req->crtc_w, plane_req->crtc_h,
plane_req->crtc_x, plane_req->crtc_y);
return -ERANGE;
}
/* /*
* First, find the plane, crtc, and fb objects. If not available, * First, find the plane, crtc, and fb objects. If not available,
* we don't bother to call the driver. * we don't bother to call the driver.
...@@ -2775,6 +2804,23 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ...@@ -2775,6 +2804,23 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
/*
* Check whether the primary plane supports the fb pixel format.
* Drivers not implementing the universal planes API use a
* default formats list provided by the DRM core which doesn't
* match real hardware capabilities. Skip the check in that
* case.
*/
if (!crtc->primary->format_default) {
ret = drm_plane_check_pixel_format(crtc->primary,
fb->pixel_format);
if (ret) {
DRM_DEBUG_KMS("Invalid pixel format %s\n",
drm_get_format_name(fb->pixel_format));
goto out;
}
}
ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
mode, fb); mode, fb);
if (ret) if (ret)
...@@ -3252,6 +3298,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) ...@@ -3252,6 +3298,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
return -EINVAL; return -EINVAL;
} }
if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
return -EINVAL;
}
} }
return 0; return 0;
...@@ -3266,7 +3318,7 @@ internal_framebuffer_create(struct drm_device *dev, ...@@ -3266,7 +3318,7 @@ internal_framebuffer_create(struct drm_device *dev,
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
int ret; int ret;
if (r->flags & ~DRM_MODE_FB_INTERLACED) { if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
...@@ -3282,6 +3334,12 @@ internal_framebuffer_create(struct drm_device *dev, ...@@ -3282,6 +3334,12 @@ internal_framebuffer_create(struct drm_device *dev,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (r->flags & DRM_MODE_FB_MODIFIERS &&
!dev->mode_config.allow_fb_modifiers) {
DRM_DEBUG_KMS("driver does not support fb modifiers\n");
return ERR_PTR(-EINVAL);
}
ret = framebuffer_check(r); ret = framebuffer_check(r);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -5543,6 +5601,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, ...@@ -5543,6 +5601,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
mutex_unlock(&dev->mode_config.idr_mutex); mutex_unlock(&dev->mode_config.idr_mutex);
return NULL; return NULL;
} }
EXPORT_SYMBOL(drm_mode_get_tile_group);
/** /**
* drm_mode_create_tile_group - create a tile group from a displayid description * drm_mode_create_tile_group - create a tile group from a displayid description
...@@ -5581,3 +5640,4 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, ...@@ -5581,3 +5640,4 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
mutex_unlock(&dev->mode_config.idr_mutex); mutex_unlock(&dev->mode_config.idr_mutex);
return tg; return tg;
} }
EXPORT_SYMBOL(drm_mode_create_tile_group);
...@@ -161,7 +161,7 @@ EXPORT_SYMBOL(drm_helper_crtc_in_use); ...@@ -161,7 +161,7 @@ EXPORT_SYMBOL(drm_helper_crtc_in_use);
static void static void
drm_encoder_disable(struct drm_encoder *encoder) drm_encoder_disable(struct drm_encoder *encoder)
{ {
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
if (encoder->bridge) if (encoder->bridge)
encoder->bridge->funcs->disable(encoder->bridge); encoder->bridge->funcs->disable(encoder->bridge);
...@@ -191,7 +191,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) ...@@ -191,7 +191,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
} }
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
crtc->enabled = drm_helper_crtc_in_use(crtc); crtc->enabled = drm_helper_crtc_in_use(crtc);
if (!crtc->enabled) { if (!crtc->enabled) {
if (crtc_funcs->disable) if (crtc_funcs->disable)
...@@ -229,7 +229,7 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions); ...@@ -229,7 +229,7 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
static void static void
drm_crtc_prepare_encoders(struct drm_device *dev) drm_crtc_prepare_encoders(struct drm_device *dev)
{ {
struct drm_encoder_helper_funcs *encoder_funcs; const struct drm_encoder_helper_funcs *encoder_funcs;
struct drm_encoder *encoder; struct drm_encoder *encoder;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
...@@ -270,9 +270,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -270,9 +270,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_display_mode *adjusted_mode, saved_mode; struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct drm_encoder_helper_funcs *encoder_funcs; const struct drm_encoder_helper_funcs *encoder_funcs;
int saved_x, saved_y; int saved_x, saved_y;
bool saved_enabled; bool saved_enabled;
struct drm_encoder *encoder; struct drm_encoder *encoder;
...@@ -292,6 +292,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -292,6 +292,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
} }
saved_mode = crtc->mode; saved_mode = crtc->mode;
saved_hwmode = crtc->hwmode;
saved_x = crtc->x; saved_x = crtc->x;
saved_y = crtc->y; saved_y = crtc->y;
...@@ -334,6 +335,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -334,6 +335,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
} }
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
crtc->hwmode = *adjusted_mode;
/* Prepare the encoders and CRTCs before setting the mode. */ /* Prepare the encoders and CRTCs before setting the mode. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
...@@ -396,9 +399,6 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -396,9 +399,6 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
encoder->bridge->funcs->enable(encoder->bridge); encoder->bridge->funcs->enable(encoder->bridge);
} }
/* Store real post-adjustment hardware mode. */
crtc->hwmode = *adjusted_mode;
/* Calculate and store various constants which /* Calculate and store various constants which
* are later needed by vblank and swap-completion * are later needed by vblank and swap-completion
* timestamping. They are derived from true hwmode. * timestamping. They are derived from true hwmode.
...@@ -411,6 +411,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -411,6 +411,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!ret) { if (!ret) {
crtc->enabled = saved_enabled; crtc->enabled = saved_enabled;
crtc->mode = saved_mode; crtc->mode = saved_mode;
crtc->hwmode = saved_hwmode;
crtc->x = saved_x; crtc->x = saved_x;
crtc->y = saved_y; crtc->y = saved_y;
} }
...@@ -472,7 +473,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -472,7 +473,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
bool fb_changed = false; /* if true and !mode_changed just do a flip */ bool fb_changed = false; /* if true and !mode_changed just do a flip */
struct drm_connector *save_connectors, *connector; struct drm_connector *save_connectors, *connector;
int count = 0, ro, fail = 0; int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs; const struct drm_crtc_helper_funcs *crtc_funcs;
struct drm_mode_set save_set; struct drm_mode_set save_set;
int ret; int ret;
int i; int i;
...@@ -572,7 +573,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -572,7 +573,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* a) traverse passed in connector list and get encoders for them */ /* a) traverse passed in connector list and get encoders for them */
count = 0; count = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct drm_connector_helper_funcs *connector_funcs = const struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private; connector->helper_private;
new_encoder = connector->encoder; new_encoder = connector->encoder;
for (ro = 0; ro < set->num_connectors; ro++) { for (ro = 0; ro < set->num_connectors; ro++) {
...@@ -732,7 +733,7 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) ...@@ -732,7 +733,7 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode) static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
{ {
struct drm_bridge *bridge = encoder->bridge; struct drm_bridge *bridge = encoder->bridge;
struct drm_encoder_helper_funcs *encoder_funcs; const struct drm_encoder_helper_funcs *encoder_funcs;
if (bridge) { if (bridge) {
if (mode == DRM_MODE_DPMS_ON) if (mode == DRM_MODE_DPMS_ON)
...@@ -794,7 +795,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) ...@@ -794,7 +795,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
/* from off to on, do crtc then encoder */ /* from off to on, do crtc then encoder */
if (mode < old_dpms) { if (mode < old_dpms) {
if (crtc) { if (crtc) {
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
if (crtc_funcs->dpms) if (crtc_funcs->dpms)
(*crtc_funcs->dpms) (crtc, (*crtc_funcs->dpms) (crtc,
drm_helper_choose_crtc_dpms(crtc)); drm_helper_choose_crtc_dpms(crtc));
...@@ -808,7 +809,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) ...@@ -808,7 +809,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
if (encoder) if (encoder)
drm_helper_encoder_dpms(encoder, encoder_dpms); drm_helper_encoder_dpms(encoder, encoder_dpms);
if (crtc) { if (crtc) {
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
if (crtc_funcs->dpms) if (crtc_funcs->dpms)
(*crtc_funcs->dpms) (crtc, (*crtc_funcs->dpms) (crtc,
drm_helper_choose_crtc_dpms(crtc)); drm_helper_choose_crtc_dpms(crtc));
...@@ -837,6 +838,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, ...@@ -837,6 +838,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
fb->pitches[i] = mode_cmd->pitches[i]; fb->pitches[i] = mode_cmd->pitches[i];
fb->offsets[i] = mode_cmd->offsets[i]; fb->offsets[i] = mode_cmd->offsets[i];
fb->modifier[i] = mode_cmd->modifier[i];
} }
drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
&fb->bits_per_pixel); &fb->bits_per_pixel);
...@@ -869,7 +871,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) ...@@ -869,7 +871,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_crtc_helper_funcs *crtc_funcs; const struct drm_crtc_helper_funcs *crtc_funcs;
int encoder_dpms; int encoder_dpms;
bool ret; bool ret;
...@@ -934,7 +936,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod ...@@ -934,7 +936,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
int ret; int ret;
if (crtc->funcs->atomic_duplicate_state) if (crtc->funcs->atomic_duplicate_state)
......
...@@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) ...@@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
* retrying the transaction as appropriate. It is assumed that the * retrying the transaction as appropriate. It is assumed that the
* aux->transfer function does not modify anything in the msg other than the * aux->transfer function does not modify anything in the msg other than the
* reply field. * reply field.
*
* Returns bytes transferred on success, or a negative error code on failure.
*/ */
static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{ {
unsigned int retry; unsigned int retry;
int err; int ret;
/* /*
* DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
...@@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
*/ */
for (retry = 0; retry < 7; retry++) { for (retry = 0; retry < 7; retry++) {
mutex_lock(&aux->hw_mutex); mutex_lock(&aux->hw_mutex);
err = aux->transfer(aux, msg); ret = aux->transfer(aux, msg);
mutex_unlock(&aux->hw_mutex); mutex_unlock(&aux->hw_mutex);
if (err < 0) { if (ret < 0) {
if (err == -EBUSY) if (ret == -EBUSY)
continue; continue;
DRM_DEBUG_KMS("transaction failed: %d\n", err); DRM_DEBUG_KMS("transaction failed: %d\n", ret);
return err; return ret;
} }
...@@ -460,7 +462,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -460,7 +462,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
break; break;
case DP_AUX_NATIVE_REPLY_NACK: case DP_AUX_NATIVE_REPLY_NACK:
DRM_DEBUG_KMS("native nack\n"); DRM_DEBUG_KMS("native nack (result=%d, size=%zu)\n", ret, msg->size);
return -EREMOTEIO; return -EREMOTEIO;
case DP_AUX_NATIVE_REPLY_DEFER: case DP_AUX_NATIVE_REPLY_DEFER:
...@@ -488,12 +490,10 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -488,12 +490,10 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
* Both native ACK and I2C ACK replies received. We * Both native ACK and I2C ACK replies received. We
* can assume the transfer was successful. * can assume the transfer was successful.
*/ */
if (err < msg->size) return ret;
return -EPROTO;
return 0;
case DP_AUX_I2C_REPLY_NACK: case DP_AUX_I2C_REPLY_NACK:
DRM_DEBUG_KMS("I2C nack\n"); DRM_DEBUG_KMS("I2C nack (result=%d, size=%zu\n", ret, msg->size);
aux->i2c_nack_count++; aux->i2c_nack_count++;
return -EREMOTEIO; return -EREMOTEIO;
...@@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
return -EREMOTEIO; return -EREMOTEIO;
} }
/*
* Keep retrying drm_dp_i2c_do_msg until all data has been transferred.
*
* Returns an error code on failure, or a recommended transfer size on success.
*/
static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg)
{
int err, ret = orig_msg->size;
struct drm_dp_aux_msg msg = *orig_msg;
while (msg.size > 0) {
err = drm_dp_i2c_do_msg(aux, &msg);
if (err <= 0)
return err == 0 ? -EPROTO : err;
if (err < msg.size && err < ret) {
DRM_DEBUG_KMS("Partial I2C reply: requested %zu bytes got %d bytes\n",
msg.size, err);
ret = err;
}
msg.size -= err;
msg.buffer += err;
}
return ret;
}
/*
* Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX
* packets to be as large as possible. If not, the I2C transactions never
* succeed. Hence the default is maximum.
*/
static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES;
module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644);
MODULE_PARM_DESC(dp_aux_i2c_transfer_size,
"Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)");
static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
int num) int num)
{ {
struct drm_dp_aux *aux = adapter->algo_data; struct drm_dp_aux *aux = adapter->algo_data;
unsigned int i, j; unsigned int i, j;
unsigned transfer_size;
struct drm_dp_aux_msg msg; struct drm_dp_aux_msg msg;
int err = 0; int err = 0;
dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES);
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
...@@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, ...@@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
err = drm_dp_i2c_do_msg(aux, &msg); err = drm_dp_i2c_do_msg(aux, &msg);
if (err < 0) if (err < 0)
break; break;
/* /* We want each transaction to be as large as possible, but
* Many hardware implementations support FIFOs larger than a * we'll go to smaller sizes if the hardware gives us a
* single byte, but it has been empirically determined that * short reply.
* transferring data in larger chunks can actually lead to
* decreased performance. Therefore each message is simply
* transferred byte-by-byte.
*/ */
for (j = 0; j < msgs[i].len; j++) { transfer_size = dp_aux_i2c_transfer_size;
for (j = 0; j < msgs[i].len; j += msg.size) {
msg.buffer = msgs[i].buf + j; msg.buffer = msgs[i].buf + j;
msg.size = 1; msg.size = min(transfer_size, msgs[i].len - j);
err = drm_dp_i2c_do_msg(aux, &msg); err = drm_dp_i2c_drain_msg(aux, &msg);
if (err < 0) if (err < 0)
break; break;
transfer_size = err;
} }
if (err < 0) if (err < 0)
break; break;
......
...@@ -2324,6 +2324,19 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp ...@@ -2324,6 +2324,19 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp
} }
EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi); EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi);
int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
{
int slots = 0;
port = drm_dp_get_validated_port_ref(mgr, port);
if (!port)
return slots;
slots = port->vcpi.num_slots;
drm_dp_put_port(port);
return slots;
}
EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots);
/** /**
* drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI * drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI
* @mgr: manager for this port * @mgr: manager for this port
......
...@@ -70,7 +70,7 @@ void drm_err(const char *format, ...) ...@@ -70,7 +70,7 @@ void drm_err(const char *format, ...)
vaf.fmt = format; vaf.fmt = format;
vaf.va = &args; vaf.va = &args;
printk(KERN_ERR "[" DRM_NAME ":%pf] *ERROR* %pV", printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
__builtin_return_address(0), &vaf); __builtin_return_address(0), &vaf);
va_end(args); va_end(args);
......
...@@ -304,7 +304,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, ...@@ -304,7 +304,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
} }
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
offset = fbi->var.xoffset * bytes_per_pixel; offset = fbi->var.xoffset * bytes_per_pixel;
offset += fbi->var.yoffset * fb->pitches[0]; offset += fbi->var.yoffset * fb->pitches[0];
......
...@@ -238,7 +238,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) ...@@ -238,7 +238,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
int drm_fb_helper_debug_enter(struct fb_info *info) int drm_fb_helper_debug_enter(struct fb_info *info)
{ {
struct drm_fb_helper *helper = info->par; struct drm_fb_helper *helper = info->par;
struct drm_crtc_helper_funcs *funcs; const struct drm_crtc_helper_funcs *funcs;
int i; int i;
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
...@@ -285,7 +285,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) ...@@ -285,7 +285,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
{ {
struct drm_fb_helper *helper = info->par; struct drm_fb_helper *helper = info->par;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_crtc_helper_funcs *funcs; const struct drm_crtc_helper_funcs *funcs;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
int i; int i;
...@@ -765,7 +765,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) ...@@ -765,7 +765,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
{ {
struct drm_fb_helper *fb_helper = info->par; struct drm_fb_helper *fb_helper = info->par;
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
struct drm_crtc_helper_funcs *crtc_funcs; const struct drm_crtc_helper_funcs *crtc_funcs;
u16 *red, *green, *blue, *transp; u16 *red, *green, *blue, *transp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
int i, j, rc = 0; int i, j, rc = 0;
...@@ -1034,23 +1034,45 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, ...@@ -1034,23 +1034,45 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
crtc_count = 0; crtc_count = 0;
for (i = 0; i < fb_helper->crtc_count; i++) { for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_display_mode *desired_mode; struct drm_display_mode *desired_mode;
int x, y; struct drm_mode_set *mode_set;
int x, y, j;
/* in case of tile group, are we the last tile vert or horiz?
* If no tile group you are always the last one both vertically
* and horizontally
*/
bool lastv = true, lasth = true;
desired_mode = fb_helper->crtc_info[i].desired_mode; desired_mode = fb_helper->crtc_info[i].desired_mode;
mode_set = &fb_helper->crtc_info[i].mode_set;
if (!desired_mode)
continue;
crtc_count++;
x = fb_helper->crtc_info[i].x; x = fb_helper->crtc_info[i].x;
y = fb_helper->crtc_info[i].y; y = fb_helper->crtc_info[i].y;
if (desired_mode) {
if (gamma_size == 0) if (gamma_size == 0)
gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
if (desired_mode->hdisplay + x < sizes.fb_width)
sizes.fb_width = desired_mode->hdisplay + x; sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
if (desired_mode->vdisplay + y < sizes.fb_height) sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
sizes.fb_height = desired_mode->vdisplay + y;
if (desired_mode->hdisplay + x > sizes.surface_width) for (j = 0; j < mode_set->num_connectors; j++) {
sizes.surface_width = desired_mode->hdisplay + x; struct drm_connector *connector = mode_set->connectors[j];
if (desired_mode->vdisplay + y > sizes.surface_height) if (connector->has_tile) {
sizes.surface_height = desired_mode->vdisplay + y; lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
crtc_count++; lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
/* cloning to multiple tiles is just crazy-talk, so: */
break;
}
} }
if (lasth)
sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
if (lastv)
sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
} }
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
...@@ -1261,12 +1283,12 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f ...@@ -1261,12 +1283,12 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
int width, int height) int width, int height)
{ {
struct drm_cmdline_mode *cmdline_mode; struct drm_cmdline_mode *cmdline_mode;
struct drm_display_mode *mode = NULL; struct drm_display_mode *mode;
bool prefer_non_interlace; bool prefer_non_interlace;
cmdline_mode = &fb_helper_conn->connector->cmdline_mode; cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
if (cmdline_mode->specified == false) if (cmdline_mode->specified == false)
return mode; return NULL;
/* attempt to find a matching mode in the list of modes /* attempt to find a matching mode in the list of modes
* we have gotten so far, if not add a CVT mode that conforms * we have gotten so far, if not add a CVT mode that conforms
...@@ -1275,7 +1297,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f ...@@ -1275,7 +1297,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
goto create_mode; goto create_mode;
prefer_non_interlace = !cmdline_mode->interlace; prefer_non_interlace = !cmdline_mode->interlace;
again: again:
list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
/* check width/height */ /* check width/height */
if (mode->hdisplay != cmdline_mode->xres || if (mode->hdisplay != cmdline_mode->xres ||
...@@ -1529,7 +1551,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, ...@@ -1529,7 +1551,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
int c, o; int c, o;
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_helper_funcs *connector_funcs; const struct drm_connector_helper_funcs *connector_funcs;
struct drm_encoder *encoder; struct drm_encoder *encoder;
int my_score, best_score, score; int my_score, best_score, score;
struct drm_fb_helper_crtc **crtcs, *crtc; struct drm_fb_helper_crtc **crtcs, *crtc;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_gem.h> #include <drm/drm_gem.h>
#include "drm_internal.h"
#include "drm_legacy.h" #include "drm_legacy.h"
/** /**
......
...@@ -1016,7 +1016,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, ...@@ -1016,7 +1016,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
return 0; return 0;
} }
drm_ioctl_compat_t *drm_compat_ioctls[] = { static drm_ioctl_compat_t *drm_compat_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version, [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap, [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
......
...@@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ ...@@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
else else
req->value = 64; req->value = 64;
break; break;
case DRM_CAP_ADDFB2_MODIFIERS:
req->value = dev->mode_config.allow_fb_modifiers;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -521,8 +524,13 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) ...@@ -521,8 +524,13 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
return 0; return 0;
} }
#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ #define DRM_IOCTL_DEF(ioctl, _func, _flags) \
[DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl} [DRM_IOCTL_NR(ioctl)] = { \
.cmd = ioctl, \
.func = _func, \
.flags = _flags, \
.name = #ioctl \
}
/** Ioctl table */ /** Ioctl table */
static const struct drm_ioctl_desc drm_ioctls[] = { static const struct drm_ioctl_desc drm_ioctls[] = {
...@@ -660,39 +668,29 @@ long drm_ioctl(struct file *filp, ...@@ -660,39 +668,29 @@ long drm_ioctl(struct file *filp,
int retcode = -EINVAL; int retcode = -EINVAL;
char stack_kdata[128]; char stack_kdata[128];
char *kdata = NULL; char *kdata = NULL;
unsigned int usize, asize; unsigned int usize, asize, drv_size;
dev = file_priv->minor->dev; dev = file_priv->minor->dev;
if (drm_device_is_unplugged(dev)) if (drm_device_is_unplugged(dev))
return -ENODEV; return -ENODEV;
if ((nr >= DRM_CORE_IOCTL_COUNT) && if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) {
((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) /* driver ioctl */
goto err_i1; if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && goto err_i1;
(nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
u32 drv_size;
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
drv_size = _IOC_SIZE(ioctl->cmd_drv); } else {
usize = asize = _IOC_SIZE(cmd); /* core ioctl */
if (drv_size > asize) if (nr >= DRM_CORE_IOCTL_COUNT)
asize = drv_size; goto err_i1;
cmd = ioctl->cmd_drv;
}
else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
u32 drv_size;
ioctl = &drm_ioctls[nr]; ioctl = &drm_ioctls[nr];
}
drv_size = _IOC_SIZE(ioctl->cmd); drv_size = _IOC_SIZE(ioctl->cmd);
usize = asize = _IOC_SIZE(cmd); usize = _IOC_SIZE(cmd);
if (drv_size > asize) asize = max(usize, drv_size);
asize = drv_size; cmd = ioctl->cmd;
cmd = ioctl->cmd;
} else
goto err_i1;
DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
task_pid_nr(current), task_pid_nr(current),
...@@ -773,12 +771,13 @@ EXPORT_SYMBOL(drm_ioctl); ...@@ -773,12 +771,13 @@ EXPORT_SYMBOL(drm_ioctl);
*/ */
bool drm_ioctl_flags(unsigned int nr, unsigned int *flags) bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
{ {
if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) || if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END)
(nr < DRM_COMMAND_BASE)) { return false;
*flags = drm_ioctls[nr].flags;
return true; if (nr >= DRM_CORE_IOCTL_COUNT)
} return false;
return false; *flags = drm_ioctls[nr].flags;
return true;
} }
EXPORT_SYMBOL(drm_ioctl_flags); EXPORT_SYMBOL(drm_ioctl_flags);
...@@ -276,7 +276,6 @@ static void vblank_disable_fn(unsigned long arg) ...@@ -276,7 +276,6 @@ static void vblank_disable_fn(unsigned long arg)
void drm_vblank_cleanup(struct drm_device *dev) void drm_vblank_cleanup(struct drm_device *dev)
{ {
int crtc; int crtc;
unsigned long irqflags;
/* Bail if the driver didn't call drm_vblank_init() */ /* Bail if the driver didn't call drm_vblank_init() */
if (dev->num_crtcs == 0) if (dev->num_crtcs == 0)
...@@ -285,11 +284,10 @@ void drm_vblank_cleanup(struct drm_device *dev) ...@@ -285,11 +284,10 @@ void drm_vblank_cleanup(struct drm_device *dev)
for (crtc = 0; crtc < dev->num_crtcs; crtc++) { for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
del_timer_sync(&vblank->disable_timer); WARN_ON(vblank->enabled &&
drm_core_check_feature(dev, DRIVER_MODESET));
spin_lock_irqsave(&dev->vbl_lock, irqflags); del_timer_sync(&vblank->disable_timer);
vblank_disable_and_save(dev, crtc);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
} }
kfree(dev->vblank); kfree(dev->vblank);
...@@ -475,17 +473,23 @@ int drm_irq_uninstall(struct drm_device *dev) ...@@ -475,17 +473,23 @@ int drm_irq_uninstall(struct drm_device *dev)
dev->irq_enabled = false; dev->irq_enabled = false;
/* /*
* Wake up any waiters so they don't hang. * Wake up any waiters so they don't hang. This is just to paper over
* isssues for UMS drivers which aren't in full control of their
* vblank/irq handling. KMS drivers must ensure that vblanks are all
* disabled when uninstalling the irq handler.
*/ */
if (dev->num_crtcs) { if (dev->num_crtcs) {
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
for (i = 0; i < dev->num_crtcs; i++) { for (i = 0; i < dev->num_crtcs; i++) {
struct drm_vblank_crtc *vblank = &dev->vblank[i]; struct drm_vblank_crtc *vblank = &dev->vblank[i];
if (!vblank->enabled)
continue;
WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
vblank_disable_and_save(dev, i);
wake_up(&vblank->queue); wake_up(&vblank->queue);
vblank->enabled = false;
vblank->last =
dev->driver->get_vblank_counter(dev, i);
} }
spin_unlock_irqrestore(&dev->vbl_lock, irqflags); spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
} }
...@@ -1052,7 +1056,7 @@ EXPORT_SYMBOL(drm_vblank_get); ...@@ -1052,7 +1056,7 @@ EXPORT_SYMBOL(drm_vblank_get);
* Acquire a reference count on vblank events to avoid having them disabled * Acquire a reference count on vblank events to avoid having them disabled
* while in use. * while in use.
* *
* This is the native kms version of drm_vblank_off(). * This is the native kms version of drm_vblank_get().
* *
* Returns: * Returns:
* Zero on success, nonzero on failure. * Zero on success, nonzero on failure.
...@@ -1232,6 +1236,38 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) ...@@ -1232,6 +1236,38 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
} }
EXPORT_SYMBOL(drm_crtc_vblank_off); EXPORT_SYMBOL(drm_crtc_vblank_off);
/**
* drm_crtc_vblank_reset - reset vblank state to off on a CRTC
* @crtc: CRTC in question
*
* Drivers can use this function to reset the vblank state to off at load time.
* Drivers should use this together with the drm_crtc_vblank_off() and
* drm_crtc_vblank_on() functions. The difference compared to
* drm_crtc_vblank_off() is that this function doesn't save the vblank counter
* and hence doesn't need to call any driver hooks.
*/
void drm_crtc_vblank_reset(struct drm_crtc *drm_crtc)
{
struct drm_device *dev = drm_crtc->dev;
unsigned long irqflags;
int crtc = drm_crtc_index(drm_crtc);
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/*
* Prevent subsequent drm_vblank_get() from enabling the vblank
* interrupt by bumping the refcount.
*/
if (!vblank->inmodeset) {
atomic_inc(&vblank->refcount);
vblank->inmodeset = 1;
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
WARN_ON(!list_empty(&dev->vblank_event_list));
}
EXPORT_SYMBOL(drm_crtc_vblank_reset);
/** /**
* drm_vblank_on - enable vblank events on a CRTC * drm_vblank_on - enable vblank events on a CRTC
* @dev: DRM device * @dev: DRM device
...@@ -1653,7 +1689,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) ...@@ -1653,7 +1689,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
struct timeval tvblank; struct timeval tvblank;
unsigned long irqflags; unsigned long irqflags;
if (!dev->num_crtcs) if (WARN_ON_ONCE(!dev->num_crtcs))
return false; return false;
if (WARN_ON(crtc >= dev->num_crtcs)) if (WARN_ON(crtc >= dev->num_crtcs))
......
...@@ -278,7 +278,7 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, ...@@ -278,7 +278,7 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
hblank = drm_mode->hdisplay * hblank_percentage / hblank = drm_mode->hdisplay * hblank_percentage /
(100 * HV_FACTOR - hblank_percentage); (100 * HV_FACTOR - hblank_percentage);
hblank -= hblank % (2 * CVT_H_GRANULARITY); hblank -= hblank % (2 * CVT_H_GRANULARITY);
/* 14. find the total pixes per line */ /* 14. find the total pixels per line */
drm_mode->htotal = drm_mode->hdisplay + hblank; drm_mode->htotal = drm_mode->hdisplay + hblank;
drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2; drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
drm_mode->hsync_start = drm_mode->hsync_end - drm_mode->hsync_start = drm_mode->hsync_end -
...@@ -903,6 +903,12 @@ EXPORT_SYMBOL(drm_mode_duplicate); ...@@ -903,6 +903,12 @@ EXPORT_SYMBOL(drm_mode_duplicate);
*/ */
bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
{ {
if (!mode1 && !mode2)
return true;
if (!mode1 || !mode2)
return false;
/* do clock check convert to PICOS so fb modes get matched /* do clock check convert to PICOS so fb modes get matched
* the same */ * the same */
if (mode1->clock && mode2->clock) { if (mode1->clock && mode2->clock) {
...@@ -1148,7 +1154,7 @@ EXPORT_SYMBOL(drm_mode_sort); ...@@ -1148,7 +1154,7 @@ EXPORT_SYMBOL(drm_mode_sort);
/** /**
* drm_mode_connector_list_update - update the mode list for the connector * drm_mode_connector_list_update - update the mode list for the connector
* @connector: the connector to update * @connector: the connector to update
* @merge_type_bits: whether to merge or overright type bits. * @merge_type_bits: whether to merge or overwrite type bits
* *
* This moves the modes from the @connector probed_modes list * This moves the modes from the @connector probed_modes list
* to the actual mode list. It compares the probed mode against the current * to the actual mode list. It compares the probed mode against the current
...@@ -1209,7 +1215,7 @@ EXPORT_SYMBOL(drm_mode_connector_list_update); ...@@ -1209,7 +1215,7 @@ EXPORT_SYMBOL(drm_mode_connector_list_update);
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
* *
* The intermediate drm_cmdline_mode structure is required to store additional * The intermediate drm_cmdline_mode structure is required to store additional
* options from the command line modline like the force-enabel/disable flag. * options from the command line modline like the force-enable/disable flag.
* *
* Returns: * Returns:
* True if a valid modeline has been parsed, false otherwise. * True if a valid modeline has been parsed, false otherwise.
......
...@@ -43,14 +43,10 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev, ...@@ -43,14 +43,10 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev,
uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
struct device_node *port) struct device_node *port)
{ {
struct device_node *remote_port, *ep = NULL; struct device_node *remote_port, *ep;
uint32_t possible_crtcs = 0; uint32_t possible_crtcs = 0;
do { for_each_endpoint_of_node(port, ep) {
ep = of_graph_get_next_endpoint(port, ep);
if (!ep)
break;
remote_port = of_graph_get_remote_port(ep); remote_port = of_graph_get_remote_port(ep);
if (!remote_port) { if (!remote_port) {
of_node_put(ep); of_node_put(ep);
...@@ -60,7 +56,7 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, ...@@ -60,7 +56,7 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
possible_crtcs |= drm_crtc_port_mask(dev, remote_port); possible_crtcs |= drm_crtc_port_mask(dev, remote_port);
of_node_put(remote_port); of_node_put(remote_port);
} while (1); }
return possible_crtcs; return possible_crtcs;
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/export.h> #include <linux/export.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include "drm_internal.h"
#include "drm_legacy.h" #include "drm_legacy.h"
/** /**
......
...@@ -344,20 +344,7 @@ const struct drm_plane_funcs drm_primary_helper_funcs = { ...@@ -344,20 +344,7 @@ const struct drm_plane_funcs drm_primary_helper_funcs = {
}; };
EXPORT_SYMBOL(drm_primary_helper_funcs); EXPORT_SYMBOL(drm_primary_helper_funcs);
/** static struct drm_plane *create_primary_plane(struct drm_device *dev)
* drm_primary_helper_create_plane() - Create a generic primary plane
* @dev: drm device
* @formats: pixel formats supported, or NULL for a default safe list
* @num_formats: size of @formats; ignored if @formats is NULL
*
* Allocates and initializes a primary plane that can be used with the primary
* plane helpers. Drivers that wish to use driver-specific plane structures or
* provide custom handler functions may perform their own allocation and
* initialization rather than calling this function.
*/
struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
const uint32_t *formats,
int num_formats)
{ {
struct drm_plane *primary; struct drm_plane *primary;
int ret; int ret;
...@@ -368,15 +355,17 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, ...@@ -368,15 +355,17 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
return NULL; return NULL;
} }
if (formats == NULL) { /*
formats = safe_modeset_formats; * Remove the format_default field from drm_plane when dropping
num_formats = ARRAY_SIZE(safe_modeset_formats); * this helper.
} */
primary->format_default = true;
/* possible_crtc's will be filled in later by crtc_init */ /* possible_crtc's will be filled in later by crtc_init */
ret = drm_universal_plane_init(dev, primary, 0, ret = drm_universal_plane_init(dev, primary, 0,
&drm_primary_helper_funcs, &drm_primary_helper_funcs,
formats, num_formats, safe_modeset_formats,
ARRAY_SIZE(safe_modeset_formats),
DRM_PLANE_TYPE_PRIMARY); DRM_PLANE_TYPE_PRIMARY);
if (ret) { if (ret) {
kfree(primary); kfree(primary);
...@@ -385,7 +374,6 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, ...@@ -385,7 +374,6 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
return primary; return primary;
} }
EXPORT_SYMBOL(drm_primary_helper_create_plane);
/** /**
* drm_crtc_init - Legacy CRTC initialization function * drm_crtc_init - Legacy CRTC initialization function
...@@ -404,7 +392,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, ...@@ -404,7 +392,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
{ {
struct drm_plane *primary; struct drm_plane *primary;
primary = drm_primary_helper_create_plane(dev, NULL, 0); primary = create_primary_plane(dev);
return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
} }
EXPORT_SYMBOL(drm_crtc_init); EXPORT_SYMBOL(drm_crtc_init);
...@@ -413,9 +401,9 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -413,9 +401,9 @@ int drm_plane_helper_commit(struct drm_plane *plane,
struct drm_plane_state *plane_state, struct drm_plane_state *plane_state,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct drm_plane_helper_funcs *plane_funcs; const struct drm_plane_helper_funcs *plane_funcs;
struct drm_crtc *crtc[2]; struct drm_crtc *crtc[2];
struct drm_crtc_helper_funcs *crtc_funcs[2]; const struct drm_crtc_helper_funcs *crtc_funcs[2];
int i, ret = 0; int i, ret = 0;
plane_funcs = plane->helper_private; plane_funcs = plane->helper_private;
...@@ -437,7 +425,8 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -437,7 +425,8 @@ int drm_plane_helper_commit(struct drm_plane *plane,
if (plane_funcs->prepare_fb && plane_state->fb && if (plane_funcs->prepare_fb && plane_state->fb &&
plane_state->fb != old_fb) { plane_state->fb != old_fb) {
ret = plane_funcs->prepare_fb(plane, plane_state->fb); ret = plane_funcs->prepare_fb(plane, plane_state->fb,
plane_state);
if (ret) if (ret)
goto out; goto out;
} }
...@@ -487,7 +476,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -487,7 +476,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
} }
if (plane_funcs->cleanup_fb && old_fb) if (plane_funcs->cleanup_fb && old_fb)
plane_funcs->cleanup_fb(plane, old_fb); plane_funcs->cleanup_fb(plane, old_fb, plane_state);
out: out:
if (plane_state) { if (plane_state) {
if (plane->funcs->atomic_destroy_state) if (plane->funcs->atomic_destroy_state)
......
...@@ -98,7 +98,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect ...@@ -98,7 +98,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_display_mode *mode; struct drm_display_mode *mode;
struct drm_connector_helper_funcs *connector_funcs = const struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private; connector->helper_private;
int count = 0; int count = 0;
int mode_flags = 0; int mode_flags = 0;
......
此差异已折叠。
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#endif #endif
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include "drm_internal.h"
#include "drm_legacy.h" #include "drm_legacy.h"
struct drm_vma_entry { struct drm_vma_entry {
......
...@@ -32,10 +32,16 @@ ...@@ -32,10 +32,16 @@
#include <drm/bridge/ptn3460.h> #include <drm/bridge/ptn3460.h>
#include "exynos_dp_core.h" #include "exynos_dp_core.h"
#include "exynos_drm_fimd.h"
#define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \
connector) connector)
static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp)
{
return to_exynos_crtc(dp->encoder->crtc);
}
static inline struct exynos_dp_device * static inline struct exynos_dp_device *
display_to_dp(struct exynos_drm_display *d) display_to_dp(struct exynos_drm_display *d)
{ {
...@@ -1070,6 +1076,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) ...@@ -1070,6 +1076,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
} }
} }
fimd_dp_clock_enable(dp_to_crtc(dp), true);
clk_prepare_enable(dp->clock); clk_prepare_enable(dp->clock);
exynos_dp_phy_init(dp); exynos_dp_phy_init(dp);
exynos_dp_init_dp(dp); exynos_dp_init_dp(dp);
...@@ -1094,6 +1102,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) ...@@ -1094,6 +1102,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
exynos_dp_phy_exit(dp); exynos_dp_phy_exit(dp);
clk_disable_unprepare(dp->clock); clk_disable_unprepare(dp->clock);
fimd_dp_clock_enable(dp_to_crtc(dp), false);
if (dp->panel) { if (dp->panel) {
if (drm_panel_unprepare(dp->panel)) if (drm_panel_unprepare(dp->panel))
DRM_ERROR("failed to turnoff the panel\n"); DRM_ERROR("failed to turnoff the panel\n");
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册