diff options
67 files changed, 2766 insertions, 479 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 5a1732b78707..e4e90104d7c3 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci | |||
| @@ -299,5 +299,5 @@ What: /sys/bus/pci/devices/.../revision | |||
| 299 | Date: November 2016 | 299 | Date: November 2016 |
| 300 | Contact: Emil Velikov <emil.l.velikov@gmail.com> | 300 | Contact: Emil Velikov <emil.l.velikov@gmail.com> |
| 301 | Description: | 301 | Description: |
| 302 | This file contains the revision field of the the PCI device. | 302 | This file contains the revision field of the PCI device. |
| 303 | The value comes from device config space. The file is read only. | 303 | The value comes from device config space. The file is read only. |
diff --git a/Documentation/admin-guide/security-bugs.rst b/Documentation/admin-guide/security-bugs.rst index 4f7414cad586..47574b382d75 100644 --- a/Documentation/admin-guide/security-bugs.rst +++ b/Documentation/admin-guide/security-bugs.rst | |||
| @@ -14,14 +14,17 @@ Contact | |||
| 14 | The Linux kernel security team can be contacted by email at | 14 | The Linux kernel security team can be contacted by email at |
| 15 | <security@kernel.org>. This is a private list of security officers | 15 | <security@kernel.org>. This is a private list of security officers |
| 16 | who will help verify the bug report and develop and release a fix. | 16 | who will help verify the bug report and develop and release a fix. |
| 17 | It is possible that the security team will bring in extra help from | 17 | If you already have a fix, please include it with your report, as |
| 18 | area maintainers to understand and fix the security vulnerability. | 18 | that can speed up the process considerably. It is possible that the |
| 19 | security team will bring in extra help from area maintainers to | ||
| 20 | understand and fix the security vulnerability. | ||
| 19 | 21 | ||
| 20 | As it is with any bug, the more information provided the easier it | 22 | As it is with any bug, the more information provided the easier it |
| 21 | will be to diagnose and fix. Please review the procedure outlined in | 23 | will be to diagnose and fix. Please review the procedure outlined in |
| 22 | admin-guide/reporting-bugs.rst if you are unclear about what information is helpful. | 24 | admin-guide/reporting-bugs.rst if you are unclear about what |
| 23 | Any exploit code is very helpful and will not be released without | 25 | information is helpful. Any exploit code is very helpful and will not |
| 24 | consent from the reporter unless it has already been made public. | 26 | be released without consent from the reporter unless it has already been |
| 27 | made public. | ||
| 25 | 28 | ||
| 26 | Disclosure | 29 | Disclosure |
| 27 | ---------- | 30 | ---------- |
| @@ -39,6 +42,32 @@ disclosure is from immediate (esp. if it's already publicly known) | |||
| 39 | to a few weeks. As a basic default policy, we expect report date to | 42 | to a few weeks. As a basic default policy, we expect report date to |
| 40 | disclosure date to be on the order of 7 days. | 43 | disclosure date to be on the order of 7 days. |
| 41 | 44 | ||
| 45 | Coordination | ||
| 46 | ------------ | ||
| 47 | |||
| 48 | Fixes for sensitive bugs, such as those that might lead to privilege | ||
| 49 | escalations, may need to be coordinated with the private | ||
| 50 | <linux-distros@vs.openwall.org> mailing list so that distribution vendors | ||
| 51 | are well prepared to issue a fixed kernel upon public disclosure of the | ||
| 52 | upstream fix. Distros will need some time to test the proposed patch and | ||
| 53 | will generally request at least a few days of embargo, and vendor update | ||
| 54 | publication prefers to happen Tuesday through Thursday. When appropriate, | ||
| 55 | the security team can assist with this coordination, or the reporter can | ||
| 56 | include linux-distros from the start. In this case, remember to prefix | ||
| 57 | the email Subject line with "[vs]" as described in the linux-distros wiki: | ||
| 58 | <http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists> | ||
| 59 | |||
| 60 | CVE assignment | ||
| 61 | -------------- | ||
| 62 | |||
| 63 | The security team does not normally assign CVEs, nor do we require them | ||
| 64 | for reports or fixes, as this can needlessly complicate the process and | ||
| 65 | may delay the bug handling. If a reporter wishes to have a CVE identifier | ||
| 66 | assigned ahead of public disclosure, they will need to contact the private | ||
| 67 | linux-distros list, described above. When such a CVE identifier is known | ||
| 68 | before a patch is provided, it is desirable to mention it in the commit | ||
| 69 | message, though. | ||
| 70 | |||
| 42 | Non-disclosure agreements | 71 | Non-disclosure agreements |
| 43 | ------------------------- | 72 | ------------------------- |
| 44 | 73 | ||
diff --git a/Documentation/conf.py b/Documentation/conf.py index 7fadb3b83293..f2b916158377 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py | |||
| @@ -34,7 +34,7 @@ from load_config import loadConfig | |||
| 34 | # Add any Sphinx extension module names here, as strings. They can be | 34 | # Add any Sphinx extension module names here, as strings. They can be |
| 35 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | 35 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom |
| 36 | # ones. | 36 | # ones. |
| 37 | extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain'] | 37 | extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure'] |
| 38 | 38 | ||
| 39 | # The name of the math extension changed on Sphinx 1.4 | 39 | # The name of the math extension changed on Sphinx 1.4 |
| 40 | if major == 1 and minor > 3: | 40 | if major == 1 and minor > 3: |
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index f71e6be26b83..434c49cc7330 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt | |||
| @@ -231,7 +231,7 @@ the reference implementation in drivers/cpufreq/longrun.c | |||
| 231 | Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset. | 231 | Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset. |
| 232 | 232 | ||
| 233 | get_intermediate should return a stable intermediate frequency platform wants to | 233 | get_intermediate should return a stable intermediate frequency platform wants to |
| 234 | switch to, and target_intermediate() should set CPU to to that frequency, before | 234 | switch to, and target_intermediate() should set CPU to that frequency, before |
| 235 | jumping to the frequency corresponding to 'index'. Core will take care of | 235 | jumping to the frequency corresponding to 'index'. Core will take care of |
| 236 | sending notifications and driver doesn't have to handle them in | 236 | sending notifications and driver doesn't have to handle them in |
| 237 | target_intermediate() or target_index(). | 237 | target_intermediate() or target_index(). |
diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt index 34c7fddcea39..ca02d3e4db91 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt +++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | |||
| @@ -34,6 +34,9 @@ Optional properties for HDMI: | |||
| 34 | - hpd-gpios: The GPIO pin for HDMI hotplug detect (if it doesn't appear | 34 | - hpd-gpios: The GPIO pin for HDMI hotplug detect (if it doesn't appear |
| 35 | as an interrupt/status bit in the HDMI controller | 35 | as an interrupt/status bit in the HDMI controller |
| 36 | itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt | 36 | itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt |
| 37 | - dmas: Should contain one entry pointing to the DMA channel used to | ||
| 38 | transfer audio data | ||
| 39 | - dma-names: Should contain "audio-rx" | ||
| 37 | 40 | ||
| 38 | Required properties for DPI: | 41 | Required properties for DPI: |
| 39 | - compatible: Should be "brcm,bcm2835-dpi" | 42 | - compatible: Should be "brcm,bcm2835-dpi" |
diff --git a/Documentation/doc-guide/hello.dot b/Documentation/doc-guide/hello.dot new file mode 100644 index 000000000000..504621dfc595 --- /dev/null +++ b/Documentation/doc-guide/hello.dot | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | graph G { | ||
| 2 | Hello -- World | ||
| 3 | } | ||
diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst index 96fe7ccb2c67..731334de3efd 100644 --- a/Documentation/doc-guide/sphinx.rst +++ b/Documentation/doc-guide/sphinx.rst | |||
| @@ -34,8 +34,9 @@ format-specific subdirectories under ``Documentation/output``. | |||
| 34 | 34 | ||
| 35 | To generate documentation, Sphinx (``sphinx-build``) must obviously be | 35 | To generate documentation, Sphinx (``sphinx-build``) must obviously be |
| 36 | installed. For prettier HTML output, the Read the Docs Sphinx theme | 36 | installed. For prettier HTML output, the Read the Docs Sphinx theme |
| 37 | (``sphinx_rtd_theme``) is used if available. For PDF output, ``rst2pdf`` is also | 37 | (``sphinx_rtd_theme``) is used if available. For PDF output you'll also need |
| 38 | needed. All of these are widely available and packaged in distributions. | 38 | ``XeLaTeX`` and ``convert(1)`` from ImageMagick (https://www.imagemagick.org). |
| 39 | All of these are widely available and packaged in distributions. | ||
| 39 | 40 | ||
| 40 | To pass extra options to Sphinx, you can use the ``SPHINXOPTS`` make | 41 | To pass extra options to Sphinx, you can use the ``SPHINXOPTS`` make |
| 41 | variable. For example, use ``make SPHINXOPTS=-v htmldocs`` to get more verbose | 42 | variable. For example, use ``make SPHINXOPTS=-v htmldocs`` to get more verbose |
| @@ -73,7 +74,16 @@ Specific guidelines for the kernel documentation | |||
| 73 | 74 | ||
| 74 | Here are some specific guidelines for the kernel documentation: | 75 | Here are some specific guidelines for the kernel documentation: |
| 75 | 76 | ||
| 76 | * Please don't go overboard with reStructuredText markup. Keep it simple. | 77 | * Please don't go overboard with reStructuredText markup. Keep it |
| 78 | simple. For the most part the documentation should be plain text with | ||
| 79 | just enough consistency in formatting that it can be converted to | ||
| 80 | other formats. | ||
| 81 | |||
| 82 | * Please keep the formatting changes minimal when converting existing | ||
| 83 | documentation to reStructuredText. | ||
| 84 | |||
| 85 | * Also update the content, not just the formatting, when converting | ||
| 86 | documentation. | ||
| 77 | 87 | ||
| 78 | * Please stick to this order of heading adornments: | 88 | * Please stick to this order of heading adornments: |
| 79 | 89 | ||
| @@ -103,6 +113,12 @@ Here are some specific guidelines for the kernel documentation: | |||
| 103 | the order as encountered."), having the higher levels the same overall makes | 113 | the order as encountered."), having the higher levels the same overall makes |
| 104 | it easier to follow the documents. | 114 | it easier to follow the documents. |
| 105 | 115 | ||
| 116 | * For inserting fixed width text blocks (for code examples, use case | ||
| 117 | examples, etc.), use ``::`` for anything that doesn't really benefit | ||
| 118 | from syntax highlighting, especially short snippets. Use | ||
| 119 | ``.. code-block:: <language>`` for longer code blocks that benefit | ||
| 120 | from highlighting. | ||
| 121 | |||
| 106 | 122 | ||
| 107 | the C domain | 123 | the C domain |
| 108 | ------------ | 124 | ------------ |
| @@ -217,3 +233,96 @@ Rendered as: | |||
| 217 | * .. _`last row`: | 233 | * .. _`last row`: |
| 218 | 234 | ||
| 219 | - column 3 | 235 | - column 3 |
| 236 | |||
| 237 | |||
| 238 | Figures & Images | ||
| 239 | ================ | ||
| 240 | |||
| 241 | If you want to add an image, you should use the ``kernel-figure`` and | ||
| 242 | ``kernel-image`` directives. E.g. to insert a figure with a scalable | ||
| 243 | image format use SVG (:ref:`svg_image_example`):: | ||
| 244 | |||
| 245 | .. kernel-figure:: svg_image.svg | ||
| 246 | :alt: simple SVG image | ||
| 247 | |||
| 248 | SVG image example | ||
| 249 | |||
| 250 | .. _svg_image_example: | ||
| 251 | |||
| 252 | .. kernel-figure:: svg_image.svg | ||
| 253 | :alt: simple SVG image | ||
| 254 | |||
| 255 | SVG image example | ||
| 256 | |||
| 257 | The kernel figure (and image) directive support **DOT** formated files, see | ||
| 258 | |||
| 259 | * DOT: http://graphviz.org/pdf/dotguide.pdf | ||
| 260 | * Graphviz: http://www.graphviz.org/content/dot-language | ||
| 261 | |||
| 262 | A simple example (:ref:`hello_dot_file`):: | ||
| 263 | |||
| 264 | .. kernel-figure:: hello.dot | ||
| 265 | :alt: hello world | ||
| 266 | |||
| 267 | DOT's hello world example | ||
| 268 | |||
| 269 | .. _hello_dot_file: | ||
| 270 | |||
| 271 | .. kernel-figure:: hello.dot | ||
| 272 | :alt: hello world | ||
| 273 | |||
| 274 | DOT's hello world example | ||
| 275 | |||
| 276 | Embed *render* markups (or languages) like Graphviz's **DOT** is provided by the | ||
| 277 | ``kernel-render`` directives.:: | ||
| 278 | |||
| 279 | .. kernel-render:: DOT | ||
| 280 | :alt: foobar digraph | ||
| 281 | :caption: Embedded **DOT** (Graphviz) code | ||
| 282 | |||
| 283 | digraph foo { | ||
| 284 | "bar" -> "baz"; | ||
| 285 | } | ||
| 286 | |||
| 287 | How this will be rendered depends on the installed tools. If Graphviz is | ||
| 288 | installed, you will see an vector image. If not the raw markup is inserted as | ||
| 289 | *literal-block* (:ref:`hello_dot_render`). | ||
| 290 | |||
| 291 | .. _hello_dot_render: | ||
| 292 | |||
| 293 | .. kernel-render:: DOT | ||
| 294 | :alt: foobar digraph | ||
| 295 | :caption: Embedded **DOT** (Graphviz) code | ||
| 296 | |||
| 297 | digraph foo { | ||
| 298 | "bar" -> "baz"; | ||
| 299 | } | ||
| 300 | |||
| 301 | The *render* directive has all the options known from the *figure* directive, | ||
| 302 | plus option ``caption``. If ``caption`` has a value, a *figure* node is | ||
| 303 | inserted. If not, a *image* node is inserted. A ``caption`` is also needed, if | ||
| 304 | you want to refer it (:ref:`hello_svg_render`). | ||
| 305 | |||
| 306 | Embedded **SVG**:: | ||
| 307 | |||
| 308 | .. kernel-render:: SVG | ||
| 309 | :caption: Embedded **SVG** markup | ||
| 310 | :alt: so-nw-arrow | ||
| 311 | |||
| 312 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 313 | <svg xmlns="http://www.w3.org/2000/svg" version="1.1" ...> | ||
| 314 | ... | ||
| 315 | </svg> | ||
| 316 | |||
| 317 | .. _hello_svg_render: | ||
| 318 | |||
| 319 | .. kernel-render:: SVG | ||
| 320 | :caption: Embedded **SVG** markup | ||
| 321 | :alt: so-nw-arrow | ||
| 322 | |||
| 323 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 324 | <svg xmlns="http://www.w3.org/2000/svg" | ||
| 325 | version="1.1" baseProfile="full" width="70px" height="40px" viewBox="0 0 700 400"> | ||
| 326 | <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/> | ||
| 327 | <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/> | ||
| 328 | </svg> | ||
diff --git a/Documentation/doc-guide/svg_image.svg b/Documentation/doc-guide/svg_image.svg new file mode 100644 index 000000000000..5405f85b8137 --- /dev/null +++ b/Documentation/doc-guide/svg_image.svg | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <!-- originate: https://commons.wikimedia.org/wiki/File:Variable_Resistor.svg --> | ||
| 3 | <svg xmlns="http://www.w3.org/2000/svg" | ||
| 4 | version="1.1" baseProfile="full" | ||
| 5 | width="70px" height="40px" viewBox="0 0 700 400"> | ||
| 6 | <line x1="0" y1="200" x2="700" y2="200" stroke="black" stroke-width="20px"/> | ||
| 7 | <rect x="100" y="100" width="500" height="200" fill="white" stroke="black" stroke-width="20px"/> | ||
| 8 | <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/> | ||
| 9 | <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/> | ||
| 10 | </svg> | ||
diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 3bb4d937cdfe..a09c721f9e89 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst | |||
| @@ -140,12 +140,12 @@ Device Instance and Driver Handling | |||
| 140 | .. kernel-doc:: drivers/gpu/drm/drm_drv.c | 140 | .. kernel-doc:: drivers/gpu/drm/drm_drv.c |
| 141 | :doc: driver instance overview | 141 | :doc: driver instance overview |
| 142 | 142 | ||
| 143 | .. kernel-doc:: drivers/gpu/drm/drm_drv.c | ||
| 144 | :export: | ||
| 145 | |||
| 146 | .. kernel-doc:: include/drm/drm_drv.h | 143 | .. kernel-doc:: include/drm/drm_drv.h |
| 147 | :internal: | 144 | :internal: |
| 148 | 145 | ||
| 146 | .. kernel-doc:: drivers/gpu/drm/drm_drv.c | ||
| 147 | :export: | ||
| 148 | |||
| 149 | Driver Load | 149 | Driver Load |
| 150 | ----------- | 150 | ----------- |
| 151 | 151 | ||
| @@ -243,61 +243,15 @@ drivers. | |||
| 243 | Open/Close, File Operations and IOCTLs | 243 | Open/Close, File Operations and IOCTLs |
| 244 | ====================================== | 244 | ====================================== |
| 245 | 245 | ||
| 246 | Open and Close | ||
| 247 | -------------- | ||
| 248 | |||
| 249 | Open and close handlers. None of those methods are mandatory:: | ||
| 250 | |||
| 251 | int (*firstopen) (struct drm_device *); | ||
| 252 | void (*lastclose) (struct drm_device *); | ||
| 253 | int (*open) (struct drm_device *, struct drm_file *); | ||
| 254 | void (*preclose) (struct drm_device *, struct drm_file *); | ||
| 255 | void (*postclose) (struct drm_device *, struct drm_file *); | ||
| 256 | |||
| 257 | The firstopen method is called by the DRM core for legacy UMS (User Mode | ||
| 258 | Setting) drivers only when an application opens a device that has no | ||
| 259 | other opened file handle. UMS drivers can implement it to acquire device | ||
| 260 | resources. KMS drivers can't use the method and must acquire resources | ||
| 261 | in the load method instead. | ||
| 262 | |||
| 263 | Similarly the lastclose method is called when the last application | ||
| 264 | holding a file handle opened on the device closes it, for both UMS and | ||
| 265 | KMS drivers. Additionally, the method is also called at module unload | ||
| 266 | time or, for hot-pluggable devices, when the device is unplugged. The | ||
| 267 | firstopen and lastclose calls can thus be unbalanced. | ||
| 268 | |||
| 269 | The open method is called every time the device is opened by an | ||
| 270 | application. Drivers can allocate per-file private data in this method | ||
| 271 | and store them in the struct :c:type:`struct drm_file | ||
| 272 | <drm_file>` driver_priv field. Note that the open method is | ||
| 273 | called before firstopen. | ||
| 274 | |||
| 275 | The close operation is split into preclose and postclose methods. | ||
| 276 | Drivers must stop and cleanup all per-file operations in the preclose | ||
| 277 | method. For instance pending vertical blanking and page flip events must | ||
| 278 | be cancelled. No per-file operation is allowed on the file handle after | ||
| 279 | returning from the preclose method. | ||
| 280 | |||
| 281 | Finally the postclose method is called as the last step of the close | ||
| 282 | operation, right before calling the lastclose method if no other open | ||
| 283 | file handle exists for the device. Drivers that have allocated per-file | ||
| 284 | private data in the open method should free it here. | ||
| 285 | |||
| 286 | The lastclose method should restore CRTC and plane properties to default | ||
| 287 | value, so that a subsequent open of the device will not inherit state | ||
| 288 | from the previous user. It can also be used to execute delayed power | ||
| 289 | switching state changes, e.g. in conjunction with the :ref:`vga_switcheroo` | ||
| 290 | infrastructure. Beyond that KMS drivers should not do any | ||
| 291 | further cleanup. Only legacy UMS drivers might need to clean up device | ||
| 292 | state so that the vga console or an independent fbdev driver could take | ||
| 293 | over. | ||
| 294 | |||
| 295 | File Operations | 246 | File Operations |
| 296 | --------------- | 247 | --------------- |
| 297 | 248 | ||
| 298 | .. kernel-doc:: drivers/gpu/drm/drm_file.c | 249 | .. kernel-doc:: drivers/gpu/drm/drm_file.c |
| 299 | :doc: file operations | 250 | :doc: file operations |
| 300 | 251 | ||
| 252 | .. kernel-doc:: include/drm/drm_file.h | ||
| 253 | :internal: | ||
| 254 | |||
| 301 | .. kernel-doc:: drivers/gpu/drm/drm_file.c | 255 | .. kernel-doc:: drivers/gpu/drm/drm_file.c |
| 302 | :export: | 256 | :export: |
| 303 | 257 | ||
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 03040aa14fe8..c075aadd7078 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst | |||
| @@ -37,10 +37,12 @@ Modeset Helper Reference for Common Vtables | |||
| 37 | =========================================== | 37 | =========================================== |
| 38 | 38 | ||
| 39 | .. kernel-doc:: include/drm/drm_modeset_helper_vtables.h | 39 | .. kernel-doc:: include/drm/drm_modeset_helper_vtables.h |
| 40 | :internal: | 40 | :doc: overview |
| 41 | 41 | ||
| 42 | .. kernel-doc:: include/drm/drm_modeset_helper_vtables.h | 42 | .. kernel-doc:: include/drm/drm_modeset_helper_vtables.h |
| 43 | :doc: overview | 43 | :internal: |
| 44 | |||
| 45 | .. _drm_atomic_helper: | ||
| 44 | 46 | ||
| 45 | Atomic Modeset Helper Functions Reference | 47 | Atomic Modeset Helper Functions Reference |
| 46 | ========================================= | 48 | ========================================= |
| @@ -84,27 +86,27 @@ Legacy CRTC/Modeset Helper Functions Reference | |||
| 84 | Simple KMS Helper Reference | 86 | Simple KMS Helper Reference |
| 85 | =========================== | 87 | =========================== |
| 86 | 88 | ||
| 89 | .. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c | ||
| 90 | :doc: overview | ||
| 91 | |||
| 87 | .. kernel-doc:: include/drm/drm_simple_kms_helper.h | 92 | .. kernel-doc:: include/drm/drm_simple_kms_helper.h |
| 88 | :internal: | 93 | :internal: |
| 89 | 94 | ||
| 90 | .. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c | 95 | .. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c |
| 91 | :export: | 96 | :export: |
| 92 | 97 | ||
| 93 | .. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c | ||
| 94 | :doc: overview | ||
| 95 | |||
| 96 | fbdev Helper Functions Reference | 98 | fbdev Helper Functions Reference |
| 97 | ================================ | 99 | ================================ |
| 98 | 100 | ||
| 99 | .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c | 101 | .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c |
| 100 | :doc: fbdev helpers | 102 | :doc: fbdev helpers |
| 101 | 103 | ||
| 102 | .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c | ||
| 103 | :export: | ||
| 104 | |||
| 105 | .. kernel-doc:: include/drm/drm_fb_helper.h | 104 | .. kernel-doc:: include/drm/drm_fb_helper.h |
| 106 | :internal: | 105 | :internal: |
| 107 | 106 | ||
| 107 | .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c | ||
| 108 | :export: | ||
| 109 | |||
| 108 | Framebuffer CMA Helper Functions Reference | 110 | Framebuffer CMA Helper Functions Reference |
| 109 | ========================================== | 111 | ========================================== |
| 110 | 112 | ||
| @@ -114,6 +116,8 @@ Framebuffer CMA Helper Functions Reference | |||
| 114 | .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c | 116 | .. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c |
| 115 | :export: | 117 | :export: |
| 116 | 118 | ||
| 119 | .. _drm_bridges: | ||
| 120 | |||
| 117 | Bridges | 121 | Bridges |
| 118 | ======= | 122 | ======= |
| 119 | 123 | ||
| @@ -139,18 +143,20 @@ Bridge Helper Reference | |||
| 139 | .. kernel-doc:: drivers/gpu/drm/drm_bridge.c | 143 | .. kernel-doc:: drivers/gpu/drm/drm_bridge.c |
| 140 | :export: | 144 | :export: |
| 141 | 145 | ||
| 146 | .. _drm_panel_helper: | ||
| 147 | |||
| 142 | Panel Helper Reference | 148 | Panel Helper Reference |
| 143 | ====================== | 149 | ====================== |
| 144 | 150 | ||
| 151 | .. kernel-doc:: drivers/gpu/drm/drm_panel.c | ||
| 152 | :doc: drm panel | ||
| 153 | |||
| 145 | .. kernel-doc:: include/drm/drm_panel.h | 154 | .. kernel-doc:: include/drm/drm_panel.h |
| 146 | :internal: | 155 | :internal: |
| 147 | 156 | ||
| 148 | .. kernel-doc:: drivers/gpu/drm/drm_panel.c | 157 | .. kernel-doc:: drivers/gpu/drm/drm_panel.c |
| 149 | :export: | 158 | :export: |
| 150 | 159 | ||
| 151 | .. kernel-doc:: drivers/gpu/drm/drm_panel.c | ||
| 152 | :doc: drm panel | ||
| 153 | |||
| 154 | Display Port Helper Functions Reference | 160 | Display Port Helper Functions Reference |
| 155 | ======================================= | 161 | ======================================= |
| 156 | 162 | ||
| @@ -217,6 +223,18 @@ EDID Helper Functions Reference | |||
| 217 | .. kernel-doc:: drivers/gpu/drm/drm_edid.c | 223 | .. kernel-doc:: drivers/gpu/drm/drm_edid.c |
| 218 | :export: | 224 | :export: |
| 219 | 225 | ||
| 226 | SCDC Helper Functions Reference | ||
| 227 | =============================== | ||
| 228 | |||
| 229 | .. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c | ||
| 230 | :doc: scdc helpers | ||
| 231 | |||
| 232 | .. kernel-doc:: include/drm/drm_scdc_helper.h | ||
| 233 | :internal: | ||
| 234 | |||
| 235 | .. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c | ||
| 236 | :export: | ||
| 237 | |||
| 220 | Rectangle Utilities Reference | 238 | Rectangle Utilities Reference |
| 221 | ============================= | 239 | ============================= |
| 222 | 240 | ||
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 4d4068855ec4..bfecd21a8cdf 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst | |||
| @@ -15,35 +15,271 @@ be setup by initializing the following fields. | |||
| 15 | - struct drm_mode_config_funcs \*funcs; | 15 | - struct drm_mode_config_funcs \*funcs; |
| 16 | Mode setting functions. | 16 | Mode setting functions. |
| 17 | 17 | ||
| 18 | Mode Configuration | 18 | Overview |
| 19 | ======== | ||
| 20 | |||
| 21 | .. kernel-render:: DOT | ||
| 22 | :alt: KMS Display Pipeline | ||
| 23 | :caption: KMS Display Pipeline Overview | ||
| 24 | |||
| 25 | digraph "KMS" { | ||
| 26 | node [shape=box] | ||
| 27 | |||
| 28 | subgraph cluster_static { | ||
| 29 | style=dashed | ||
| 30 | label="Static Objects" | ||
| 31 | |||
| 32 | node [bgcolor=grey style=filled] | ||
| 33 | "drm_plane A" -> "drm_crtc" | ||
| 34 | "drm_plane B" -> "drm_crtc" | ||
| 35 | "drm_crtc" -> "drm_encoder A" | ||
| 36 | "drm_crtc" -> "drm_encoder B" | ||
| 37 | } | ||
| 38 | |||
| 39 | subgraph cluster_user_created { | ||
| 40 | style=dashed | ||
| 41 | label="Userspace-Created" | ||
| 42 | |||
| 43 | node [shape=oval] | ||
| 44 | "drm_framebuffer 1" -> "drm_plane A" | ||
| 45 | "drm_framebuffer 2" -> "drm_plane B" | ||
| 46 | } | ||
| 47 | |||
| 48 | subgraph cluster_connector { | ||
| 49 | style=dashed | ||
| 50 | label="Hotpluggable" | ||
| 51 | |||
| 52 | "drm_encoder A" -> "drm_connector A" | ||
| 53 | "drm_encoder B" -> "drm_connector B" | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | The basic object structure KMS presents to userspace is fairly simple. | ||
| 58 | Framebuffers (represented by :c:type:`struct drm_framebuffer <drm_framebuffer>`, | ||
| 59 | see `Frame Buffer Abstraction`_) feed into planes. One or more (or even no) | ||
| 60 | planes feed their pixel data into a CRTC (represented by :c:type:`struct | ||
| 61 | drm_crtc <drm_crtc>`, see `CRTC Abstraction`_) for blending. The precise | ||
| 62 | blending step is explained in more detail in `Plane Composition Properties`_ and | ||
| 63 | related chapters. | ||
| 64 | |||
| 65 | For the output routing the first step is encoders (represented by | ||
| 66 | :c:type:`struct drm_encoder <drm_encoder>`, see `Encoder Abstraction`_). Those | ||
| 67 | are really just internal artifacts of the helper libraries used to implement KMS | ||
| 68 | drivers. Besides that they make it unecessarily more complicated for userspace | ||
| 69 | to figure out which connections between a CRTC and a connector are possible, and | ||
| 70 | what kind of cloning is supported, they serve no purpose in the userspace API. | ||
| 71 | Unfortunately encoders have been exposed to userspace, hence can't remove them | ||
| 72 | at this point. Futhermore the exposed restrictions are often wrongly set by | ||
| 73 | drivers, and in many cases not powerful enough to express the real restrictions. | ||
| 74 | A CRTC can be connected to multiple encoders, and for an active CRTC there must | ||
| 75 | be at least one encoder. | ||
| 76 | |||
| 77 | The final, and real, endpoint in the display chain is the connector (represented | ||
| 78 | by :c:type:`struct drm_connector <drm_connector>`, see `Connector | ||
| 79 | Abstraction`_). Connectors can have different possible encoders, but the kernel | ||
| 80 | driver selects which encoder to use for each connector. The use case is DVI, | ||
| 81 | which could switch between an analog and a digital encoder. Encoders can also | ||
| 82 | drive multiple different connectors. There is exactly one active connector for | ||
| 83 | every active encoder. | ||
| 84 | |||
| 85 | Internally the output pipeline is a bit more complex and matches today's | ||
| 86 | hardware more closely: | ||
| 87 | |||
| 88 | .. kernel-render:: DOT | ||
| 89 | :alt: KMS Output Pipeline | ||
| 90 | :caption: KMS Output Pipeline | ||
| 91 | |||
| 92 | digraph "Output Pipeline" { | ||
| 93 | node [shape=box] | ||
| 94 | |||
| 95 | subgraph { | ||
| 96 | "drm_crtc" [bgcolor=grey style=filled] | ||
| 97 | } | ||
| 98 | |||
| 99 | subgraph cluster_internal { | ||
| 100 | style=dashed | ||
| 101 | label="Internal Pipeline" | ||
| 102 | { | ||
| 103 | node [bgcolor=grey style=filled] | ||
| 104 | "drm_encoder A"; | ||
| 105 | "drm_encoder B"; | ||
| 106 | "drm_encoder C"; | ||
| 107 | } | ||
| 108 | |||
| 109 | { | ||
| 110 | node [bgcolor=grey style=filled] | ||
| 111 | "drm_encoder B" -> "drm_bridge B" | ||
| 112 | "drm_encoder C" -> "drm_bridge C1" | ||
| 113 | "drm_bridge C1" -> "drm_bridge C2"; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | "drm_crtc" -> "drm_encoder A" | ||
| 118 | "drm_crtc" -> "drm_encoder B" | ||
| 119 | "drm_crtc" -> "drm_encoder C" | ||
| 120 | |||
| 121 | |||
| 122 | subgraph cluster_output { | ||
| 123 | style=dashed | ||
| 124 | label="Outputs" | ||
| 125 | |||
| 126 | "drm_encoder A" -> "drm_connector A"; | ||
| 127 | "drm_bridge B" -> "drm_connector B"; | ||
| 128 | "drm_bridge C2" -> "drm_connector C"; | ||
| 129 | |||
| 130 | "drm_panel" | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | Internally two additional helper objects come into play. First, to be able to | ||
| 135 | share code for encoders (sometimes on the same SoC, sometimes off-chip) one or | ||
| 136 | more :ref:`drm_bridges` (represented by :c:type:`struct drm_bridge | ||
| 137 | <drm_bridge>`) can be linked to an encoder. This link is static and cannot be | ||
| 138 | changed, which means the cross-bar (if there is any) needs to be mapped between | ||
| 139 | the CRTC and any encoders. Often for drivers with bridges there's no code left | ||
| 140 | at the encoder level. Atomic drivers can leave out all the encoder callbacks to | ||
| 141 | essentially only leave a dummy routing object behind, which is needed for | ||
| 142 | backwards compatibility since encoders are exposed to userspace. | ||
| 143 | |||
| 144 | The second object is for panels, represented by :c:type:`struct drm_panel | ||
| 145 | <drm_panel>`, see :ref:`drm_panel_helper`. Panels do not have a fixed binding | ||
| 146 | point, but are generally linked to the driver private structure that embeds | ||
| 147 | :c:type:`struct drm_connector <drm_connector>`. | ||
| 148 | |||
| 149 | Note that currently the bridge chaining and interactions with connectors and | ||
| 150 | panels are still in-flux and not really fully sorted out yet. | ||
| 19 | 151 | ||
| 20 | KMS Core Structures and Functions | 152 | KMS Core Structures and Functions |
| 21 | ================================= | 153 | ================================= |
| 22 | 154 | ||
| 23 | .. kernel-doc:: drivers/gpu/drm/drm_mode_config.c | ||
| 24 | :export: | ||
| 25 | |||
| 26 | .. kernel-doc:: include/drm/drm_mode_config.h | 155 | .. kernel-doc:: include/drm/drm_mode_config.h |
| 27 | :internal: | 156 | :internal: |
| 28 | 157 | ||
| 158 | .. kernel-doc:: drivers/gpu/drm/drm_mode_config.c | ||
| 159 | :export: | ||
| 160 | |||
| 29 | Modeset Base Object Abstraction | 161 | Modeset Base Object Abstraction |
| 30 | =============================== | 162 | =============================== |
| 31 | 163 | ||
| 164 | .. kernel-render:: DOT | ||
| 165 | :alt: Mode Objects and Properties | ||
| 166 | :caption: Mode Objects and Properties | ||
| 167 | |||
| 168 | digraph { | ||
| 169 | node [shape=box] | ||
| 170 | |||
| 171 | "drm_property A" -> "drm_mode_object A" | ||
| 172 | "drm_property A" -> "drm_mode_object B" | ||
| 173 | "drm_property B" -> "drm_mode_object A" | ||
| 174 | } | ||
| 175 | |||
| 176 | The base structure for all KMS objects is :c:type:`struct drm_mode_object | ||
| 177 | <drm_mode_object>`. One of the base services it provides is tracking properties, | ||
| 178 | which are especially important for the atomic IOCTL (see `Atomic Mode | ||
| 179 | Setting`_). The somewhat surprising part here is that properties are not | ||
| 180 | directly instantiated on each object, but free-standing mode objects themselves, | ||
| 181 | represented by :c:type:`struct drm_property <drm_property>`, which only specify | ||
| 182 | the type and value range of a property. Any given property can be attached | ||
| 183 | multiple times to different objects using :c:func:`drm_object_attach_property() | ||
| 184 | <drm_object_attach_property>`. | ||
| 185 | |||
| 32 | .. kernel-doc:: include/drm/drm_mode_object.h | 186 | .. kernel-doc:: include/drm/drm_mode_object.h |
| 33 | :internal: | 187 | :internal: |
| 34 | 188 | ||
| 35 | .. kernel-doc:: drivers/gpu/drm/drm_mode_object.c | 189 | .. kernel-doc:: drivers/gpu/drm/drm_mode_object.c |
| 36 | :export: | 190 | :export: |
| 37 | 191 | ||
| 38 | Atomic Mode Setting Function Reference | 192 | Atomic Mode Setting |
| 39 | ====================================== | 193 | =================== |
| 40 | 194 | ||
| 41 | .. kernel-doc:: drivers/gpu/drm/drm_atomic.c | 195 | |
| 42 | :export: | 196 | .. kernel-render:: DOT |
| 197 | :alt: Mode Objects and Properties | ||
| 198 | :caption: Mode Objects and Properties | ||
| 199 | |||
| 200 | digraph { | ||
| 201 | node [shape=box] | ||
| 202 | |||
| 203 | subgraph cluster_state { | ||
| 204 | style=dashed | ||
| 205 | label="Free-standing state" | ||
| 206 | |||
| 207 | "drm_atomic_state" -> "duplicated drm_plane_state A" | ||
| 208 | "drm_atomic_state" -> "duplicated drm_plane_state B" | ||
| 209 | "drm_atomic_state" -> "duplicated drm_crtc_state" | ||
| 210 | "drm_atomic_state" -> "duplicated drm_connector_state" | ||
| 211 | "drm_atomic_state" -> "duplicated driver private state" | ||
| 212 | } | ||
| 213 | |||
| 214 | subgraph cluster_current { | ||
| 215 | style=dashed | ||
| 216 | label="Current state" | ||
| 217 | |||
| 218 | "drm_device" -> "drm_plane A" | ||
| 219 | "drm_device" -> "drm_plane B" | ||
| 220 | "drm_device" -> "drm_crtc" | ||
| 221 | "drm_device" -> "drm_connector" | ||
| 222 | "drm_device" -> "driver private object" | ||
| 223 | |||
| 224 | "drm_plane A" -> "drm_plane_state A" | ||
| 225 | "drm_plane B" -> "drm_plane_state B" | ||
| 226 | "drm_crtc" -> "drm_crtc_state" | ||
| 227 | "drm_connector" -> "drm_connector_state" | ||
| 228 | "driver private object" -> "driver private state" | ||
| 229 | } | ||
| 230 | |||
| 231 | "drm_atomic_state" -> "drm_device" [label="atomic_commit"] | ||
| 232 | "duplicated drm_plane_state A" -> "drm_device"[style=invis] | ||
| 233 | } | ||
| 234 | |||
| 235 | Atomic provides transactional modeset (including planes) updates, but a | ||
| 236 | bit differently from the usual transactional approach of try-commit and | ||
| 237 | rollback: | ||
| 238 | |||
| 239 | - Firstly, no hardware changes are allowed when the commit would fail. This | ||
| 240 | allows us to implement the DRM_MODE_ATOMIC_TEST_ONLY mode, which allows | ||
| 241 | userspace to explore whether certain configurations would work or not. | ||
| 242 | |||
| 243 | - This would still allow setting and rollback of just the software state, | ||
| 244 | simplifying conversion of existing drivers. But auditing drivers for | ||
| 245 | correctness of the atomic_check code becomes really hard with that: Rolling | ||
| 246 | back changes in data structures all over the place is hard to get right. | ||
| 247 | |||
| 248 | - Lastly, for backwards compatibility and to support all use-cases, atomic | ||
| 249 | updates need to be incremental and be able to execute in parallel. Hardware | ||
| 250 | doesn't always allow it, but where possible plane updates on different CRTCs | ||
| 251 | should not interfere, and not get stalled due to output routing changing on | ||
| 252 | different CRTCs. | ||
| 253 | |||
| 254 | Taken all together there's two consequences for the atomic design: | ||
| 255 | |||
| 256 | - The overall state is split up into per-object state structures: | ||
| 257 | :c:type:`struct drm_plane_state <drm_plane_state>` for planes, :c:type:`struct | ||
| 258 | drm_crtc_state <drm_crtc_state>` for CRTCs and :c:type:`struct | ||
| 259 | drm_connector_state <drm_connector_state>` for connectors. These are the only | ||
| 260 | objects with userspace-visible and settable state. For internal state drivers | ||
| 261 | can subclass these structures through embeddeding, or add entirely new state | ||
| 262 | structures for their globally shared hardware functions. | ||
| 263 | |||
| 264 | - An atomic update is assembled and validated as an entirely free-standing pile | ||
| 265 | of structures within the :c:type:`drm_atomic_state <drm_atomic_state>` | ||
| 266 | container. Again drivers can subclass that container for their own state | ||
| 267 | structure tracking needs. Only when a state is committed is it applied to the | ||
| 268 | driver and modeset objects. This way rolling back an update boils down to | ||
| 269 | releasing memory and unreferencing objects like framebuffers. | ||
| 270 | |||
| 271 | Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed | ||
| 272 | coverage of specific topics. | ||
| 273 | |||
| 274 | Atomic Mode Setting Function Reference | ||
| 275 | -------------------------------------- | ||
| 43 | 276 | ||
| 44 | .. kernel-doc:: include/drm/drm_atomic.h | 277 | .. kernel-doc:: include/drm/drm_atomic.h |
| 45 | :internal: | 278 | :internal: |
| 46 | 279 | ||
| 280 | .. kernel-doc:: drivers/gpu/drm/drm_atomic.c | ||
| 281 | :export: | ||
| 282 | |||
| 47 | CRTC Abstraction | 283 | CRTC Abstraction |
| 48 | ================ | 284 | ================ |
| 49 | 285 | ||
| @@ -68,12 +304,12 @@ Frame Buffer Abstraction | |||
| 68 | Frame Buffer Functions Reference | 304 | Frame Buffer Functions Reference |
| 69 | -------------------------------- | 305 | -------------------------------- |
| 70 | 306 | ||
| 71 | .. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c | ||
| 72 | :export: | ||
| 73 | |||
| 74 | .. kernel-doc:: include/drm/drm_framebuffer.h | 307 | .. kernel-doc:: include/drm/drm_framebuffer.h |
| 75 | :internal: | 308 | :internal: |
| 76 | 309 | ||
| 310 | .. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c | ||
| 311 | :export: | ||
| 312 | |||
| 77 | DRM Format Handling | 313 | DRM Format Handling |
| 78 | =================== | 314 | =================== |
| 79 | 315 | ||
| @@ -376,8 +612,8 @@ operation handler. | |||
| 376 | Vertical Blanking and Interrupt Handling Functions Reference | 612 | Vertical Blanking and Interrupt Handling Functions Reference |
| 377 | ------------------------------------------------------------ | 613 | ------------------------------------------------------------ |
| 378 | 614 | ||
| 379 | .. kernel-doc:: drivers/gpu/drm/drm_irq.c | ||
| 380 | :export: | ||
| 381 | |||
| 382 | .. kernel-doc:: include/drm/drm_irq.h | 615 | .. kernel-doc:: include/drm/drm_irq.h |
| 383 | :internal: | 616 | :internal: |
| 617 | |||
| 618 | .. kernel-doc:: drivers/gpu/drm/drm_irq.c | ||
| 619 | :export: | ||
diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index d7a29d41789f..96b9c34c21e4 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst | |||
| @@ -365,36 +365,36 @@ from the client in libdrm. | |||
| 365 | GEM Function Reference | 365 | GEM Function Reference |
| 366 | ---------------------- | 366 | ---------------------- |
| 367 | 367 | ||
| 368 | .. kernel-doc:: drivers/gpu/drm/drm_gem.c | ||
| 369 | :export: | ||
| 370 | |||
| 371 | .. kernel-doc:: include/drm/drm_gem.h | 368 | .. kernel-doc:: include/drm/drm_gem.h |
| 372 | :internal: | 369 | :internal: |
| 373 | 370 | ||
| 371 | .. kernel-doc:: drivers/gpu/drm/drm_gem.c | ||
| 372 | :export: | ||
| 373 | |||
| 374 | GEM CMA Helper Functions Reference | 374 | GEM CMA Helper Functions Reference |
| 375 | ---------------------------------- | 375 | ---------------------------------- |
| 376 | 376 | ||
| 377 | .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c | 377 | .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c |
| 378 | :doc: cma helpers | 378 | :doc: cma helpers |
| 379 | 379 | ||
| 380 | .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c | ||
| 381 | :export: | ||
| 382 | |||
| 383 | .. kernel-doc:: include/drm/drm_gem_cma_helper.h | 380 | .. kernel-doc:: include/drm/drm_gem_cma_helper.h |
| 384 | :internal: | 381 | :internal: |
| 385 | 382 | ||
| 383 | .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c | ||
| 384 | :export: | ||
| 385 | |||
| 386 | VMA Offset Manager | 386 | VMA Offset Manager |
| 387 | ================== | 387 | ================== |
| 388 | 388 | ||
| 389 | .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c | 389 | .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c |
| 390 | :doc: vma offset manager | 390 | :doc: vma offset manager |
| 391 | 391 | ||
| 392 | .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c | ||
| 393 | :export: | ||
| 394 | |||
| 395 | .. kernel-doc:: include/drm/drm_vma_manager.h | 392 | .. kernel-doc:: include/drm/drm_vma_manager.h |
| 396 | :internal: | 393 | :internal: |
| 397 | 394 | ||
| 395 | .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c | ||
| 396 | :export: | ||
| 397 | |||
| 398 | PRIME Buffer Sharing | 398 | PRIME Buffer Sharing |
| 399 | ==================== | 399 | ==================== |
| 400 | 400 | ||
| @@ -473,12 +473,12 @@ LRU Scan/Eviction Support | |||
| 473 | DRM MM Range Allocator Function References | 473 | DRM MM Range Allocator Function References |
| 474 | ------------------------------------------ | 474 | ------------------------------------------ |
| 475 | 475 | ||
| 476 | .. kernel-doc:: drivers/gpu/drm/drm_mm.c | ||
| 477 | :export: | ||
| 478 | |||
| 479 | .. kernel-doc:: include/drm/drm_mm.h | 476 | .. kernel-doc:: include/drm/drm_mm.h |
| 480 | :internal: | 477 | :internal: |
| 481 | 478 | ||
| 479 | .. kernel-doc:: drivers/gpu/drm/drm_mm.c | ||
| 480 | :export: | ||
| 481 | |||
| 482 | DRM Cache Handling | 482 | DRM Cache Handling |
| 483 | ================== | 483 | ================== |
| 484 | 484 | ||
diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index fcc228ef5bc4..352652810dab 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst | |||
| @@ -21,6 +21,8 @@ libdrm Device Lookup | |||
| 21 | :doc: getunique and setversion story | 21 | :doc: getunique and setversion story |
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | .. _drm_primary_node: | ||
| 25 | |||
| 24 | Primary Nodes, DRM Master and Authentication | 26 | Primary Nodes, DRM Master and Authentication |
| 25 | ============================================ | 27 | ============================================ |
| 26 | 28 | ||
| @@ -103,6 +105,8 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs | |||
| 103 | for the same thing co-existing. If we add a few more complete mistakes into the | 105 | for the same thing co-existing. If we add a few more complete mistakes into the |
| 104 | mix every year it would be entirely unmanageable. | 106 | mix every year it would be entirely unmanageable. |
| 105 | 107 | ||
| 108 | .. _drm_render_node: | ||
| 109 | |||
| 106 | Render nodes | 110 | Render nodes |
| 107 | ============ | 111 | ============ |
| 108 | 112 | ||
diff --git a/Documentation/phy.txt b/Documentation/phy.txt index 0aa994bd9a91..383cdd863f08 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt | |||
| @@ -97,7 +97,7 @@ should contain the phy name as given in the dt data and in the case of | |||
| 97 | non-dt boot, it should contain the label of the PHY. The two | 97 | non-dt boot, it should contain the label of the PHY. The two |
| 98 | devm_phy_get associates the device with the PHY using devres on | 98 | devm_phy_get associates the device with the PHY using devres on |
| 99 | successful PHY get. On driver detach, release function is invoked on | 99 | successful PHY get. On driver detach, release function is invoked on |
| 100 | the the devres data and devres data is freed. phy_optional_get and | 100 | the devres data and devres data is freed. phy_optional_get and |
| 101 | devm_phy_optional_get should be used when the phy is optional. These | 101 | devm_phy_optional_get should be used when the phy is optional. These |
| 102 | two functions will never return -ENODEV, but instead returns NULL when | 102 | two functions will never return -ENODEV, but instead returns NULL when |
| 103 | the phy cannot be found.Some generic drivers, such as ehci, may use multiple | 103 | the phy cannot be found.Some generic drivers, such as ehci, may use multiple |
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 56ce66114665..e4f25038ef65 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst | |||
| @@ -318,9 +318,10 @@ PDF outputs, it is recommended to use version 1.4.6. | |||
| 318 | .. note:: | 318 | .. note:: |
| 319 | 319 | ||
| 320 | Please notice that, for PDF and LaTeX output, you'll also need ``XeLaTeX`` | 320 | Please notice that, for PDF and LaTeX output, you'll also need ``XeLaTeX`` |
| 321 | version 3.14159265. Depending on the distribution, you may also need | 321 | version 3.14159265. Depending on the distribution, you may also need to |
| 322 | to install a series of ``texlive`` packages that provide the minimal | 322 | install a series of ``texlive`` packages that provide the minimal set of |
| 323 | set of functionalities required for ``XeLaTex`` to work. | 323 | functionalities required for ``XeLaTex`` to work. For PDF output you'll also |
| 324 | need ``convert(1)`` from ImageMagick (https://www.imagemagick.org). | ||
| 324 | 325 | ||
| 325 | Other tools | 326 | Other tools |
| 326 | ----------- | 327 | ----------- |
diff --git a/Documentation/sphinx/kfigure.py b/Documentation/sphinx/kfigure.py new file mode 100644 index 000000000000..cef4ad19624c --- /dev/null +++ b/Documentation/sphinx/kfigure.py | |||
| @@ -0,0 +1,551 @@ | |||
| 1 | # -*- coding: utf-8; mode: python -*- | ||
| 2 | # pylint: disable=C0103, R0903, R0912, R0915 | ||
| 3 | u""" | ||
| 4 | scalable figure and image handling | ||
| 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 6 | |||
| 7 | Sphinx extension which implements scalable image handling. | ||
| 8 | |||
| 9 | :copyright: Copyright (C) 2016 Markus Heiser | ||
| 10 | :license: GPL Version 2, June 1991 see Linux/COPYING for details. | ||
| 11 | |||
| 12 | The build for image formats depend on image's source format and output's | ||
| 13 | destination format. This extension implement methods to simplify image | ||
| 14 | handling from the author's POV. Directives like ``kernel-figure`` implement | ||
| 15 | methods *to* always get the best output-format even if some tools are not | ||
| 16 | installed. For more details take a look at ``convert_image(...)`` which is | ||
| 17 | the core of all conversions. | ||
| 18 | |||
| 19 | * ``.. kernel-image``: for image handling / a ``.. image::`` replacement | ||
| 20 | |||
| 21 | * ``.. kernel-figure``: for figure handling / a ``.. figure::`` replacement | ||
| 22 | |||
| 23 | * ``.. kernel-render``: for render markup / a concept to embed *render* | ||
| 24 | markups (or languages). Supported markups (see ``RENDER_MARKUP_EXT``) | ||
| 25 | |||
| 26 | - ``DOT``: render embedded Graphviz's **DOC** | ||
| 27 | - ``SVG``: render embedded Scalable Vector Graphics (**SVG**) | ||
| 28 | - ... *developable* | ||
| 29 | |||
| 30 | Used tools: | ||
| 31 | |||
| 32 | * ``dot(1)``: Graphviz (http://www.graphviz.org). If Graphviz is not | ||
| 33 | available, the DOT language is inserted as literal-block. | ||
| 34 | |||
| 35 | * SVG to PDF: To generate PDF, you need at least one of this tools: | ||
| 36 | |||
| 37 | - ``convert(1)``: ImageMagick (https://www.imagemagick.org) | ||
| 38 | |||
| 39 | List of customizations: | ||
| 40 | |||
| 41 | * generate PDF from SVG / used by PDF (LaTeX) builder | ||
| 42 | |||
| 43 | * generate SVG (html-builder) and PDF (latex-builder) from DOT files. | ||
| 44 | DOT: see http://www.graphviz.org/content/dot-language | ||
| 45 | |||
| 46 | """ | ||
| 47 | |||
| 48 | import os | ||
| 49 | from os import path | ||
| 50 | import subprocess | ||
| 51 | from hashlib import sha1 | ||
| 52 | import sys | ||
| 53 | |||
| 54 | from docutils import nodes | ||
| 55 | from docutils.statemachine import ViewList | ||
| 56 | from docutils.parsers.rst import directives | ||
| 57 | from docutils.parsers.rst.directives import images | ||
| 58 | import sphinx | ||
| 59 | |||
| 60 | from sphinx.util.nodes import clean_astext | ||
| 61 | from six import iteritems | ||
| 62 | |||
| 63 | PY3 = sys.version_info[0] == 3 | ||
| 64 | |||
| 65 | if PY3: | ||
| 66 | _unicode = str | ||
| 67 | else: | ||
| 68 | _unicode = unicode | ||
| 69 | |||
| 70 | # Get Sphinx version | ||
| 71 | major, minor, patch = sphinx.version_info[:3] | ||
| 72 | if major == 1 and minor > 3: | ||
| 73 | # patches.Figure only landed in Sphinx 1.4 | ||
| 74 | from sphinx.directives.patches import Figure # pylint: disable=C0413 | ||
| 75 | else: | ||
| 76 | Figure = images.Figure | ||
| 77 | |||
| 78 | __version__ = '1.0.0' | ||
| 79 | |||
| 80 | # simple helper | ||
| 81 | # ------------- | ||
| 82 | |||
| 83 | def which(cmd): | ||
| 84 | """Searches the ``cmd`` in the ``PATH`` enviroment. | ||
| 85 | |||
| 86 | This *which* searches the PATH for executable ``cmd`` . First match is | ||
| 87 | returned, if nothing is found, ``None` is returned. | ||
| 88 | """ | ||
| 89 | envpath = os.environ.get('PATH', None) or os.defpath | ||
| 90 | for folder in envpath.split(os.pathsep): | ||
| 91 | fname = folder + os.sep + cmd | ||
| 92 | if path.isfile(fname): | ||
| 93 | return fname | ||
| 94 | |||
| 95 | def mkdir(folder, mode=0o775): | ||
| 96 | if not path.isdir(folder): | ||
| 97 | os.makedirs(folder, mode) | ||
| 98 | |||
| 99 | def file2literal(fname): | ||
| 100 | with open(fname, "r") as src: | ||
| 101 | data = src.read() | ||
| 102 | node = nodes.literal_block(data, data) | ||
| 103 | return node | ||
| 104 | |||
| 105 | def isNewer(path1, path2): | ||
| 106 | """Returns True if ``path1`` is newer than ``path2`` | ||
| 107 | |||
| 108 | If ``path1`` exists and is newer than ``path2`` the function returns | ||
| 109 | ``True`` is returned otherwise ``False`` | ||
| 110 | """ | ||
| 111 | return (path.exists(path1) | ||
| 112 | and os.stat(path1).st_ctime > os.stat(path2).st_ctime) | ||
| 113 | |||
| 114 | def pass_handle(self, node): # pylint: disable=W0613 | ||
| 115 | pass | ||
| 116 | |||
| 117 | # setup conversion tools and sphinx extension | ||
| 118 | # ------------------------------------------- | ||
| 119 | |||
| 120 | # Graphviz's dot(1) support | ||
| 121 | dot_cmd = None | ||
| 122 | |||
| 123 | # ImageMagick' convert(1) support | ||
| 124 | convert_cmd = None | ||
| 125 | |||
| 126 | |||
| 127 | def setup(app): | ||
| 128 | # check toolchain first | ||
| 129 | app.connect('builder-inited', setupTools) | ||
| 130 | |||
| 131 | # image handling | ||
| 132 | app.add_directive("kernel-image", KernelImage) | ||
| 133 | app.add_node(kernel_image, | ||
| 134 | html = (visit_kernel_image, pass_handle), | ||
| 135 | latex = (visit_kernel_image, pass_handle), | ||
| 136 | texinfo = (visit_kernel_image, pass_handle), | ||
| 137 | text = (visit_kernel_image, pass_handle), | ||
| 138 | man = (visit_kernel_image, pass_handle), ) | ||
| 139 | |||
| 140 | # figure handling | ||
| 141 | app.add_directive("kernel-figure", KernelFigure) | ||
| 142 | app.add_node(kernel_figure, | ||
| 143 | html = (visit_kernel_figure, pass_handle), | ||
| 144 | latex = (visit_kernel_figure, pass_handle), | ||
| 145 | texinfo = (visit_kernel_figure, pass_handle), | ||
| 146 | text = (visit_kernel_figure, pass_handle), | ||
| 147 | man = (visit_kernel_figure, pass_handle), ) | ||
| 148 | |||
| 149 | # render handling | ||
| 150 | app.add_directive('kernel-render', KernelRender) | ||
| 151 | app.add_node(kernel_render, | ||
| 152 | html = (visit_kernel_render, pass_handle), | ||
| 153 | latex = (visit_kernel_render, pass_handle), | ||
| 154 | texinfo = (visit_kernel_render, pass_handle), | ||
| 155 | text = (visit_kernel_render, pass_handle), | ||
| 156 | man = (visit_kernel_render, pass_handle), ) | ||
| 157 | |||
| 158 | app.connect('doctree-read', add_kernel_figure_to_std_domain) | ||
| 159 | |||
| 160 | return dict( | ||
| 161 | version = __version__, | ||
| 162 | parallel_read_safe = True, | ||
| 163 | parallel_write_safe = True | ||
| 164 | ) | ||
| 165 | |||
| 166 | |||
| 167 | def setupTools(app): | ||
| 168 | u""" | ||
| 169 | Check available build tools and log some *verbose* messages. | ||
| 170 | |||
| 171 | This function is called once, when the builder is initiated. | ||
| 172 | """ | ||
| 173 | global dot_cmd, convert_cmd # pylint: disable=W0603 | ||
| 174 | app.verbose("kfigure: check installed tools ...") | ||
| 175 | |||
| 176 | dot_cmd = which('dot') | ||
| 177 | convert_cmd = which('convert') | ||
| 178 | |||
| 179 | if dot_cmd: | ||
| 180 | app.verbose("use dot(1) from: " + dot_cmd) | ||
| 181 | else: | ||
| 182 | app.warn("dot(1) not found, for better output quality install " | ||
| 183 | "graphviz from http://www.graphviz.org") | ||
| 184 | if convert_cmd: | ||
| 185 | app.verbose("use convert(1) from: " + convert_cmd) | ||
| 186 | else: | ||
| 187 | app.warn( | ||
| 188 | "convert(1) not found, for SVG to PDF conversion install " | ||
| 189 | "ImageMagick (https://www.imagemagick.org)") | ||
| 190 | |||
| 191 | |||
| 192 | # integrate conversion tools | ||
| 193 | # -------------------------- | ||
| 194 | |||
| 195 | RENDER_MARKUP_EXT = { | ||
| 196 | # The '.ext' must be handled by convert_image(..) function's *in_ext* input. | ||
| 197 | # <name> : <.ext> | ||
| 198 | 'DOT' : '.dot', | ||
| 199 | 'SVG' : '.svg' | ||
| 200 | } | ||
| 201 | |||
| 202 | def convert_image(img_node, translator, src_fname=None): | ||
| 203 | """Convert a image node for the builder. | ||
| 204 | |||
| 205 | Different builder prefer different image formats, e.g. *latex* builder | ||
| 206 | prefer PDF while *html* builder prefer SVG format for images. | ||
| 207 | |||
| 208 | This function handles output image formats in dependence of source the | ||
| 209 | format (of the image) and the translator's output format. | ||
| 210 | """ | ||
| 211 | app = translator.builder.app | ||
| 212 | |||
| 213 | fname, in_ext = path.splitext(path.basename(img_node['uri'])) | ||
| 214 | if src_fname is None: | ||
| 215 | src_fname = path.join(translator.builder.srcdir, img_node['uri']) | ||
| 216 | if not path.exists(src_fname): | ||
| 217 | src_fname = path.join(translator.builder.outdir, img_node['uri']) | ||
| 218 | |||
| 219 | dst_fname = None | ||
| 220 | |||
| 221 | # in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages | ||
| 222 | |||
| 223 | app.verbose('assert best format for: ' + img_node['uri']) | ||
| 224 | |||
| 225 | if in_ext == '.dot': | ||
| 226 | |||
| 227 | if not dot_cmd: | ||
| 228 | app.verbose("dot from graphviz not available / include DOT raw.") | ||
| 229 | img_node.replace_self(file2literal(src_fname)) | ||
| 230 | |||
| 231 | elif translator.builder.format == 'latex': | ||
| 232 | dst_fname = path.join(translator.builder.outdir, fname + '.pdf') | ||
| 233 | img_node['uri'] = fname + '.pdf' | ||
| 234 | img_node['candidates'] = {'*': fname + '.pdf'} | ||
| 235 | |||
| 236 | |||
| 237 | elif translator.builder.format == 'html': | ||
| 238 | dst_fname = path.join( | ||
| 239 | translator.builder.outdir, | ||
| 240 | translator.builder.imagedir, | ||
| 241 | fname + '.svg') | ||
| 242 | img_node['uri'] = path.join( | ||
| 243 | translator.builder.imgpath, fname + '.svg') | ||
| 244 | img_node['candidates'] = { | ||
| 245 | '*': path.join(translator.builder.imgpath, fname + '.svg')} | ||
| 246 | |||
| 247 | else: | ||
| 248 | # all other builder formats will include DOT as raw | ||
| 249 | img_node.replace_self(file2literal(src_fname)) | ||
| 250 | |||
| 251 | elif in_ext == '.svg': | ||
| 252 | |||
| 253 | if translator.builder.format == 'latex': | ||
| 254 | if convert_cmd is None: | ||
| 255 | app.verbose("no SVG to PDF conversion available / include SVG raw.") | ||
| 256 | img_node.replace_self(file2literal(src_fname)) | ||
| 257 | else: | ||
| 258 | dst_fname = path.join(translator.builder.outdir, fname + '.pdf') | ||
| 259 | img_node['uri'] = fname + '.pdf' | ||
| 260 | img_node['candidates'] = {'*': fname + '.pdf'} | ||
| 261 | |||
| 262 | if dst_fname: | ||
| 263 | # the builder needs not to copy one more time, so pop it if exists. | ||
| 264 | translator.builder.images.pop(img_node['uri'], None) | ||
| 265 | _name = dst_fname[len(translator.builder.outdir) + 1:] | ||
| 266 | |||
| 267 | if isNewer(dst_fname, src_fname): | ||
| 268 | app.verbose("convert: {out}/%s already exists and is newer" % _name) | ||
| 269 | |||
| 270 | else: | ||
| 271 | ok = False | ||
| 272 | mkdir(path.dirname(dst_fname)) | ||
| 273 | |||
| 274 | if in_ext == '.dot': | ||
| 275 | app.verbose('convert DOT to: {out}/' + _name) | ||
| 276 | ok = dot2format(app, src_fname, dst_fname) | ||
| 277 | |||
| 278 | elif in_ext == '.svg': | ||
| 279 | app.verbose('convert SVG to: {out}/' + _name) | ||
| 280 | ok = svg2pdf(app, src_fname, dst_fname) | ||
| 281 | |||
| 282 | if not ok: | ||
| 283 | img_node.replace_self(file2literal(src_fname)) | ||
| 284 | |||
| 285 | |||
| 286 | def dot2format(app, dot_fname, out_fname): | ||
| 287 | """Converts DOT file to ``out_fname`` using ``dot(1)``. | ||
| 288 | |||
| 289 | * ``dot_fname`` pathname of the input DOT file, including extension ``.dot`` | ||
| 290 | * ``out_fname`` pathname of the output file, including format extension | ||
| 291 | |||
| 292 | The *format extension* depends on the ``dot`` command (see ``man dot`` | ||
| 293 | option ``-Txxx``). Normally you will use one of the following extensions: | ||
| 294 | |||
| 295 | - ``.ps`` for PostScript, | ||
| 296 | - ``.svg`` or ``svgz`` for Structured Vector Graphics, | ||
| 297 | - ``.fig`` for XFIG graphics and | ||
| 298 | - ``.png`` or ``gif`` for common bitmap graphics. | ||
| 299 | |||
| 300 | """ | ||
| 301 | out_format = path.splitext(out_fname)[1][1:] | ||
| 302 | cmd = [dot_cmd, '-T%s' % out_format, dot_fname] | ||
| 303 | exit_code = 42 | ||
| 304 | |||
| 305 | with open(out_fname, "w") as out: | ||
| 306 | exit_code = subprocess.call(cmd, stdout = out) | ||
| 307 | if exit_code != 0: | ||
| 308 | app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd))) | ||
| 309 | return bool(exit_code == 0) | ||
| 310 | |||
| 311 | def svg2pdf(app, svg_fname, pdf_fname): | ||
| 312 | """Converts SVG to PDF with ``convert(1)`` command. | ||
| 313 | |||
| 314 | Uses ``convert(1)`` from ImageMagick (https://www.imagemagick.org) for | ||
| 315 | conversion. Returns ``True`` on success and ``False`` if an error occurred. | ||
| 316 | |||
| 317 | * ``svg_fname`` pathname of the input SVG file with extension (``.svg``) | ||
| 318 | * ``pdf_name`` pathname of the output PDF file with extension (``.pdf``) | ||
| 319 | |||
| 320 | """ | ||
| 321 | cmd = [convert_cmd, svg_fname, pdf_fname] | ||
| 322 | # use stdout and stderr from parent | ||
| 323 | exit_code = subprocess.call(cmd) | ||
| 324 | if exit_code != 0: | ||
| 325 | app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd))) | ||
| 326 | return bool(exit_code == 0) | ||
| 327 | |||
| 328 | |||
| 329 | # image handling | ||
| 330 | # --------------------- | ||
| 331 | |||
| 332 | def visit_kernel_image(self, node): # pylint: disable=W0613 | ||
| 333 | """Visitor of the ``kernel_image`` Node. | ||
| 334 | |||
| 335 | Handles the ``image`` child-node with the ``convert_image(...)``. | ||
| 336 | """ | ||
| 337 | img_node = node[0] | ||
| 338 | convert_image(img_node, self) | ||
| 339 | |||
| 340 | class kernel_image(nodes.image): | ||
| 341 | """Node for ``kernel-image`` directive.""" | ||
| 342 | pass | ||
| 343 | |||
| 344 | class KernelImage(images.Image): | ||
| 345 | u"""KernelImage directive | ||
| 346 | |||
| 347 | Earns everything from ``.. image::`` directive, except *remote URI* and | ||
| 348 | *glob* pattern. The KernelImage wraps a image node into a | ||
| 349 | kernel_image node. See ``visit_kernel_image``. | ||
| 350 | """ | ||
| 351 | |||
| 352 | def run(self): | ||
| 353 | uri = self.arguments[0] | ||
| 354 | if uri.endswith('.*') or uri.find('://') != -1: | ||
| 355 | raise self.severe( | ||
| 356 | 'Error in "%s: %s": glob pattern and remote images are not allowed' | ||
| 357 | % (self.name, uri)) | ||
| 358 | result = images.Image.run(self) | ||
| 359 | if len(result) == 2 or isinstance(result[0], nodes.system_message): | ||
| 360 | return result | ||
| 361 | (image_node,) = result | ||
| 362 | # wrap image node into a kernel_image node / see visitors | ||
| 363 | node = kernel_image('', image_node) | ||
| 364 | return [node] | ||
| 365 | |||
| 366 | # figure handling | ||
| 367 | # --------------------- | ||
| 368 | |||
| 369 | def visit_kernel_figure(self, node): # pylint: disable=W0613 | ||
| 370 | """Visitor of the ``kernel_figure`` Node. | ||
| 371 | |||
| 372 | Handles the ``image`` child-node with the ``convert_image(...)``. | ||
| 373 | """ | ||
| 374 | img_node = node[0][0] | ||
| 375 | convert_image(img_node, self) | ||
| 376 | |||
| 377 | class kernel_figure(nodes.figure): | ||
| 378 | """Node for ``kernel-figure`` directive.""" | ||
| 379 | |||
| 380 | class KernelFigure(Figure): | ||
| 381 | u"""KernelImage directive | ||
| 382 | |||
| 383 | Earns everything from ``.. figure::`` directive, except *remote URI* and | ||
| 384 | *glob* pattern. The KernelFigure wraps a figure node into a kernel_figure | ||
| 385 | node. See ``visit_kernel_figure``. | ||
| 386 | """ | ||
| 387 | |||
| 388 | def run(self): | ||
| 389 | uri = self.arguments[0] | ||
| 390 | if uri.endswith('.*') or uri.find('://') != -1: | ||
| 391 | raise self.severe( | ||
| 392 | 'Error in "%s: %s":' | ||
| 393 | ' glob pattern and remote images are not allowed' | ||
| 394 | % (self.name, uri)) | ||
| 395 | result = Figure.run(self) | ||
| 396 | if len(result) == 2 or isinstance(result[0], nodes.system_message): | ||
| 397 | return result | ||
| 398 | (figure_node,) = result | ||
| 399 | # wrap figure node into a kernel_figure node / see visitors | ||
| 400 | node = kernel_figure('', figure_node) | ||
| 401 | return [node] | ||
| 402 | |||
| 403 | |||
| 404 | # render handling | ||
| 405 | # --------------------- | ||
| 406 | |||
| 407 | def visit_kernel_render(self, node): | ||
| 408 | """Visitor of the ``kernel_render`` Node. | ||
| 409 | |||
| 410 | If rendering tools available, save the markup of the ``literal_block`` child | ||
| 411 | node into a file and replace the ``literal_block`` node with a new created | ||
| 412 | ``image`` node, pointing to the saved markup file. Afterwards, handle the | ||
| 413 | image child-node with the ``convert_image(...)``. | ||
| 414 | """ | ||
| 415 | app = self.builder.app | ||
| 416 | srclang = node.get('srclang') | ||
| 417 | |||
| 418 | app.verbose('visit kernel-render node lang: "%s"' % (srclang)) | ||
| 419 | |||
| 420 | tmp_ext = RENDER_MARKUP_EXT.get(srclang, None) | ||
| 421 | if tmp_ext is None: | ||
| 422 | app.warn('kernel-render: "%s" unknow / include raw.' % (srclang)) | ||
| 423 | return | ||
| 424 | |||
| 425 | if not dot_cmd and tmp_ext == '.dot': | ||
| 426 | app.verbose("dot from graphviz not available / include raw.") | ||
| 427 | return | ||
| 428 | |||
| 429 | literal_block = node[0] | ||
| 430 | |||
| 431 | code = literal_block.astext() | ||
| 432 | hashobj = code.encode('utf-8') # str(node.attributes) | ||
| 433 | fname = path.join('%s-%s' % (srclang, sha1(hashobj).hexdigest())) | ||
| 434 | |||
| 435 | tmp_fname = path.join( | ||
| 436 | self.builder.outdir, self.builder.imagedir, fname + tmp_ext) | ||
| 437 | |||
| 438 | if not path.isfile(tmp_fname): | ||
| 439 | mkdir(path.dirname(tmp_fname)) | ||
| 440 | with open(tmp_fname, "w") as out: | ||
| 441 | out.write(code) | ||
| 442 | |||
| 443 | img_node = nodes.image(node.rawsource, **node.attributes) | ||
| 444 | img_node['uri'] = path.join(self.builder.imgpath, fname + tmp_ext) | ||
| 445 | img_node['candidates'] = { | ||
| 446 | '*': path.join(self.builder.imgpath, fname + tmp_ext)} | ||
| 447 | |||
| 448 | literal_block.replace_self(img_node) | ||
| 449 | convert_image(img_node, self, tmp_fname) | ||
| 450 | |||
| 451 | |||
| 452 | class kernel_render(nodes.General, nodes.Inline, nodes.Element): | ||
| 453 | """Node for ``kernel-render`` directive.""" | ||
| 454 | pass | ||
| 455 | |||
| 456 | class KernelRender(Figure): | ||
| 457 | u"""KernelRender directive | ||
| 458 | |||
| 459 | Render content by external tool. Has all the options known from the | ||
| 460 | *figure* directive, plus option ``caption``. If ``caption`` has a | ||
| 461 | value, a figure node with the *caption* is inserted. If not, a image node is | ||
| 462 | inserted. | ||
| 463 | |||
| 464 | The KernelRender directive wraps the text of the directive into a | ||
| 465 | literal_block node and wraps it into a kernel_render node. See | ||
| 466 | ``visit_kernel_render``. | ||
| 467 | """ | ||
| 468 | has_content = True | ||
| 469 | required_arguments = 1 | ||
| 470 | optional_arguments = 0 | ||
| 471 | final_argument_whitespace = False | ||
| 472 | |||
| 473 | # earn options from 'figure' | ||
| 474 | option_spec = Figure.option_spec.copy() | ||
| 475 | option_spec['caption'] = directives.unchanged | ||
| 476 | |||
| 477 | def run(self): | ||
| 478 | return [self.build_node()] | ||
| 479 | |||
| 480 | def build_node(self): | ||
| 481 | |||
| 482 | srclang = self.arguments[0].strip() | ||
| 483 | if srclang not in RENDER_MARKUP_EXT.keys(): | ||
| 484 | return [self.state_machine.reporter.warning( | ||
| 485 | 'Unknow source language "%s", use one of: %s.' % ( | ||
| 486 | srclang, ",".join(RENDER_MARKUP_EXT.keys())), | ||
| 487 | line=self.lineno)] | ||
| 488 | |||
| 489 | code = '\n'.join(self.content) | ||
| 490 | if not code.strip(): | ||
| 491 | return [self.state_machine.reporter.warning( | ||
| 492 | 'Ignoring "%s" directive without content.' % ( | ||
| 493 | self.name), | ||
| 494 | line=self.lineno)] | ||
| 495 | |||
| 496 | node = kernel_render() | ||
| 497 | node['alt'] = self.options.get('alt','') | ||
| 498 | node['srclang'] = srclang | ||
| 499 | literal_node = nodes.literal_block(code, code) | ||
| 500 | node += literal_node | ||
| 501 | |||
| 502 | caption = self.options.get('caption') | ||
| 503 | if caption: | ||
| 504 | # parse caption's content | ||
| 505 | parsed = nodes.Element() | ||
| 506 | self.state.nested_parse( | ||
| 507 | ViewList([caption], source=''), self.content_offset, parsed) | ||
| 508 | caption_node = nodes.caption( | ||
| 509 | parsed[0].rawsource, '', *parsed[0].children) | ||
| 510 | caption_node.source = parsed[0].source | ||
| 511 | caption_node.line = parsed[0].line | ||
| 512 | |||
| 513 | figure_node = nodes.figure('', node) | ||
| 514 | for k,v in self.options.items(): | ||
| 515 | figure_node[k] = v | ||
| 516 | figure_node += caption_node | ||
| 517 | |||
| 518 | node = figure_node | ||
| 519 | |||
| 520 | return node | ||
| 521 | |||
| 522 | def add_kernel_figure_to_std_domain(app, doctree): | ||
| 523 | """Add kernel-figure anchors to 'std' domain. | ||
| 524 | |||
| 525 | The ``StandardDomain.process_doc(..)`` method does not know how to resolve | ||
| 526 | the caption (label) of ``kernel-figure`` directive (it only knows about | ||
| 527 | standard nodes, e.g. table, figure etc.). Without any additional handling | ||
| 528 | this will result in a 'undefined label' for kernel-figures. | ||
| 529 | |||
| 530 | This handle adds labels of kernel-figure to the 'std' domain labels. | ||
| 531 | """ | ||
| 532 | |||
| 533 | std = app.env.domains["std"] | ||
| 534 | docname = app.env.docname | ||
| 535 | labels = std.data["labels"] | ||
| 536 | |||
| 537 | for name, explicit in iteritems(doctree.nametypes): | ||
| 538 | if not explicit: | ||
| 539 | continue | ||
| 540 | labelid = doctree.nameids[name] | ||
| 541 | if labelid is None: | ||
| 542 | continue | ||
| 543 | node = doctree.ids[labelid] | ||
| 544 | |||
| 545 | if node.tagname == 'kernel_figure': | ||
| 546 | for n in node.next_node(): | ||
| 547 | if n.tagname == 'caption': | ||
| 548 | sectname = clean_astext(n) | ||
| 549 | # add label to std domain | ||
| 550 | labels[name] = docname, labelid, sectname | ||
| 551 | break | ||
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 67eb7c8fb88c..0350829ba62e 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c | |||
| @@ -144,3 +144,29 @@ struct dma_fence_array *dma_fence_array_create(int num_fences, | |||
| 144 | return array; | 144 | return array; |
| 145 | } | 145 | } |
| 146 | EXPORT_SYMBOL(dma_fence_array_create); | 146 | EXPORT_SYMBOL(dma_fence_array_create); |
| 147 | |||
| 148 | /** | ||
| 149 | * dma_fence_match_context - Check if all fences are from the given context | ||
| 150 | * @fence: [in] fence or fence array | ||
| 151 | * @context: [in] fence context to check all fences against | ||
| 152 | * | ||
| 153 | * Checks the provided fence or, for a fence array, all fences in the array | ||
| 154 | * against the given context. Returns false if any fence is from a different | ||
| 155 | * context. | ||
| 156 | */ | ||
| 157 | bool dma_fence_match_context(struct dma_fence *fence, u64 context) | ||
| 158 | { | ||
| 159 | struct dma_fence_array *array = to_dma_fence_array(fence); | ||
| 160 | unsigned i; | ||
| 161 | |||
| 162 | if (!dma_fence_is_array(fence)) | ||
| 163 | return fence->context == context; | ||
| 164 | |||
| 165 | for (i = 0; i < array->num_fences; i++) { | ||
| 166 | if (array->fences[i]->context != context) | ||
| 167 | return false; | ||
| 168 | } | ||
| 169 | |||
| 170 | return true; | ||
| 171 | } | ||
| 172 | EXPORT_SYMBOL(dma_fence_match_context); | ||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 59aae43005ee..59f0f9b696eb 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
| @@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | |||
| 31 | drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ | 31 | drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ |
| 32 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ | 32 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ |
| 33 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ | 33 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ |
| 34 | drm_simple_kms_helper.o drm_modeset_helper.o | 34 | drm_simple_kms_helper.o drm_modeset_helper.o \ |
| 35 | drm_scdc_helper.o | ||
| 35 | 36 | ||
| 36 | drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | 37 | drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o |
| 37 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 38 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 4840dc277339..0e74880b5e94 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c | |||
| @@ -239,17 +239,7 @@ static int hdlcd_debugfs_init(struct drm_minor *minor) | |||
| 239 | } | 239 | } |
| 240 | #endif | 240 | #endif |
| 241 | 241 | ||
| 242 | static const struct file_operations fops = { | 242 | DEFINE_DRM_GEM_CMA_FOPS(fops); |
| 243 | .owner = THIS_MODULE, | ||
| 244 | .open = drm_open, | ||
| 245 | .release = drm_release, | ||
| 246 | .unlocked_ioctl = drm_ioctl, | ||
| 247 | .compat_ioctl = drm_compat_ioctl, | ||
| 248 | .poll = drm_poll, | ||
| 249 | .read = drm_read, | ||
| 250 | .llseek = noop_llseek, | ||
| 251 | .mmap = drm_gem_cma_mmap, | ||
| 252 | }; | ||
| 253 | 243 | ||
| 254 | static struct drm_driver hdlcd_driver = { | 244 | static struct drm_driver hdlcd_driver = { |
| 255 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | | 245 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | |
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index a9608a2e5a29..ea2546f766c2 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c | |||
| @@ -178,17 +178,7 @@ static void malidp_lastclose(struct drm_device *drm) | |||
| 178 | drm_fbdev_cma_restore_mode(malidp->fbdev); | 178 | drm_fbdev_cma_restore_mode(malidp->fbdev); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | static const struct file_operations fops = { | 181 | DEFINE_DRM_GEM_CMA_FOPS(fops); |
| 182 | .owner = THIS_MODULE, | ||
| 183 | .open = drm_open, | ||
| 184 | .release = drm_release, | ||
| 185 | .unlocked_ioctl = drm_ioctl, | ||
| 186 | .compat_ioctl = drm_compat_ioctl, | ||
| 187 | .poll = drm_poll, | ||
| 188 | .read = drm_read, | ||
| 189 | .llseek = noop_llseek, | ||
| 190 | .mmap = drm_gem_cma_mmap, | ||
| 191 | }; | ||
| 192 | 182 | ||
| 193 | static struct drm_driver malidp_driver = { | 183 | static struct drm_driver malidp_driver = { |
| 194 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | | 184 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | |
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 408e00b64cf6..e618fab7f519 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c | |||
| @@ -60,16 +60,7 @@ static void armada_drm_lastclose(struct drm_device *dev) | |||
| 60 | armada_fbdev_lastclose(dev); | 60 | armada_fbdev_lastclose(dev); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static const struct file_operations armada_drm_fops = { | 63 | DEFINE_DRM_GEM_FOPS(armada_drm_fops); |
| 64 | .owner = THIS_MODULE, | ||
| 65 | .llseek = no_llseek, | ||
| 66 | .read = drm_read, | ||
| 67 | .poll = drm_poll, | ||
| 68 | .unlocked_ioctl = drm_ioctl, | ||
| 69 | .mmap = drm_gem_mmap, | ||
| 70 | .open = drm_open, | ||
| 71 | .release = drm_release, | ||
| 72 | }; | ||
| 73 | 64 | ||
| 74 | static struct drm_driver armada_drm_driver = { | 65 | static struct drm_driver armada_drm_driver = { |
| 75 | .lastclose = armada_drm_lastclose, | 66 | .lastclose = armada_drm_lastclose, |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index 6b50fb706c0e..53bfa56ca47a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | |||
| @@ -55,14 +55,12 @@ drm_crtc_state_to_atmel_hlcdc_crtc_state(struct drm_crtc_state *state) | |||
| 55 | * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device | 55 | * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device |
| 56 | * @event: pointer to the current page flip event | 56 | * @event: pointer to the current page flip event |
| 57 | * @id: CRTC id (returned by drm_crtc_index) | 57 | * @id: CRTC id (returned by drm_crtc_index) |
| 58 | * @enabled: CRTC state | ||
| 59 | */ | 58 | */ |
| 60 | struct atmel_hlcdc_crtc { | 59 | struct atmel_hlcdc_crtc { |
| 61 | struct drm_crtc base; | 60 | struct drm_crtc base; |
| 62 | struct atmel_hlcdc_dc *dc; | 61 | struct atmel_hlcdc_dc *dc; |
| 63 | struct drm_pending_vblank_event *event; | 62 | struct drm_pending_vblank_event *event; |
| 64 | int id; | 63 | int id; |
| 65 | bool enabled; | ||
| 66 | }; | 64 | }; |
| 67 | 65 | ||
| 68 | static inline struct atmel_hlcdc_crtc * | 66 | static inline struct atmel_hlcdc_crtc * |
| @@ -158,9 +156,6 @@ static void atmel_hlcdc_crtc_disable(struct drm_crtc *c) | |||
| 158 | struct regmap *regmap = crtc->dc->hlcdc->regmap; | 156 | struct regmap *regmap = crtc->dc->hlcdc->regmap; |
| 159 | unsigned int status; | 157 | unsigned int status; |
| 160 | 158 | ||
| 161 | if (!crtc->enabled) | ||
| 162 | return; | ||
| 163 | |||
| 164 | drm_crtc_vblank_off(c); | 159 | drm_crtc_vblank_off(c); |
| 165 | 160 | ||
| 166 | pm_runtime_get_sync(dev->dev); | 161 | pm_runtime_get_sync(dev->dev); |
| @@ -186,8 +181,6 @@ static void atmel_hlcdc_crtc_disable(struct drm_crtc *c) | |||
| 186 | pm_runtime_allow(dev->dev); | 181 | pm_runtime_allow(dev->dev); |
| 187 | 182 | ||
| 188 | pm_runtime_put_sync(dev->dev); | 183 | pm_runtime_put_sync(dev->dev); |
| 189 | |||
| 190 | crtc->enabled = false; | ||
| 191 | } | 184 | } |
| 192 | 185 | ||
| 193 | static void atmel_hlcdc_crtc_enable(struct drm_crtc *c) | 186 | static void atmel_hlcdc_crtc_enable(struct drm_crtc *c) |
| @@ -197,9 +190,6 @@ static void atmel_hlcdc_crtc_enable(struct drm_crtc *c) | |||
| 197 | struct regmap *regmap = crtc->dc->hlcdc->regmap; | 190 | struct regmap *regmap = crtc->dc->hlcdc->regmap; |
| 198 | unsigned int status; | 191 | unsigned int status; |
| 199 | 192 | ||
| 200 | if (crtc->enabled) | ||
| 201 | return; | ||
| 202 | |||
| 203 | pm_runtime_get_sync(dev->dev); | 193 | pm_runtime_get_sync(dev->dev); |
| 204 | 194 | ||
| 205 | pm_runtime_forbid(dev->dev); | 195 | pm_runtime_forbid(dev->dev); |
| @@ -226,29 +216,6 @@ static void atmel_hlcdc_crtc_enable(struct drm_crtc *c) | |||
| 226 | pm_runtime_put_sync(dev->dev); | 216 | pm_runtime_put_sync(dev->dev); |
| 227 | 217 | ||
| 228 | drm_crtc_vblank_on(c); | 218 | drm_crtc_vblank_on(c); |
| 229 | |||
| 230 | crtc->enabled = true; | ||
| 231 | } | ||
| 232 | |||
| 233 | void atmel_hlcdc_crtc_suspend(struct drm_crtc *c) | ||
| 234 | { | ||
| 235 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | ||
| 236 | |||
| 237 | if (crtc->enabled) { | ||
| 238 | atmel_hlcdc_crtc_disable(c); | ||
| 239 | /* save enable state for resume */ | ||
| 240 | crtc->enabled = true; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | void atmel_hlcdc_crtc_resume(struct drm_crtc *c) | ||
| 245 | { | ||
| 246 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | ||
| 247 | |||
| 248 | if (crtc->enabled) { | ||
| 249 | crtc->enabled = false; | ||
| 250 | atmel_hlcdc_crtc_enable(c); | ||
| 251 | } | ||
| 252 | } | 219 | } |
| 253 | 220 | ||
| 254 | #define ATMEL_HLCDC_RGB444_OUTPUT BIT(0) | 221 | #define ATMEL_HLCDC_RGB444_OUTPUT BIT(0) |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 970bd87d7cce..f4a3065f7f51 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
| @@ -724,17 +724,7 @@ static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev) | |||
| 724 | regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr); | 724 | regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr); |
| 725 | } | 725 | } |
| 726 | 726 | ||
| 727 | static const struct file_operations fops = { | 727 | DEFINE_DRM_GEM_CMA_FOPS(fops); |
| 728 | .owner = THIS_MODULE, | ||
| 729 | .open = drm_open, | ||
| 730 | .release = drm_release, | ||
| 731 | .unlocked_ioctl = drm_ioctl, | ||
| 732 | .compat_ioctl = drm_compat_ioctl, | ||
| 733 | .poll = drm_poll, | ||
| 734 | .read = drm_read, | ||
| 735 | .llseek = no_llseek, | ||
| 736 | .mmap = drm_gem_cma_mmap, | ||
| 737 | }; | ||
| 738 | 728 | ||
| 739 | static struct drm_driver atmel_hlcdc_dc_driver = { | 729 | static struct drm_driver atmel_hlcdc_dc_driver = { |
| 740 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | | 730 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | |
| @@ -810,31 +800,32 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev) | |||
| 810 | static int atmel_hlcdc_dc_drm_suspend(struct device *dev) | 800 | static int atmel_hlcdc_dc_drm_suspend(struct device *dev) |
| 811 | { | 801 | { |
| 812 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 802 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
| 813 | struct drm_crtc *crtc; | 803 | struct atmel_hlcdc_dc *dc = drm_dev->dev_private; |
| 804 | struct regmap *regmap = dc->hlcdc->regmap; | ||
| 805 | struct drm_atomic_state *state; | ||
| 806 | |||
| 807 | state = drm_atomic_helper_suspend(drm_dev); | ||
| 808 | if (IS_ERR(state)) | ||
| 809 | return PTR_ERR(state); | ||
| 814 | 810 | ||
| 815 | if (pm_runtime_suspended(dev)) | 811 | dc->suspend.state = state; |
| 816 | return 0; | 812 | |
| 813 | regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr); | ||
| 814 | regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr); | ||
| 815 | clk_disable_unprepare(dc->hlcdc->periph_clk); | ||
| 817 | 816 | ||
| 818 | drm_modeset_lock_all(drm_dev); | ||
| 819 | list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) | ||
| 820 | atmel_hlcdc_crtc_suspend(crtc); | ||
| 821 | drm_modeset_unlock_all(drm_dev); | ||
| 822 | return 0; | 817 | return 0; |
| 823 | } | 818 | } |
| 824 | 819 | ||
| 825 | static int atmel_hlcdc_dc_drm_resume(struct device *dev) | 820 | static int atmel_hlcdc_dc_drm_resume(struct device *dev) |
| 826 | { | 821 | { |
| 827 | struct drm_device *drm_dev = dev_get_drvdata(dev); | 822 | struct drm_device *drm_dev = dev_get_drvdata(dev); |
| 828 | struct drm_crtc *crtc; | 823 | struct atmel_hlcdc_dc *dc = drm_dev->dev_private; |
| 829 | 824 | ||
| 830 | if (pm_runtime_suspended(dev)) | 825 | clk_prepare_enable(dc->hlcdc->periph_clk); |
| 831 | return 0; | 826 | regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr); |
| 832 | 827 | ||
| 833 | drm_modeset_lock_all(drm_dev); | 828 | return drm_atomic_helper_resume(drm_dev, dc->suspend.state); |
| 834 | list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) | ||
| 835 | atmel_hlcdc_crtc_resume(crtc); | ||
| 836 | drm_modeset_unlock_all(drm_dev); | ||
| 837 | return 0; | ||
| 838 | } | 829 | } |
| 839 | #endif | 830 | #endif |
| 840 | 831 | ||
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h index da7f25a59be5..433641b6e23b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h | |||
| @@ -358,6 +358,7 @@ struct atmel_hlcdc_plane_properties { | |||
| 358 | * @planes: instantiated planes | 358 | * @planes: instantiated planes |
| 359 | * @layers: active HLCDC layers | 359 | * @layers: active HLCDC layers |
| 360 | * @wq: display controller workqueue | 360 | * @wq: display controller workqueue |
| 361 | * @suspend: used to store the HLCDC state when entering suspend | ||
| 361 | * @commit: used for async commit handling | 362 | * @commit: used for async commit handling |
| 362 | */ | 363 | */ |
| 363 | struct atmel_hlcdc_dc { | 364 | struct atmel_hlcdc_dc { |
| @@ -369,6 +370,10 @@ struct atmel_hlcdc_dc { | |||
| 369 | struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS]; | 370 | struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS]; |
| 370 | struct workqueue_struct *wq; | 371 | struct workqueue_struct *wq; |
| 371 | struct { | 372 | struct { |
| 373 | u32 imr; | ||
| 374 | struct drm_atomic_state *state; | ||
| 375 | } suspend; | ||
| 376 | struct { | ||
| 372 | wait_queue_head_t wait; | 377 | wait_queue_head_t wait; |
| 373 | bool pending; | 378 | bool pending; |
| 374 | } commit; | 379 | } commit; |
| @@ -428,9 +433,6 @@ int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state); | |||
| 428 | 433 | ||
| 429 | void atmel_hlcdc_crtc_irq(struct drm_crtc *c); | 434 | void atmel_hlcdc_crtc_irq(struct drm_crtc *c); |
| 430 | 435 | ||
| 431 | void atmel_hlcdc_crtc_suspend(struct drm_crtc *crtc); | ||
| 432 | void atmel_hlcdc_crtc_resume(struct drm_crtc *crtc); | ||
| 433 | |||
| 434 | int atmel_hlcdc_crtc_create(struct drm_device *dev); | 436 | int atmel_hlcdc_crtc_create(struct drm_device *dev); |
| 435 | 437 | ||
| 436 | int atmel_hlcdc_create_outputs(struct drm_device *dev); | 438 | int atmel_hlcdc_create_outputs(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index a11debaad626..471bd588550b 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c | |||
| @@ -132,6 +132,7 @@ static int bochsfb_create(struct drm_fb_helper *helper, | |||
| 132 | info->fix.smem_start = 0; | 132 | info->fix.smem_start = 0; |
| 133 | info->fix.smem_len = size; | 133 | info->fix.smem_len = size; |
| 134 | 134 | ||
| 135 | bochs->fb.initialized = true; | ||
| 135 | return 0; | 136 | return 0; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| @@ -148,7 +149,6 @@ static int bochs_fbdev_destroy(struct bochs_device *bochs) | |||
| 148 | gfb->obj = NULL; | 149 | gfb->obj = NULL; |
| 149 | } | 150 | } |
| 150 | 151 | ||
| 151 | drm_fb_helper_fini(&bochs->fb.helper); | ||
| 152 | drm_framebuffer_unregister_private(&gfb->base); | 152 | drm_framebuffer_unregister_private(&gfb->base); |
| 153 | drm_framebuffer_cleanup(&gfb->base); | 153 | drm_framebuffer_cleanup(&gfb->base); |
| 154 | 154 | ||
| @@ -180,7 +180,6 @@ int bochs_fbdev_init(struct bochs_device *bochs) | |||
| 180 | if (ret) | 180 | if (ret) |
| 181 | goto fini; | 181 | goto fini; |
| 182 | 182 | ||
| 183 | bochs->fb.initialized = true; | ||
| 184 | return 0; | 183 | return 0; |
| 185 | 184 | ||
| 186 | fini: | 185 | fini: |
| @@ -190,9 +189,9 @@ fini: | |||
| 190 | 189 | ||
| 191 | void bochs_fbdev_fini(struct bochs_device *bochs) | 190 | void bochs_fbdev_fini(struct bochs_device *bochs) |
| 192 | { | 191 | { |
| 193 | if (!bochs->fb.initialized) | 192 | if (bochs->fb.initialized) |
| 194 | return; | 193 | bochs_fbdev_destroy(bochs); |
| 195 | 194 | ||
| 196 | bochs_fbdev_destroy(bochs); | 195 | drm_fb_helper_fini(&bochs->fb.helper); |
| 197 | bochs->fb.initialized = false; | 196 | bochs->fb.initialized = false; |
| 198 | } | 197 | } |
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 026a0dce7661..af93f7a20697 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include "dw-hdmi.h" | 33 | #include "dw-hdmi.h" |
| 34 | #include "dw-hdmi-audio.h" | 34 | #include "dw-hdmi-audio.h" |
| 35 | 35 | ||
| 36 | #define DDC_SEGMENT_ADDR 0x30 | ||
| 36 | #define HDMI_EDID_LEN 512 | 37 | #define HDMI_EDID_LEN 512 |
| 37 | 38 | ||
| 38 | #define RGB 0 | 39 | #define RGB 0 |
| @@ -112,6 +113,7 @@ struct dw_hdmi_i2c { | |||
| 112 | 113 | ||
| 113 | u8 slave_reg; | 114 | u8 slave_reg; |
| 114 | bool is_regaddr; | 115 | bool is_regaddr; |
| 116 | bool is_segment; | ||
| 115 | }; | 117 | }; |
| 116 | 118 | ||
| 117 | struct dw_hdmi_phy_data { | 119 | struct dw_hdmi_phy_data { |
| @@ -247,8 +249,12 @@ static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi, | |||
| 247 | reinit_completion(&i2c->cmp); | 249 | reinit_completion(&i2c->cmp); |
| 248 | 250 | ||
| 249 | hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS); | 251 | hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS); |
| 250 | hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ, | 252 | if (i2c->is_segment) |
| 251 | HDMI_I2CM_OPERATION); | 253 | hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT, |
| 254 | HDMI_I2CM_OPERATION); | ||
| 255 | else | ||
| 256 | hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ, | ||
| 257 | HDMI_I2CM_OPERATION); | ||
| 252 | 258 | ||
| 253 | stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); | 259 | stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); |
| 254 | if (!stat) | 260 | if (!stat) |
| @@ -260,6 +266,7 @@ static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi, | |||
| 260 | 266 | ||
| 261 | *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI); | 267 | *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI); |
| 262 | } | 268 | } |
| 269 | i2c->is_segment = false; | ||
| 263 | 270 | ||
| 264 | return 0; | 271 | return 0; |
| 265 | } | 272 | } |
| @@ -309,12 +316,6 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap, | |||
| 309 | dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr); | 316 | dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr); |
| 310 | 317 | ||
| 311 | for (i = 0; i < num; i++) { | 318 | for (i = 0; i < num; i++) { |
| 312 | if (msgs[i].addr != addr) { | ||
| 313 | dev_warn(hdmi->dev, | ||
| 314 | "unsupported transfer, changed slave address\n"); | ||
| 315 | return -EOPNOTSUPP; | ||
| 316 | } | ||
| 317 | |||
| 318 | if (msgs[i].len == 0) { | 319 | if (msgs[i].len == 0) { |
| 319 | dev_dbg(hdmi->dev, | 320 | dev_dbg(hdmi->dev, |
| 320 | "unsupported transfer %d/%d, no data\n", | 321 | "unsupported transfer %d/%d, no data\n", |
| @@ -334,15 +335,24 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap, | |||
| 334 | /* Set slave device register address on transfer */ | 335 | /* Set slave device register address on transfer */ |
| 335 | i2c->is_regaddr = false; | 336 | i2c->is_regaddr = false; |
| 336 | 337 | ||
| 338 | /* Set segment pointer for I2C extended read mode operation */ | ||
| 339 | i2c->is_segment = false; | ||
| 340 | |||
| 337 | for (i = 0; i < num; i++) { | 341 | for (i = 0; i < num; i++) { |
| 338 | dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", | 342 | dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", |
| 339 | i + 1, num, msgs[i].len, msgs[i].flags); | 343 | i + 1, num, msgs[i].len, msgs[i].flags); |
| 340 | 344 | if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) { | |
| 341 | if (msgs[i].flags & I2C_M_RD) | 345 | i2c->is_segment = true; |
| 342 | ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf, msgs[i].len); | 346 | hdmi_writeb(hdmi, DDC_SEGMENT_ADDR, HDMI_I2CM_SEGADDR); |
| 343 | else | 347 | hdmi_writeb(hdmi, *msgs[i].buf, HDMI_I2CM_SEGPTR); |
| 344 | ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf, msgs[i].len); | 348 | } else { |
| 345 | 349 | if (msgs[i].flags & I2C_M_RD) | |
| 350 | ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf, | ||
| 351 | msgs[i].len); | ||
| 352 | else | ||
| 353 | ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf, | ||
| 354 | msgs[i].len); | ||
| 355 | } | ||
| 346 | if (ret < 0) | 356 | if (ret < 0) |
| 347 | break; | 357 | break; |
| 348 | } | 358 | } |
| @@ -1230,6 +1240,58 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) | |||
| 1230 | hdmi_writeb(hdmi, (frame.right_bar >> 8) & 0xff, HDMI_FC_AVISRB1); | 1240 | hdmi_writeb(hdmi, (frame.right_bar >> 8) & 0xff, HDMI_FC_AVISRB1); |
| 1231 | } | 1241 | } |
| 1232 | 1242 | ||
| 1243 | static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, | ||
| 1244 | struct drm_display_mode *mode) | ||
| 1245 | { | ||
| 1246 | struct hdmi_vendor_infoframe frame; | ||
| 1247 | u8 buffer[10]; | ||
| 1248 | ssize_t err; | ||
| 1249 | |||
| 1250 | err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode); | ||
| 1251 | if (err < 0) | ||
| 1252 | /* | ||
| 1253 | * Going into that statement does not means vendor infoframe | ||
| 1254 | * fails. It just informed us that vendor infoframe is not | ||
| 1255 | * needed for the selected mode. Only 4k or stereoscopic 3D | ||
| 1256 | * mode requires vendor infoframe. So just simply return. | ||
| 1257 | */ | ||
| 1258 | return; | ||
| 1259 | |||
| 1260 | err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
| 1261 | if (err < 0) { | ||
| 1262 | dev_err(hdmi->dev, "Failed to pack vendor infoframe: %zd\n", | ||
| 1263 | err); | ||
| 1264 | return; | ||
| 1265 | } | ||
| 1266 | hdmi_mask_writeb(hdmi, 0, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET, | ||
| 1267 | HDMI_FC_DATAUTO0_VSD_MASK); | ||
| 1268 | |||
| 1269 | /* Set the length of HDMI vendor specific InfoFrame payload */ | ||
| 1270 | hdmi_writeb(hdmi, buffer[2], HDMI_FC_VSDSIZE); | ||
| 1271 | |||
| 1272 | /* Set 24bit IEEE Registration Identifier */ | ||
| 1273 | hdmi_writeb(hdmi, buffer[4], HDMI_FC_VSDIEEEID0); | ||
| 1274 | hdmi_writeb(hdmi, buffer[5], HDMI_FC_VSDIEEEID1); | ||
| 1275 | hdmi_writeb(hdmi, buffer[6], HDMI_FC_VSDIEEEID2); | ||
| 1276 | |||
| 1277 | /* Set HDMI_Video_Format and HDMI_VIC/3D_Structure */ | ||
| 1278 | hdmi_writeb(hdmi, buffer[7], HDMI_FC_VSDPAYLOAD0); | ||
| 1279 | hdmi_writeb(hdmi, buffer[8], HDMI_FC_VSDPAYLOAD1); | ||
| 1280 | |||
| 1281 | if (frame.s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) | ||
| 1282 | hdmi_writeb(hdmi, buffer[9], HDMI_FC_VSDPAYLOAD2); | ||
| 1283 | |||
| 1284 | /* Packet frame interpolation */ | ||
| 1285 | hdmi_writeb(hdmi, 1, HDMI_FC_DATAUTO1); | ||
| 1286 | |||
| 1287 | /* Auto packets per frame and line spacing */ | ||
| 1288 | hdmi_writeb(hdmi, 0x11, HDMI_FC_DATAUTO2); | ||
| 1289 | |||
| 1290 | /* Configures the Frame Composer On RDRB mode */ | ||
| 1291 | hdmi_mask_writeb(hdmi, 1, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET, | ||
| 1292 | HDMI_FC_DATAUTO0_VSD_MASK); | ||
| 1293 | } | ||
| 1294 | |||
| 1233 | static void hdmi_av_composer(struct dw_hdmi *hdmi, | 1295 | static void hdmi_av_composer(struct dw_hdmi *hdmi, |
| 1234 | const struct drm_display_mode *mode) | 1296 | const struct drm_display_mode *mode) |
| 1235 | { | 1297 | { |
| @@ -1479,6 +1541,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) | |||
| 1479 | 1541 | ||
| 1480 | /* HDMI Initialization Step F - Configure AVI InfoFrame */ | 1542 | /* HDMI Initialization Step F - Configure AVI InfoFrame */ |
| 1481 | hdmi_config_AVI(hdmi, mode); | 1543 | hdmi_config_AVI(hdmi, mode); |
| 1544 | hdmi_config_vendor_specific_infoframe(hdmi, mode); | ||
| 1482 | } else { | 1545 | } else { |
| 1483 | dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); | 1546 | dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); |
| 1484 | } | 1547 | } |
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h index 325b0b8ae639..c59f87e1483e 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | |||
| @@ -854,6 +854,10 @@ enum { | |||
| 854 | HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, | 854 | HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, |
| 855 | HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1, | 855 | HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1, |
| 856 | 856 | ||
| 857 | /* FC_DATAUTO0 field values */ | ||
| 858 | HDMI_FC_DATAUTO0_VSD_MASK = 0x08, | ||
| 859 | HDMI_FC_DATAUTO0_VSD_OFFSET = 3, | ||
| 860 | |||
| 857 | /* PHY_CONF0 field values */ | 861 | /* PHY_CONF0 field values */ |
| 858 | HDMI_PHY_CONF0_PDZ_MASK = 0x80, | 862 | HDMI_PHY_CONF0_PDZ_MASK = 0x80, |
| 859 | HDMI_PHY_CONF0_PDZ_OFFSET = 7, | 863 | HDMI_PHY_CONF0_PDZ_OFFSET = 7, |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 171d7a02ace0..99144f879a4f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <drm/drm_edid.h> | 37 | #include <drm/drm_edid.h> |
| 38 | #include <drm/drm_encoder.h> | 38 | #include <drm/drm_encoder.h> |
| 39 | #include <drm/drm_displayid.h> | 39 | #include <drm/drm_displayid.h> |
| 40 | #include <drm/drm_scdc_helper.h> | ||
| 40 | 41 | ||
| 41 | #include "drm_crtc_internal.h" | 42 | #include "drm_crtc_internal.h" |
| 42 | 43 | ||
| @@ -3248,6 +3249,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) | |||
| 3248 | return hdmi_id == HDMI_IEEE_OUI; | 3249 | return hdmi_id == HDMI_IEEE_OUI; |
| 3249 | } | 3250 | } |
| 3250 | 3251 | ||
| 3252 | static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) | ||
| 3253 | { | ||
| 3254 | unsigned int oui; | ||
| 3255 | |||
| 3256 | if (cea_db_tag(db) != VENDOR_BLOCK) | ||
| 3257 | return false; | ||
| 3258 | |||
| 3259 | if (cea_db_payload_len(db) < 7) | ||
| 3260 | return false; | ||
| 3261 | |||
| 3262 | oui = db[3] << 16 | db[2] << 8 | db[1]; | ||
| 3263 | |||
| 3264 | return oui == HDMI_FORUM_IEEE_OUI; | ||
| 3265 | } | ||
| 3266 | |||
| 3251 | #define for_each_cea_db(cea, i, start, end) \ | 3267 | #define for_each_cea_db(cea, i, start, end) \ |
| 3252 | for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) | 3268 | for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) |
| 3253 | 3269 | ||
| @@ -3799,6 +3815,48 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode) | |||
| 3799 | } | 3815 | } |
| 3800 | EXPORT_SYMBOL(drm_default_rgb_quant_range); | 3816 | EXPORT_SYMBOL(drm_default_rgb_quant_range); |
| 3801 | 3817 | ||
| 3818 | static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, | ||
| 3819 | const u8 *hf_vsdb) | ||
| 3820 | { | ||
| 3821 | struct drm_display_info *display = &connector->display_info; | ||
| 3822 | struct drm_hdmi_info *hdmi = &display->hdmi; | ||
| 3823 | |||
| 3824 | if (hf_vsdb[6] & 0x80) { | ||
| 3825 | hdmi->scdc.supported = true; | ||
| 3826 | if (hf_vsdb[6] & 0x40) | ||
| 3827 | hdmi->scdc.read_request = true; | ||
| 3828 | } | ||
| 3829 | |||
| 3830 | /* | ||
| 3831 | * All HDMI 2.0 monitors must support scrambling at rates > 340 MHz. | ||
| 3832 | * And as per the spec, three factors confirm this: | ||
| 3833 | * * Availability of a HF-VSDB block in EDID (check) | ||
| 3834 | * * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check) | ||
| 3835 | * * SCDC support available (let's check) | ||
| 3836 | * Lets check it out. | ||
| 3837 | */ | ||
| 3838 | |||
| 3839 | if (hf_vsdb[5]) { | ||
| 3840 | /* max clock is 5000 KHz times block value */ | ||
| 3841 | u32 max_tmds_clock = hf_vsdb[5] * 5000; | ||
| 3842 | struct drm_scdc *scdc = &hdmi->scdc; | ||
| 3843 | |||
| 3844 | if (max_tmds_clock > 340000) { | ||
| 3845 | display->max_tmds_clock = max_tmds_clock; | ||
| 3846 | DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n", | ||
| 3847 | display->max_tmds_clock); | ||
| 3848 | } | ||
| 3849 | |||
| 3850 | if (scdc->supported) { | ||
| 3851 | scdc->scrambling.supported = true; | ||
| 3852 | |||
| 3853 | /* Few sinks support scrambling for cloks < 340M */ | ||
| 3854 | if ((hf_vsdb[6] & 0x8)) | ||
| 3855 | scdc->scrambling.low_rates = true; | ||
| 3856 | } | ||
| 3857 | } | ||
| 3858 | } | ||
| 3859 | |||
| 3802 | static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, | 3860 | static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, |
| 3803 | const u8 *hdmi) | 3861 | const u8 *hdmi) |
| 3804 | { | 3862 | { |
| @@ -3913,6 +3971,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, | |||
| 3913 | 3971 | ||
| 3914 | if (cea_db_is_hdmi_vsdb(db)) | 3972 | if (cea_db_is_hdmi_vsdb(db)) |
| 3915 | drm_parse_hdmi_vsdb_video(connector, db); | 3973 | drm_parse_hdmi_vsdb_video(connector, db); |
| 3974 | if (cea_db_is_hdmi_forum_vsdb(db)) | ||
| 3975 | drm_parse_hdmi_forum_vsdb(connector, db); | ||
| 3916 | } | 3976 | } |
| 3917 | } | 3977 | } |
| 3918 | 3978 | ||
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index d9e63d73d3ec..3783b659cd38 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c | |||
| @@ -50,12 +50,14 @@ DEFINE_MUTEX(drm_global_mutex); | |||
| 50 | * | 50 | * |
| 51 | * Drivers must define the file operations structure that forms the DRM | 51 | * Drivers must define the file operations structure that forms the DRM |
| 52 | * userspace API entry point, even though most of those operations are | 52 | * userspace API entry point, even though most of those operations are |
| 53 | * implemented in the DRM core. The mandatory functions are drm_open(), | 53 | * implemented in the DRM core. The resulting &struct file_operations must be |
| 54 | * stored in the &drm_driver.fops field. The mandatory functions are drm_open(), | ||
| 54 | * drm_read(), drm_ioctl() and drm_compat_ioctl() if CONFIG_COMPAT is enabled | 55 | * drm_read(), drm_ioctl() and drm_compat_ioctl() if CONFIG_COMPAT is enabled |
| 55 | * (note that drm_compat_ioctl will be NULL if CONFIG_COMPAT=n). Drivers which | 56 | * Note that drm_compat_ioctl will be NULL if CONFIG_COMPAT=n, so there's no |
| 56 | * implement private ioctls that require 32/64 bit compatibility support must | 57 | * need to sprinkle #ifdef into the code. Drivers which implement private ioctls |
| 57 | * provide their own .compat_ioctl() handler that processes private ioctls and | 58 | * that require 32/64 bit compatibility support must provide their own |
| 58 | * calls drm_compat_ioctl() for core ioctls. | 59 | * &file_operations.compat_ioctl handler that processes private ioctls and calls |
| 60 | * drm_compat_ioctl() for core ioctls. | ||
| 59 | * | 61 | * |
| 60 | * In addition drm_read() and drm_poll() provide support for DRM events. DRM | 62 | * In addition drm_read() and drm_poll() provide support for DRM events. DRM |
| 61 | * events are a generic and extensible means to send asynchronous events to | 63 | * events are a generic and extensible means to send asynchronous events to |
| @@ -63,10 +65,14 @@ DEFINE_MUTEX(drm_global_mutex); | |||
| 63 | * page flip completions by the KMS API. But drivers can also use it for their | 65 | * page flip completions by the KMS API. But drivers can also use it for their |
| 64 | * own needs, e.g. to signal completion of rendering. | 66 | * own needs, e.g. to signal completion of rendering. |
| 65 | * | 67 | * |
| 68 | * For the driver-side event interface see drm_event_reserve_init() and | ||
| 69 | * drm_send_event() as the main starting points. | ||
| 70 | * | ||
| 66 | * The memory mapping implementation will vary depending on how the driver | 71 | * The memory mapping implementation will vary depending on how the driver |
| 67 | * manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() | 72 | * manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() |
| 68 | * function, modern drivers should use one of the provided memory-manager | 73 | * function, modern drivers should use one of the provided memory-manager |
| 69 | * specific implementations. For GEM-based drivers this is drm_gem_mmap(). | 74 | * specific implementations. For GEM-based drivers this is drm_gem_mmap(), and |
| 75 | * for drivers which use the CMA GEM helpers it's drm_gem_cma_mmap(). | ||
| 70 | * | 76 | * |
| 71 | * No other file operations are supported by the DRM userspace API. Overall the | 77 | * No other file operations are supported by the DRM userspace API. Overall the |
| 72 | * following is an example #file_operations structure:: | 78 | * following is an example #file_operations structure:: |
| @@ -82,6 +88,10 @@ DEFINE_MUTEX(drm_global_mutex); | |||
| 82 | * .llseek = no_llseek, | 88 | * .llseek = no_llseek, |
| 83 | * .mmap = drm_gem_mmap, | 89 | * .mmap = drm_gem_mmap, |
| 84 | * }; | 90 | * }; |
| 91 | * | ||
| 92 | * For plain GEM based drivers there is the DEFINE_DRM_GEM_FOPS() macro, and for | ||
| 93 | * CMA based drivers there is the DEFINE_DRM_GEM_CMA_FOPS() macro to make this | ||
| 94 | * simpler. | ||
| 85 | */ | 95 | */ |
| 86 | 96 | ||
| 87 | static int drm_open_helper(struct file *filp, struct drm_minor *minor); | 97 | static int drm_open_helper(struct file *filp, struct drm_minor *minor); |
| @@ -111,9 +121,9 @@ static int drm_setup(struct drm_device * dev) | |||
| 111 | * @inode: device inode | 121 | * @inode: device inode |
| 112 | * @filp: file pointer. | 122 | * @filp: file pointer. |
| 113 | * | 123 | * |
| 114 | * This function must be used by drivers as their .open() #file_operations | 124 | * This function must be used by drivers as their &file_operations.open method. |
| 115 | * method. It looks up the correct DRM device and instantiates all the per-file | 125 | * It looks up the correct DRM device and instantiates all the per-file |
| 116 | * resources for it. | 126 | * resources for it. It also calls the &drm_driver.open driver callback. |
| 117 | * | 127 | * |
| 118 | * RETURNS: | 128 | * RETURNS: |
| 119 | * | 129 | * |
| @@ -298,11 +308,6 @@ static void drm_events_release(struct drm_file *file_priv) | |||
| 298 | spin_unlock_irqrestore(&dev->event_lock, flags); | 308 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 299 | } | 309 | } |
| 300 | 310 | ||
| 301 | /* | ||
| 302 | * drm_legacy_dev_reinit | ||
| 303 | * | ||
| 304 | * Reinitializes a legacy/ums drm device in it's lastclose function. | ||
| 305 | */ | ||
| 306 | static void drm_legacy_dev_reinit(struct drm_device *dev) | 311 | static void drm_legacy_dev_reinit(struct drm_device *dev) |
| 307 | { | 312 | { |
| 308 | if (dev->irq_enabled) | 313 | if (dev->irq_enabled) |
| @@ -327,15 +332,6 @@ static void drm_legacy_dev_reinit(struct drm_device *dev) | |||
| 327 | DRM_DEBUG("lastclose completed\n"); | 332 | DRM_DEBUG("lastclose completed\n"); |
| 328 | } | 333 | } |
| 329 | 334 | ||
| 330 | /* | ||
| 331 | * Take down the DRM device. | ||
| 332 | * | ||
| 333 | * \param dev DRM device structure. | ||
| 334 | * | ||
| 335 | * Frees every resource in \p dev. | ||
| 336 | * | ||
| 337 | * \sa drm_device | ||
| 338 | */ | ||
| 339 | void drm_lastclose(struct drm_device * dev) | 335 | void drm_lastclose(struct drm_device * dev) |
| 340 | { | 336 | { |
| 341 | DRM_DEBUG("\n"); | 337 | DRM_DEBUG("\n"); |
| @@ -353,9 +349,11 @@ void drm_lastclose(struct drm_device * dev) | |||
| 353 | * @inode: device inode | 349 | * @inode: device inode |
| 354 | * @filp: file pointer. | 350 | * @filp: file pointer. |
| 355 | * | 351 | * |
| 356 | * This function must be used by drivers as their .release() #file_operations | 352 | * This function must be used by drivers as their &file_operations.release |
| 357 | * method. It frees any resources associated with the open file, and if this is | 353 | * method. It frees any resources associated with the open file, and calls the |
| 358 | * the last open file for the DRM device also proceeds to call drm_lastclose(). | 354 | * &drm_driver.preclose and &drm_driver.lastclose driver callbacks. If this is |
| 355 | * the last open file for the DRM device also proceeds to call the | ||
| 356 | * &drm_driver.lastclose driver callback. | ||
| 359 | * | 357 | * |
| 360 | * RETURNS: | 358 | * RETURNS: |
| 361 | * | 359 | * |
| @@ -443,13 +441,13 @@ EXPORT_SYMBOL(drm_release); | |||
| 443 | * @count: count in bytes to read | 441 | * @count: count in bytes to read |
| 444 | * @offset: offset to read | 442 | * @offset: offset to read |
| 445 | * | 443 | * |
| 446 | * This function must be used by drivers as their .read() #file_operations | 444 | * This function must be used by drivers as their &file_operations.read |
| 447 | * method iff they use DRM events for asynchronous signalling to userspace. | 445 | * method iff they use DRM events for asynchronous signalling to userspace. |
| 448 | * Since events are used by the KMS API for vblank and page flip completion this | 446 | * Since events are used by the KMS API for vblank and page flip completion this |
| 449 | * means all modern display drivers must use it. | 447 | * means all modern display drivers must use it. |
| 450 | * | 448 | * |
| 451 | * @offset is ignore, DRM events are read like a pipe. Therefore drivers also | 449 | * @offset is ignored, DRM events are read like a pipe. Therefore drivers also |
| 452 | * must set the .llseek() #file_operation to no_llseek(). Polling support is | 450 | * must set the &file_operation.llseek to no_llseek(). Polling support is |
| 453 | * provided by drm_poll(). | 451 | * provided by drm_poll(). |
| 454 | * | 452 | * |
| 455 | * This function will only ever read a full event. Therefore userspace must | 453 | * This function will only ever read a full event. Therefore userspace must |
| @@ -537,10 +535,10 @@ EXPORT_SYMBOL(drm_read); | |||
| 537 | * @filp: file pointer | 535 | * @filp: file pointer |
| 538 | * @wait: poll waiter table | 536 | * @wait: poll waiter table |
| 539 | * | 537 | * |
| 540 | * This function must be used by drivers as their .read() #file_operations | 538 | * This function must be used by drivers as their &file_operations.read method |
| 541 | * method iff they use DRM events for asynchronous signalling to userspace. | 539 | * iff they use DRM events for asynchronous signalling to userspace. Since |
| 542 | * Since events are used by the KMS API for vblank and page flip completion this | 540 | * events are used by the KMS API for vblank and page flip completion this means |
| 543 | * means all modern display drivers must use it. | 541 | * all modern display drivers must use it. |
| 544 | * | 542 | * |
| 545 | * See also drm_read(). | 543 | * See also drm_read(). |
| 546 | * | 544 | * |
| @@ -650,7 +648,8 @@ EXPORT_SYMBOL(drm_event_reserve_init); | |||
| 650 | * @p: tracking structure for the pending event | 648 | * @p: tracking structure for the pending event |
| 651 | * | 649 | * |
| 652 | * This function frees the event @p initialized with drm_event_reserve_init() | 650 | * This function frees the event @p initialized with drm_event_reserve_init() |
| 653 | * and releases any allocated space. | 651 | * and releases any allocated space. It is used to cancel an event when the |
| 652 | * nonblocking operation could not be submitted and needed to be aborted. | ||
| 654 | */ | 653 | */ |
| 655 | void drm_event_cancel_free(struct drm_device *dev, | 654 | void drm_event_cancel_free(struct drm_device *dev, |
| 656 | struct drm_pending_event *p) | 655 | struct drm_pending_event *p) |
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index bb968e76779b..bc28e7575254 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c | |||
| @@ -338,6 +338,9 @@ static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj, | |||
| 338 | * as their ->mmap() handler in the DRM device file's file_operations | 338 | * as their ->mmap() handler in the DRM device file's file_operations |
| 339 | * structure. | 339 | * structure. |
| 340 | * | 340 | * |
| 341 | * Instead of directly referencing this function, drivers should use the | ||
| 342 | * DEFINE_DRM_GEM_CMA_FOPS().macro. | ||
| 343 | * | ||
| 341 | * Returns: | 344 | * Returns: |
| 342 | * 0 on success or a negative error code on failure. | 345 | * 0 on success or a negative error code on failure. |
| 343 | */ | 346 | */ |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 1906723af389..53a526c7b24d 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
| @@ -978,7 +978,7 @@ static void send_vblank_event(struct drm_device *dev, | |||
| 978 | e->event.tv_sec = now->tv_sec; | 978 | e->event.tv_sec = now->tv_sec; |
| 979 | e->event.tv_usec = now->tv_usec; | 979 | e->event.tv_usec = now->tv_usec; |
| 980 | 980 | ||
| 981 | trace_drm_vblank_event_delivered(e->base.pid, e->pipe, | 981 | trace_drm_vblank_event_delivered(e->base.file_priv, e->pipe, |
| 982 | e->event.sequence); | 982 | e->event.sequence); |
| 983 | 983 | ||
| 984 | drm_send_event_locked(dev, &e->base); | 984 | drm_send_event_locked(dev, &e->base); |
| @@ -1198,9 +1198,9 @@ static void drm_vblank_put(struct drm_device *dev, unsigned int pipe) | |||
| 1198 | if (atomic_dec_and_test(&vblank->refcount)) { | 1198 | if (atomic_dec_and_test(&vblank->refcount)) { |
| 1199 | if (drm_vblank_offdelay == 0) | 1199 | if (drm_vblank_offdelay == 0) |
| 1200 | return; | 1200 | return; |
| 1201 | else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) | 1201 | else if (drm_vblank_offdelay < 0) |
| 1202 | vblank_disable_fn((unsigned long)vblank); | 1202 | vblank_disable_fn((unsigned long)vblank); |
| 1203 | else | 1203 | else if (!dev->vblank_disable_immediate) |
| 1204 | mod_timer(&vblank->disable_timer, | 1204 | mod_timer(&vblank->disable_timer, |
| 1205 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); | 1205 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); |
| 1206 | } | 1206 | } |
| @@ -1505,7 +1505,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, | |||
| 1505 | } | 1505 | } |
| 1506 | 1506 | ||
| 1507 | e->pipe = pipe; | 1507 | e->pipe = pipe; |
| 1508 | e->base.pid = current->pid; | ||
| 1509 | e->event.base.type = DRM_EVENT_VBLANK; | 1508 | e->event.base.type = DRM_EVENT_VBLANK; |
| 1510 | e->event.base.length = sizeof(e->event); | 1509 | e->event.base.length = sizeof(e->event); |
| 1511 | e->event.user_data = vblwait->request.signal; | 1510 | e->event.user_data = vblwait->request.signal; |
| @@ -1534,7 +1533,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, | |||
| 1534 | DRM_DEBUG("event on vblank count %u, current %u, crtc %u\n", | 1533 | DRM_DEBUG("event on vblank count %u, current %u, crtc %u\n", |
| 1535 | vblwait->request.sequence, seq, pipe); | 1534 | vblwait->request.sequence, seq, pipe); |
| 1536 | 1535 | ||
| 1537 | trace_drm_vblank_event_queued(current->pid, pipe, | 1536 | trace_drm_vblank_event_queued(file_priv, pipe, |
| 1538 | vblwait->request.sequence); | 1537 | vblwait->request.sequence); |
| 1539 | 1538 | ||
| 1540 | e->event.sequence = vblwait->request.sequence; | 1539 | e->event.sequence = vblwait->request.sequence; |
| @@ -1611,7 +1610,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 1611 | 1610 | ||
| 1612 | ret = drm_vblank_get(dev, pipe); | 1611 | ret = drm_vblank_get(dev, pipe); |
| 1613 | if (ret) { | 1612 | if (ret) { |
| 1614 | DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); | 1613 | DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); |
| 1615 | return ret; | 1614 | return ret; |
| 1616 | } | 1615 | } |
| 1617 | seq = drm_vblank_count(dev, pipe); | 1616 | seq = drm_vblank_count(dev, pipe); |
| @@ -1639,13 +1638,15 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 1639 | return drm_queue_vblank_event(dev, pipe, vblwait, file_priv); | 1638 | return drm_queue_vblank_event(dev, pipe, vblwait, file_priv); |
| 1640 | } | 1639 | } |
| 1641 | 1640 | ||
| 1642 | DRM_DEBUG("waiting on vblank count %u, crtc %u\n", | 1641 | if (vblwait->request.sequence != seq) { |
| 1643 | vblwait->request.sequence, pipe); | 1642 | DRM_DEBUG("waiting on vblank count %u, crtc %u\n", |
| 1644 | DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, | 1643 | vblwait->request.sequence, pipe); |
| 1645 | (((drm_vblank_count(dev, pipe) - | 1644 | DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, |
| 1646 | vblwait->request.sequence) <= (1 << 23)) || | 1645 | (((drm_vblank_count(dev, pipe) - |
| 1647 | !vblank->enabled || | 1646 | vblwait->request.sequence) <= (1 << 23)) || |
| 1648 | !dev->irq_enabled)); | 1647 | !vblank->enabled || |
| 1648 | !dev->irq_enabled)); | ||
| 1649 | } | ||
| 1649 | 1650 | ||
| 1650 | if (ret != -EINTR) { | 1651 | if (ret != -EINTR) { |
| 1651 | struct timeval now; | 1652 | struct timeval now; |
| @@ -1654,10 +1655,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 1654 | vblwait->reply.tval_sec = now.tv_sec; | 1655 | vblwait->reply.tval_sec = now.tv_sec; |
| 1655 | vblwait->reply.tval_usec = now.tv_usec; | 1656 | vblwait->reply.tval_usec = now.tv_usec; |
| 1656 | 1657 | ||
| 1657 | DRM_DEBUG("returning %u to client\n", | 1658 | DRM_DEBUG("crtc %d returning %u to client\n", |
| 1658 | vblwait->reply.sequence); | 1659 | pipe, vblwait->reply.sequence); |
| 1659 | } else { | 1660 | } else { |
| 1660 | DRM_DEBUG("vblank wait interrupted by signal\n"); | 1661 | DRM_DEBUG("crtc %d vblank wait interrupted by signal\n", pipe); |
| 1661 | } | 1662 | } |
| 1662 | 1663 | ||
| 1663 | done: | 1664 | done: |
| @@ -1735,6 +1736,16 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) | |||
| 1735 | wake_up(&vblank->queue); | 1736 | wake_up(&vblank->queue); |
| 1736 | drm_handle_vblank_events(dev, pipe); | 1737 | drm_handle_vblank_events(dev, pipe); |
| 1737 | 1738 | ||
| 1739 | /* With instant-off, we defer disabling the interrupt until after | ||
| 1740 | * we finish processing the following vblank. The disable has to | ||
| 1741 | * be last (after drm_handle_vblank_events) so that the timestamp | ||
| 1742 | * is always accurate. | ||
| 1743 | */ | ||
| 1744 | if (dev->vblank_disable_immediate && | ||
| 1745 | drm_vblank_offdelay > 0 && | ||
| 1746 | !atomic_read(&vblank->refcount)) | ||
| 1747 | vblank_disable_fn((unsigned long)vblank); | ||
| 1748 | |||
| 1738 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | 1749 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
| 1739 | 1750 | ||
| 1740 | return true; | 1751 | return true; |
diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c new file mode 100644 index 000000000000..3cd96a95736d --- /dev/null +++ b/drivers/gpu/drm/drm_scdc_helper.c | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2015 NVIDIA Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the | ||
| 12 | * next paragraph) shall be included in all copies or substantial portions | ||
| 13 | * of the Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | |||
| 27 | #include <drm/drm_scdc_helper.h> | ||
| 28 | #include <drm/drmP.h> | ||
| 29 | |||
| 30 | /** | ||
| 31 | * DOC: scdc helpers | ||
| 32 | * | ||
| 33 | * Status and Control Data Channel (SCDC) is a mechanism introduced by the | ||
| 34 | * HDMI 2.0 specification. It is a point-to-point protocol that allows the | ||
| 35 | * HDMI source and HDMI sink to exchange data. The same I2C interface that | ||
| 36 | * is used to access EDID serves as the transport mechanism for SCDC. | ||
| 37 | */ | ||
| 38 | |||
| 39 | #define SCDC_I2C_SLAVE_ADDRESS 0x54 | ||
| 40 | |||
| 41 | /** | ||
| 42 | * drm_scdc_read - read a block of data from SCDC | ||
| 43 | * @adapter: I2C controller | ||
| 44 | * @offset: start offset of block to read | ||
| 45 | * @buffer: return location for the block to read | ||
| 46 | * @size: size of the block to read | ||
| 47 | * | ||
| 48 | * Reads a block of data from SCDC, starting at a given offset. | ||
| 49 | * | ||
| 50 | * Returns: | ||
| 51 | * 0 on success, negative error code on failure. | ||
| 52 | */ | ||
| 53 | ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer, | ||
| 54 | size_t size) | ||
| 55 | { | ||
| 56 | int ret; | ||
| 57 | struct i2c_msg msgs[2] = { | ||
| 58 | { | ||
| 59 | .addr = SCDC_I2C_SLAVE_ADDRESS, | ||
| 60 | .flags = 0, | ||
| 61 | .len = 1, | ||
| 62 | .buf = &offset, | ||
| 63 | }, { | ||
| 64 | .addr = SCDC_I2C_SLAVE_ADDRESS, | ||
| 65 | .flags = I2C_M_RD, | ||
| 66 | .len = size, | ||
| 67 | .buf = buffer, | ||
| 68 | } | ||
| 69 | }; | ||
| 70 | |||
| 71 | ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); | ||
| 72 | if (ret < 0) | ||
| 73 | return ret; | ||
| 74 | if (ret != ARRAY_SIZE(msgs)) | ||
| 75 | return -EPROTO; | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | EXPORT_SYMBOL(drm_scdc_read); | ||
| 80 | |||
| 81 | /** | ||
| 82 | * drm_scdc_write - write a block of data to SCDC | ||
| 83 | * @adapter: I2C controller | ||
| 84 | * @offset: start offset of block to write | ||
| 85 | * @buffer: block of data to write | ||
| 86 | * @size: size of the block to write | ||
| 87 | * | ||
| 88 | * Writes a block of data to SCDC, starting at a given offset. | ||
| 89 | * | ||
| 90 | * Returns: | ||
| 91 | * 0 on success, negative error code on failure. | ||
| 92 | */ | ||
| 93 | ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, | ||
| 94 | const void *buffer, size_t size) | ||
| 95 | { | ||
| 96 | struct i2c_msg msg = { | ||
| 97 | .addr = SCDC_I2C_SLAVE_ADDRESS, | ||
| 98 | .flags = 0, | ||
| 99 | .len = 1 + size, | ||
| 100 | .buf = NULL, | ||
| 101 | }; | ||
| 102 | void *data; | ||
| 103 | int err; | ||
| 104 | |||
| 105 | data = kmalloc(1 + size, GFP_TEMPORARY); | ||
| 106 | if (!data) | ||
| 107 | return -ENOMEM; | ||
| 108 | |||
| 109 | msg.buf = data; | ||
| 110 | |||
| 111 | memcpy(data, &offset, sizeof(offset)); | ||
| 112 | memcpy(data + 1, buffer, size); | ||
| 113 | |||
| 114 | err = i2c_transfer(adapter, &msg, 1); | ||
| 115 | |||
| 116 | kfree(data); | ||
| 117 | |||
| 118 | if (err < 0) | ||
| 119 | return err; | ||
| 120 | if (err != 1) | ||
| 121 | return -EPROTO; | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | EXPORT_SYMBOL(drm_scdc_write); | ||
| 126 | |||
| 127 | /** | ||
| 128 | * drm_scdc_check_scrambling_status - what is status of scrambling? | ||
| 129 | * @adapter: I2C adapter for DDC channel | ||
| 130 | * | ||
| 131 | * Reads the scrambler status over SCDC, and checks the | ||
| 132 | * scrambling status. | ||
| 133 | * | ||
| 134 | * Returns: | ||
| 135 | * True if the scrambling is enabled, false otherwise. | ||
| 136 | */ | ||
| 137 | |||
| 138 | bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter) | ||
| 139 | { | ||
| 140 | u8 status; | ||
| 141 | int ret; | ||
| 142 | |||
| 143 | ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status); | ||
| 144 | if (ret < 0) { | ||
| 145 | DRM_ERROR("Failed to read scrambling status, error %d\n", ret); | ||
| 146 | return false; | ||
| 147 | } | ||
| 148 | |||
| 149 | return status & SCDC_SCRAMBLING_STATUS; | ||
| 150 | } | ||
| 151 | EXPORT_SYMBOL(drm_scdc_get_scrambling_status); | ||
| 152 | |||
| 153 | /** | ||
| 154 | * drm_scdc_set_scrambling - enable scrambling | ||
| 155 | * @adapter: I2C adapter for DDC channel | ||
| 156 | * @enable: bool to indicate if scrambling is to be enabled/disabled | ||
| 157 | * | ||
| 158 | * Writes the TMDS config register over SCDC channel, and: | ||
| 159 | * enables scrambling when enable = 1 | ||
| 160 | * disables scrambling when enable = 0 | ||
| 161 | * | ||
| 162 | * Returns: | ||
| 163 | * True if scrambling is set/reset successfully, false otherwise. | ||
| 164 | */ | ||
| 165 | |||
| 166 | bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable) | ||
| 167 | { | ||
| 168 | u8 config; | ||
| 169 | int ret; | ||
| 170 | |||
| 171 | ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); | ||
| 172 | if (ret < 0) { | ||
| 173 | DRM_ERROR("Failed to read tmds config, err=%d\n", ret); | ||
| 174 | return false; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (enable) | ||
| 178 | config |= SCDC_SCRAMBLING_ENABLE; | ||
| 179 | else | ||
| 180 | config &= ~SCDC_SCRAMBLING_ENABLE; | ||
| 181 | |||
| 182 | ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); | ||
| 183 | if (ret < 0) { | ||
| 184 | DRM_ERROR("Failed to enable scrambling, error %d\n", ret); | ||
| 185 | return false; | ||
| 186 | } | ||
| 187 | |||
| 188 | return true; | ||
| 189 | } | ||
| 190 | EXPORT_SYMBOL(drm_scdc_set_scrambling); | ||
| 191 | |||
| 192 | /** | ||
| 193 | * drm_scdc_set_high_tmds_clock_ratio - set TMDS clock ratio | ||
| 194 | * @adapter: I2C adapter for DDC channel | ||
| 195 | * @set: ret or reset the high clock ratio | ||
| 196 | * | ||
| 197 | * TMDS clock ratio calculations go like this: | ||
| 198 | * TMDS character = 10 bit TMDS encoded value | ||
| 199 | * TMDS character rate = The rate at which TMDS characters are transmitted(Mcsc) | ||
| 200 | * TMDS bit rate = 10x TMDS character rate | ||
| 201 | * As per the spec: | ||
| 202 | * TMDS clock rate for pixel clock < 340 MHz = 1x the character rate | ||
| 203 | * = 1/10 pixel clock rate | ||
| 204 | * TMDS clock rate for pixel clock > 340 MHz = 0.25x the character rate | ||
| 205 | * = 1/40 pixel clock rate | ||
| 206 | * | ||
| 207 | * Writes to the TMDS config register over SCDC channel, and: | ||
| 208 | * sets TMDS clock ratio to 1/40 when set = 1 | ||
| 209 | * sets TMDS clock ratio to 1/10 when set = 0 | ||
| 210 | * | ||
| 211 | * Returns: | ||
| 212 | * True if write is successful, false otherwise. | ||
| 213 | */ | ||
| 214 | bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set) | ||
| 215 | { | ||
| 216 | u8 config; | ||
| 217 | int ret; | ||
| 218 | |||
| 219 | ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); | ||
| 220 | if (ret < 0) { | ||
| 221 | DRM_ERROR("Failed to read tmds config, err=%d\n", ret); | ||
| 222 | return false; | ||
| 223 | } | ||
| 224 | |||
| 225 | if (set) | ||
| 226 | config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40; | ||
| 227 | else | ||
| 228 | config &= ~SCDC_TMDS_BIT_CLOCK_RATIO_BY_40; | ||
| 229 | |||
| 230 | ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config); | ||
| 231 | if (ret < 0) { | ||
| 232 | DRM_ERROR("Failed to set TMDS clock ratio, error %d\n", ret); | ||
| 233 | return false; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* | ||
| 237 | * The spec says that a source should wait minimum 1ms and maximum | ||
| 238 | * 100ms after writing the TMDS config for clock ratio. Lets allow a | ||
| 239 | * wait of upto 2ms here. | ||
| 240 | */ | ||
| 241 | usleep_range(1000, 2000); | ||
| 242 | return true; | ||
| 243 | } | ||
| 244 | EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio); | ||
diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h index ce3c42813fbb..14c5a777682e 100644 --- a/drivers/gpu/drm/drm_trace.h +++ b/drivers/gpu/drm/drm_trace.h | |||
| @@ -24,36 +24,36 @@ TRACE_EVENT(drm_vblank_event, | |||
| 24 | ); | 24 | ); |
| 25 | 25 | ||
| 26 | TRACE_EVENT(drm_vblank_event_queued, | 26 | TRACE_EVENT(drm_vblank_event_queued, |
| 27 | TP_PROTO(pid_t pid, int crtc, unsigned int seq), | 27 | TP_PROTO(struct drm_file *file, int crtc, unsigned int seq), |
| 28 | TP_ARGS(pid, crtc, seq), | 28 | TP_ARGS(file, crtc, seq), |
| 29 | TP_STRUCT__entry( | 29 | TP_STRUCT__entry( |
| 30 | __field(pid_t, pid) | 30 | __field(struct drm_file *, file) |
| 31 | __field(int, crtc) | 31 | __field(int, crtc) |
| 32 | __field(unsigned int, seq) | 32 | __field(unsigned int, seq) |
| 33 | ), | 33 | ), |
| 34 | TP_fast_assign( | 34 | TP_fast_assign( |
| 35 | __entry->pid = pid; | 35 | __entry->file = file; |
| 36 | __entry->crtc = crtc; | 36 | __entry->crtc = crtc; |
| 37 | __entry->seq = seq; | 37 | __entry->seq = seq; |
| 38 | ), | 38 | ), |
| 39 | TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \ | 39 | TP_printk("file=%p, crtc=%d, seq=%u", __entry->file, __entry->crtc, \ |
| 40 | __entry->seq) | 40 | __entry->seq) |
| 41 | ); | 41 | ); |
| 42 | 42 | ||
| 43 | TRACE_EVENT(drm_vblank_event_delivered, | 43 | TRACE_EVENT(drm_vblank_event_delivered, |
| 44 | TP_PROTO(pid_t pid, int crtc, unsigned int seq), | 44 | TP_PROTO(struct drm_file *file, int crtc, unsigned int seq), |
| 45 | TP_ARGS(pid, crtc, seq), | 45 | TP_ARGS(file, crtc, seq), |
| 46 | TP_STRUCT__entry( | 46 | TP_STRUCT__entry( |
| 47 | __field(pid_t, pid) | 47 | __field(struct drm_file *, file) |
| 48 | __field(int, crtc) | 48 | __field(int, crtc) |
| 49 | __field(unsigned int, seq) | 49 | __field(unsigned int, seq) |
| 50 | ), | 50 | ), |
| 51 | TP_fast_assign( | 51 | TP_fast_assign( |
| 52 | __entry->pid = pid; | 52 | __entry->file = file; |
| 53 | __entry->crtc = crtc; | 53 | __entry->crtc = crtc; |
| 54 | __entry->seq = seq; | 54 | __entry->seq = seq; |
| 55 | ), | 55 | ), |
| 56 | TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \ | 56 | TP_printk("file=%p, crtc=%d, seq=%u", __entry->file, __entry->crtc, \ |
| 57 | __entry->seq) | 57 | __entry->seq) |
| 58 | ); | 58 | ); |
| 59 | 59 | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index b5391c124c64..6e00f4b267f1 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | |||
| @@ -161,17 +161,7 @@ static void fsl_dcu_drm_lastclose(struct drm_device *dev) | |||
| 161 | drm_fbdev_cma_restore_mode(fsl_dev->fbdev); | 161 | drm_fbdev_cma_restore_mode(fsl_dev->fbdev); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static const struct file_operations fsl_dcu_drm_fops = { | 164 | DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops); |
| 165 | .owner = THIS_MODULE, | ||
| 166 | .open = drm_open, | ||
| 167 | .release = drm_release, | ||
| 168 | .unlocked_ioctl = drm_ioctl, | ||
| 169 | .compat_ioctl = drm_compat_ioctl, | ||
| 170 | .poll = drm_poll, | ||
| 171 | .read = drm_read, | ||
| 172 | .llseek = no_llseek, | ||
| 173 | .mmap = drm_gem_cma_mmap, | ||
| 174 | }; | ||
| 175 | 165 | ||
| 176 | static struct drm_driver fsl_dcu_drm_driver = { | 166 | static struct drm_driver fsl_dcu_drm_driver = { |
| 177 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | 167 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 7ec93aec7e88..df4f50713e54 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | |||
| @@ -146,17 +146,7 @@ err_mode_config_cleanup: | |||
| 146 | return ret; | 146 | return ret; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | static const struct file_operations kirin_drm_fops = { | 149 | DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops); |
| 150 | .owner = THIS_MODULE, | ||
| 151 | .open = drm_open, | ||
| 152 | .release = drm_release, | ||
| 153 | .unlocked_ioctl = drm_ioctl, | ||
| 154 | .compat_ioctl = drm_compat_ioctl, | ||
| 155 | .poll = drm_poll, | ||
| 156 | .read = drm_read, | ||
| 157 | .llseek = no_llseek, | ||
| 158 | .mmap = drm_gem_cma_mmap, | ||
| 159 | }; | ||
| 160 | 150 | ||
| 161 | static int kirin_gem_cma_dumb_create(struct drm_file *file, | 151 | static int kirin_gem_cma_dumb_create(struct drm_file *file, |
| 162 | struct drm_device *dev, | 152 | struct drm_device *dev, |
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index b6dbcd17f1e6..1888bf3920fc 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c | |||
| @@ -53,16 +53,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm) | |||
| 53 | drm_fbdev_cma_restore_mode(imxdrm->fbhelper); | 53 | drm_fbdev_cma_restore_mode(imxdrm->fbhelper); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static const struct file_operations imx_drm_driver_fops = { | 56 | DEFINE_DRM_GEM_CMA_FOPS(imx_drm_driver_fops); |
| 57 | .owner = THIS_MODULE, | ||
| 58 | .open = drm_open, | ||
| 59 | .release = drm_release, | ||
| 60 | .unlocked_ioctl = drm_ioctl, | ||
| 61 | .mmap = drm_gem_cma_mmap, | ||
| 62 | .poll = drm_poll, | ||
| 63 | .read = drm_read, | ||
| 64 | .llseek = noop_llseek, | ||
| 65 | }; | ||
| 66 | 57 | ||
| 67 | void imx_drm_connector_destroy(struct drm_connector *connector) | 58 | void imx_drm_connector_destroy(struct drm_connector *connector) |
| 68 | { | 59 | { |
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 8d17d0e59cbe..bc562a07847b 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c | |||
| @@ -91,19 +91,7 @@ static irqreturn_t meson_irq(int irq, void *arg) | |||
| 91 | return IRQ_HANDLED; | 91 | return IRQ_HANDLED; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | static const struct file_operations fops = { | 94 | DEFINE_DRM_GEM_CMA_FOPS(fops); |
| 95 | .owner = THIS_MODULE, | ||
| 96 | .open = drm_open, | ||
| 97 | .release = drm_release, | ||
| 98 | .unlocked_ioctl = drm_ioctl, | ||
| 99 | #ifdef CONFIG_COMPAT | ||
| 100 | .compat_ioctl = drm_compat_ioctl, | ||
| 101 | #endif | ||
| 102 | .poll = drm_poll, | ||
| 103 | .read = drm_read, | ||
| 104 | .llseek = no_llseek, | ||
| 105 | .mmap = drm_gem_cma_mmap, | ||
| 106 | }; | ||
| 107 | 95 | ||
| 108 | static struct drm_driver meson_driver = { | 96 | static struct drm_driver meson_driver = { |
| 109 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | | 97 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | |
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b51fb0d70f43..b885c3d5ae4d 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
| @@ -311,6 +311,8 @@ void msm_perf_debugfs_cleanup(struct msm_drm_private *priv); | |||
| 311 | #else | 311 | #else |
| 312 | static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; } | 312 | static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; } |
| 313 | static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {} | 313 | static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {} |
| 314 | static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {} | ||
| 315 | static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {} | ||
| 314 | #endif | 316 | #endif |
| 315 | 317 | ||
| 316 | struct clk *msm_clk_get(struct platform_device *pdev, const char *name); | 318 | struct clk *msm_clk_get(struct platform_device *pdev, const char *name); |
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index a4633ada8429..5ac712325c75 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c | |||
| @@ -319,19 +319,7 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data) | |||
| 319 | return IRQ_HANDLED; | 319 | return IRQ_HANDLED; |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | static const struct file_operations fops = { | 322 | DEFINE_DRM_GEM_CMA_FOPS(fops); |
| 323 | .owner = THIS_MODULE, | ||
| 324 | .open = drm_open, | ||
| 325 | .release = drm_release, | ||
| 326 | .unlocked_ioctl = drm_ioctl, | ||
| 327 | #ifdef CONFIG_COMPAT | ||
| 328 | .compat_ioctl = drm_compat_ioctl, | ||
| 329 | #endif | ||
| 330 | .poll = drm_poll, | ||
| 331 | .read = drm_read, | ||
| 332 | .llseek = noop_llseek, | ||
| 333 | .mmap = drm_gem_cma_mmap, | ||
| 334 | }; | ||
| 335 | 323 | ||
| 336 | static struct drm_driver mxsfb_driver = { | 324 | static struct drm_driver mxsfb_driver = { |
| 337 | .driver_features = DRIVER_GEM | DRIVER_MODESET | | 325 | .driver_features = DRIVER_GEM | DRIVER_MODESET | |
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c index afbdbed1a690..9dc10b17ad34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_usif.c +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c | |||
| @@ -211,7 +211,6 @@ usif_notify_get(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) | |||
| 211 | goto done; | 211 | goto done; |
| 212 | ntfy->p->base.event = &ntfy->p->e.base; | 212 | ntfy->p->base.event = &ntfy->p->e.base; |
| 213 | ntfy->p->base.file_priv = f; | 213 | ntfy->p->base.file_priv = f; |
| 214 | ntfy->p->base.pid = current->pid; | ||
| 215 | ntfy->p->e.base.type = DRM_NOUVEAU_EVENT_NVIF; | 214 | ntfy->p->e.base.type = DRM_NOUVEAU_EVENT_NVIF; |
| 216 | ntfy->p->e.base.length = sizeof(ntfy->p->e.base) + ntfy->reply; | 215 | ntfy->p->e.base.length = sizeof(ntfy->p->e.base) + ntfy->reply; |
| 217 | 216 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 9548bb58d3bc..058340a002c2 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c | |||
| @@ -572,6 +572,8 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane, | |||
| 572 | ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), | 572 | ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), |
| 573 | QXL_RELEASE_CURSOR_CMD, | 573 | QXL_RELEASE_CURSOR_CMD, |
| 574 | &release, NULL); | 574 | &release, NULL); |
| 575 | if (ret) | ||
| 576 | return; | ||
| 575 | 577 | ||
| 576 | cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release); | 578 | cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release); |
| 577 | 579 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 192346d4fb34..62a3b3e32153 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c | |||
| @@ -226,17 +226,7 @@ static void rcar_du_lastclose(struct drm_device *dev) | |||
| 226 | drm_fbdev_cma_restore_mode(rcdu->fbdev); | 226 | drm_fbdev_cma_restore_mode(rcdu->fbdev); |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | static const struct file_operations rcar_du_fops = { | 229 | DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops); |
| 230 | .owner = THIS_MODULE, | ||
| 231 | .open = drm_open, | ||
| 232 | .release = drm_release, | ||
| 233 | .unlocked_ioctl = drm_ioctl, | ||
| 234 | .compat_ioctl = drm_compat_ioctl, | ||
| 235 | .poll = drm_poll, | ||
| 236 | .read = drm_read, | ||
| 237 | .llseek = no_llseek, | ||
| 238 | .mmap = drm_gem_cma_mmap, | ||
| 239 | }; | ||
| 240 | 230 | ||
| 241 | static struct drm_driver rcar_du_driver = { | 231 | static struct drm_driver rcar_du_driver = { |
| 242 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | 232 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index fd79a70b8552..9edb8dc1ea14 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c | |||
| @@ -94,7 +94,7 @@ static int cdn_dp_grf_write(struct cdn_dp_device *dp, | |||
| 94 | static int cdn_dp_clk_enable(struct cdn_dp_device *dp) | 94 | static int cdn_dp_clk_enable(struct cdn_dp_device *dp) |
| 95 | { | 95 | { |
| 96 | int ret; | 96 | int ret; |
| 97 | u32 rate; | 97 | unsigned long rate; |
| 98 | 98 | ||
| 99 | ret = clk_prepare_enable(dp->pclk); | 99 | ret = clk_prepare_enable(dp->pclk); |
| 100 | if (ret < 0) { | 100 | if (ret < 0) { |
| @@ -123,7 +123,8 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp) | |||
| 123 | 123 | ||
| 124 | rate = clk_get_rate(dp->core_clk); | 124 | rate = clk_get_rate(dp->core_clk); |
| 125 | if (!rate) { | 125 | if (!rate) { |
| 126 | DRM_DEV_ERROR(dp->dev, "get clk rate failed: %d\n", rate); | 126 | DRM_DEV_ERROR(dp->dev, "get clk rate failed\n"); |
| 127 | ret = -EINVAL; | ||
| 127 | goto err_set_rate; | 128 | goto err_set_rate; |
| 128 | } | 129 | } |
| 129 | 130 | ||
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index 319dbbaa3609..b14d211f6c21 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | #define LINK_TRAINING_RETRY_MS 20 | 29 | #define LINK_TRAINING_RETRY_MS 20 |
| 30 | #define LINK_TRAINING_TIMEOUT_MS 500 | 30 | #define LINK_TRAINING_TIMEOUT_MS 500 |
| 31 | 31 | ||
| 32 | void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk) | 32 | void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk) |
| 33 | { | 33 | { |
| 34 | writel(clk / 1000000, dp->regs + SW_CLK_H); | 34 | writel(clk / 1000000, dp->regs + SW_CLK_H); |
| 35 | } | 35 | } |
| @@ -671,6 +671,10 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) | |||
| 671 | rem = do_div(symbol, 1000); | 671 | rem = do_div(symbol, 1000); |
| 672 | if (tu_size_reg > 64) { | 672 | if (tu_size_reg > 64) { |
| 673 | ret = -EINVAL; | 673 | ret = -EINVAL; |
| 674 | DRM_DEV_ERROR(dp->dev, | ||
| 675 | "tu error, clk:%d, lanes:%d, rate:%d\n", | ||
| 676 | mode->clock, dp->link.num_lanes, | ||
| 677 | link_rate); | ||
| 674 | goto err_config_video; | 678 | goto err_config_video; |
| 675 | } | 679 | } |
| 676 | } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || | 680 | } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || |
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h index b5f215324694..c4bbb4a83319 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h | |||
| @@ -121,12 +121,11 @@ | |||
| 121 | 121 | ||
| 122 | /* dptx phy addr */ | 122 | /* dptx phy addr */ |
| 123 | #define DP_TX_PHY_CONFIG_REG 0x2000 | 123 | #define DP_TX_PHY_CONFIG_REG 0x2000 |
| 124 | #define DP_TX_PHY_STATUS_REG 0x2004 | 124 | #define DP_TX_PHY_SW_RESET 0x2004 |
| 125 | #define DP_TX_PHY_SW_RESET 0x2008 | 125 | #define DP_TX_PHY_SCRAMBLER_SEED 0x2008 |
| 126 | #define DP_TX_PHY_SCRAMBLER_SEED 0x200c | 126 | #define DP_TX_PHY_TRAINING_01_04 0x200c |
| 127 | #define DP_TX_PHY_TRAINING_01_04 0x2010 | 127 | #define DP_TX_PHY_TRAINING_05_08 0x2010 |
| 128 | #define DP_TX_PHY_TRAINING_05_08 0x2014 | 128 | #define DP_TX_PHY_TRAINING_09_10 0x2014 |
| 129 | #define DP_TX_PHY_TRAINING_09_10 0x2018 | ||
| 130 | #define TEST_COR 0x23fc | 129 | #define TEST_COR 0x23fc |
| 131 | 130 | ||
| 132 | /* dptx hpd addr */ | 131 | /* dptx hpd addr */ |
| @@ -462,7 +461,7 @@ enum vic_bt_type { | |||
| 462 | 461 | ||
| 463 | void cdn_dp_clock_reset(struct cdn_dp_device *dp); | 462 | void cdn_dp_clock_reset(struct cdn_dp_device *dp); |
| 464 | 463 | ||
| 465 | void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, u32 clk); | 464 | void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk); |
| 466 | int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, | 465 | int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, |
| 467 | u32 i_size, const u32 *d_mem, u32 d_size); | 466 | u32 i_size, const u32 *d_mem, u32 d_size); |
| 468 | int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable); | 467 | int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable); |
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 1c7b318b8998..800d1d2c435d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c | |||
| @@ -127,17 +127,7 @@ static irqreturn_t shmob_drm_irq(int irq, void *arg) | |||
| 127 | return IRQ_HANDLED; | 127 | return IRQ_HANDLED; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static const struct file_operations shmob_drm_fops = { | 130 | DEFINE_DRM_GEM_CMA_FOPS(shmob_drm_fops); |
| 131 | .owner = THIS_MODULE, | ||
| 132 | .open = drm_open, | ||
| 133 | .release = drm_release, | ||
| 134 | .unlocked_ioctl = drm_ioctl, | ||
| 135 | .compat_ioctl = drm_compat_ioctl, | ||
| 136 | .poll = drm_poll, | ||
| 137 | .read = drm_read, | ||
| 138 | .llseek = no_llseek, | ||
| 139 | .mmap = drm_gem_cma_mmap, | ||
| 140 | }; | ||
| 141 | 131 | ||
| 142 | static struct drm_driver shmob_drm_driver = { | 132 | static struct drm_driver shmob_drm_driver = { |
| 143 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | 133 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 6003c664ba0b..a4b574283269 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c | |||
| @@ -167,16 +167,7 @@ static void sti_mode_config_init(struct drm_device *dev) | |||
| 167 | dev->mode_config.funcs = &sti_mode_config_funcs; | 167 | dev->mode_config.funcs = &sti_mode_config_funcs; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | static const struct file_operations sti_driver_fops = { | 170 | DEFINE_DRM_GEM_CMA_FOPS(sti_driver_fops); |
| 171 | .owner = THIS_MODULE, | ||
| 172 | .open = drm_open, | ||
| 173 | .mmap = drm_gem_cma_mmap, | ||
| 174 | .poll = drm_poll, | ||
| 175 | .read = drm_read, | ||
| 176 | .unlocked_ioctl = drm_ioctl, | ||
| 177 | .compat_ioctl = drm_compat_ioctl, | ||
| 178 | .release = drm_release, | ||
| 179 | }; | ||
| 180 | 171 | ||
| 181 | static struct drm_driver sti_driver = { | 172 | static struct drm_driver sti_driver = { |
| 182 | .driver_features = DRIVER_MODESET | | 173 | .driver_features = DRIVER_MODESET | |
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 9ccf7c4deb6d..329ea56106a5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c | |||
| @@ -25,17 +25,7 @@ | |||
| 25 | #include "sun4i_framebuffer.h" | 25 | #include "sun4i_framebuffer.h" |
| 26 | #include "sun4i_layer.h" | 26 | #include "sun4i_layer.h" |
| 27 | 27 | ||
| 28 | static const struct file_operations sun4i_drv_fops = { | 28 | DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); |
| 29 | .owner = THIS_MODULE, | ||
| 30 | .open = drm_open, | ||
| 31 | .release = drm_release, | ||
| 32 | .unlocked_ioctl = drm_ioctl, | ||
| 33 | .compat_ioctl = drm_compat_ioctl, | ||
| 34 | .poll = drm_poll, | ||
| 35 | .read = drm_read, | ||
| 36 | .llseek = no_llseek, | ||
| 37 | .mmap = drm_gem_cma_mmap, | ||
| 38 | }; | ||
| 39 | 29 | ||
| 40 | static struct drm_driver sun4i_drv_driver = { | 30 | static struct drm_driver sun4i_drv_driver = { |
| 41 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, | 31 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 5b4ed0ea7768..d7ae5be56d12 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | |||
| @@ -529,17 +529,7 @@ static int tilcdc_debugfs_init(struct drm_minor *minor) | |||
| 529 | } | 529 | } |
| 530 | #endif | 530 | #endif |
| 531 | 531 | ||
| 532 | static const struct file_operations fops = { | 532 | DEFINE_DRM_GEM_CMA_FOPS(fops); |
| 533 | .owner = THIS_MODULE, | ||
| 534 | .open = drm_open, | ||
| 535 | .release = drm_release, | ||
| 536 | .unlocked_ioctl = drm_ioctl, | ||
| 537 | .compat_ioctl = drm_compat_ioctl, | ||
| 538 | .poll = drm_poll, | ||
| 539 | .read = drm_read, | ||
| 540 | .llseek = no_llseek, | ||
| 541 | .mmap = drm_gem_cma_mmap, | ||
| 542 | }; | ||
| 543 | 533 | ||
| 544 | static struct drm_driver tilcdc_driver = { | 534 | static struct drm_driver tilcdc_driver = { |
| 545 | .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | | 535 | .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | |
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index 29c0939f5247..f4eb412f3604 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c | |||
| @@ -590,7 +590,7 @@ static int mipi_dbi_spi1e_transfer(struct mipi_dbi *mipi, int dc, | |||
| 590 | ret = spi_sync(spi, &m); | 590 | ret = spi_sync(spi, &m); |
| 591 | if (ret) | 591 | if (ret) |
| 592 | return ret; | 592 | return ret; |
| 593 | }; | 593 | } |
| 594 | 594 | ||
| 595 | return 0; | 595 | return 0; |
| 596 | } | 596 | } |
| @@ -654,7 +654,7 @@ static int mipi_dbi_spi1_transfer(struct mipi_dbi *mipi, int dc, | |||
| 654 | ret = spi_sync(spi, &m); | 654 | ret = spi_sync(spi, &m); |
| 655 | if (ret) | 655 | if (ret) |
| 656 | return ret; | 656 | return ret; |
| 657 | }; | 657 | } |
| 658 | 658 | ||
| 659 | return 0; | 659 | return 0; |
| 660 | } | 660 | } |
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig index e1517d07cb7d..973b4203c0b2 100644 --- a/drivers/gpu/drm/vc4/Kconfig +++ b/drivers/gpu/drm/vc4/Kconfig | |||
| @@ -2,11 +2,15 @@ config DRM_VC4 | |||
| 2 | tristate "Broadcom VC4 Graphics" | 2 | tristate "Broadcom VC4 Graphics" |
| 3 | depends on ARCH_BCM2835 || COMPILE_TEST | 3 | depends on ARCH_BCM2835 || COMPILE_TEST |
| 4 | depends on DRM | 4 | depends on DRM |
| 5 | depends on SND && SND_SOC | ||
| 5 | depends on COMMON_CLK | 6 | depends on COMMON_CLK |
| 6 | select DRM_KMS_HELPER | 7 | select DRM_KMS_HELPER |
| 7 | select DRM_KMS_CMA_HELPER | 8 | select DRM_KMS_CMA_HELPER |
| 8 | select DRM_GEM_CMA_HELPER | 9 | select DRM_GEM_CMA_HELPER |
| 9 | select DRM_PANEL | 10 | select DRM_PANEL |
| 11 | select SND_PCM | ||
| 12 | select SND_PCM_ELD | ||
| 13 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
| 10 | select DRM_MIPI_DSI | 14 | select DRM_MIPI_DSI |
| 11 | help | 15 | help |
| 12 | Choose this option if you have a system that has a Broadcom | 16 | Choose this option if you have a system that has a Broadcom |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 205c1961ffb4..61e674baf3a6 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c | |||
| @@ -349,26 +349,20 @@ static struct platform_driver vc4_platform_driver = { | |||
| 349 | 349 | ||
| 350 | static int __init vc4_drm_register(void) | 350 | static int __init vc4_drm_register(void) |
| 351 | { | 351 | { |
| 352 | int i, ret; | 352 | int ret; |
| 353 | |||
| 354 | ret = platform_register_drivers(component_drivers, | ||
| 355 | ARRAY_SIZE(component_drivers)); | ||
| 356 | if (ret) | ||
| 357 | return ret; | ||
| 353 | 358 | ||
| 354 | for (i = 0; i < ARRAY_SIZE(component_drivers); i++) { | ||
| 355 | ret = platform_driver_register(component_drivers[i]); | ||
| 356 | if (ret) { | ||
| 357 | while (--i >= 0) | ||
| 358 | platform_driver_unregister(component_drivers[i]); | ||
| 359 | return ret; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | return platform_driver_register(&vc4_platform_driver); | 359 | return platform_driver_register(&vc4_platform_driver); |
| 363 | } | 360 | } |
| 364 | 361 | ||
| 365 | static void __exit vc4_drm_unregister(void) | 362 | static void __exit vc4_drm_unregister(void) |
| 366 | { | 363 | { |
| 367 | int i; | 364 | platform_unregister_drivers(component_drivers, |
| 368 | 365 | ARRAY_SIZE(component_drivers)); | |
| 369 | for (i = ARRAY_SIZE(component_drivers) - 1; i >= 0; i--) | ||
| 370 | platform_driver_unregister(component_drivers[i]); | ||
| 371 | |||
| 372 | platform_driver_unregister(&vc4_platform_driver); | 366 | platform_driver_unregister(&vc4_platform_driver); |
| 373 | } | 367 | } |
| 374 | 368 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1be1e8304720..e9cbe269710b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c | |||
| @@ -48,11 +48,27 @@ | |||
| 48 | #include "linux/clk.h" | 48 | #include "linux/clk.h" |
| 49 | #include "linux/component.h" | 49 | #include "linux/component.h" |
| 50 | #include "linux/i2c.h" | 50 | #include "linux/i2c.h" |
| 51 | #include "linux/of_address.h" | ||
| 51 | #include "linux/of_gpio.h" | 52 | #include "linux/of_gpio.h" |
| 52 | #include "linux/of_platform.h" | 53 | #include "linux/of_platform.h" |
| 54 | #include "linux/rational.h" | ||
| 55 | #include "sound/dmaengine_pcm.h" | ||
| 56 | #include "sound/pcm_drm_eld.h" | ||
| 57 | #include "sound/pcm_params.h" | ||
| 58 | #include "sound/soc.h" | ||
| 53 | #include "vc4_drv.h" | 59 | #include "vc4_drv.h" |
| 54 | #include "vc4_regs.h" | 60 | #include "vc4_regs.h" |
| 55 | 61 | ||
| 62 | /* HDMI audio information */ | ||
| 63 | struct vc4_hdmi_audio { | ||
| 64 | struct snd_soc_card card; | ||
| 65 | struct snd_soc_dai_link link; | ||
| 66 | int samplerate; | ||
| 67 | int channels; | ||
| 68 | struct snd_dmaengine_dai_dma_data dma_data; | ||
| 69 | struct snd_pcm_substream *substream; | ||
| 70 | }; | ||
| 71 | |||
| 56 | /* General HDMI hardware state. */ | 72 | /* General HDMI hardware state. */ |
| 57 | struct vc4_hdmi { | 73 | struct vc4_hdmi { |
| 58 | struct platform_device *pdev; | 74 | struct platform_device *pdev; |
| @@ -60,6 +76,8 @@ struct vc4_hdmi { | |||
| 60 | struct drm_encoder *encoder; | 76 | struct drm_encoder *encoder; |
| 61 | struct drm_connector *connector; | 77 | struct drm_connector *connector; |
| 62 | 78 | ||
| 79 | struct vc4_hdmi_audio audio; | ||
| 80 | |||
| 63 | struct i2c_adapter *ddc; | 81 | struct i2c_adapter *ddc; |
| 64 | void __iomem *hdmicore_regs; | 82 | void __iomem *hdmicore_regs; |
| 65 | void __iomem *hd_regs; | 83 | void __iomem *hd_regs; |
| @@ -115,6 +133,10 @@ static const struct { | |||
| 115 | HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), | 133 | HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), |
| 116 | HDMI_REG(VC4_HDMI_HOTPLUG_INT), | 134 | HDMI_REG(VC4_HDMI_HOTPLUG_INT), |
| 117 | HDMI_REG(VC4_HDMI_HOTPLUG), | 135 | HDMI_REG(VC4_HDMI_HOTPLUG), |
| 136 | HDMI_REG(VC4_HDMI_MAI_CHANNEL_MAP), | ||
| 137 | HDMI_REG(VC4_HDMI_MAI_CONFIG), | ||
| 138 | HDMI_REG(VC4_HDMI_MAI_FORMAT), | ||
| 139 | HDMI_REG(VC4_HDMI_AUDIO_PACKET_CONFIG), | ||
| 118 | HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG), | 140 | HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG), |
| 119 | HDMI_REG(VC4_HDMI_HORZA), | 141 | HDMI_REG(VC4_HDMI_HORZA), |
| 120 | HDMI_REG(VC4_HDMI_HORZB), | 142 | HDMI_REG(VC4_HDMI_HORZB), |
| @@ -125,6 +147,7 @@ static const struct { | |||
| 125 | HDMI_REG(VC4_HDMI_VERTB0), | 147 | HDMI_REG(VC4_HDMI_VERTB0), |
| 126 | HDMI_REG(VC4_HDMI_VERTB1), | 148 | HDMI_REG(VC4_HDMI_VERTB1), |
| 127 | HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), | 149 | HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), |
| 150 | HDMI_REG(VC4_HDMI_TX_PHY_CTL0), | ||
| 128 | }; | 151 | }; |
| 129 | 152 | ||
| 130 | static const struct { | 153 | static const struct { |
| @@ -133,6 +156,9 @@ static const struct { | |||
| 133 | } hd_regs[] = { | 156 | } hd_regs[] = { |
| 134 | HDMI_REG(VC4_HD_M_CTL), | 157 | HDMI_REG(VC4_HD_M_CTL), |
| 135 | HDMI_REG(VC4_HD_MAI_CTL), | 158 | HDMI_REG(VC4_HD_MAI_CTL), |
| 159 | HDMI_REG(VC4_HD_MAI_THR), | ||
| 160 | HDMI_REG(VC4_HD_MAI_FMT), | ||
| 161 | HDMI_REG(VC4_HD_MAI_SMP), | ||
| 136 | HDMI_REG(VC4_HD_VID_CTL), | 162 | HDMI_REG(VC4_HD_VID_CTL), |
| 137 | HDMI_REG(VC4_HD_CSC_CTL), | 163 | HDMI_REG(VC4_HD_CSC_CTL), |
| 138 | HDMI_REG(VC4_HD_FRAME_COUNT), | 164 | HDMI_REG(VC4_HD_FRAME_COUNT), |
| @@ -232,6 +258,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) | |||
| 232 | 258 | ||
| 233 | drm_mode_connector_update_edid_property(connector, edid); | 259 | drm_mode_connector_update_edid_property(connector, edid); |
| 234 | ret = drm_add_edid_modes(connector, edid); | 260 | ret = drm_add_edid_modes(connector, edid); |
| 261 | drm_edid_to_eld(connector, edid); | ||
| 235 | 262 | ||
| 236 | return ret; | 263 | return ret; |
| 237 | } | 264 | } |
| @@ -317,7 +344,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, | |||
| 317 | struct drm_device *dev = encoder->dev; | 344 | struct drm_device *dev = encoder->dev; |
| 318 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 345 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
| 319 | u32 packet_id = frame->any.type - 0x80; | 346 | u32 packet_id = frame->any.type - 0x80; |
| 320 | u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id; | 347 | u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id); |
| 321 | uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; | 348 | uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; |
| 322 | ssize_t len, i; | 349 | ssize_t len, i; |
| 323 | int ret; | 350 | int ret; |
| @@ -398,6 +425,24 @@ static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) | |||
| 398 | vc4_hdmi_write_infoframe(encoder, &frame); | 425 | vc4_hdmi_write_infoframe(encoder, &frame); |
| 399 | } | 426 | } |
| 400 | 427 | ||
| 428 | static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder) | ||
| 429 | { | ||
| 430 | struct drm_device *drm = encoder->dev; | ||
| 431 | struct vc4_dev *vc4 = drm->dev_private; | ||
| 432 | struct vc4_hdmi *hdmi = vc4->hdmi; | ||
| 433 | union hdmi_infoframe frame; | ||
| 434 | int ret; | ||
| 435 | |||
| 436 | ret = hdmi_audio_infoframe_init(&frame.audio); | ||
| 437 | |||
| 438 | frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; | ||
| 439 | frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; | ||
| 440 | frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; | ||
| 441 | frame.audio.channels = hdmi->audio.channels; | ||
| 442 | |||
| 443 | vc4_hdmi_write_infoframe(encoder, &frame); | ||
| 444 | } | ||
| 445 | |||
| 401 | static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) | 446 | static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) |
| 402 | { | 447 | { |
| 403 | vc4_hdmi_set_avi_infoframe(encoder); | 448 | vc4_hdmi_set_avi_infoframe(encoder); |
| @@ -606,6 +651,447 @@ static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { | |||
| 606 | .enable = vc4_hdmi_encoder_enable, | 651 | .enable = vc4_hdmi_encoder_enable, |
| 607 | }; | 652 | }; |
| 608 | 653 | ||
| 654 | /* HDMI audio codec callbacks */ | ||
| 655 | static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *hdmi) | ||
| 656 | { | ||
| 657 | struct drm_device *drm = hdmi->encoder->dev; | ||
| 658 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
| 659 | u32 hsm_clock = clk_get_rate(hdmi->hsm_clock); | ||
| 660 | unsigned long n, m; | ||
| 661 | |||
| 662 | rational_best_approximation(hsm_clock, hdmi->audio.samplerate, | ||
| 663 | VC4_HD_MAI_SMP_N_MASK >> | ||
| 664 | VC4_HD_MAI_SMP_N_SHIFT, | ||
| 665 | (VC4_HD_MAI_SMP_M_MASK >> | ||
| 666 | VC4_HD_MAI_SMP_M_SHIFT) + 1, | ||
| 667 | &n, &m); | ||
| 668 | |||
| 669 | HD_WRITE(VC4_HD_MAI_SMP, | ||
| 670 | VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | | ||
| 671 | VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); | ||
| 672 | } | ||
| 673 | |||
| 674 | static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi) | ||
| 675 | { | ||
| 676 | struct drm_encoder *encoder = hdmi->encoder; | ||
| 677 | struct drm_crtc *crtc = encoder->crtc; | ||
| 678 | struct drm_device *drm = encoder->dev; | ||
| 679 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
| 680 | const struct drm_display_mode *mode = &crtc->state->adjusted_mode; | ||
| 681 | u32 samplerate = hdmi->audio.samplerate; | ||
| 682 | u32 n, cts; | ||
| 683 | u64 tmp; | ||
| 684 | |||
| 685 | n = 128 * samplerate / 1000; | ||
| 686 | tmp = (u64)(mode->clock * 1000) * n; | ||
| 687 | do_div(tmp, 128 * samplerate); | ||
| 688 | cts = tmp; | ||
| 689 | |||
| 690 | HDMI_WRITE(VC4_HDMI_CRP_CFG, | ||
| 691 | VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN | | ||
| 692 | VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N)); | ||
| 693 | |||
| 694 | /* | ||
| 695 | * We could get slightly more accurate clocks in some cases by | ||
| 696 | * providing a CTS_1 value. The two CTS values are alternated | ||
| 697 | * between based on the period fields | ||
| 698 | */ | ||
| 699 | HDMI_WRITE(VC4_HDMI_CTS_0, cts); | ||
| 700 | HDMI_WRITE(VC4_HDMI_CTS_1, cts); | ||
| 701 | } | ||
| 702 | |||
| 703 | static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) | ||
| 704 | { | ||
| 705 | struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai); | ||
| 706 | |||
| 707 | return snd_soc_card_get_drvdata(card); | ||
| 708 | } | ||
| 709 | |||
| 710 | static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream, | ||
| 711 | struct snd_soc_dai *dai) | ||
| 712 | { | ||
| 713 | struct vc4_hdmi *hdmi = dai_to_hdmi(dai); | ||
| 714 | struct drm_encoder *encoder = hdmi->encoder; | ||
| 715 | struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); | ||
| 716 | int ret; | ||
| 717 | |||
| 718 | if (hdmi->audio.substream && hdmi->audio.substream != substream) | ||
| 719 | return -EINVAL; | ||
| 720 | |||
| 721 | hdmi->audio.substream = substream; | ||
| 722 | |||
| 723 | /* | ||
| 724 | * If the HDMI encoder hasn't probed, or the encoder is | ||
| 725 | * currently in DVI mode, treat the codec dai as missing. | ||
| 726 | */ | ||
| 727 | if (!encoder->crtc || !(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & | ||
| 728 | VC4_HDMI_RAM_PACKET_ENABLE)) | ||
| 729 | return -ENODEV; | ||
| 730 | |||
| 731 | ret = snd_pcm_hw_constraint_eld(substream->runtime, | ||
| 732 | hdmi->connector->eld); | ||
| 733 | if (ret) | ||
| 734 | return ret; | ||
| 735 | |||
| 736 | return 0; | ||
| 737 | } | ||
| 738 | |||
| 739 | static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
| 740 | { | ||
| 741 | return 0; | ||
| 742 | } | ||
| 743 | |||
| 744 | static void vc4_hdmi_audio_reset(struct vc4_hdmi *hdmi) | ||
| 745 | { | ||
| 746 | struct drm_encoder *encoder = hdmi->encoder; | ||
| 747 | struct drm_device *drm = encoder->dev; | ||
| 748 | struct device *dev = &hdmi->pdev->dev; | ||
| 749 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
| 750 | int ret; | ||
| 751 | |||
| 752 | ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO); | ||
| 753 | if (ret) | ||
| 754 | dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); | ||
| 755 | |||
| 756 | HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_RESET); | ||
| 757 | HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); | ||
| 758 | HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); | ||
| 759 | } | ||
| 760 | |||
| 761 | static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream, | ||
| 762 | struct snd_soc_dai *dai) | ||
| 763 | { | ||
| 764 | struct vc4_hdmi *hdmi = dai_to_hdmi(dai); | ||
| 765 | |||
| 766 | if (substream != hdmi->audio.substream) | ||
| 767 | return; | ||
| 768 | |||
| 769 | vc4_hdmi_audio_reset(hdmi); | ||
| 770 | |||
| 771 | hdmi->audio.substream = NULL; | ||
| 772 | } | ||
| 773 | |||
| 774 | /* HDMI audio codec callbacks */ | ||
| 775 | static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream, | ||
| 776 | struct snd_pcm_hw_params *params, | ||
| 777 | struct snd_soc_dai *dai) | ||
| 778 | { | ||
| 779 | struct vc4_hdmi *hdmi = dai_to_hdmi(dai); | ||
| 780 | struct drm_encoder *encoder = hdmi->encoder; | ||
| 781 | struct drm_device *drm = encoder->dev; | ||
| 782 | struct device *dev = &hdmi->pdev->dev; | ||
| 783 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
| 784 | u32 audio_packet_config, channel_mask; | ||
| 785 | u32 channel_map, i; | ||
| 786 | |||
| 787 | if (substream != hdmi->audio.substream) | ||
| 788 | return -EINVAL; | ||
| 789 | |||
| 790 | dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, | ||
| 791 | params_rate(params), params_width(params), | ||
| 792 | params_channels(params)); | ||
| 793 | |||
| 794 | hdmi->audio.channels = params_channels(params); | ||
| 795 | hdmi->audio.samplerate = params_rate(params); | ||
| 796 | |||
| 797 | HD_WRITE(VC4_HD_MAI_CTL, | ||
| 798 | VC4_HD_MAI_CTL_RESET | | ||
| 799 | VC4_HD_MAI_CTL_FLUSH | | ||
| 800 | VC4_HD_MAI_CTL_DLATE | | ||
| 801 | VC4_HD_MAI_CTL_ERRORE | | ||
| 802 | VC4_HD_MAI_CTL_ERRORF); | ||
| 803 | |||
| 804 | vc4_hdmi_audio_set_mai_clock(hdmi); | ||
| 805 | |||
| 806 | audio_packet_config = | ||
| 807 | VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT | | ||
| 808 | VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS | | ||
| 809 | VC4_SET_FIELD(0xf, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); | ||
| 810 | |||
| 811 | channel_mask = GENMASK(hdmi->audio.channels - 1, 0); | ||
| 812 | audio_packet_config |= VC4_SET_FIELD(channel_mask, | ||
| 813 | VC4_HDMI_AUDIO_PACKET_CEA_MASK); | ||
| 814 | |||
| 815 | /* Set the MAI threshold. This logic mimics the firmware's. */ | ||
| 816 | if (hdmi->audio.samplerate > 96000) { | ||
| 817 | HD_WRITE(VC4_HD_MAI_THR, | ||
| 818 | VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) | | ||
| 819 | VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); | ||
| 820 | } else if (hdmi->audio.samplerate > 48000) { | ||
| 821 | HD_WRITE(VC4_HD_MAI_THR, | ||
| 822 | VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) | | ||
| 823 | VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); | ||
| 824 | } else { | ||
| 825 | HD_WRITE(VC4_HD_MAI_THR, | ||
| 826 | VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) | | ||
| 827 | VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) | | ||
| 828 | VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) | | ||
| 829 | VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW)); | ||
| 830 | } | ||
| 831 | |||
| 832 | HDMI_WRITE(VC4_HDMI_MAI_CONFIG, | ||
| 833 | VC4_HDMI_MAI_CONFIG_BIT_REVERSE | | ||
| 834 | VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK)); | ||
| 835 | |||
| 836 | channel_map = 0; | ||
| 837 | for (i = 0; i < 8; i++) { | ||
| 838 | if (channel_mask & BIT(i)) | ||
| 839 | channel_map |= i << (3 * i); | ||
| 840 | } | ||
| 841 | |||
| 842 | HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map); | ||
| 843 | HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); | ||
| 844 | vc4_hdmi_set_n_cts(hdmi); | ||
| 845 | |||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, | ||
| 850 | struct snd_soc_dai *dai) | ||
| 851 | { | ||
| 852 | struct vc4_hdmi *hdmi = dai_to_hdmi(dai); | ||
| 853 | struct drm_encoder *encoder = hdmi->encoder; | ||
| 854 | struct drm_device *drm = encoder->dev; | ||
| 855 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
| 856 | |||
| 857 | switch (cmd) { | ||
| 858 | case SNDRV_PCM_TRIGGER_START: | ||
| 859 | vc4_hdmi_set_audio_infoframe(encoder); | ||
| 860 | HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, | ||
| 861 | HDMI_READ(VC4_HDMI_TX_PHY_CTL0) & | ||
| 862 | ~VC4_HDMI_TX_PHY_RNG_PWRDN); | ||
| 863 | HD_WRITE(VC4_HD_MAI_CTL, | ||
| 864 | VC4_SET_FIELD(hdmi->audio.channels, | ||
| 865 | VC4_HD_MAI_CTL_CHNUM) | | ||
| 866 | VC4_HD_MAI_CTL_ENABLE); | ||
| 867 | break; | ||
| 868 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 869 | HD_WRITE(VC4_HD_MAI_CTL, | ||
| 870 | VC4_HD_MAI_CTL_DLATE | | ||
| 871 | VC4_HD_MAI_CTL_ERRORE | | ||
| 872 | VC4_HD_MAI_CTL_ERRORF); | ||
| 873 | HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, | ||
| 874 | HDMI_READ(VC4_HDMI_TX_PHY_CTL0) | | ||
| 875 | VC4_HDMI_TX_PHY_RNG_PWRDN); | ||
| 876 | break; | ||
| 877 | default: | ||
| 878 | break; | ||
| 879 | } | ||
| 880 | |||
| 881 | return 0; | ||
| 882 | } | ||
| 883 | |||
| 884 | static inline struct vc4_hdmi * | ||
| 885 | snd_component_to_hdmi(struct snd_soc_component *component) | ||
| 886 | { | ||
| 887 | struct snd_soc_card *card = snd_soc_component_get_drvdata(component); | ||
| 888 | |||
| 889 | return snd_soc_card_get_drvdata(card); | ||
| 890 | } | ||
| 891 | |||
| 892 | static int vc4_hdmi_audio_eld_ctl_info(struct snd_kcontrol *kcontrol, | ||
| 893 | struct snd_ctl_elem_info *uinfo) | ||
| 894 | { | ||
| 895 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
| 896 | struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); | ||
| 897 | |||
| 898 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
| 899 | uinfo->count = sizeof(hdmi->connector->eld); | ||
| 900 | |||
| 901 | return 0; | ||
| 902 | } | ||
| 903 | |||
| 904 | static int vc4_hdmi_audio_eld_ctl_get(struct snd_kcontrol *kcontrol, | ||
| 905 | struct snd_ctl_elem_value *ucontrol) | ||
| 906 | { | ||
| 907 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
| 908 | struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); | ||
| 909 | |||
| 910 | memcpy(ucontrol->value.bytes.data, hdmi->connector->eld, | ||
| 911 | sizeof(hdmi->connector->eld)); | ||
| 912 | |||
| 913 | return 0; | ||
| 914 | } | ||
| 915 | |||
| 916 | static const struct snd_kcontrol_new vc4_hdmi_audio_controls[] = { | ||
| 917 | { | ||
| 918 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
| 919 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
| 920 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 921 | .name = "ELD", | ||
| 922 | .info = vc4_hdmi_audio_eld_ctl_info, | ||
| 923 | .get = vc4_hdmi_audio_eld_ctl_get, | ||
| 924 | }, | ||
| 925 | }; | ||
| 926 | |||
| 927 | static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = { | ||
| 928 | SND_SOC_DAPM_OUTPUT("TX"), | ||
| 929 | }; | ||
| 930 | |||
| 931 | static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = { | ||
| 932 | { "TX", NULL, "Playback" }, | ||
| 933 | }; | ||
| 934 | |||
| 935 | static const struct snd_soc_codec_driver vc4_hdmi_audio_codec_drv = { | ||
| 936 | .component_driver = { | ||
| 937 | .controls = vc4_hdmi_audio_controls, | ||
| 938 | .num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls), | ||
| 939 | .dapm_widgets = vc4_hdmi_audio_widgets, | ||
| 940 | .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets), | ||
| 941 | .dapm_routes = vc4_hdmi_audio_routes, | ||
| 942 | .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes), | ||
| 943 | }, | ||
| 944 | }; | ||
| 945 | |||
| 946 | static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = { | ||
| 947 | .startup = vc4_hdmi_audio_startup, | ||
| 948 | .shutdown = vc4_hdmi_audio_shutdown, | ||
| 949 | .hw_params = vc4_hdmi_audio_hw_params, | ||
| 950 | .set_fmt = vc4_hdmi_audio_set_fmt, | ||
| 951 | .trigger = vc4_hdmi_audio_trigger, | ||
| 952 | }; | ||
| 953 | |||
| 954 | static struct snd_soc_dai_driver vc4_hdmi_audio_codec_dai_drv = { | ||
| 955 | .name = "vc4-hdmi-hifi", | ||
| 956 | .playback = { | ||
| 957 | .stream_name = "Playback", | ||
| 958 | .channels_min = 2, | ||
| 959 | .channels_max = 8, | ||
| 960 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
| 961 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | ||
| 962 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
| 963 | SNDRV_PCM_RATE_192000, | ||
| 964 | .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, | ||
| 965 | }, | ||
| 966 | }; | ||
| 967 | |||
| 968 | static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { | ||
| 969 | .name = "vc4-hdmi-cpu-dai-component", | ||
| 970 | }; | ||
| 971 | |||
| 972 | static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) | ||
| 973 | { | ||
| 974 | struct vc4_hdmi *hdmi = dai_to_hdmi(dai); | ||
| 975 | |||
| 976 | snd_soc_dai_init_dma_data(dai, &hdmi->audio.dma_data, NULL); | ||
| 977 | |||
| 978 | return 0; | ||
| 979 | } | ||
| 980 | |||
| 981 | static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { | ||
| 982 | .name = "vc4-hdmi-cpu-dai", | ||
| 983 | .probe = vc4_hdmi_audio_cpu_dai_probe, | ||
| 984 | .playback = { | ||
| 985 | .stream_name = "Playback", | ||
| 986 | .channels_min = 1, | ||
| 987 | .channels_max = 8, | ||
| 988 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
| 989 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | ||
| 990 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
| 991 | SNDRV_PCM_RATE_192000, | ||
| 992 | .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, | ||
| 993 | }, | ||
| 994 | .ops = &vc4_hdmi_audio_dai_ops, | ||
| 995 | }; | ||
| 996 | |||
| 997 | static const struct snd_dmaengine_pcm_config pcm_conf = { | ||
| 998 | .chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "audio-rx", | ||
| 999 | .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, | ||
| 1000 | }; | ||
| 1001 | |||
| 1002 | static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi) | ||
| 1003 | { | ||
| 1004 | struct snd_soc_dai_link *dai_link = &hdmi->audio.link; | ||
| 1005 | struct snd_soc_card *card = &hdmi->audio.card; | ||
| 1006 | struct device *dev = &hdmi->pdev->dev; | ||
| 1007 | const __be32 *addr; | ||
| 1008 | int ret; | ||
| 1009 | |||
| 1010 | if (!of_find_property(dev->of_node, "dmas", NULL)) { | ||
| 1011 | dev_warn(dev, | ||
| 1012 | "'dmas' DT property is missing, no HDMI audio\n"); | ||
| 1013 | return 0; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | /* | ||
| 1017 | * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve | ||
| 1018 | * the bus address specified in the DT, because the physical address | ||
| 1019 | * (the one returned by platform_get_resource()) is not appropriate | ||
| 1020 | * for DMA transfers. | ||
| 1021 | * This VC/MMU should probably be exposed to avoid this kind of hacks. | ||
| 1022 | */ | ||
| 1023 | addr = of_get_address(dev->of_node, 1, NULL, NULL); | ||
| 1024 | hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA; | ||
| 1025 | hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 1026 | hdmi->audio.dma_data.maxburst = 2; | ||
| 1027 | |||
| 1028 | ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0); | ||
| 1029 | if (ret) { | ||
| 1030 | dev_err(dev, "Could not register PCM component: %d\n", ret); | ||
| 1031 | return ret; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_cpu_dai_comp, | ||
| 1035 | &vc4_hdmi_audio_cpu_dai_drv, 1); | ||
| 1036 | if (ret) { | ||
| 1037 | dev_err(dev, "Could not register CPU DAI: %d\n", ret); | ||
| 1038 | return ret; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | /* register codec and codec dai */ | ||
| 1042 | ret = snd_soc_register_codec(dev, &vc4_hdmi_audio_codec_drv, | ||
| 1043 | &vc4_hdmi_audio_codec_dai_drv, 1); | ||
| 1044 | if (ret) { | ||
| 1045 | dev_err(dev, "Could not register codec: %d\n", ret); | ||
| 1046 | return ret; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | dai_link->name = "MAI"; | ||
| 1050 | dai_link->stream_name = "MAI PCM"; | ||
| 1051 | dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name; | ||
| 1052 | dai_link->cpu_dai_name = dev_name(dev); | ||
| 1053 | dai_link->codec_name = dev_name(dev); | ||
| 1054 | dai_link->platform_name = dev_name(dev); | ||
| 1055 | |||
| 1056 | card->dai_link = dai_link; | ||
| 1057 | card->num_links = 1; | ||
| 1058 | card->name = "vc4-hdmi"; | ||
| 1059 | card->dev = dev; | ||
| 1060 | |||
| 1061 | /* | ||
| 1062 | * Be careful, snd_soc_register_card() calls dev_set_drvdata() and | ||
| 1063 | * stores a pointer to the snd card object in dev->driver_data. This | ||
| 1064 | * means we cannot use it for something else. The hdmi back-pointer is | ||
| 1065 | * now stored in card->drvdata and should be retrieved with | ||
| 1066 | * snd_soc_card_get_drvdata() if needed. | ||
| 1067 | */ | ||
| 1068 | snd_soc_card_set_drvdata(card, hdmi); | ||
| 1069 | ret = devm_snd_soc_register_card(dev, card); | ||
| 1070 | if (ret) { | ||
| 1071 | dev_err(dev, "Could not register sound card: %d\n", ret); | ||
| 1072 | goto unregister_codec; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | return 0; | ||
| 1076 | |||
| 1077 | unregister_codec: | ||
| 1078 | snd_soc_unregister_codec(dev); | ||
| 1079 | |||
| 1080 | return ret; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | static void vc4_hdmi_audio_cleanup(struct vc4_hdmi *hdmi) | ||
| 1084 | { | ||
| 1085 | struct device *dev = &hdmi->pdev->dev; | ||
| 1086 | |||
| 1087 | /* | ||
| 1088 | * If drvdata is not set this means the audio card was not | ||
| 1089 | * registered, just skip codec unregistration in this case. | ||
| 1090 | */ | ||
| 1091 | if (dev_get_drvdata(dev)) | ||
| 1092 | snd_soc_unregister_codec(dev); | ||
| 1093 | } | ||
| 1094 | |||
| 609 | static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) | 1095 | static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) |
| 610 | { | 1096 | { |
| 611 | struct platform_device *pdev = to_platform_device(dev); | 1097 | struct platform_device *pdev = to_platform_device(dev); |
| @@ -737,6 +1223,10 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 737 | goto err_destroy_encoder; | 1223 | goto err_destroy_encoder; |
| 738 | } | 1224 | } |
| 739 | 1225 | ||
| 1226 | ret = vc4_hdmi_audio_init(hdmi); | ||
| 1227 | if (ret) | ||
| 1228 | goto err_destroy_encoder; | ||
| 1229 | |||
| 740 | return 0; | 1230 | return 0; |
| 741 | 1231 | ||
| 742 | err_destroy_encoder: | 1232 | err_destroy_encoder: |
| @@ -758,6 +1248,8 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master, | |||
| 758 | struct vc4_dev *vc4 = drm->dev_private; | 1248 | struct vc4_dev *vc4 = drm->dev_private; |
| 759 | struct vc4_hdmi *hdmi = vc4->hdmi; | 1249 | struct vc4_hdmi *hdmi = vc4->hdmi; |
| 760 | 1250 | ||
| 1251 | vc4_hdmi_audio_cleanup(hdmi); | ||
| 1252 | |||
| 761 | vc4_hdmi_connector_destroy(hdmi->connector); | 1253 | vc4_hdmi_connector_destroy(hdmi->connector); |
| 762 | vc4_hdmi_encoder_destroy(hdmi->encoder); | 1254 | vc4_hdmi_encoder_destroy(hdmi->encoder); |
| 763 | 1255 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 110224c3a3ac..0f4564beb017 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c | |||
| @@ -842,10 +842,8 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, | |||
| 842 | 842 | ||
| 843 | vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), | 843 | vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), |
| 844 | GFP_KERNEL); | 844 | GFP_KERNEL); |
| 845 | if (!vc4_plane) { | 845 | if (!vc4_plane) |
| 846 | ret = -ENOMEM; | 846 | return ERR_PTR(-ENOMEM); |
| 847 | goto fail; | ||
| 848 | } | ||
| 849 | 847 | ||
| 850 | for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { | 848 | for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { |
| 851 | /* Don't allow YUV in cursor planes, since that means | 849 | /* Don't allow YUV in cursor planes, since that means |
| @@ -866,9 +864,4 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, | |||
| 866 | drm_plane_helper_add(plane, &vc4_plane_helper_funcs); | 864 | drm_plane_helper_add(plane, &vc4_plane_helper_funcs); |
| 867 | 865 | ||
| 868 | return plane; | 866 | return plane; |
| 869 | fail: | ||
| 870 | if (plane) | ||
| 871 | vc4_plane_destroy(plane); | ||
| 872 | |||
| 873 | return ERR_PTR(ret); | ||
| 874 | } | 867 | } |
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index 385405a2df05..932093936178 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h | |||
| @@ -446,11 +446,62 @@ | |||
| 446 | #define VC4_HDMI_HOTPLUG 0x00c | 446 | #define VC4_HDMI_HOTPLUG 0x00c |
| 447 | # define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) | 447 | # define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) |
| 448 | 448 | ||
| 449 | /* 3 bits per field, where each field maps from that corresponding MAI | ||
| 450 | * bus channel to the given HDMI channel. | ||
| 451 | */ | ||
| 452 | #define VC4_HDMI_MAI_CHANNEL_MAP 0x090 | ||
| 453 | |||
| 454 | #define VC4_HDMI_MAI_CONFIG 0x094 | ||
| 455 | # define VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE BIT(27) | ||
| 456 | # define VC4_HDMI_MAI_CONFIG_BIT_REVERSE BIT(26) | ||
| 457 | # define VC4_HDMI_MAI_CHANNEL_MASK_MASK VC4_MASK(15, 0) | ||
| 458 | # define VC4_HDMI_MAI_CHANNEL_MASK_SHIFT 0 | ||
| 459 | |||
| 460 | /* Last received format word on the MAI bus. */ | ||
| 461 | #define VC4_HDMI_MAI_FORMAT 0x098 | ||
| 462 | |||
| 463 | #define VC4_HDMI_AUDIO_PACKET_CONFIG 0x09c | ||
| 464 | # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT BIT(29) | ||
| 465 | # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS BIT(24) | ||
| 466 | # define VC4_HDMI_AUDIO_PACKET_FORCE_SAMPLE_PRESENT BIT(19) | ||
| 467 | # define VC4_HDMI_AUDIO_PACKET_FORCE_B_FRAME BIT(18) | ||
| 468 | # define VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER_MASK VC4_MASK(13, 10) | ||
| 469 | # define VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER_SHIFT 10 | ||
| 470 | /* If set, then multichannel, otherwise 2 channel. */ | ||
| 471 | # define VC4_HDMI_AUDIO_PACKET_AUDIO_LAYOUT BIT(9) | ||
| 472 | /* If set, then AUDIO_LAYOUT overrides audio_cea_mask */ | ||
| 473 | # define VC4_HDMI_AUDIO_PACKET_FORCE_AUDIO_LAYOUT BIT(8) | ||
| 474 | # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK VC4_MASK(7, 0) | ||
| 475 | # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT 0 | ||
| 476 | |||
| 449 | #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 | 477 | #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 |
| 450 | # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) | 478 | # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) |
| 451 | 479 | ||
| 452 | #define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 | 480 | #define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 |
| 453 | 481 | ||
| 482 | #define VC4_HDMI_CRP_CFG 0x0a8 | ||
| 483 | /* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead | ||
| 484 | * of pixel clock. | ||
| 485 | */ | ||
| 486 | # define VC4_HDMI_CRP_USE_MAI_BUS_SYNC_FOR_CTS BIT(26) | ||
| 487 | /* When set, no CRP packets will be sent. */ | ||
| 488 | # define VC4_HDMI_CRP_CFG_DISABLE BIT(25) | ||
| 489 | /* If set, generates CTS values based on N, audio clock, and video | ||
| 490 | * clock. N must be divisible by 128. | ||
| 491 | */ | ||
| 492 | # define VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN BIT(24) | ||
| 493 | # define VC4_HDMI_CRP_CFG_N_MASK VC4_MASK(19, 0) | ||
| 494 | # define VC4_HDMI_CRP_CFG_N_SHIFT 0 | ||
| 495 | |||
| 496 | /* 20-bit fields containing CTS values to be transmitted if !EXTERNAL_CTS_EN */ | ||
| 497 | #define VC4_HDMI_CTS_0 0x0ac | ||
| 498 | #define VC4_HDMI_CTS_1 0x0b0 | ||
| 499 | /* 20-bit fields containing number of clocks to send CTS0/1 before | ||
| 500 | * switching to the other one. | ||
| 501 | */ | ||
| 502 | #define VC4_HDMI_CTS_PERIOD_0 0x0b4 | ||
| 503 | #define VC4_HDMI_CTS_PERIOD_1 0x0b8 | ||
| 504 | |||
| 454 | #define VC4_HDMI_HORZA 0x0c4 | 505 | #define VC4_HDMI_HORZA 0x0c4 |
| 455 | # define VC4_HDMI_HORZA_VPOS BIT(14) | 506 | # define VC4_HDMI_HORZA_VPOS BIT(14) |
| 456 | # define VC4_HDMI_HORZA_HPOS BIT(13) | 507 | # define VC4_HDMI_HORZA_HPOS BIT(13) |
| @@ -512,7 +563,11 @@ | |||
| 512 | 563 | ||
| 513 | #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 | 564 | #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 |
| 514 | 565 | ||
| 515 | #define VC4_HDMI_GCP_0 0x400 | 566 | #define VC4_HDMI_TX_PHY_CTL0 0x2c4 |
| 567 | # define VC4_HDMI_TX_PHY_RNG_PWRDN BIT(25) | ||
| 568 | |||
| 569 | #define VC4_HDMI_GCP(x) (0x400 + ((x) * 0x4)) | ||
| 570 | #define VC4_HDMI_RAM_PACKET(x) (0x400 + ((x) * 0x24)) | ||
| 516 | #define VC4_HDMI_PACKET_STRIDE 0x24 | 571 | #define VC4_HDMI_PACKET_STRIDE 0x24 |
| 517 | 572 | ||
| 518 | #define VC4_HD_M_CTL 0x00c | 573 | #define VC4_HD_M_CTL 0x00c |
| @@ -522,6 +577,56 @@ | |||
| 522 | # define VC4_HD_M_ENABLE BIT(0) | 577 | # define VC4_HD_M_ENABLE BIT(0) |
| 523 | 578 | ||
| 524 | #define VC4_HD_MAI_CTL 0x014 | 579 | #define VC4_HD_MAI_CTL 0x014 |
| 580 | /* Set when audio stream is received at a slower rate than the | ||
| 581 | * sampling period, so MAI fifo goes empty. Write 1 to clear. | ||
| 582 | */ | ||
| 583 | # define VC4_HD_MAI_CTL_DLATE BIT(15) | ||
| 584 | # define VC4_HD_MAI_CTL_BUSY BIT(14) | ||
| 585 | # define VC4_HD_MAI_CTL_CHALIGN BIT(13) | ||
| 586 | # define VC4_HD_MAI_CTL_WHOLSMP BIT(12) | ||
| 587 | # define VC4_HD_MAI_CTL_FULL BIT(11) | ||
| 588 | # define VC4_HD_MAI_CTL_EMPTY BIT(10) | ||
| 589 | # define VC4_HD_MAI_CTL_FLUSH BIT(9) | ||
| 590 | /* If set, MAI bus generates SPDIF (bit 31) parity instead of passing | ||
| 591 | * through. | ||
| 592 | */ | ||
| 593 | # define VC4_HD_MAI_CTL_PAREN BIT(8) | ||
| 594 | # define VC4_HD_MAI_CTL_CHNUM_MASK VC4_MASK(7, 4) | ||
| 595 | # define VC4_HD_MAI_CTL_CHNUM_SHIFT 4 | ||
| 596 | # define VC4_HD_MAI_CTL_ENABLE BIT(3) | ||
| 597 | /* Underflow error status bit, write 1 to clear. */ | ||
| 598 | # define VC4_HD_MAI_CTL_ERRORE BIT(2) | ||
| 599 | /* Overflow error status bit, write 1 to clear. */ | ||
| 600 | # define VC4_HD_MAI_CTL_ERRORF BIT(1) | ||
| 601 | /* Single-shot reset bit. Read value is undefined. */ | ||
| 602 | # define VC4_HD_MAI_CTL_RESET BIT(0) | ||
| 603 | |||
| 604 | #define VC4_HD_MAI_THR 0x018 | ||
| 605 | # define VC4_HD_MAI_THR_PANICHIGH_MASK VC4_MASK(29, 24) | ||
| 606 | # define VC4_HD_MAI_THR_PANICHIGH_SHIFT 24 | ||
| 607 | # define VC4_HD_MAI_THR_PANICLOW_MASK VC4_MASK(21, 16) | ||
| 608 | # define VC4_HD_MAI_THR_PANICLOW_SHIFT 16 | ||
| 609 | # define VC4_HD_MAI_THR_DREQHIGH_MASK VC4_MASK(13, 8) | ||
| 610 | # define VC4_HD_MAI_THR_DREQHIGH_SHIFT 8 | ||
| 611 | # define VC4_HD_MAI_THR_DREQLOW_MASK VC4_MASK(5, 0) | ||
| 612 | # define VC4_HD_MAI_THR_DREQLOW_SHIFT 0 | ||
| 613 | |||
| 614 | /* Format header to be placed on the MAI data. Unused. */ | ||
| 615 | #define VC4_HD_MAI_FMT 0x01c | ||
| 616 | |||
| 617 | /* Register for DMAing in audio data to be transported over the MAI | ||
| 618 | * bus to the Falcon core. | ||
| 619 | */ | ||
| 620 | #define VC4_HD_MAI_DATA 0x020 | ||
| 621 | |||
| 622 | /* Divider from HDMI HSM clock to MAI serial clock. Sampling period | ||
| 623 | * converges to N / (M + 1) cycles. | ||
| 624 | */ | ||
| 625 | #define VC4_HD_MAI_SMP 0x02c | ||
| 626 | # define VC4_HD_MAI_SMP_N_MASK VC4_MASK(31, 8) | ||
| 627 | # define VC4_HD_MAI_SMP_N_SHIFT 8 | ||
| 628 | # define VC4_HD_MAI_SMP_M_MASK VC4_MASK(7, 0) | ||
| 629 | # define VC4_HD_MAI_SMP_M_SHIFT 0 | ||
| 525 | 630 | ||
| 526 | #define VC4_HD_VID_CTL 0x038 | 631 | #define VC4_HD_VID_CTL 0x038 |
| 527 | # define VC4_HD_VID_CTL_ENABLE BIT(31) | 632 | # define VC4_HD_VID_CTL_ENABLE BIT(31) |
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index a1f42d125e6e..9fee38a942c4 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c | |||
| @@ -104,7 +104,7 @@ static int vgem_open(struct drm_device *dev, struct drm_file *file) | |||
| 104 | return 0; | 104 | return 0; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static void vgem_preclose(struct drm_device *dev, struct drm_file *file) | 107 | static void vgem_postclose(struct drm_device *dev, struct drm_file *file) |
| 108 | { | 108 | { |
| 109 | struct vgem_file *vfile = file->driver_priv; | 109 | struct vgem_file *vfile = file->driver_priv; |
| 110 | 110 | ||
| @@ -303,7 +303,7 @@ static int vgem_prime_mmap(struct drm_gem_object *obj, | |||
| 303 | static struct drm_driver vgem_driver = { | 303 | static struct drm_driver vgem_driver = { |
| 304 | .driver_features = DRIVER_GEM | DRIVER_PRIME, | 304 | .driver_features = DRIVER_GEM | DRIVER_PRIME, |
| 305 | .open = vgem_open, | 305 | .open = vgem_open, |
| 306 | .preclose = vgem_preclose, | 306 | .postclose = vgem_postclose, |
| 307 | .gem_free_object_unlocked = vgem_gem_free_object, | 307 | .gem_free_object_unlocked = vgem_gem_free_object, |
| 308 | .gem_vm_ops = &vgem_gem_vm_ops, | 308 | .gem_vm_ops = &vgem_gem_vm_ops, |
| 309 | .ioctls = vgem_ioctls, | 309 | .ioctls = vgem_ioctls, |
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 472e34986a44..9eb96fb2c147 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c | |||
| @@ -97,8 +97,8 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev, | |||
| 97 | struct virtio_gpu_vbuffer *vbuf; | 97 | struct virtio_gpu_vbuffer *vbuf; |
| 98 | 98 | ||
| 99 | vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL); | 99 | vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL); |
| 100 | if (IS_ERR(vbuf)) | 100 | if (!vbuf) |
| 101 | return ERR_CAST(vbuf); | 101 | return ERR_PTR(-ENOMEM); |
| 102 | memset(vbuf, 0, VBUFFER_SIZE); | 102 | memset(vbuf, 0, VBUFFER_SIZE); |
| 103 | 103 | ||
| 104 | BUG_ON(size > MAX_INLINE_CMD_SIZE); | 104 | BUG_ON(size > MAX_INLINE_CMD_SIZE); |
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c index b24a70ba4b83..614e854f6be5 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.c +++ b/drivers/gpu/drm/zte/zx_drm_drv.c | |||
| @@ -53,19 +53,7 @@ static void zx_drm_lastclose(struct drm_device *drm) | |||
| 53 | drm_fbdev_cma_restore_mode(priv->fbdev); | 53 | drm_fbdev_cma_restore_mode(priv->fbdev); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static const struct file_operations zx_drm_fops = { | 56 | DEFINE_DRM_GEM_CMA_FOPS(zx_drm_fops); |
| 57 | .owner = THIS_MODULE, | ||
| 58 | .open = drm_open, | ||
| 59 | .release = drm_release, | ||
| 60 | .unlocked_ioctl = drm_ioctl, | ||
| 61 | #ifdef CONFIG_COMPAT | ||
| 62 | .compat_ioctl = drm_compat_ioctl, | ||
| 63 | #endif | ||
| 64 | .poll = drm_poll, | ||
| 65 | .read = drm_read, | ||
| 66 | .llseek = noop_llseek, | ||
| 67 | .mmap = drm_gem_cma_mmap, | ||
| 68 | }; | ||
| 69 | 57 | ||
| 70 | static struct drm_driver zx_drm_driver = { | 58 | static struct drm_driver zx_drm_driver = { |
| 71 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | | 59 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | |
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index fabb35aba5f6..f8b766d70a46 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h | |||
| @@ -87,6 +87,53 @@ enum subpixel_order { | |||
| 87 | SubPixelVerticalRGB, | 87 | SubPixelVerticalRGB, |
| 88 | SubPixelVerticalBGR, | 88 | SubPixelVerticalBGR, |
| 89 | SubPixelNone, | 89 | SubPixelNone, |
| 90 | |||
| 91 | }; | ||
| 92 | |||
| 93 | /** | ||
| 94 | * struct drm_scrambling: sink's scrambling support. | ||
| 95 | */ | ||
| 96 | struct drm_scrambling { | ||
| 97 | /** | ||
| 98 | * @supported: scrambling supported for rates > 340 Mhz. | ||
| 99 | */ | ||
| 100 | bool supported; | ||
| 101 | /** | ||
| 102 | * @low_rates: scrambling supported for rates <= 340 Mhz. | ||
| 103 | */ | ||
| 104 | bool low_rates; | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* | ||
| 108 | * struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink | ||
| 109 | * | ||
| 110 | * Provides SCDC register support and capabilities related information on a | ||
| 111 | * HDMI 2.0 sink. In case of a HDMI 1.4 sink, all parameter must be 0. | ||
| 112 | */ | ||
| 113 | struct drm_scdc { | ||
| 114 | /** | ||
| 115 | * @supported: status control & data channel present. | ||
| 116 | */ | ||
| 117 | bool supported; | ||
| 118 | /** | ||
| 119 | * @read_request: sink is capable of generating scdc read request. | ||
| 120 | */ | ||
| 121 | bool read_request; | ||
| 122 | /** | ||
| 123 | * @scrambling: sink's scrambling capabilities | ||
| 124 | */ | ||
| 125 | struct drm_scrambling scrambling; | ||
| 126 | }; | ||
| 127 | |||
| 128 | |||
| 129 | /** | ||
| 130 | * struct drm_hdmi_info - runtime information about the connected HDMI sink | ||
| 131 | * | ||
| 132 | * Describes if a given display supports advanced HDMI 2.0 features. | ||
| 133 | * This information is available in CEA-861-F extension blocks (like HF-VSDB). | ||
| 134 | */ | ||
| 135 | struct drm_hdmi_info { | ||
| 136 | struct drm_scdc scdc; | ||
| 90 | }; | 137 | }; |
| 91 | 138 | ||
| 92 | /** | 139 | /** |
| @@ -204,6 +251,11 @@ struct drm_display_info { | |||
| 204 | * @cea_rev: CEA revision of the HDMI sink. | 251 | * @cea_rev: CEA revision of the HDMI sink. |
| 205 | */ | 252 | */ |
| 206 | u8 cea_rev; | 253 | u8 cea_rev; |
| 254 | |||
| 255 | /** | ||
| 256 | * @hdmi: advance features of a HDMI sink. | ||
| 257 | */ | ||
| 258 | struct drm_hdmi_info hdmi; | ||
| 207 | }; | 259 | }; |
| 208 | 260 | ||
| 209 | int drm_display_info_set_bus_formats(struct drm_display_info *info, | 261 | int drm_display_info_set_bus_formats(struct drm_display_info *info, |
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 4321d012c4ba..8f900fb30275 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h | |||
| @@ -64,7 +64,6 @@ struct drm_mode_create_dumb; | |||
| 64 | * structure for GEM drivers. | 64 | * structure for GEM drivers. |
| 65 | */ | 65 | */ |
| 66 | struct drm_driver { | 66 | struct drm_driver { |
| 67 | |||
| 68 | /** | 67 | /** |
| 69 | * @load: | 68 | * @load: |
| 70 | * | 69 | * |
| @@ -76,14 +75,94 @@ struct drm_driver { | |||
| 76 | * See drm_dev_init() and drm_dev_register() for proper and | 75 | * See drm_dev_init() and drm_dev_register() for proper and |
| 77 | * race-free way to set up a &struct drm_device. | 76 | * race-free way to set up a &struct drm_device. |
| 78 | * | 77 | * |
| 78 | * This is deprecated, do not use! | ||
| 79 | * | ||
| 79 | * Returns: | 80 | * Returns: |
| 80 | * | 81 | * |
| 81 | * Zero on success, non-zero value on failure. | 82 | * Zero on success, non-zero value on failure. |
| 82 | */ | 83 | */ |
| 83 | int (*load) (struct drm_device *, unsigned long flags); | 84 | int (*load) (struct drm_device *, unsigned long flags); |
| 85 | |||
| 86 | /** | ||
| 87 | * @open: | ||
| 88 | * | ||
| 89 | * Driver callback when a new &struct drm_file is opened. Useful for | ||
| 90 | * setting up driver-private data structures like buffer allocators, | ||
| 91 | * execution contexts or similar things. Such driver-private resources | ||
| 92 | * must be released again in @postclose. | ||
| 93 | * | ||
| 94 | * Since the display/modeset side of DRM can only be owned by exactly | ||
| 95 | * one &struct drm_file (see &drm_file.is_master and &drm_device.master) | ||
| 96 | * there should never be a need to set up any modeset related resources | ||
| 97 | * in this callback. Doing so would be a driver design bug. | ||
| 98 | * | ||
| 99 | * Returns: | ||
| 100 | * | ||
| 101 | * 0 on success, a negative error code on failure, which will be | ||
| 102 | * promoted to userspace as the result of the open() system call. | ||
| 103 | */ | ||
| 84 | int (*open) (struct drm_device *, struct drm_file *); | 104 | int (*open) (struct drm_device *, struct drm_file *); |
| 105 | |||
| 106 | /** | ||
| 107 | * @preclose: | ||
| 108 | * | ||
| 109 | * One of the driver callbacks when a new &struct drm_file is closed. | ||
| 110 | * Useful for tearing down driver-private data structures allocated in | ||
| 111 | * @open like buffer allocators, execution contexts or similar things. | ||
| 112 | * | ||
| 113 | * Since the display/modeset side of DRM can only be owned by exactly | ||
| 114 | * one &struct drm_file (see &drm_file.is_master and &drm_device.master) | ||
| 115 | * there should never be a need to tear down any modeset related | ||
| 116 | * resources in this callback. Doing so would be a driver design bug. | ||
| 117 | * | ||
| 118 | * FIXME: It is not really clear why there's both @preclose and | ||
| 119 | * @postclose. Without a really good reason, use @postclose only. | ||
| 120 | */ | ||
| 85 | void (*preclose) (struct drm_device *, struct drm_file *file_priv); | 121 | void (*preclose) (struct drm_device *, struct drm_file *file_priv); |
| 122 | |||
| 123 | /** | ||
| 124 | * @postclose: | ||
| 125 | * | ||
| 126 | * One of the driver callbacks when a new &struct drm_file is closed. | ||
| 127 | * Useful for tearing down driver-private data structures allocated in | ||
| 128 | * @open like buffer allocators, execution contexts or similar things. | ||
| 129 | * | ||
| 130 | * Since the display/modeset side of DRM can only be owned by exactly | ||
| 131 | * one &struct drm_file (see &drm_file.is_master and &drm_device.master) | ||
| 132 | * there should never be a need to tear down any modeset related | ||
| 133 | * resources in this callback. Doing so would be a driver design bug. | ||
| 134 | * | ||
| 135 | * FIXME: It is not really clear why there's both @preclose and | ||
| 136 | * @postclose. Without a really good reason, use @postclose only. | ||
| 137 | */ | ||
| 86 | void (*postclose) (struct drm_device *, struct drm_file *); | 138 | void (*postclose) (struct drm_device *, struct drm_file *); |
| 139 | |||
| 140 | /** | ||
| 141 | * @lastclose: | ||
| 142 | * | ||
| 143 | * Called when the last &struct drm_file has been closed and there's | ||
| 144 | * currently no userspace client for the &struct drm_device. | ||
| 145 | * | ||
| 146 | * Modern drivers should only use this to force-restore the fbdev | ||
| 147 | * framebuffer using drm_fb_helper_restore_fbdev_mode_unlocked(). | ||
| 148 | * Anything else would indicate there's something seriously wrong. | ||
| 149 | * Modern drivers can also use this to execute delayed power switching | ||
| 150 | * state changes, e.g. in conjunction with the :ref:`vga_switcheroo` | ||
| 151 | * infrastructure. | ||
| 152 | * | ||
| 153 | * This is called after @preclose and @postclose have been called. | ||
| 154 | * | ||
| 155 | * NOTE: | ||
| 156 | * | ||
| 157 | * All legacy drivers use this callback to de-initialize the hardware. | ||
| 158 | * This is purely because of the shadow-attach model, where the DRM | ||
| 159 | * kernel driver does not really own the hardware. Instead ownershipe is | ||
| 160 | * handled with the help of userspace through an inheritedly racy dance | ||
| 161 | * to set/unset the VT into raw mode. | ||
| 162 | * | ||
| 163 | * Legacy drivers initialize the hardware in the @firstopen callback, | ||
| 164 | * which isn't even called for modern drivers. | ||
| 165 | */ | ||
| 87 | void (*lastclose) (struct drm_device *); | 166 | void (*lastclose) (struct drm_device *); |
| 88 | 167 | ||
| 89 | /** | 168 | /** |
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 3ead84d93792..7b9f48b62e07 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h | |||
| @@ -476,5 +476,4 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, | |||
| 476 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, | 476 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, |
| 477 | int hsize, int vsize, int fresh, | 477 | int hsize, int vsize, int fresh, |
| 478 | bool rb); | 478 | bool rb); |
| 479 | |||
| 480 | #endif /* __DRM_EDID_H__ */ | 479 | #endif /* __DRM_EDID_H__ */ |
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index d1a25cc17fd1..5dd27ae5c47c 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h | |||
| @@ -45,6 +45,7 @@ struct drm_device; | |||
| 45 | * FIXME: Not sure we want to have drm_minor here in the end, but to avoid | 45 | * FIXME: Not sure we want to have drm_minor here in the end, but to avoid |
| 46 | * header include loops we need it here for now. | 46 | * header include loops we need it here for now. |
| 47 | */ | 47 | */ |
| 48 | |||
| 48 | enum drm_minor_type { | 49 | enum drm_minor_type { |
| 49 | DRM_MINOR_PRIMARY, | 50 | DRM_MINOR_PRIMARY, |
| 50 | DRM_MINOR_CONTROL, | 51 | DRM_MINOR_CONTROL, |
| @@ -52,12 +53,19 @@ enum drm_minor_type { | |||
| 52 | }; | 53 | }; |
| 53 | 54 | ||
| 54 | /** | 55 | /** |
| 55 | * DRM minor structure. This structure represents a drm minor number. | 56 | * struct drm_minor - DRM device minor structure |
| 57 | * | ||
| 58 | * This structure represents a DRM minor number for device nodes in /dev. | ||
| 59 | * Entirely opaque to drivers and should never be inspected directly by drivers. | ||
| 60 | * Drivers instead should only interact with &struct drm_file and of course | ||
| 61 | * &struct drm_device, which is also where driver-private data and resources can | ||
| 62 | * be attached to. | ||
| 56 | */ | 63 | */ |
| 57 | struct drm_minor { | 64 | struct drm_minor { |
| 58 | int index; /**< Minor device number */ | 65 | /* private: */ |
| 59 | int type; /**< Control or render */ | 66 | int index; /* Minor device number */ |
| 60 | struct device *kdev; /**< Linux device */ | 67 | int type; /* Control or render */ |
| 68 | struct device *kdev; /* Linux device */ | ||
| 61 | struct drm_device *dev; | 69 | struct drm_device *dev; |
| 62 | 70 | ||
| 63 | struct dentry *debugfs_root; | 71 | struct dentry *debugfs_root; |
| @@ -66,91 +74,286 @@ struct drm_minor { | |||
| 66 | struct mutex debugfs_lock; /* Protects debugfs_list. */ | 74 | struct mutex debugfs_lock; /* Protects debugfs_list. */ |
| 67 | }; | 75 | }; |
| 68 | 76 | ||
| 69 | /* Event queued up for userspace to read */ | 77 | /** |
| 78 | * struct drm_pending_event - Event queued up for userspace to read | ||
| 79 | * | ||
| 80 | * This represents a DRM event. Drivers can use this as a generic completion | ||
| 81 | * mechanism, which supports kernel-internal &struct completion, &struct dma_fence | ||
| 82 | * and also the DRM-specific &struct drm_event delivery mechanism. | ||
| 83 | */ | ||
| 70 | struct drm_pending_event { | 84 | struct drm_pending_event { |
| 85 | /** | ||
| 86 | * @completion: | ||
| 87 | * | ||
| 88 | * Optional pointer to a kernel internal completion signalled when | ||
| 89 | * drm_send_event() is called, useful to internally synchronize with | ||
| 90 | * nonblocking operations. | ||
| 91 | */ | ||
| 71 | struct completion *completion; | 92 | struct completion *completion; |
| 93 | |||
| 94 | /** | ||
| 95 | * @completion_release: | ||
| 96 | * | ||
| 97 | * Optional callback currently only used by the atomic modeset helpers | ||
| 98 | * to clean up the reference count for the structure @completion is | ||
| 99 | * stored in. | ||
| 100 | */ | ||
| 72 | void (*completion_release)(struct completion *completion); | 101 | void (*completion_release)(struct completion *completion); |
| 102 | |||
| 103 | /** | ||
| 104 | * @event: | ||
| 105 | * | ||
| 106 | * Pointer to the actual event that should be sent to userspace to be | ||
| 107 | * read using drm_read(). Can be optional, since nowadays events are | ||
| 108 | * also used to signal kernel internal threads with @completion or DMA | ||
| 109 | * transactions using @fence. | ||
| 110 | */ | ||
| 73 | struct drm_event *event; | 111 | struct drm_event *event; |
| 112 | |||
| 113 | /** | ||
| 114 | * @fence: | ||
| 115 | * | ||
| 116 | * Optional DMA fence to unblock other hardware transactions which | ||
| 117 | * depend upon the nonblocking DRM operation this event represents. | ||
| 118 | */ | ||
| 74 | struct dma_fence *fence; | 119 | struct dma_fence *fence; |
| 120 | |||
| 121 | /** | ||
| 122 | * @file_priv: | ||
| 123 | * | ||
| 124 | * &struct drm_file where @event should be delivered to. Only set when | ||
| 125 | * @event is set. | ||
| 126 | */ | ||
| 127 | struct drm_file *file_priv; | ||
| 128 | |||
| 129 | /** | ||
| 130 | * @link: | ||
| 131 | * | ||
| 132 | * Double-linked list to keep track of this event. Can be used by the | ||
| 133 | * driver up to the point when it calls drm_send_event(), after that | ||
| 134 | * this list entry is owned by the core for its own book-keeping. | ||
| 135 | */ | ||
| 75 | struct list_head link; | 136 | struct list_head link; |
| 137 | |||
| 138 | /** | ||
| 139 | * @pending_link: | ||
| 140 | * | ||
| 141 | * Entry on &drm_file.pending_event_list, to keep track of all pending | ||
| 142 | * events for @file_priv, to allow correct unwinding of them when | ||
| 143 | * userspace closes the file before the event is delivered. | ||
| 144 | */ | ||
| 76 | struct list_head pending_link; | 145 | struct list_head pending_link; |
| 77 | struct drm_file *file_priv; | ||
| 78 | pid_t pid; /* pid of requester, no guarantee it's valid by the time | ||
| 79 | we deliver the event, for tracing only */ | ||
| 80 | }; | 146 | }; |
| 81 | 147 | ||
| 82 | /** File private data */ | 148 | /** |
| 149 | * struct drm_file - DRM file private data | ||
| 150 | * | ||
| 151 | * This structure tracks DRM state per open file descriptor. | ||
| 152 | */ | ||
| 83 | struct drm_file { | 153 | struct drm_file { |
| 154 | /** | ||
| 155 | * @authenticated: | ||
| 156 | * | ||
| 157 | * Whether the client is allowed to submit rendering, which for legacy | ||
| 158 | * nodes means it must be authenticated. | ||
| 159 | * | ||
| 160 | * See also the :ref:`section on primary nodes and authentication | ||
| 161 | * <drm_primary_node>`. | ||
| 162 | */ | ||
| 84 | unsigned authenticated :1; | 163 | unsigned authenticated :1; |
| 85 | /* true when the client has asked us to expose stereo 3D mode flags */ | 164 | |
| 165 | /** | ||
| 166 | * @stereo_allowed: | ||
| 167 | * | ||
| 168 | * True when the client has asked us to expose stereo 3D mode flags. | ||
| 169 | */ | ||
| 86 | unsigned stereo_allowed :1; | 170 | unsigned stereo_allowed :1; |
| 87 | /* | 171 | |
| 88 | * true if client understands CRTC primary planes and cursor planes | 172 | /** |
| 89 | * in the plane list | 173 | * @universal_planes: |
| 174 | * | ||
| 175 | * True if client understands CRTC primary planes and cursor planes | ||
| 176 | * in the plane list. Automatically set when @atomic is set. | ||
| 90 | */ | 177 | */ |
| 91 | unsigned universal_planes:1; | 178 | unsigned universal_planes:1; |
| 92 | /* true if client understands atomic properties */ | 179 | |
| 180 | /** @atomic: True if client understands atomic properties. */ | ||
| 93 | unsigned atomic:1; | 181 | unsigned atomic:1; |
| 94 | /* | 182 | |
| 95 | * This client is the creator of @master. | 183 | /** |
| 96 | * Protected by struct drm_device::master_mutex. | 184 | * @is_master: |
| 185 | * | ||
| 186 | * This client is the creator of @master. Protected by struct | ||
| 187 | * &drm_device.master_mutex. | ||
| 188 | * | ||
| 189 | * See also the :ref:`section on primary nodes and authentication | ||
| 190 | * <drm_primary_node>`. | ||
| 97 | */ | 191 | */ |
| 98 | unsigned is_master:1; | 192 | unsigned is_master:1; |
| 99 | 193 | ||
| 194 | /** | ||
| 195 | * @master: | ||
| 196 | * | ||
| 197 | * Master this node is currently associated with. Only relevant if | ||
| 198 | * drm_is_primary_client() returns true. Note that this only | ||
| 199 | * matches &drm_device.master if the master is the currently active one. | ||
| 200 | * | ||
| 201 | * See also @authentication and @is_master and the :ref:`section on | ||
| 202 | * primary nodes and authentication <drm_primary_node>`. | ||
| 203 | */ | ||
| 204 | struct drm_master *master; | ||
| 205 | |||
| 206 | /** @pid: Process that opened this file. */ | ||
| 100 | struct pid *pid; | 207 | struct pid *pid; |
| 208 | |||
| 209 | /** @magic: Authentication magic, see @authenticated. */ | ||
| 101 | drm_magic_t magic; | 210 | drm_magic_t magic; |
| 211 | |||
| 212 | /** | ||
| 213 | * @lhead: | ||
| 214 | * | ||
| 215 | * List of all open files of a DRM device, linked into | ||
| 216 | * &drm_device.filelist. Protected by &drm_device.filelist_mutex. | ||
| 217 | */ | ||
| 102 | struct list_head lhead; | 218 | struct list_head lhead; |
| 219 | |||
| 220 | /** @minor: &struct drm_minor for this file. */ | ||
| 103 | struct drm_minor *minor; | 221 | struct drm_minor *minor; |
| 104 | unsigned long lock_count; | ||
| 105 | 222 | ||
| 106 | /** Mapping of mm object handles to object pointers. */ | 223 | /** |
| 224 | * @object_idr: | ||
| 225 | * | ||
| 226 | * Mapping of mm object handles to object pointers. Used by the GEM | ||
| 227 | * subsystem. Protected by @table_lock. | ||
| 228 | */ | ||
| 107 | struct idr object_idr; | 229 | struct idr object_idr; |
| 108 | /** Lock for synchronization of access to object_idr. */ | 230 | |
| 231 | /** @table_lock: Protects @object_idr. */ | ||
| 109 | spinlock_t table_lock; | 232 | spinlock_t table_lock; |
| 110 | 233 | ||
| 234 | /** @filp: Pointer to the core file structure. */ | ||
| 111 | struct file *filp; | 235 | struct file *filp; |
| 236 | |||
| 237 | /** | ||
| 238 | * @driver_priv: | ||
| 239 | * | ||
| 240 | * Optional pointer for driver private data. Can be allocated in | ||
| 241 | * &drm_driver.open and should be freed in &drm_driver.postclose. | ||
| 242 | */ | ||
| 112 | void *driver_priv; | 243 | void *driver_priv; |
| 113 | 244 | ||
| 114 | struct drm_master *master; /* master this node is currently associated with | ||
| 115 | N.B. not always dev->master */ | ||
| 116 | /** | 245 | /** |
| 117 | * fbs - List of framebuffers associated with this file. | 246 | * @fbs: |
| 247 | * | ||
| 248 | * List of &struct drm_framebuffer associated with this file, using the | ||
| 249 | * &drm_framebuffer.filp_head entry. | ||
| 118 | * | 250 | * |
| 119 | * Protected by fbs_lock. Note that the fbs list holds a reference on | 251 | * Protected by @fbs_lock. Note that the @fbs list holds a reference on |
| 120 | * the fb object to prevent it from untimely disappearing. | 252 | * the framebuffer object to prevent it from untimely disappearing. |
| 121 | */ | 253 | */ |
| 122 | struct list_head fbs; | 254 | struct list_head fbs; |
| 255 | |||
| 256 | /** @fbs_lock: Protects @fbs. */ | ||
| 123 | struct mutex fbs_lock; | 257 | struct mutex fbs_lock; |
| 124 | 258 | ||
| 125 | /** User-created blob properties; this retains a reference on the | 259 | /** |
| 126 | * property. */ | 260 | * @blobs: |
| 261 | * | ||
| 262 | * User-created blob properties; this retains a reference on the | ||
| 263 | * property. | ||
| 264 | * | ||
| 265 | * Protected by @drm_mode_config.blob_lock; | ||
| 266 | */ | ||
| 127 | struct list_head blobs; | 267 | struct list_head blobs; |
| 128 | 268 | ||
| 269 | /** @event_wait: Waitqueue for new events added to @event_list. */ | ||
| 129 | wait_queue_head_t event_wait; | 270 | wait_queue_head_t event_wait; |
| 271 | |||
| 272 | /** | ||
| 273 | * @pending_event_list: | ||
| 274 | * | ||
| 275 | * List of pending &struct drm_pending_event, used to clean up pending | ||
| 276 | * events in case this file gets closed before the event is signalled. | ||
| 277 | * Uses the &drm_pending_event.pending_link entry. | ||
| 278 | * | ||
| 279 | * Protect by &drm_device.event_lock. | ||
| 280 | */ | ||
| 130 | struct list_head pending_event_list; | 281 | struct list_head pending_event_list; |
| 282 | |||
| 283 | /** | ||
| 284 | * @event_list: | ||
| 285 | * | ||
| 286 | * List of &struct drm_pending_event, ready for delivery to userspace | ||
| 287 | * through drm_read(). Uses the &drm_pending_event.link entry. | ||
| 288 | * | ||
| 289 | * Protect by &drm_device.event_lock. | ||
| 290 | */ | ||
| 131 | struct list_head event_list; | 291 | struct list_head event_list; |
| 292 | |||
| 293 | /** | ||
| 294 | * @event_space: | ||
| 295 | * | ||
| 296 | * Available event space to prevent userspace from | ||
| 297 | * exhausting kernel memory. Currently limited to the fairly arbitrary | ||
| 298 | * value of 4KB. | ||
| 299 | */ | ||
| 132 | int event_space; | 300 | int event_space; |
| 133 | 301 | ||
| 302 | /** @event_read_lock: Serializes drm_read(). */ | ||
| 134 | struct mutex event_read_lock; | 303 | struct mutex event_read_lock; |
| 135 | 304 | ||
| 305 | /** | ||
| 306 | * @prime: | ||
| 307 | * | ||
| 308 | * Per-file buffer caches used by the PRIME buffer sharing code. | ||
| 309 | */ | ||
| 136 | struct drm_prime_file_private prime; | 310 | struct drm_prime_file_private prime; |
| 311 | |||
| 312 | /* private: */ | ||
| 313 | unsigned long lock_count; /* DRI1 legacy lock count */ | ||
| 137 | }; | 314 | }; |
| 138 | 315 | ||
| 316 | /** | ||
| 317 | * drm_is_primary_client - is this an open file of the primary node | ||
| 318 | * @file_priv: DRM file | ||
| 319 | * | ||
| 320 | * Returns true if this is an open file of the primary node, i.e. | ||
| 321 | * &drm_file.minor of @file_priv is a primary minor. | ||
| 322 | * | ||
| 323 | * See also the :ref:`section on primary nodes and authentication | ||
| 324 | * <drm_primary_node>`. | ||
| 325 | */ | ||
| 326 | static inline bool drm_is_primary_client(const struct drm_file *file_priv) | ||
| 327 | { | ||
| 328 | return file_priv->minor->type == DRM_MINOR_PRIMARY; | ||
| 329 | } | ||
| 330 | |||
| 331 | /** | ||
| 332 | * drm_is_render_client - is this an open file of the render node | ||
| 333 | * @file_priv: DRM file | ||
| 334 | * | ||
| 335 | * Returns true if this is an open file of the render node, i.e. | ||
| 336 | * &drm_file.minor of @file_priv is a render minor. | ||
| 337 | * | ||
| 338 | * See also the :ref:`section on render nodes <drm_render_node>`. | ||
| 339 | */ | ||
| 139 | static inline bool drm_is_render_client(const struct drm_file *file_priv) | 340 | static inline bool drm_is_render_client(const struct drm_file *file_priv) |
| 140 | { | 341 | { |
| 141 | return file_priv->minor->type == DRM_MINOR_RENDER; | 342 | return file_priv->minor->type == DRM_MINOR_RENDER; |
| 142 | } | 343 | } |
| 143 | 344 | ||
| 345 | /** | ||
| 346 | * drm_is_control_client - is this an open file of the control node | ||
| 347 | * @file_priv: DRM file | ||
| 348 | * | ||
| 349 | * Control nodes are deprecated and in the process of getting removed from the | ||
| 350 | * DRM userspace API. Do not ever use! | ||
| 351 | */ | ||
| 144 | static inline bool drm_is_control_client(const struct drm_file *file_priv) | 352 | static inline bool drm_is_control_client(const struct drm_file *file_priv) |
| 145 | { | 353 | { |
| 146 | return file_priv->minor->type == DRM_MINOR_CONTROL; | 354 | return file_priv->minor->type == DRM_MINOR_CONTROL; |
| 147 | } | 355 | } |
| 148 | 356 | ||
| 149 | static inline bool drm_is_primary_client(const struct drm_file *file_priv) | ||
| 150 | { | ||
| 151 | return file_priv->minor->type == DRM_MINOR_PRIMARY; | ||
| 152 | } | ||
| 153 | |||
| 154 | int drm_open(struct inode *inode, struct file *filp); | 357 | int drm_open(struct inode *inode, struct file *filp); |
| 155 | ssize_t drm_read(struct file *filp, char __user *buffer, | 358 | ssize_t drm_read(struct file *filp, char __user *buffer, |
| 156 | size_t count, loff_t *offset); | 359 | size_t count, loff_t *offset); |
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index b9ade75ecd82..663d80358057 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h | |||
| @@ -178,6 +178,32 @@ struct drm_gem_object { | |||
| 178 | struct dma_buf_attachment *import_attach; | 178 | struct dma_buf_attachment *import_attach; |
| 179 | }; | 179 | }; |
| 180 | 180 | ||
| 181 | /** | ||
| 182 | * DEFINE_DRM_GEM_FOPS() - macro to generate file operations for GEM drivers | ||
| 183 | * @name: name for the generated structure | ||
| 184 | * | ||
| 185 | * This macro autogenerates a suitable &struct file_operations for GEM based | ||
| 186 | * drivers, which can be assigned to &drm_driver.fops. Note that this structure | ||
| 187 | * cannot be shared between drivers, because it contains a reference to the | ||
| 188 | * current module using THIS_MODULE. | ||
| 189 | * | ||
| 190 | * Note that the declaration is already marked as static - if you need a | ||
| 191 | * non-static version of this you're probably doing it wrong and will break the | ||
| 192 | * THIS_MODULE reference by accident. | ||
| 193 | */ | ||
| 194 | #define DEFINE_DRM_GEM_FOPS(name) \ | ||
| 195 | static const struct file_operations name = {\ | ||
| 196 | .owner = THIS_MODULE,\ | ||
| 197 | .open = drm_open,\ | ||
| 198 | .release = drm_release,\ | ||
| 199 | .unlocked_ioctl = drm_ioctl,\ | ||
| 200 | .compat_ioctl = drm_compat_ioctl,\ | ||
| 201 | .poll = drm_poll,\ | ||
| 202 | .read = drm_read,\ | ||
| 203 | .llseek = noop_llseek,\ | ||
| 204 | .mmap = drm_gem_mmap,\ | ||
| 205 | } | ||
| 206 | |||
| 181 | void drm_gem_object_release(struct drm_gem_object *obj); | 207 | void drm_gem_object_release(struct drm_gem_object *obj); |
| 182 | void drm_gem_object_free(struct kref *kref); | 208 | void drm_gem_object_free(struct kref *kref); |
| 183 | int drm_gem_object_init(struct drm_device *dev, | 209 | int drm_gem_object_init(struct drm_device *dev, |
diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index 2abcd5190cc1..f962d33667cf 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h | |||
| @@ -26,6 +26,32 @@ to_drm_gem_cma_obj(struct drm_gem_object *gem_obj) | |||
| 26 | return container_of(gem_obj, struct drm_gem_cma_object, base); | 26 | return container_of(gem_obj, struct drm_gem_cma_object, base); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | /** | ||
| 30 | * DEFINE_DRM_GEM_CMA_FOPS() - macro to generate file operations for CMA drivers | ||
| 31 | * @name: name for the generated structure | ||
| 32 | * | ||
| 33 | * This macro autogenerates a suitable &struct file_operations for CMA based | ||
| 34 | * drivers, which can be assigned to &drm_driver.fops. Note that this structure | ||
| 35 | * cannot be shared between drivers, because it contains a reference to the | ||
| 36 | * current module using THIS_MODULE. | ||
| 37 | * | ||
| 38 | * Note that the declaration is already marked as static - if you need a | ||
| 39 | * non-static version of this you're probably doing it wrong and will break the | ||
| 40 | * THIS_MODULE reference by accident. | ||
| 41 | */ | ||
| 42 | #define DEFINE_DRM_GEM_CMA_FOPS(name) \ | ||
| 43 | static const struct file_operations name = {\ | ||
| 44 | .owner = THIS_MODULE,\ | ||
| 45 | .open = drm_open,\ | ||
| 46 | .release = drm_release,\ | ||
| 47 | .unlocked_ioctl = drm_ioctl,\ | ||
| 48 | .compat_ioctl = drm_compat_ioctl,\ | ||
| 49 | .poll = drm_poll,\ | ||
| 50 | .read = drm_read,\ | ||
| 51 | .llseek = noop_llseek,\ | ||
| 52 | .mmap = drm_gem_cma_mmap,\ | ||
| 53 | } | ||
| 54 | |||
| 29 | /* free GEM object */ | 55 | /* free GEM object */ |
| 30 | void drm_gem_cma_free_object(struct drm_gem_object *gem_obj); | 56 | void drm_gem_cma_free_object(struct drm_gem_object *gem_obj); |
| 31 | 57 | ||
diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h new file mode 100644 index 000000000000..ab6bcfbceba9 --- /dev/null +++ b/include/drm/drm_scdc_helper.h | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2015 NVIDIA Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the | ||
| 12 | * next paragraph) shall be included in all copies or substantial portions | ||
| 13 | * of the Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #ifndef DRM_SCDC_HELPER_H | ||
| 25 | #define DRM_SCDC_HELPER_H | ||
| 26 | |||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include <linux/types.h> | ||
| 29 | |||
| 30 | #define SCDC_SINK_VERSION 0x01 | ||
| 31 | |||
| 32 | #define SCDC_SOURCE_VERSION 0x02 | ||
| 33 | |||
| 34 | #define SCDC_UPDATE_0 0x10 | ||
| 35 | #define SCDC_READ_REQUEST_TEST (1 << 2) | ||
| 36 | #define SCDC_CED_UPDATE (1 << 1) | ||
| 37 | #define SCDC_STATUS_UPDATE (1 << 0) | ||
| 38 | |||
| 39 | #define SCDC_UPDATE_1 0x11 | ||
| 40 | |||
| 41 | #define SCDC_TMDS_CONFIG 0x20 | ||
| 42 | #define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 (1 << 1) | ||
| 43 | #define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) | ||
| 44 | #define SCDC_SCRAMBLING_ENABLE (1 << 0) | ||
| 45 | |||
| 46 | #define SCDC_SCRAMBLER_STATUS 0x21 | ||
| 47 | #define SCDC_SCRAMBLING_STATUS (1 << 0) | ||
| 48 | |||
| 49 | #define SCDC_CONFIG_0 0x30 | ||
| 50 | #define SCDC_READ_REQUEST_ENABLE (1 << 0) | ||
| 51 | |||
| 52 | #define SCDC_STATUS_FLAGS_0 0x40 | ||
| 53 | #define SCDC_CH2_LOCK (1 < 3) | ||
| 54 | #define SCDC_CH1_LOCK (1 < 2) | ||
| 55 | #define SCDC_CH0_LOCK (1 < 1) | ||
| 56 | #define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) | ||
| 57 | #define SCDC_CLOCK_DETECT (1 << 0) | ||
| 58 | |||
| 59 | #define SCDC_STATUS_FLAGS_1 0x41 | ||
| 60 | |||
| 61 | #define SCDC_ERR_DET_0_L 0x50 | ||
| 62 | #define SCDC_ERR_DET_0_H 0x51 | ||
| 63 | #define SCDC_ERR_DET_1_L 0x52 | ||
| 64 | #define SCDC_ERR_DET_1_H 0x53 | ||
| 65 | #define SCDC_ERR_DET_2_L 0x54 | ||
| 66 | #define SCDC_ERR_DET_2_H 0x55 | ||
| 67 | #define SCDC_CHANNEL_VALID (1 << 7) | ||
| 68 | |||
| 69 | #define SCDC_ERR_DET_CHECKSUM 0x56 | ||
| 70 | |||
| 71 | #define SCDC_TEST_CONFIG_0 0xc0 | ||
| 72 | #define SCDC_TEST_READ_REQUEST (1 << 7) | ||
| 73 | #define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f) | ||
| 74 | |||
| 75 | #define SCDC_MANUFACTURER_IEEE_OUI 0xd0 | ||
| 76 | #define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3 | ||
| 77 | |||
| 78 | #define SCDC_DEVICE_ID 0xd3 | ||
| 79 | #define SCDC_DEVICE_ID_SIZE 8 | ||
| 80 | |||
| 81 | #define SCDC_DEVICE_HARDWARE_REVISION 0xdb | ||
| 82 | #define SCDC_GET_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) | ||
| 83 | #define SCDC_GET_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf) | ||
| 84 | |||
| 85 | #define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc | ||
| 86 | #define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd | ||
| 87 | |||
| 88 | #define SCDC_MANUFACTURER_SPECIFIC 0xde | ||
| 89 | #define SCDC_MANUFACTURER_SPECIFIC_SIZE 34 | ||
| 90 | |||
| 91 | ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer, | ||
| 92 | size_t size); | ||
| 93 | ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset, | ||
| 94 | const void *buffer, size_t size); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * drm_scdc_readb - read a single byte from SCDC | ||
| 98 | * @adapter: I2C adapter | ||
| 99 | * @offset: offset of register to read | ||
| 100 | * @value: return location for the register value | ||
| 101 | * | ||
| 102 | * Reads a single byte from SCDC. This is a convenience wrapper around the | ||
| 103 | * drm_scdc_read() function. | ||
| 104 | * | ||
| 105 | * Returns: | ||
| 106 | * 0 on success or a negative error code on failure. | ||
| 107 | */ | ||
| 108 | static inline int drm_scdc_readb(struct i2c_adapter *adapter, u8 offset, | ||
| 109 | u8 *value) | ||
| 110 | { | ||
| 111 | return drm_scdc_read(adapter, offset, value, sizeof(*value)); | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * drm_scdc_writeb - write a single byte to SCDC | ||
| 116 | * @adapter: I2C adapter | ||
| 117 | * @offset: offset of register to read | ||
| 118 | * @value: return location for the register value | ||
| 119 | * | ||
| 120 | * Writes a single byte to SCDC. This is a convenience wrapper around the | ||
| 121 | * drm_scdc_write() function. | ||
| 122 | * | ||
| 123 | * Returns: | ||
| 124 | * 0 on success or a negative error code on failure. | ||
| 125 | */ | ||
| 126 | static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, | ||
| 127 | u8 value) | ||
| 128 | { | ||
| 129 | return drm_scdc_write(adapter, offset, &value, sizeof(value)); | ||
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * drm_scdc_set_scrambling - enable scrambling | ||
| 134 | * @adapter: I2C adapter for DDC channel | ||
| 135 | * @enable: bool to indicate if scrambling is to be enabled/disabled | ||
| 136 | * | ||
| 137 | * Writes the TMDS config register over SCDC channel, and: | ||
| 138 | * enables scrambling when enable = 1 | ||
| 139 | * disables scrambling when enable = 0 | ||
| 140 | * | ||
| 141 | * Returns: | ||
| 142 | * True if scrambling is set/reset successfully, false otherwise. | ||
| 143 | */ | ||
| 144 | bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable); | ||
| 145 | |||
| 146 | /** | ||
| 147 | * drm_scdc_set_high_tmds_clock_ratio - set TMDS clock ratio | ||
| 148 | * @adapter: I2C adapter for DDC channel | ||
| 149 | * @set: ret or reset the high clock ratio | ||
| 150 | * | ||
| 151 | * Writes to the TMDS config register over SCDC channel, and: | ||
| 152 | * sets TMDS clock ratio to 1/40 when set = 1 | ||
| 153 | * sets TMDS clock ratio to 1/10 when set = 0 | ||
| 154 | * | ||
| 155 | * Returns: | ||
| 156 | * True if write is successful, false otherwise. | ||
| 157 | */ | ||
| 158 | bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set); | ||
| 159 | #endif | ||
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h index 5900945f962d..332a5420243c 100644 --- a/include/linux/dma-fence-array.h +++ b/include/linux/dma-fence-array.h | |||
| @@ -83,4 +83,6 @@ struct dma_fence_array *dma_fence_array_create(int num_fences, | |||
| 83 | u64 context, unsigned seqno, | 83 | u64 context, unsigned seqno, |
| 84 | bool signal_on_any); | 84 | bool signal_on_any); |
| 85 | 85 | ||
| 86 | bool dma_fence_match_context(struct dma_fence *fence, u64 context); | ||
| 87 | |||
| 86 | #endif /* __LINUX_DMA_FENCE_ARRAY_H */ | 88 | #endif /* __LINUX_DMA_FENCE_ARRAY_H */ |
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index edbb4fc674ed..d271ff23984f 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h | |||
| @@ -35,6 +35,7 @@ enum hdmi_infoframe_type { | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | #define HDMI_IEEE_OUI 0x000c03 | 37 | #define HDMI_IEEE_OUI 0x000c03 |
| 38 | #define HDMI_FORUM_IEEE_OUI 0xc45dd8 | ||
| 38 | #define HDMI_INFOFRAME_HEADER_SIZE 4 | 39 | #define HDMI_INFOFRAME_HEADER_SIZE 4 |
| 39 | #define HDMI_AVI_INFOFRAME_SIZE 13 | 40 | #define HDMI_AVI_INFOFRAME_SIZE 13 |
| 40 | #define HDMI_SPD_INFOFRAME_SIZE 25 | 41 | #define HDMI_SPD_INFOFRAME_SIZE 25 |
