提交 18589d74 编写于 作者: D Daniel Vetter

Merge tag 'drm-misc-next-2020-12-17' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v5.12:

UAPI Changes:
- Not necessarily one, but we document that userspace needs to force probe connectors.

Cross-subsystem Changes:
- Require FB_ATY_CT for aty on sparc64.
- video: Fix documentation, and a few compiler warnings.
- Add devicetree bindings for DP connectors.
- dma-buf: Update kernel-doc, and add might_lock for resv objects in begin/end_cpu_access.

Core Changes:
- ttm: Warn when releasing a pinned bo.
- ttm: Cleanup bo size handling.
- cma-helper: Remove prime infix, and implement mmap as GEM CMA functions.
- Split drm_prime_sg_to_page_addr_arrays into 2 functions.
- Add a new api to install irq using devm.
- Update panel kerneldoc to inline style.
- Add DP support to drm/bridge.
- Assorted small fixes to ttm, fb-helper, scheduler.
- Add atomic_commit_setup function callback.
- Automatically use the atomic gamma_set, instead of forcing drivers to declare the default atomic version.
- Allow using degamma for legacy gamma if gamma is not available.
- Clarify that primary/cursor planes are not tied to 1 crtc (depending on possible_crtcs).
- ttm: Cleanup the lru handler.

Driver Changes:
- Add pm support to ingenic.
- Assorted small fixes in radeon, via, rockchip, omap2fb, kmb, gma500, nouveau, virtio, hisilicon, ingenic, s6e63m0 panel, ast, udlfb.
- Add BOE NV110WTM-N61, ys57pss36bh5gq, Khadas TS050 panels.
- Stop using pages with drm_prime_sg_to_page_addr_arrays, and switch all callers to use ttm_sg_tt_init.
- Cleanup compiler and docbook warnings in a lot of fbdev devices.
- Use the drmm_vram_helper in hisilicon.
- Add support for BCM2711 DSI1 in vc4.
- Add support for 8-bit delta RGB panels to ingenic.
- Add documentation on how to test vkms.
- Convert vc4 to atomic helpers.
- Use degamma instead of gamma table in omap, to add support for CTM and color encoding/range properties.
- Rework omap DSI code, and merge all omapdrm modules now that the last omap panel is now a drm panel.
- More refactoring of omap dsi code.
- Enable 10/12 bpc outputs in vc4.
Signed-off-by: NDaniel Vetter <daniel.vetter@ffwll.ch>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/78381a4f-45fd-aed4-174a-94ba051edd37@linux.intel.com
...@@ -18,6 +18,7 @@ properties: ...@@ -18,6 +18,7 @@ properties:
compatible: compatible:
enum: enum:
- brcm,bcm2711-dsi1
- brcm,bcm2835-dsi0 - brcm,bcm2835-dsi0
- brcm,bcm2835-dsi1 - brcm,bcm2835-dsi1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/connector/dp-connector.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: DisplayPort Connector
maintainers:
- Tomi Valkeinen <tomi.valkeinen@ti.com>
properties:
compatible:
const: dp-connector
label: true
type:
enum:
- full-size
- mini
hpd-gpios:
description: A GPIO line connected to HPD
maxItems: 1
dp-pwr-supply:
description: Power supply for the DP_PWR pin
maxItems: 1
port:
$ref: /schemas/graph.yaml#/properties/port
description: Connection to controller providing DP signals
required:
- compatible
- type
- port
additionalProperties: false
examples:
- |
connector {
compatible = "dp-connector";
label = "dp0";
type = "full-size";
port {
dp_connector_in: endpoint {
remote-endpoint = <&dp_out>;
};
};
};
...
...@@ -20,6 +20,7 @@ properties: ...@@ -20,6 +20,7 @@ properties:
compatible: compatible:
enum: enum:
- mantix,mlaf057we51-x - mantix,mlaf057we51-x
- ys,ys57pss36bh5gq
port: true port: true
reg: reg:
......
...@@ -35,6 +35,8 @@ properties: ...@@ -35,6 +35,8 @@ properties:
- boe,tv080wum-nl0 - boe,tv080wum-nl0
# Innolux P079ZCA 7.85" 768x1024 TFT LCD panel # Innolux P079ZCA 7.85" 768x1024 TFT LCD panel
- innolux,p079zca - innolux,p079zca
# Khadas TS050 5" 1080x1920 LCD panel
- khadas,ts050
# Kingdisplay KD097D04 9.7" 1536x2048 TFT LCD panel # Kingdisplay KD097D04 9.7" 1536x2048 TFT LCD panel
- kingdisplay,kd097d04 - kingdisplay,kd097d04
# LG ACX467AKM-7 4.95" 1080×1920 LCD Panel # LG ACX467AKM-7 4.95" 1080×1920 LCD Panel
......
...@@ -76,6 +76,8 @@ properties: ...@@ -76,6 +76,8 @@ properties:
# BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel # BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel
- boe,nv101wxmn51 - boe,nv101wxmn51
# BOE NV133FHM-N61 13.3" FHD (1920x1080) TFT LCD Panel # BOE NV133FHM-N61 13.3" FHD (1920x1080) TFT LCD Panel
- boe,nv110wtm-n61
# BOE NV110WTM-N61 11.0" 2160x1440 TFT LCD Panel
- boe,nv133fhm-n61 - boe,nv133fhm-n61
# BOE NV133FHM-N62 13.3" FHD (1920x1080) TFT LCD Panel # BOE NV133FHM-N62 13.3" FHD (1920x1080) TFT LCD Panel
- boe,nv133fhm-n62 - boe,nv133fhm-n62
......
ST-Ericsson Multi Channel Display Engine MCDE
The ST-Ericsson MCDE is a display controller with support for compositing
and displaying several channels memory resident graphics data on DSI or
LCD displays or bridges. It is used in the ST-Ericsson U8500 platform.
Required properties:
- compatible: must be:
"ste,mcde"
- reg: register base for the main MCDE control registers, should be
0x1000 in size
- interrupts: the interrupt line for the MCDE
- epod-supply: a phandle to the EPOD regulator
- vana-supply: a phandle to the analog voltage regulator
- clocks: an array of the MCDE clocks in this strict order:
MCDECLK (main MCDE clock), LCDCLK (LCD clock), PLLDSI
(HDMI clock), DSI0ESCLK (DSI0 energy save clock),
DSI1ESCLK (DSI1 energy save clock), DSI2ESCLK (DSI2 energy
save clock)
- clock-names: must be the following array:
"mcde", "lcd", "hdmi"
to match the required clock inputs above.
- #address-cells: should be <1> (for the DSI hosts that will be children)
- #size-cells: should be <1> (for the DSI hosts that will be children)
- ranges: this should always be stated
Required subnodes:
The devicetree must specify subnodes for the DSI host adapters.
These must have the following characteristics:
- compatible: must be:
"ste,mcde-dsi"
- reg: must specify the register range for the DSI host
- vana-supply: phandle to the VANA voltage regulator
- clocks: phandles to the high speed and low power (energy save) clocks
the high speed clock is not present on the third (dsi2) block, so it
should only have the "lp" clock
- clock-names: "hs" for the high speed clock and "lp" for the low power
(energy save) clock
- #address-cells: should be <1>
- #size-cells: should be <0>
Display panels and bridges will appear as children on the DSI hosts, and
the displays are connected to the DSI hosts using the common binding
for video transmitter interfaces; see
Documentation/devicetree/bindings/media/video-interfaces.txt
If a DSI host is unused (not connected) it will have no children defined.
Example:
mcde@a0350000 {
compatible = "ste,mcde";
reg = <0xa0350000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
epod-supply = <&db8500_b2r2_mcde_reg>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_MCDECLK>, /* Main MCDE clock */
<&prcmu_clk PRCMU_LCDCLK>, /* LCD clock */
<&prcmu_clk PRCMU_PLLDSI>; /* HDMI clock */
clock-names = "mcde", "lcd", "hdmi";
#address-cells = <1>;
#size-cells = <1>;
ranges;
dsi0: dsi@a0351000 {
compatible = "ste,mcde-dsi";
reg = <0xa0351000 0x1000>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_DSI0CLK>, <&prcmu_clk PRCMU_DSI0ESCCLK>;
clock-names = "hs", "lp";
#address-cells = <1>;
#size-cells = <0>;
panel {
compatible = "samsung,s6d16d0";
reg = <0>;
vdd1-supply = <&ab8500_ldo_aux1_reg>;
reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
};
};
dsi1: dsi@a0352000 {
compatible = "ste,mcde-dsi";
reg = <0xa0352000 0x1000>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_DSI1CLK>, <&prcmu_clk PRCMU_DSI1ESCCLK>;
clock-names = "hs", "lp";
#address-cells = <1>;
#size-cells = <0>;
};
dsi2: dsi@a0353000 {
compatible = "ste,mcde-dsi";
reg = <0xa0353000 0x1000>;
vana-supply = <&ab8500_ldo_ana_reg>;
/* This DSI port only has the Low Power / Energy Save clock */
clocks = <&prcmu_clk PRCMU_DSI2ESCCLK>;
clock-names = "lp";
#address-cells = <1>;
#size-cells = <0>;
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/ste,mcde.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ST-Ericsson Multi Channel Display Engine MCDE
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
const: ste,mcde
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
description: an array of the MCDE clocks
items:
- description: MCDECLK (main MCDE clock)
- description: LCDCLK (LCD clock)
- description: PLLDSI (HDMI clock)
clock-names:
items:
- const: mcde
- const: lcd
- const: hdmi
resets:
maxItems: 1
epod-supply:
description: a phandle to the EPOD regulator
vana-supply:
description: a phandle to the analog voltage regulator
port:
type: object
description:
A DPI port node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
patternProperties:
"^dsi@[0-9a-f]+$":
description: subnodes for the three DSI host adapters
type: object
allOf:
- $ref: dsi-controller.yaml#
properties:
compatible:
const: ste,mcde-dsi
reg:
maxItems: 1
vana-supply:
description: a phandle to the analog voltage regulator
clocks:
description: phandles to the high speed and low power (energy save) clocks
the high speed clock is not present on the third (dsi2) block, so it
should only have the "lp" clock
minItems: 1
maxItems: 2
clock-names:
oneOf:
- items:
- const: hs
- const: lp
- items:
- const: lp
required:
- compatible
- reg
- vana-supply
- clocks
- clock-names
unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- epod-supply
- vana-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mfd/dbx500-prcmu.h>
#include <dt-bindings/gpio/gpio.h>
mcde@a0350000 {
compatible = "ste,mcde";
reg = <0xa0350000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
epod-supply = <&db8500_b2r2_mcde_reg>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_MCDECLK>,
<&prcmu_clk PRCMU_LCDCLK>,
<&prcmu_clk PRCMU_PLLDSI>;
clock-names = "mcde", "lcd", "hdmi";
#address-cells = <1>;
#size-cells = <1>;
ranges;
dsi0: dsi@a0351000 {
compatible = "ste,mcde-dsi";
reg = <0xa0351000 0x1000>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_DSI0CLK>, <&prcmu_clk PRCMU_DSI0ESCCLK>;
clock-names = "hs", "lp";
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "samsung,s6d16d0";
reg = <0>;
vdd1-supply = <&ab8500_ldo_aux1_reg>;
reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
};
};
dsi1: dsi@a0352000 {
compatible = "ste,mcde-dsi";
reg = <0xa0352000 0x1000>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_DSI1CLK>, <&prcmu_clk PRCMU_DSI1ESCCLK>;
clock-names = "hs", "lp";
#address-cells = <1>;
#size-cells = <0>;
};
dsi2: dsi@a0353000 {
compatible = "ste,mcde-dsi";
reg = <0xa0353000 0x1000>;
vana-supply = <&ab8500_ldo_ana_reg>;
/* This DSI port only has the Low Power / Energy Save clock */
clocks = <&prcmu_clk PRCMU_DSI2ESCCLK>;
clock-names = "lp";
#address-cells = <1>;
#size-cells = <0>;
};
};
...
...@@ -1260,6 +1260,8 @@ patternProperties: ...@@ -1260,6 +1260,8 @@ patternProperties:
description: YSH & ATIL description: YSH & ATIL
"^yones-toptech,.*": "^yones-toptech,.*":
description: Yones Toptech Co., Ltd. description: Yones Toptech Co., Ltd.
"^ys,.*":
description: Shenzhen Yashi Changhua Intelligent Technology Co., Ltd.
"^ysoft,.*": "^ysoft,.*":
description: Y Soft Corporation a.s. description: Y Soft Corporation a.s.
"^zealz,.*": "^zealz,.*":
......
...@@ -7,6 +7,76 @@ ...@@ -7,6 +7,76 @@
.. kernel-doc:: drivers/gpu/drm/vkms/vkms_drv.c .. kernel-doc:: drivers/gpu/drm/vkms/vkms_drv.c
:doc: vkms (Virtual Kernel Modesetting) :doc: vkms (Virtual Kernel Modesetting)
Setup
=====
The VKMS driver can be setup with the following steps:
To check if VKMS is loaded, run::
lsmod | grep vkms
This should list the VKMS driver. If no output is obtained, then
you need to enable and/or load the VKMS driver.
Ensure that the VKMS driver has been set as a loadable module in your
kernel config file. Do::
make nconfig
Go to `Device Drivers> Graphics support`
Enable `Virtual KMS (EXPERIMENTAL)`
Compile and build the kernel for the changes to get reflected.
Now, to load the driver, use::
sudo modprobe vkms
On running the lsmod command now, the VKMS driver will appear listed.
You can also observe the driver being loaded in the dmesg logs.
To disable the driver, use ::
sudo modprobe -r vkms
Testing With IGT
================
The IGT GPU Tools is a test suite used specifically for debugging and
development of the DRM drivers.
The IGT Tools can be installed from
`here <https://gitlab.freedesktop.org/drm/igt-gpu-tools>`_ .
The tests need to be run without a compositor, so you need to switch to text
only mode. You can do this by::
sudo systemctl isolate multi-user.target
To return to graphical mode, do::
sudo systemctl isolate graphical.target
Once you are in text only mode, you can run tests using the --device switch
or IGT_DEVICE variable to specify the device filter for the driver we want
to test. IGT_DEVICE can also be used with the run-test.sh script to run the
tests for a specific driver::
sudo ./build/tests/<name of test> --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/<name of test>
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./scripts/run-tests.sh -t <name of test>
For example, to test the functionality of the writeback library,
we can run the kms_writeback test::
sudo ./build/tests/kms_writeback --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/kms_writeback
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./scripts/run-tests.sh -t kms_writeback
You can also run subtests if you do not want to run the entire test::
sudo ./build/tests/kms_flip --run-subtest basic-plain-flip --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/kms_flip --run-subtest basic-plain-flip
TODO TODO
==== ====
......
...@@ -518,6 +518,9 @@ ...@@ -518,6 +518,9 @@
clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>, clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>,
<&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>; <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>;
clock-names = "fck", "sys_clk"; clock-names = "fck", "sys_clk";
#address-cells = <1>;
#size-cells = <0>;
}; };
}; };
...@@ -550,6 +553,9 @@ ...@@ -550,6 +553,9 @@
clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>, clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>,
<&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>; <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>;
clock-names = "fck", "sys_clk"; clock-names = "fck", "sys_clk";
#address-cells = <1>;
#size-cells = <0>;
}; };
}; };
......
...@@ -369,8 +369,8 @@ CONFIG_DRM_OMAP=m ...@@ -369,8 +369,8 @@ CONFIG_DRM_OMAP=m
CONFIG_OMAP5_DSS_HDMI=y CONFIG_OMAP5_DSS_HDMI=y
CONFIG_OMAP2_DSS_SDI=y CONFIG_OMAP2_DSS_SDI=y
CONFIG_OMAP2_DSS_DSI=y CONFIG_OMAP2_DSS_DSI=y
CONFIG_DRM_OMAP_PANEL_DSI_CM=m
CONFIG_DRM_TILCDC=m CONFIG_DRM_TILCDC=m
CONFIG_DRM_PANEL_DSI_CM=m
CONFIG_DRM_PANEL_SIMPLE=m CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_PANEL_LG_LB035Q02=m CONFIG_DRM_PANEL_LG_LB035Q02=m
CONFIG_DRM_PANEL_NEC_NL8048HL11=m CONFIG_DRM_PANEL_NEC_NL8048HL11=m
......
...@@ -480,7 +480,7 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags) ...@@ -480,7 +480,7 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
* *
* 4. Once a driver is done with a shared buffer it needs to call * 4. Once a driver is done with a shared buffer it needs to call
* dma_buf_detach() (after cleaning up any mappings) and then release the * dma_buf_detach() (after cleaning up any mappings) and then release the
* reference acquired with dma_buf_get by calling dma_buf_put(). * reference acquired with dma_buf_get() by calling dma_buf_put().
* *
* For the detailed semantics exporters are expected to implement see * For the detailed semantics exporters are expected to implement see
* &dma_buf_ops. * &dma_buf_ops.
...@@ -496,9 +496,10 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags) ...@@ -496,9 +496,10 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
* by the exporter. see &struct dma_buf_export_info * by the exporter. see &struct dma_buf_export_info
* for further details. * for further details.
* *
* Returns, on success, a newly created dma_buf object, which wraps the * Returns, on success, a newly created struct dma_buf object, which wraps the
* supplied private data and operations for dma_buf_ops. On either missing * supplied private data and operations for struct dma_buf_ops. On either
* ops, or error in allocating struct dma_buf, will return negative error. * missing ops, or error in allocating struct dma_buf, will return negative
* error.
* *
* For most cases the easiest way to create @exp_info is through the * For most cases the easiest way to create @exp_info is through the
* %DEFINE_DMA_BUF_EXPORT_INFO macro. * %DEFINE_DMA_BUF_EXPORT_INFO macro.
...@@ -584,7 +585,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) ...@@ -584,7 +585,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
EXPORT_SYMBOL_GPL(dma_buf_export); EXPORT_SYMBOL_GPL(dma_buf_export);
/** /**
* dma_buf_fd - returns a file descriptor for the given dma_buf * dma_buf_fd - returns a file descriptor for the given struct dma_buf
* @dmabuf: [in] pointer to dma_buf for which fd is required. * @dmabuf: [in] pointer to dma_buf for which fd is required.
* @flags: [in] flags to give to fd * @flags: [in] flags to give to fd
* *
...@@ -608,10 +609,10 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags) ...@@ -608,10 +609,10 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags)
EXPORT_SYMBOL_GPL(dma_buf_fd); EXPORT_SYMBOL_GPL(dma_buf_fd);
/** /**
* dma_buf_get - returns the dma_buf structure related to an fd * dma_buf_get - returns the struct dma_buf related to an fd
* @fd: [in] fd associated with the dma_buf to be returned * @fd: [in] fd associated with the struct dma_buf to be returned
* *
* On success, returns the dma_buf structure associated with an fd; uses * On success, returns the struct dma_buf associated with an fd; uses
* file's refcounting done by fget to increase refcount. returns ERR_PTR * file's refcounting done by fget to increase refcount. returns ERR_PTR
* otherwise. * otherwise.
*/ */
...@@ -653,8 +654,7 @@ void dma_buf_put(struct dma_buf *dmabuf) ...@@ -653,8 +654,7 @@ void dma_buf_put(struct dma_buf *dmabuf)
EXPORT_SYMBOL_GPL(dma_buf_put); EXPORT_SYMBOL_GPL(dma_buf_put);
/** /**
* dma_buf_dynamic_attach - Add the device to dma_buf's attachments list; optionally, * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list
* calls attach() of dma_buf_ops to allow device-specific attach functionality
* @dmabuf: [in] buffer to attach device to. * @dmabuf: [in] buffer to attach device to.
* @dev: [in] device to be attached. * @dev: [in] device to be attached.
* @importer_ops: [in] importer operations for the attachment * @importer_ops: [in] importer operations for the attachment
...@@ -663,6 +663,9 @@ EXPORT_SYMBOL_GPL(dma_buf_put); ...@@ -663,6 +663,9 @@ EXPORT_SYMBOL_GPL(dma_buf_put);
* Returns struct dma_buf_attachment pointer for this attachment. Attachments * Returns struct dma_buf_attachment pointer for this attachment. Attachments
* must be cleaned up by calling dma_buf_detach(). * must be cleaned up by calling dma_buf_detach().
* *
* Optionally this calls &dma_buf_ops.attach to allow device-specific attach
* functionality.
*
* Returns: * Returns:
* *
* A pointer to newly created &dma_buf_attachment on success, or a negative * A pointer to newly created &dma_buf_attachment on success, or a negative
...@@ -769,12 +772,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, ...@@ -769,12 +772,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
EXPORT_SYMBOL_GPL(dma_buf_attach); EXPORT_SYMBOL_GPL(dma_buf_attach);
/** /**
* dma_buf_detach - Remove the given attachment from dmabuf's attachments list; * dma_buf_detach - Remove the given attachment from dmabuf's attachments list
* optionally calls detach() of dma_buf_ops for device-specific detach
* @dmabuf: [in] buffer to detach from. * @dmabuf: [in] buffer to detach from.
* @attach: [in] attachment to be detached; is free'd after this call. * @attach: [in] attachment to be detached; is free'd after this call.
* *
* Clean up a device attachment obtained by calling dma_buf_attach(). * Clean up a device attachment obtained by calling dma_buf_attach().
*
* Optionally this calls &dma_buf_ops.detach for device-specific detach.
*/ */
void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
{ {
...@@ -805,9 +809,15 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); ...@@ -805,9 +809,15 @@ EXPORT_SYMBOL_GPL(dma_buf_detach);
/** /**
* dma_buf_pin - Lock down the DMA-buf * dma_buf_pin - Lock down the DMA-buf
*
* @attach: [in] attachment which should be pinned * @attach: [in] attachment which should be pinned
* *
* Only dynamic importers (who set up @attach with dma_buf_dynamic_attach()) may
* call this, and only for limited use cases like scanout and not for temporary
* pin operations. It is not permitted to allow userspace to pin arbitrary
* amounts of buffers through this interface.
*
* Buffers must be unpinned by calling dma_buf_unpin().
*
* Returns: * Returns:
* 0 on success, negative error code on failure. * 0 on success, negative error code on failure.
*/ */
...@@ -816,6 +826,8 @@ int dma_buf_pin(struct dma_buf_attachment *attach) ...@@ -816,6 +826,8 @@ int dma_buf_pin(struct dma_buf_attachment *attach)
struct dma_buf *dmabuf = attach->dmabuf; struct dma_buf *dmabuf = attach->dmabuf;
int ret = 0; int ret = 0;
WARN_ON(!dma_buf_attachment_is_dynamic(attach));
dma_resv_assert_held(dmabuf->resv); dma_resv_assert_held(dmabuf->resv);
if (dmabuf->ops->pin) if (dmabuf->ops->pin)
...@@ -826,14 +838,19 @@ int dma_buf_pin(struct dma_buf_attachment *attach) ...@@ -826,14 +838,19 @@ int dma_buf_pin(struct dma_buf_attachment *attach)
EXPORT_SYMBOL_GPL(dma_buf_pin); EXPORT_SYMBOL_GPL(dma_buf_pin);
/** /**
* dma_buf_unpin - Remove lock from DMA-buf * dma_buf_unpin - Unpin a DMA-buf
*
* @attach: [in] attachment which should be unpinned * @attach: [in] attachment which should be unpinned
*
* This unpins a buffer pinned by dma_buf_pin() and allows the exporter to move
* any mapping of @attach again and inform the importer through
* &dma_buf_attach_ops.move_notify.
*/ */
void dma_buf_unpin(struct dma_buf_attachment *attach) void dma_buf_unpin(struct dma_buf_attachment *attach)
{ {
struct dma_buf *dmabuf = attach->dmabuf; struct dma_buf *dmabuf = attach->dmabuf;
WARN_ON(!dma_buf_attachment_is_dynamic(attach));
dma_resv_assert_held(dmabuf->resv); dma_resv_assert_held(dmabuf->resv);
if (dmabuf->ops->unpin) if (dmabuf->ops->unpin)
...@@ -1001,15 +1018,15 @@ EXPORT_SYMBOL_GPL(dma_buf_move_notify); ...@@ -1001,15 +1018,15 @@ EXPORT_SYMBOL_GPL(dma_buf_move_notify);
* vmalloc space might be limited and result in vmap calls failing. * vmalloc space might be limited and result in vmap calls failing.
* *
* Interfaces:: * Interfaces::
*
* void \*dma_buf_vmap(struct dma_buf \*dmabuf) * void \*dma_buf_vmap(struct dma_buf \*dmabuf)
* void dma_buf_vunmap(struct dma_buf \*dmabuf, void \*vaddr) * void dma_buf_vunmap(struct dma_buf \*dmabuf, void \*vaddr)
* *
* The vmap call can fail if there is no vmap support in the exporter, or if * The vmap call can fail if there is no vmap support in the exporter, or if
* it runs out of vmalloc space. Fallback to kmap should be implemented. Note * it runs out of vmalloc space. Note that the dma-buf layer keeps a reference
* that the dma-buf layer keeps a reference count for all vmap access and * count for all vmap access and calls down into the exporter's vmap function
* calls down into the exporter's vmap function only when no vmapping exists, * only when no vmapping exists, and only unmaps it once. Protection against
* and only unmaps it once. Protection against concurrent vmap/vunmap calls is * concurrent vmap/vunmap calls is provided by taking the &dma_buf.lock mutex.
* provided by taking the dma_buf->lock mutex.
* *
* - For full compatibility on the importer side with existing userspace * - For full compatibility on the importer side with existing userspace
* interfaces, which might already support mmap'ing buffers. This is needed in * interfaces, which might already support mmap'ing buffers. This is needed in
...@@ -1061,11 +1078,12 @@ EXPORT_SYMBOL_GPL(dma_buf_move_notify); ...@@ -1061,11 +1078,12 @@ EXPORT_SYMBOL_GPL(dma_buf_move_notify);
* shootdowns would increase the complexity quite a bit. * shootdowns would increase the complexity quite a bit.
* *
* Interface:: * Interface::
*
* int dma_buf_mmap(struct dma_buf \*, struct vm_area_struct \*, * int dma_buf_mmap(struct dma_buf \*, struct vm_area_struct \*,
* unsigned long); * unsigned long);
* *
* If the importing subsystem simply provides a special-purpose mmap call to * If the importing subsystem simply provides a special-purpose mmap call to
* set up a mapping in userspace, calling do_mmap with dma_buf->file will * set up a mapping in userspace, calling do_mmap with &dma_buf.file will
* equally achieve that for a dma-buf object. * equally achieve that for a dma-buf object.
*/ */
...@@ -1098,6 +1116,11 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf, ...@@ -1098,6 +1116,11 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
* dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is * dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is
* it guaranteed to be coherent with other DMA access. * it guaranteed to be coherent with other DMA access.
* *
* This function will also wait for any DMA transactions tracked through
* implicit synchronization in &dma_buf.resv. For DMA transactions with explicit
* synchronization this function will only ensure cache coherency, callers must
* ensure synchronization with such DMA transactions on their own.
*
* Can return negative error values, returns 0 on success. * Can return negative error values, returns 0 on success.
*/ */
int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
...@@ -1108,6 +1131,8 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, ...@@ -1108,6 +1131,8 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
if (WARN_ON(!dmabuf)) if (WARN_ON(!dmabuf))
return -EINVAL; return -EINVAL;
might_lock(&dmabuf->resv->lock.base);
if (dmabuf->ops->begin_cpu_access) if (dmabuf->ops->begin_cpu_access)
ret = dmabuf->ops->begin_cpu_access(dmabuf, direction); ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
...@@ -1141,6 +1166,8 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf, ...@@ -1141,6 +1166,8 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf,
WARN_ON(!dmabuf); WARN_ON(!dmabuf);
might_lock(&dmabuf->resv->lock.base);
if (dmabuf->ops->end_cpu_access) if (dmabuf->ops->end_cpu_access)
ret = dmabuf->ops->end_cpu_access(dmabuf, direction); ret = dmabuf->ops->end_cpu_access(dmabuf, direction);
...@@ -1199,7 +1226,10 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap); ...@@ -1199,7 +1226,10 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
* This call may fail due to lack of virtual mapping address space. * This call may fail due to lack of virtual mapping address space.
* These calls are optional in drivers. The intended use for them * These calls are optional in drivers. The intended use for them
* is for mapping objects linear in kernel space for high use objects. * is for mapping objects linear in kernel space for high use objects.
* Please attempt to use kmap/kunmap before thinking about these interfaces. *
* To ensure coherency users must call dma_buf_begin_cpu_access() and
* dma_buf_end_cpu_access() around any cpu access performed through this
* mapping.
* *
* Returns 0 on success, or a negative errno code otherwise. * Returns 0 on success, or a negative errno code otherwise.
*/ */
......
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
#include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_module.h>
#include <drm/ttm/ttm_execbuf_util.h> #include <drm/ttm/ttm_execbuf_util.h>
#include <drm/amdgpu_drm.h> #include <drm/amdgpu_drm.h>
......
...@@ -453,7 +453,7 @@ static int add_bo_to_vm(struct amdgpu_device *adev, struct kgd_mem *mem, ...@@ -453,7 +453,7 @@ static int add_bo_to_vm(struct amdgpu_device *adev, struct kgd_mem *mem,
struct amdgpu_bo *bo = mem->bo; struct amdgpu_bo *bo = mem->bo;
uint64_t va = mem->va; uint64_t va = mem->va;
struct list_head *list_bo_va = &mem->bo_va_list; struct list_head *list_bo_va = &mem->bo_va_list;
unsigned long bo_size = bo->tbo.mem.size; unsigned long bo_size = bo->tbo.base.size;
if (!va) { if (!va) {
pr_err("Invalid VA when adding BO to VM\n"); pr_err("Invalid VA when adding BO to VM\n");
...@@ -1281,7 +1281,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( ...@@ -1281,7 +1281,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
struct kgd_dev *kgd, struct kgd_mem *mem, uint64_t *size) struct kgd_dev *kgd, struct kgd_mem *mem, uint64_t *size)
{ {
struct amdkfd_process_info *process_info = mem->process_info; struct amdkfd_process_info *process_info = mem->process_info;
unsigned long bo_size = mem->bo->tbo.mem.size; unsigned long bo_size = mem->bo->tbo.base.size;
struct kfd_bo_va_list *entry, *tmp; struct kfd_bo_va_list *entry, *tmp;
struct bo_vm_reservation_context ctx; struct bo_vm_reservation_context ctx;
struct ttm_validate_buffer *bo_list_entry; struct ttm_validate_buffer *bo_list_entry;
...@@ -1402,7 +1402,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( ...@@ -1402,7 +1402,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
mutex_lock(&mem->lock); mutex_lock(&mem->lock);
domain = mem->domain; domain = mem->domain;
bo_size = bo->tbo.mem.size; bo_size = bo->tbo.base.size;
pr_debug("Map VA 0x%llx - 0x%llx to vm %p domain %s\n", pr_debug("Map VA 0x%llx - 0x%llx to vm %p domain %s\n",
mem->va, mem->va,
...@@ -1506,7 +1506,7 @@ int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( ...@@ -1506,7 +1506,7 @@ int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
struct amdgpu_device *adev = get_amdgpu_device(kgd); struct amdgpu_device *adev = get_amdgpu_device(kgd);
struct amdkfd_process_info *process_info = struct amdkfd_process_info *process_info =
((struct amdgpu_vm *)vm)->process_info; ((struct amdgpu_vm *)vm)->process_info;
unsigned long bo_size = mem->bo->tbo.mem.size; unsigned long bo_size = mem->bo->tbo.base.size;
struct kfd_bo_va_list *entry; struct kfd_bo_va_list *entry;
struct bo_vm_reservation_context ctx; struct bo_vm_reservation_context ctx;
int ret; int ret;
......
...@@ -1427,7 +1427,7 @@ static void amdgpu_ib_preempt_job_recovery(struct drm_gpu_scheduler *sched) ...@@ -1427,7 +1427,7 @@ static void amdgpu_ib_preempt_job_recovery(struct drm_gpu_scheduler *sched)
struct dma_fence *fence; struct dma_fence *fence;
spin_lock(&sched->job_list_lock); spin_lock(&sched->job_list_lock);
list_for_each_entry(s_job, &sched->ring_mirror_list, node) { list_for_each_entry(s_job, &sched->pending_list, list) {
fence = sched->ops->run_job(s_job); fence = sched->ops->run_job(s_job);
dma_fence_put(fence); dma_fence_put(fence);
} }
...@@ -1459,10 +1459,10 @@ static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring) ...@@ -1459,10 +1459,10 @@ static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring)
no_preempt: no_preempt:
spin_lock(&sched->job_list_lock); spin_lock(&sched->job_list_lock);
list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) { list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
if (dma_fence_is_signaled(&s_job->s_fence->finished)) { if (dma_fence_is_signaled(&s_job->s_fence->finished)) {
/* remove job from ring_mirror_list */ /* remove job from ring_mirror_list */
list_del_init(&s_job->node); list_del_init(&s_job->list);
sched->ops->free_job(s_job); sched->ops->free_job(s_job);
continue; continue;
} }
......
...@@ -4155,8 +4155,8 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev) ...@@ -4155,8 +4155,8 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev)
continue; continue;
spin_lock(&ring->sched.job_list_lock); spin_lock(&ring->sched.job_list_lock);
job = list_first_entry_or_null(&ring->sched.ring_mirror_list, job = list_first_entry_or_null(&ring->sched.pending_list,
struct drm_sched_job, node); struct drm_sched_job, list);
spin_unlock(&ring->sched.job_list_lock); spin_unlock(&ring->sched.job_list_lock);
if (job) if (job)
return true; return true;
......
...@@ -269,7 +269,7 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach, ...@@ -269,7 +269,7 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
case TTM_PL_TT: case TTM_PL_TT:
sgt = drm_prime_pages_to_sg(obj->dev, sgt = drm_prime_pages_to_sg(obj->dev,
bo->tbo.ttm->pages, bo->tbo.ttm->pages,
bo->tbo.num_pages); bo->tbo.ttm->num_pages);
if (IS_ERR(sgt)) if (IS_ERR(sgt))
return sgt; return sgt;
......
...@@ -120,7 +120,7 @@ uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo) ...@@ -120,7 +120,7 @@ uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
if (bo->num_pages != 1 || bo->ttm->caching == ttm_cached) if (bo->ttm->num_pages != 1 || bo->ttm->caching == ttm_cached)
return AMDGPU_BO_INVALID_OFFSET; return AMDGPU_BO_INVALID_OFFSET;
if (bo->ttm->dma_address[0] + PAGE_SIZE >= adev->gmc.agp_size) if (bo->ttm->dma_address[0] + PAGE_SIZE >= adev->gmc.agp_size)
......
...@@ -271,7 +271,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched) ...@@ -271,7 +271,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched)
} }
/* Signal all jobs already scheduled to HW */ /* Signal all jobs already scheduled to HW */
list_for_each_entry(s_job, &sched->ring_mirror_list, node) { list_for_each_entry(s_job, &sched->pending_list, list) {
struct drm_sched_fence *s_fence = s_job->s_fence; struct drm_sched_fence *s_fence = s_job->s_fence;
dma_fence_set_error(&s_fence->finished, -EHWPOISON); dma_fence_set_error(&s_fence->finished, -EHWPOISON);
......
...@@ -787,7 +787,7 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) ...@@ -787,7 +787,7 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
if (r < 0) if (r < 0)
return r; return r;
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap); r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.mem.num_pages, &bo->kmap);
if (r) if (r)
return r; return r;
......
...@@ -174,12 +174,12 @@ static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo) ...@@ -174,12 +174,12 @@ static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo)
static inline unsigned long amdgpu_bo_size(struct amdgpu_bo *bo) static inline unsigned long amdgpu_bo_size(struct amdgpu_bo *bo)
{ {
return bo->tbo.num_pages << PAGE_SHIFT; return bo->tbo.base.size;
} }
static inline unsigned amdgpu_bo_ngpu_pages(struct amdgpu_bo *bo) static inline unsigned amdgpu_bo_ngpu_pages(struct amdgpu_bo *bo)
{ {
return (bo->tbo.num_pages << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE; return bo->tbo.base.size / AMDGPU_GPU_PAGE_SIZE;
} }
static inline unsigned amdgpu_bo_gpu_page_alignment(struct amdgpu_bo *bo) static inline unsigned amdgpu_bo_gpu_page_alignment(struct amdgpu_bo *bo)
......
...@@ -127,7 +127,7 @@ TRACE_EVENT(amdgpu_bo_create, ...@@ -127,7 +127,7 @@ TRACE_EVENT(amdgpu_bo_create,
TP_fast_assign( TP_fast_assign(
__entry->bo = bo; __entry->bo = bo;
__entry->pages = bo->tbo.num_pages; __entry->pages = bo->tbo.mem.num_pages;
__entry->type = bo->tbo.mem.mem_type; __entry->type = bo->tbo.mem.mem_type;
__entry->prefer = bo->preferred_domains; __entry->prefer = bo->preferred_domains;
__entry->allow = bo->allowed_domains; __entry->allow = bo->allowed_domains;
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_module.h>
#include <drm/drm_debugfs.h> #include <drm/drm_debugfs.h>
#include <drm/amdgpu_drm.h> #include <drm/amdgpu_drm.h>
...@@ -637,7 +636,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, ...@@ -637,7 +636,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
out: out:
/* update statistics */ /* update statistics */
atomic64_add((u64)bo->num_pages << PAGE_SHIFT, &adev->num_bytes_moved); atomic64_add(bo->base.size, &adev->num_bytes_moved);
amdgpu_bo_move_notify(bo, evict, new_mem); amdgpu_bo_move_notify(bo, evict, new_mem);
return 0; return 0;
} }
...@@ -918,8 +917,8 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_bo_device *bdev, ...@@ -918,8 +917,8 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_bo_device *bdev,
goto release_sg; goto release_sg;
/* convert SG to linear array of pages and dma addresses */ /* convert SG to linear array of pages and dma addresses */
drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
gtt->ttm.dma_address, ttm->num_pages); ttm->num_pages);
return 0; return 0;
...@@ -1265,9 +1264,8 @@ static int amdgpu_ttm_tt_populate(struct ttm_bo_device *bdev, ...@@ -1265,9 +1264,8 @@ static int amdgpu_ttm_tt_populate(struct ttm_bo_device *bdev,
ttm->sg = sgt; ttm->sg = sgt;
} }
drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
gtt->ttm.dma_address, ttm->num_pages);
ttm->num_pages);
return 0; return 0;
} }
...@@ -2124,7 +2122,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo, ...@@ -2124,7 +2122,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
return r; return r;
} }
num_pages = bo->tbo.num_pages; num_pages = bo->tbo.mem.num_pages;
mm_node = bo->tbo.mem.mm_node; mm_node = bo->tbo.mem.mm_node;
num_loops = 0; num_loops = 0;
while (num_pages) { while (num_pages) {
...@@ -2154,7 +2152,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo, ...@@ -2154,7 +2152,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
} }
} }
num_pages = bo->tbo.num_pages; num_pages = bo->tbo.mem.num_pages;
mm_node = bo->tbo.mem.mm_node; mm_node = bo->tbo.mem.mm_node;
while (num_pages) { while (num_pages) {
......
...@@ -1160,6 +1160,6 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout) ...@@ -1160,6 +1160,6 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
error: error:
dma_fence_put(fence); dma_fence_put(fence);
amdgpu_bo_unreserve(bo); amdgpu_bo_unreserve(bo);
amdgpu_bo_unref(&bo); amdgpu_bo_free_kernel(&bo, NULL, NULL);
return r; return r;
} }
...@@ -496,6 +496,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, ...@@ -496,6 +496,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
struct amdgpu_job *job; struct amdgpu_job *job;
struct amdgpu_ib *ib; struct amdgpu_ib *ib;
uint64_t addr; uint64_t addr;
void *msg = NULL;
int i, r; int i, r;
r = amdgpu_job_alloc_with_ib(adev, 64, r = amdgpu_job_alloc_with_ib(adev, 64,
...@@ -505,6 +506,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, ...@@ -505,6 +506,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
ib = &job->ibs[0]; ib = &job->ibs[0];
addr = amdgpu_bo_gpu_offset(bo); addr = amdgpu_bo_gpu_offset(bo);
msg = amdgpu_bo_kptr(bo);
ib->ptr[0] = PACKET0(adev->vcn.internal.data0, 0); ib->ptr[0] = PACKET0(adev->vcn.internal.data0, 0);
ib->ptr[1] = addr; ib->ptr[1] = addr;
ib->ptr[2] = PACKET0(adev->vcn.internal.data1, 0); ib->ptr[2] = PACKET0(adev->vcn.internal.data1, 0);
...@@ -523,7 +525,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, ...@@ -523,7 +525,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
amdgpu_bo_fence(bo, f, false); amdgpu_bo_fence(bo, f, false);
amdgpu_bo_unreserve(bo); amdgpu_bo_unreserve(bo);
amdgpu_bo_unref(&bo); amdgpu_bo_free_kernel(&bo, NULL, (void **)&msg);
if (fence) if (fence)
*fence = dma_fence_get(f); *fence = dma_fence_get(f);
...@@ -536,7 +538,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, ...@@ -536,7 +538,7 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
err: err:
amdgpu_bo_unreserve(bo); amdgpu_bo_unreserve(bo);
amdgpu_bo_unref(&bo); amdgpu_bo_free_kernel(&bo, NULL, (void **)&msg);
return r; return r;
} }
...@@ -890,6 +892,7 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) ...@@ -890,6 +892,7 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
error: error:
dma_fence_put(fence); dma_fence_put(fence);
amdgpu_bo_unreserve(bo); amdgpu_bo_unreserve(bo);
amdgpu_bo_unref(&bo); amdgpu_bo_free_kernel(&bo, NULL, NULL);
return r; return r;
} }
...@@ -653,9 +653,11 @@ void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev, ...@@ -653,9 +653,11 @@ void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
if (!bo->parent) if (!bo->parent)
continue; continue;
ttm_bo_move_to_lru_tail(&bo->tbo, &vm->lru_bulk_move); ttm_bo_move_to_lru_tail(&bo->tbo, &bo->tbo.mem,
&vm->lru_bulk_move);
if (bo->shadow) if (bo->shadow)
ttm_bo_move_to_lru_tail(&bo->shadow->tbo, ttm_bo_move_to_lru_tail(&bo->shadow->tbo,
&bo->shadow->tbo.mem,
&vm->lru_bulk_move); &vm->lru_bulk_move);
} }
spin_unlock(&ttm_bo_glob.lru_lock); spin_unlock(&ttm_bo_glob.lru_lock);
......
...@@ -554,7 +554,7 @@ static int mes_v10_1_allocate_eop_buf(struct amdgpu_device *adev) ...@@ -554,7 +554,7 @@ static int mes_v10_1_allocate_eop_buf(struct amdgpu_device *adev)
return r; return r;
} }
memset(eop, 0, adev->mes.eop_gpu_obj->tbo.mem.size); memset(eop, 0, adev->mes.eop_gpu_obj->tbo.base.size);
amdgpu_bo_kunmap(adev->mes.eop_gpu_obj); amdgpu_bo_kunmap(adev->mes.eop_gpu_obj);
amdgpu_bo_unreserve(adev->mes.eop_gpu_obj); amdgpu_bo_unreserve(adev->mes.eop_gpu_obj);
......
...@@ -5446,7 +5446,6 @@ static void dm_disable_vblank(struct drm_crtc *crtc) ...@@ -5446,7 +5446,6 @@ static void dm_disable_vblank(struct drm_crtc *crtc)
static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
.reset = dm_crtc_reset_state, .reset = dm_crtc_reset_state,
.destroy = amdgpu_dm_crtc_destroy, .destroy = amdgpu_dm_crtc_destroy,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = dm_crtc_duplicate_state, .atomic_duplicate_state = dm_crtc_duplicate_state,
......
...@@ -550,7 +550,6 @@ static void komeda_crtc_vblank_disable(struct drm_crtc *crtc) ...@@ -550,7 +550,6 @@ static void komeda_crtc_vblank_disable(struct drm_crtc *crtc)
} }
static const struct drm_crtc_funcs komeda_crtc_funcs = { static const struct drm_crtc_funcs komeda_crtc_funcs = {
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
......
...@@ -510,7 +510,6 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc) ...@@ -510,7 +510,6 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc)
} }
static const struct drm_crtc_funcs malidp_crtc_funcs = { static const struct drm_crtc_funcs malidp_crtc_funcs = {
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
......
...@@ -820,7 +820,6 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { ...@@ -820,7 +820,6 @@ static const struct drm_crtc_funcs armada_crtc_funcs = {
.cursor_set = armada_drm_crtc_cursor_set, .cursor_set = armada_drm_crtc_cursor_set,
.cursor_move = armada_drm_crtc_cursor_move, .cursor_move = armada_drm_crtc_cursor_move,
.destroy = armada_drm_crtc_destroy, .destroy = armada_drm_crtc_destroy,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
......
...@@ -39,7 +39,6 @@ static void ast_cursor_fini(struct ast_private *ast) ...@@ -39,7 +39,6 @@ static void ast_cursor_fini(struct ast_private *ast)
for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) { for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) {
gbo = ast->cursor.gbo[i]; gbo = ast->cursor.gbo[i];
drm_gem_vram_vunmap(gbo, &ast->cursor.map[i]);
drm_gem_vram_unpin(gbo); drm_gem_vram_unpin(gbo);
drm_gem_vram_put(gbo); drm_gem_vram_put(gbo);
} }
...@@ -53,14 +52,13 @@ static void ast_cursor_release(struct drm_device *dev, void *ptr) ...@@ -53,14 +52,13 @@ static void ast_cursor_release(struct drm_device *dev, void *ptr)
} }
/* /*
* Allocate cursor BOs and pins them at the end of VRAM. * Allocate cursor BOs and pin them at the end of VRAM.
*/ */
int ast_cursor_init(struct ast_private *ast) int ast_cursor_init(struct ast_private *ast)
{ {
struct drm_device *dev = &ast->base; struct drm_device *dev = &ast->base;
size_t size, i; size_t size, i;
struct drm_gem_vram_object *gbo; struct drm_gem_vram_object *gbo;
struct dma_buf_map map;
int ret; int ret;
size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE);
...@@ -77,15 +75,7 @@ int ast_cursor_init(struct ast_private *ast) ...@@ -77,15 +75,7 @@ int ast_cursor_init(struct ast_private *ast)
drm_gem_vram_put(gbo); drm_gem_vram_put(gbo);
goto err_drm_gem_vram_put; goto err_drm_gem_vram_put;
} }
ret = drm_gem_vram_vmap(gbo, &map);
if (ret) {
drm_gem_vram_unpin(gbo);
drm_gem_vram_put(gbo);
goto err_drm_gem_vram_put;
}
ast->cursor.gbo[i] = gbo; ast->cursor.gbo[i] = gbo;
ast->cursor.map[i] = map;
} }
return drmm_add_action_or_reset(dev, ast_cursor_release, NULL); return drmm_add_action_or_reset(dev, ast_cursor_release, NULL);
...@@ -94,7 +84,6 @@ int ast_cursor_init(struct ast_private *ast) ...@@ -94,7 +84,6 @@ int ast_cursor_init(struct ast_private *ast)
while (i) { while (i) {
--i; --i;
gbo = ast->cursor.gbo[i]; gbo = ast->cursor.gbo[i];
drm_gem_vram_vunmap(gbo, &ast->cursor.map[i]);
drm_gem_vram_unpin(gbo); drm_gem_vram_unpin(gbo);
drm_gem_vram_put(gbo); drm_gem_vram_put(gbo);
} }
...@@ -168,38 +157,37 @@ static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int h ...@@ -168,38 +157,37 @@ static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int h
int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb) int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb)
{ {
struct drm_device *dev = &ast->base; struct drm_device *dev = &ast->base;
struct drm_gem_vram_object *gbo; struct drm_gem_vram_object *dst_gbo = ast->cursor.gbo[ast->cursor.next_index];
struct dma_buf_map map; struct drm_gem_vram_object *src_gbo = drm_gem_vram_of_gem(fb->obj[0]);
int ret; struct dma_buf_map src_map, dst_map;
void *src;
void __iomem *dst; void __iomem *dst;
void *src;
int ret;
if (drm_WARN_ON_ONCE(dev, fb->width > AST_MAX_HWC_WIDTH) || if (drm_WARN_ON_ONCE(dev, fb->width > AST_MAX_HWC_WIDTH) ||
drm_WARN_ON_ONCE(dev, fb->height > AST_MAX_HWC_HEIGHT)) drm_WARN_ON_ONCE(dev, fb->height > AST_MAX_HWC_HEIGHT))
return -EINVAL; return -EINVAL;
gbo = drm_gem_vram_of_gem(fb->obj[0]); ret = drm_gem_vram_vmap(src_gbo, &src_map);
ret = drm_gem_vram_pin(gbo, 0);
if (ret) if (ret)
return ret; return ret;
ret = drm_gem_vram_vmap(gbo, &map); src = src_map.vaddr; /* TODO: Use mapping abstraction properly */
if (ret)
goto err_drm_gem_vram_unpin;
src = map.vaddr; /* TODO: Use mapping abstraction properly */
dst = ast->cursor.map[ast->cursor.next_index].vaddr_iomem; ret = drm_gem_vram_vmap(dst_gbo, &dst_map);
if (ret)
goto err_drm_gem_vram_vunmap;
dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */
/* do data transfer to cursor BO */ /* do data transfer to cursor BO */
update_cursor_image(dst, src, fb->width, fb->height); update_cursor_image(dst, src, fb->width, fb->height);
drm_gem_vram_vunmap(gbo, &map); drm_gem_vram_vunmap(dst_gbo, &dst_map);
drm_gem_vram_unpin(gbo); drm_gem_vram_vunmap(src_gbo, &src_map);
return 0; return 0;
err_drm_gem_vram_unpin: err_drm_gem_vram_vunmap:
drm_gem_vram_unpin(gbo); drm_gem_vram_vunmap(src_gbo, &src_map);
return ret; return ret;
} }
...@@ -251,17 +239,26 @@ static void ast_cursor_set_location(struct ast_private *ast, u16 x, u16 y, ...@@ -251,17 +239,26 @@ static void ast_cursor_set_location(struct ast_private *ast, u16 x, u16 y,
void ast_cursor_show(struct ast_private *ast, int x, int y, void ast_cursor_show(struct ast_private *ast, int x, int y,
unsigned int offset_x, unsigned int offset_y) unsigned int offset_x, unsigned int offset_y)
{ {
struct drm_device *dev = &ast->base;
struct drm_gem_vram_object *gbo = ast->cursor.gbo[ast->cursor.next_index];
struct dma_buf_map map;
u8 x_offset, y_offset; u8 x_offset, y_offset;
u8 __iomem *dst; u8 __iomem *dst;
u8 __iomem *sig; u8 __iomem *sig;
u8 jreg; u8 jreg;
int ret;
dst = ast->cursor.map[ast->cursor.next_index].vaddr; ret = drm_gem_vram_vmap(gbo, &map);
if (drm_WARN_ONCE(dev, ret, "drm_gem_vram_vmap() failed, ret=%d\n", ret))
return;
dst = map.vaddr_iomem; /* TODO: Use mapping abstraction properly */
sig = dst + AST_HWC_SIZE; sig = dst + AST_HWC_SIZE;
writel(x, sig + AST_HWC_SIGNATURE_X); writel(x, sig + AST_HWC_SIGNATURE_X);
writel(y, sig + AST_HWC_SIGNATURE_Y); writel(y, sig + AST_HWC_SIGNATURE_Y);
drm_gem_vram_vunmap(gbo, &map);
if (x < 0) { if (x < 0) {
x_offset = (-x) + offset_x; x_offset = (-x) + offset_x;
x = 0; x = 0;
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#ifndef __AST_DRV_H__ #ifndef __AST_DRV_H__
#define __AST_DRV_H__ #define __AST_DRV_H__
#include <linux/dma-buf-map.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -133,7 +132,6 @@ struct ast_private { ...@@ -133,7 +132,6 @@ struct ast_private {
struct { struct {
struct drm_gem_vram_object *gbo[AST_DEFAULT_HWC_NUM]; struct drm_gem_vram_object *gbo[AST_DEFAULT_HWC_NUM];
struct dma_buf_map map[AST_DEFAULT_HWC_NUM];
unsigned int next_index; unsigned int next_index;
} cursor; } cursor;
......
...@@ -903,7 +903,6 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, ...@@ -903,7 +903,6 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
static const struct drm_crtc_funcs ast_crtc_funcs = { static const struct drm_crtc_funcs ast_crtc_funcs = {
.reset = ast_crtc_reset, .reset = ast_crtc_reset,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
......
...@@ -473,7 +473,6 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { ...@@ -473,7 +473,6 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
.atomic_destroy_state = atmel_hlcdc_crtc_destroy_state, .atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
.enable_vblank = atmel_hlcdc_crtc_enable_vblank, .enable_vblank = atmel_hlcdc_crtc_enable_vblank,
.disable_vblank = atmel_hlcdc_crtc_disable_vblank, .disable_vblank = atmel_hlcdc_crtc_disable_vblank,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
}; };
int atmel_hlcdc_crtc_create(struct drm_device *dev) int atmel_hlcdc_crtc_create(struct drm_device *dev)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
...@@ -20,6 +21,8 @@ struct display_connector { ...@@ -20,6 +21,8 @@ struct display_connector {
struct gpio_desc *hpd_gpio; struct gpio_desc *hpd_gpio;
int hpd_irq; int hpd_irq;
struct regulator *dp_pwr;
}; };
static inline struct display_connector * static inline struct display_connector *
...@@ -172,11 +175,12 @@ static int display_connector_probe(struct platform_device *pdev) ...@@ -172,11 +175,12 @@ static int display_connector_probe(struct platform_device *pdev)
of_property_read_string(pdev->dev.of_node, "label", &label); of_property_read_string(pdev->dev.of_node, "label", &label);
/* /*
* Get the HPD GPIO for DVI and HDMI connectors. If the GPIO can provide * Get the HPD GPIO for DVI, HDMI and DP connectors. If the GPIO can provide
* edge interrupts, register an interrupt handler. * edge interrupts, register an interrupt handler.
*/ */
if (type == DRM_MODE_CONNECTOR_DVII || if (type == DRM_MODE_CONNECTOR_DVII ||
type == DRM_MODE_CONNECTOR_HDMIA) { type == DRM_MODE_CONNECTOR_HDMIA ||
type == DRM_MODE_CONNECTOR_DisplayPort) {
conn->hpd_gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", conn->hpd_gpio = devm_gpiod_get_optional(&pdev->dev, "hpd",
GPIOD_IN); GPIOD_IN);
if (IS_ERR(conn->hpd_gpio)) { if (IS_ERR(conn->hpd_gpio)) {
...@@ -223,6 +227,38 @@ static int display_connector_probe(struct platform_device *pdev) ...@@ -223,6 +227,38 @@ static int display_connector_probe(struct platform_device *pdev)
} }
} }
/* Get the DP PWR for DP connector. */
if (type == DRM_MODE_CONNECTOR_DisplayPort) {
int ret;
conn->dp_pwr = devm_regulator_get_optional(&pdev->dev, "dp-pwr");
if (IS_ERR(conn->dp_pwr)) {
ret = PTR_ERR(conn->dp_pwr);
switch (ret) {
case -ENODEV:
conn->dp_pwr = NULL;
break;
case -EPROBE_DEFER:
return -EPROBE_DEFER;
default:
dev_err(&pdev->dev, "failed to get DP PWR regulator: %d\n", ret);
return ret;
}
}
if (conn->dp_pwr) {
ret = regulator_enable(conn->dp_pwr);
if (ret) {
dev_err(&pdev->dev, "failed to enable DP PWR regulator: %d\n", ret);
return ret;
}
}
}
conn->bridge.funcs = &display_connector_bridge_funcs; conn->bridge.funcs = &display_connector_bridge_funcs;
conn->bridge.of_node = pdev->dev.of_node; conn->bridge.of_node = pdev->dev.of_node;
...@@ -251,6 +287,9 @@ static int display_connector_remove(struct platform_device *pdev) ...@@ -251,6 +287,9 @@ static int display_connector_remove(struct platform_device *pdev)
{ {
struct display_connector *conn = platform_get_drvdata(pdev); struct display_connector *conn = platform_get_drvdata(pdev);
if (conn->dp_pwr)
regulator_disable(conn->dp_pwr);
drm_bridge_remove(&conn->bridge); drm_bridge_remove(&conn->bridge);
if (!IS_ERR(conn->bridge.ddc)) if (!IS_ERR(conn->bridge.ddc))
...@@ -275,6 +314,9 @@ static const struct of_device_id display_connector_match[] = { ...@@ -275,6 +314,9 @@ static const struct of_device_id display_connector_match[] = {
}, { }, {
.compatible = "vga-connector", .compatible = "vga-connector",
.data = (void *)DRM_MODE_CONNECTOR_VGA, .data = (void *)DRM_MODE_CONNECTOR_VGA,
}, {
.compatible = "dp-connector",
.data = (void *)DRM_MODE_CONNECTOR_DisplayPort,
}, },
{}, {},
}; };
......
...@@ -2040,6 +2040,9 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc) ...@@ -2040,6 +2040,9 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
* should always call this function from their * should always call this function from their
* &drm_mode_config_funcs.atomic_commit hook. * &drm_mode_config_funcs.atomic_commit hook.
* *
* Drivers that need to extend the commit setup to private objects can use the
* &drm_mode_config_helper_funcs.atomic_commit_setup hook.
*
* To be able to use this support drivers need to use a few more helper * To be able to use this support drivers need to use a few more helper
* functions. drm_atomic_helper_wait_for_dependencies() must be called before * functions. drm_atomic_helper_wait_for_dependencies() must be called before
* actually committing the hardware state, and for nonblocking commits this call * actually committing the hardware state, and for nonblocking commits this call
...@@ -2083,8 +2086,11 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, ...@@ -2083,8 +2086,11 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
struct drm_plane *plane; struct drm_plane *plane;
struct drm_plane_state *old_plane_state, *new_plane_state; struct drm_plane_state *old_plane_state, *new_plane_state;
struct drm_crtc_commit *commit; struct drm_crtc_commit *commit;
const struct drm_mode_config_helper_funcs *funcs;
int i, ret; int i, ret;
funcs = state->dev->mode_config.helper_private;
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
commit = kzalloc(sizeof(*commit), GFP_KERNEL); commit = kzalloc(sizeof(*commit), GFP_KERNEL);
if (!commit) if (!commit)
...@@ -2169,6 +2175,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, ...@@ -2169,6 +2175,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
new_plane_state->commit = drm_crtc_commit_get(commit); new_plane_state->commit = drm_crtc_commit_get(commit);
} }
if (funcs && funcs->atomic_commit_setup)
return funcs->atomic_commit_setup(state);
return 0; return 0;
} }
EXPORT_SYMBOL(drm_atomic_helper_setup_commit); EXPORT_SYMBOL(drm_atomic_helper_setup_commit);
...@@ -3499,76 +3508,6 @@ int drm_atomic_helper_page_flip_target(struct drm_crtc *crtc, ...@@ -3499,76 +3508,6 @@ int drm_atomic_helper_page_flip_target(struct drm_crtc *crtc,
} }
EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
/**
* drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
* @crtc: CRTC object
* @red: red correction table
* @green: green correction table
* @blue: green correction table
* @size: size of the tables
* @ctx: lock acquire context
*
* Implements support for legacy gamma correction table for drivers
* that support color management through the DEGAMMA_LUT/GAMMA_LUT
* properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
* how the atomic color management and gamma tables work.
*/
int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue,
uint32_t size,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_device *dev = crtc->dev;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
struct drm_property_blob *blob = NULL;
struct drm_color_lut *blob_data;
int i, ret = 0;
bool replaced;
state = drm_atomic_state_alloc(crtc->dev);
if (!state)
return -ENOMEM;
blob = drm_property_create_blob(dev,
sizeof(struct drm_color_lut) * size,
NULL);
if (IS_ERR(blob)) {
ret = PTR_ERR(blob);
blob = NULL;
goto fail;
}
/* Prepare GAMMA_LUT with the legacy values. */
blob_data = blob->data;
for (i = 0; i < size; i++) {
blob_data[i].red = red[i];
blob_data[i].green = green[i];
blob_data[i].blue = blue[i];
}
state->acquire_ctx = ctx;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state)) {
ret = PTR_ERR(crtc_state);
goto fail;
}
/* Reset DEGAMMA_LUT and CTM properties. */
replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
crtc_state->color_mgmt_changed |= replaced;
ret = drm_atomic_commit(state);
fail:
drm_atomic_state_put(state);
drm_property_blob_put(blob);
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
/** /**
* drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
* the input end of a bridge * the input end of a bridge
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <drm/drm_atomic.h>
#include <drm/drm_color_mgmt.h> #include <drm/drm_color_mgmt.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_device.h> #include <drm/drm_device.h>
...@@ -89,9 +90,8 @@ ...@@ -89,9 +90,8 @@
* modes) appropriately. * modes) appropriately.
* *
* There is also support for a legacy gamma table, which is set up by calling * There is also support for a legacy gamma table, which is set up by calling
* drm_mode_crtc_set_gamma_size(). Drivers which support both should use * drm_mode_crtc_set_gamma_size(). The DRM core will then alias the legacy gamma
* drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the * ramp with "GAMMA_LUT" or, if that is unavailable, "DEGAMMA_LUT".
* "GAMMA_LUT" property above.
* *
* Support for different non RGB color encodings is controlled through * Support for different non RGB color encodings is controlled through
* &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They
...@@ -156,9 +156,6 @@ EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n); ...@@ -156,9 +156,6 @@ EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n);
* optional. The gamma and degamma properties are only attached if * optional. The gamma and degamma properties are only attached if
* their size is not 0 and ctm_property is only attached if has_ctm is * their size is not 0 and ctm_property is only attached if has_ctm is
* true. * true.
*
* Drivers should use drm_atomic_helper_legacy_gamma_set() to implement the
* legacy &drm_crtc_funcs.gamma_set callback.
*/ */
void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
uint degamma_lut_size, uint degamma_lut_size,
...@@ -231,6 +228,116 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, ...@@ -231,6 +228,116 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
} }
EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
/**
* drm_crtc_supports_legacy_gamma - does the crtc support legacy gamma correction table
* @crtc: CRTC object
*
* Returns true/false if the given crtc supports setting the legacy gamma
* correction table.
*/
static bool drm_crtc_supports_legacy_gamma(struct drm_crtc *crtc)
{
u32 gamma_id = crtc->dev->mode_config.gamma_lut_property->base.id;
u32 degamma_id = crtc->dev->mode_config.degamma_lut_property->base.id;
if (!crtc->gamma_size)
return false;
if (crtc->funcs->gamma_set)
return true;
return !!(drm_mode_obj_find_prop_id(&crtc->base, gamma_id) ||
drm_mode_obj_find_prop_id(&crtc->base, degamma_id));
}
/**
* drm_crtc_legacy_gamma_set - set the legacy gamma correction table
* @crtc: CRTC object
* @red: red correction table
* @green: green correction table
* @blue: green correction table
* @size: size of the tables
* @ctx: lock acquire context
*
* Implements support for legacy gamma correction table for drivers
* that have set drm_crtc_funcs.gamma_set or that support color management
* through the DEGAMMA_LUT/GAMMA_LUT properties. See
* drm_crtc_enable_color_mgmt() and the containing chapter for
* how the atomic color management and gamma tables work.
*
* This function sets the gamma using drm_crtc_funcs.gamma_set if set, or
* alternatively using crtc color management properties.
*/
static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue,
u32 size,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_device *dev = crtc->dev;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
struct drm_property_blob *blob;
struct drm_color_lut *blob_data;
u32 gamma_id = dev->mode_config.gamma_lut_property->base.id;
u32 degamma_id = dev->mode_config.degamma_lut_property->base.id;
bool use_gamma_lut;
int i, ret = 0;
bool replaced;
if (crtc->funcs->gamma_set)
return crtc->funcs->gamma_set(crtc, red, green, blue, size, ctx);
if (drm_mode_obj_find_prop_id(&crtc->base, gamma_id))
use_gamma_lut = true;
else if (drm_mode_obj_find_prop_id(&crtc->base, degamma_id))
use_gamma_lut = false;
else
return -ENODEV;
state = drm_atomic_state_alloc(crtc->dev);
if (!state)
return -ENOMEM;
blob = drm_property_create_blob(dev,
sizeof(struct drm_color_lut) * size,
NULL);
if (IS_ERR(blob)) {
ret = PTR_ERR(blob);
blob = NULL;
goto fail;
}
/* Prepare GAMMA_LUT with the legacy values. */
blob_data = blob->data;
for (i = 0; i < size; i++) {
blob_data[i].red = red[i];
blob_data[i].green = green[i];
blob_data[i].blue = blue[i];
}
state->acquire_ctx = ctx;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state)) {
ret = PTR_ERR(crtc_state);
goto fail;
}
/* Set GAMMA_LUT and reset DEGAMMA_LUT and CTM */
replaced = drm_property_replace_blob(&crtc_state->degamma_lut,
use_gamma_lut ? NULL : blob);
replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
use_gamma_lut ? blob : NULL);
crtc_state->color_mgmt_changed |= replaced;
ret = drm_atomic_commit(state);
fail:
drm_atomic_state_put(state);
drm_property_blob_put(blob);
return ret;
}
/** /**
* drm_mode_gamma_set_ioctl - set the gamma table * drm_mode_gamma_set_ioctl - set the gamma table
* @dev: DRM device * @dev: DRM device
...@@ -262,7 +369,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, ...@@ -262,7 +369,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
if (!crtc) if (!crtc)
return -ENOENT; return -ENOENT;
if (crtc->funcs->gamma_set == NULL) if (!drm_crtc_supports_legacy_gamma(crtc))
return -ENOSYS; return -ENOSYS;
/* memcpy into gamma store */ /* memcpy into gamma store */
...@@ -290,8 +397,8 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, ...@@ -290,8 +397,8 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
goto out; goto out;
} }
ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, ret = drm_crtc_legacy_gamma_set(crtc, r_base, g_base, b_base,
crtc->gamma_size, &ctx); crtc->gamma_size, &ctx);
out: out:
DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
* &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy
* operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these
* features are controlled through &drm_property and * features are controlled through &drm_property and
* &drm_mode_config_funcs.atomic_check and &drm_mode_config_funcs.atomic_check. * &drm_mode_config_funcs.atomic_check.
*/ */
/** /**
...@@ -256,6 +256,9 @@ struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc) ...@@ -256,6 +256,9 @@ struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc)
* planes). For really simple hardware which has only 1 plane look at * planes). For really simple hardware which has only 1 plane look at
* drm_simple_display_pipe_init() instead. * drm_simple_display_pipe_init() instead.
* *
* The @primary and @cursor planes are only relevant for legacy uAPI, see
* &drm_crtc.primary and &drm_crtc.cursor.
*
* Returns: * Returns:
* Zero on success, error code on failure. * Zero on success, error code on failure.
*/ */
......
...@@ -675,11 +675,8 @@ static int devm_drm_dev_init(struct device *parent, ...@@ -675,11 +675,8 @@ static int devm_drm_dev_init(struct device *parent,
if (ret) if (ret)
return ret; return ret;
ret = devm_add_action(parent, devm_drm_dev_init_release, dev); return devm_add_action_or_reset(parent,
if (ret) devm_drm_dev_init_release, dev);
devm_drm_dev_init_release(dev);
return ret;
} }
void *__devm_drm_dev_alloc(struct device *parent, void *__devm_drm_dev_alloc(struct device *parent,
...@@ -897,8 +894,6 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) ...@@ -897,8 +894,6 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
if (drm_core_check_feature(dev, DRIVER_MODESET)) if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_modeset_register_all(dev); drm_modeset_register_all(dev);
ret = 0;
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->name, driver->major, driver->minor,
driver->patchlevel, driver->date, driver->patchlevel, driver->date,
......
...@@ -946,11 +946,15 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) ...@@ -946,11 +946,15 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
drm_modeset_lock_all(fb_helper->dev); drm_modeset_lock_all(fb_helper->dev);
drm_client_for_each_modeset(modeset, &fb_helper->client) { drm_client_for_each_modeset(modeset, &fb_helper->client) {
crtc = modeset->crtc; crtc = modeset->crtc;
if (!crtc->funcs->gamma_set || !crtc->gamma_size) if (!crtc->funcs->gamma_set || !crtc->gamma_size) {
return -EINVAL; ret = -EINVAL;
goto out;
}
if (cmap->start + cmap->len > crtc->gamma_size) if (cmap->start + cmap->len > crtc->gamma_size) {
return -EINVAL; ret = -EINVAL;
goto out;
}
r = crtc->gamma_store; r = crtc->gamma_store;
g = r + crtc->gamma_size; g = r + crtc->gamma_size;
...@@ -963,8 +967,9 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) ...@@ -963,8 +967,9 @@ static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
ret = crtc->funcs->gamma_set(crtc, r, g, b, ret = crtc->funcs->gamma_set(crtc, r, g, b,
crtc->gamma_size, NULL); crtc->gamma_size, NULL);
if (ret) if (ret)
return ret; goto out;
} }
out:
drm_modeset_unlock_all(fb_helper->dev); drm_modeset_unlock_all(fb_helper->dev);
return ret; return ret;
...@@ -1054,6 +1059,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info) ...@@ -1054,6 +1059,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
goto out_state; goto out_state;
} }
/*
* FIXME: This always uses gamma_lut. Some HW have only
* degamma_lut, in which case we should reset gamma_lut and set
* degamma_lut. See drm_crtc_legacy_gamma_set().
*/
replaced = drm_property_replace_blob(&crtc_state->degamma_lut, replaced = drm_property_replace_blob(&crtc_state->degamma_lut,
NULL); NULL);
replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
......
...@@ -113,8 +113,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) ...@@ -113,8 +113,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev)
* The memory mapping implementation will vary depending on how the driver * The memory mapping implementation will vary depending on how the driver
* manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() * manages memory. Legacy drivers will use the deprecated drm_legacy_mmap()
* function, modern drivers should use one of the provided memory-manager * function, modern drivers should use one of the provided memory-manager
* specific implementations. For GEM-based drivers this is drm_gem_mmap(), and * specific implementations. For GEM-based drivers this is drm_gem_mmap().
* for drivers which use the CMA GEM helpers it's drm_gem_cma_mmap().
* *
* No other file operations are supported by the DRM userspace API. Overall the * No other file operations are supported by the DRM userspace API. Overall the
* following is an example &file_operations structure:: * following is an example &file_operations structure::
......
...@@ -36,8 +36,9 @@ ...@@ -36,8 +36,9 @@
static const struct drm_gem_object_funcs drm_gem_cma_default_funcs = { static const struct drm_gem_object_funcs drm_gem_cma_default_funcs = {
.free = drm_gem_cma_free_object, .free = drm_gem_cma_free_object,
.print_info = drm_gem_cma_print_info, .print_info = drm_gem_cma_print_info,
.get_sg_table = drm_gem_cma_prime_get_sg_table, .get_sg_table = drm_gem_cma_get_sg_table,
.vmap = drm_gem_cma_prime_vmap, .vmap = drm_gem_cma_vmap,
.mmap = drm_gem_cma_mmap,
.vm_ops = &drm_gem_cma_vm_ops, .vm_ops = &drm_gem_cma_vm_ops,
}; };
...@@ -277,62 +278,6 @@ const struct vm_operations_struct drm_gem_cma_vm_ops = { ...@@ -277,62 +278,6 @@ const struct vm_operations_struct drm_gem_cma_vm_ops = {
}; };
EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops); EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops);
static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj,
struct vm_area_struct *vma)
{
int ret;
/*
* Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
* vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
* the whole buffer.
*/
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_pgoff = 0;
ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr,
cma_obj->paddr, vma->vm_end - vma->vm_start);
if (ret)
drm_gem_vm_close(vma);
return ret;
}
/**
* drm_gem_cma_mmap - memory-map a CMA GEM object
* @filp: file object
* @vma: VMA for the area to be mapped
*
* This function implements an augmented version of the GEM DRM file mmap
* operation for CMA objects: In addition to the usual GEM VMA setup it
* immediately faults in the entire object instead of using on-demaind
* faulting. Drivers which employ the CMA helpers should use this function
* as their ->mmap() handler in the DRM device file's file_operations
* structure.
*
* Instead of directly referencing this function, drivers should use the
* DEFINE_DRM_GEM_CMA_FOPS().macro.
*
* Returns:
* 0 on success or a negative error code on failure.
*/
int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct drm_gem_cma_object *cma_obj;
struct drm_gem_object *gem_obj;
int ret;
ret = drm_gem_mmap(filp, vma);
if (ret)
return ret;
gem_obj = vma->vm_private_data;
cma_obj = to_drm_gem_cma_obj(gem_obj);
return drm_gem_cma_mmap_obj(cma_obj, vma);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_mmap);
#ifndef CONFIG_MMU #ifndef CONFIG_MMU
/** /**
* drm_gem_cma_get_unmapped_area - propose address for mapping in noMMU cases * drm_gem_cma_get_unmapped_area - propose address for mapping in noMMU cases
...@@ -424,18 +369,18 @@ void drm_gem_cma_print_info(struct drm_printer *p, unsigned int indent, ...@@ -424,18 +369,18 @@ void drm_gem_cma_print_info(struct drm_printer *p, unsigned int indent,
EXPORT_SYMBOL(drm_gem_cma_print_info); EXPORT_SYMBOL(drm_gem_cma_print_info);
/** /**
* drm_gem_cma_prime_get_sg_table - provide a scatter/gather table of pinned * drm_gem_cma_get_sg_table - provide a scatter/gather table of pinned
* pages for a CMA GEM object * pages for a CMA GEM object
* @obj: GEM object * @obj: GEM object
* *
* This function exports a scatter/gather table suitable for PRIME usage by * This function exports a scatter/gather table by
* calling the standard DMA mapping API. Drivers using the CMA helpers should * calling the standard DMA mapping API. Drivers using the CMA helpers should
* set this as their &drm_gem_object_funcs.get_sg_table callback. * set this as their &drm_gem_object_funcs.get_sg_table callback.
* *
* Returns: * Returns:
* A pointer to the scatter/gather table of pinned pages or NULL on failure. * A pointer to the scatter/gather table of pinned pages or NULL on failure.
*/ */
struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj) struct sg_table *drm_gem_cma_get_sg_table(struct drm_gem_object *obj)
{ {
struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
struct sg_table *sgt; struct sg_table *sgt;
...@@ -456,7 +401,7 @@ struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj) ...@@ -456,7 +401,7 @@ struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj)
kfree(sgt); kfree(sgt);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table); EXPORT_SYMBOL_GPL(drm_gem_cma_get_sg_table);
/** /**
* drm_gem_cma_prime_import_sg_table - produce a CMA GEM object from another * drm_gem_cma_prime_import_sg_table - produce a CMA GEM object from another
...@@ -501,40 +446,13 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev, ...@@ -501,40 +446,13 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table); EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table);
/** /**
* drm_gem_cma_prime_mmap - memory-map an exported CMA GEM object * drm_gem_cma_vmap - map a CMA GEM object into the kernel's virtual
* @obj: GEM object
* @vma: VMA for the area to be mapped
*
* This function maps a buffer imported via DRM PRIME into a userspace
* process's address space. Drivers that use the CMA helpers should set this
* as their &drm_driver.gem_prime_mmap callback.
*
* Returns:
* 0 on success or a negative error code on failure.
*/
int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
struct vm_area_struct *vma)
{
struct drm_gem_cma_object *cma_obj;
int ret;
ret = drm_gem_mmap_obj(obj, obj->size, vma);
if (ret < 0)
return ret;
cma_obj = to_drm_gem_cma_obj(obj);
return drm_gem_cma_mmap_obj(cma_obj, vma);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap);
/**
* drm_gem_cma_prime_vmap - map a CMA GEM object into the kernel's virtual
* address space * address space
* @obj: GEM object * @obj: GEM object
* @map: Returns the kernel virtual address of the CMA GEM object's backing * @map: Returns the kernel virtual address of the CMA GEM object's backing
* store. * store.
* *
* This function maps a buffer exported via DRM PRIME into the kernel's * This function maps a buffer into the kernel's
* virtual address space. Since the CMA buffers are already mapped into the * virtual address space. Since the CMA buffers are already mapped into the
* kernel virtual address space this simply returns the cached virtual * kernel virtual address space this simply returns the cached virtual
* address. Drivers using the CMA helpers should set this as their DRM * address. Drivers using the CMA helpers should set this as their DRM
...@@ -543,7 +461,7 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap); ...@@ -543,7 +461,7 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap);
* Returns: * Returns:
* 0 on success, or a negative error code otherwise. * 0 on success, or a negative error code otherwise.
*/ */
int drm_gem_cma_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) int drm_gem_cma_vmap(struct drm_gem_object *obj, struct dma_buf_map *map)
{ {
struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
...@@ -551,7 +469,44 @@ int drm_gem_cma_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) ...@@ -551,7 +469,44 @@ int drm_gem_cma_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vmap); EXPORT_SYMBOL_GPL(drm_gem_cma_vmap);
/**
* drm_gem_cma_mmap - memory-map an exported CMA GEM object
* @obj: GEM object
* @vma: VMA for the area to be mapped
*
* This function maps a buffer into a userspace process's address space.
* In addition to the usual GEM VMA setup it immediately faults in the entire
* object instead of using on-demand faulting. Drivers that use the CMA
* helpers should set this as their &drm_gem_object_funcs.mmap callback.
*
* Returns:
* 0 on success or a negative error code on failure.
*/
int drm_gem_cma_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
struct drm_gem_cma_object *cma_obj;
int ret;
/*
* Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
* vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
* the whole buffer.
*/
vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
vma->vm_flags &= ~VM_PFNMAP;
cma_obj = to_drm_gem_cma_obj(obj);
ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr,
cma_obj->paddr, vma->vm_end - vma->vm_start);
if (ret)
drm_gem_vm_close(vma);
return ret;
}
EXPORT_SYMBOL_GPL(drm_gem_cma_mmap);
/** /**
* drm_gem_cma_prime_import_sg_table_vmap - PRIME import another driver's * drm_gem_cma_prime_import_sg_table_vmap - PRIME import another driver's
......
...@@ -214,6 +214,38 @@ int drm_irq_uninstall(struct drm_device *dev) ...@@ -214,6 +214,38 @@ int drm_irq_uninstall(struct drm_device *dev)
} }
EXPORT_SYMBOL(drm_irq_uninstall); EXPORT_SYMBOL(drm_irq_uninstall);
static void devm_drm_irq_uninstall(void *data)
{
drm_irq_uninstall(data);
}
/**
* devm_drm_irq_install - install IRQ handler
* @dev: DRM device
* @irq: IRQ number to install the handler for
*
* devm_drm_irq_install is a help function of drm_irq_install.
*
* if the driver uses devm_drm_irq_install, there is no need
* to call drm_irq_uninstall when the drm module get unloaded,
* as this will done automagically.
*
* Returns:
* Zero on success or a negative error code on failure.
*/
int devm_drm_irq_install(struct drm_device *dev, int irq)
{
int ret;
ret = drm_irq_install(dev, irq);
if (ret)
return ret;
return devm_add_action_or_reset(dev->dev,
devm_drm_irq_uninstall, dev);
}
EXPORT_SYMBOL(devm_drm_irq_install);
#if IS_ENABLED(CONFIG_DRM_LEGACY) #if IS_ENABLED(CONFIG_DRM_LEGACY)
int drm_legacy_irq_control(struct drm_device *dev, void *data, int drm_legacy_irq_control(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
......
...@@ -625,6 +625,7 @@ static void validate_encoder_possible_crtcs(struct drm_encoder *encoder) ...@@ -625,6 +625,7 @@ static void validate_encoder_possible_crtcs(struct drm_encoder *encoder)
void drm_mode_config_validate(struct drm_device *dev) void drm_mode_config_validate(struct drm_device *dev)
{ {
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_crtc *crtc;
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
return; return;
...@@ -636,4 +637,22 @@ void drm_mode_config_validate(struct drm_device *dev) ...@@ -636,4 +637,22 @@ void drm_mode_config_validate(struct drm_device *dev)
validate_encoder_possible_clones(encoder); validate_encoder_possible_clones(encoder);
validate_encoder_possible_crtcs(encoder); validate_encoder_possible_crtcs(encoder);
} }
drm_for_each_crtc(crtc, dev) {
WARN(!crtc->primary, "Missing primary plane on [CRTC:%d:%s]\n",
crtc->base.id, crtc->name);
if (crtc->primary) {
WARN(!(crtc->primary->possible_crtcs & drm_crtc_mask(crtc)),
"Bogus primary plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n",
crtc->primary->base.id, crtc->primary->name,
crtc->base.id, crtc->name);
}
if (crtc->cursor) {
WARN(!(crtc->cursor->possible_crtcs & drm_crtc_mask(crtc)),
"Bogus cursor plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n",
crtc->cursor->base.id, crtc->cursor->name,
crtc->base.id, crtc->name);
}
}
} }
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* A plane represents an image source that can be blended with or overlayed on * A plane represents an image source that can be blended with or overlayed on
* top of a CRTC during the scanout process. Planes take their input data from a * top of a CRTC during the scanout process. Planes take their input data from a
* &drm_framebuffer object. The plane itself specifies the cropping and scaling * &drm_framebuffer object. The plane itself specifies the cropping and scaling
* of that image, and where it is placed on the visible are of a display * of that image, and where it is placed on the visible area of a display
* pipeline, represented by &drm_crtc. A plane can also have additional * pipeline, represented by &drm_crtc. A plane can also have additional
* properties that specify how the pixels are positioned and blended, like * properties that specify how the pixels are positioned and blended, like
* rotation or Z-position. All these properties are stored in &drm_plane_state. * rotation or Z-position. All these properties are stored in &drm_plane_state.
...@@ -49,14 +49,16 @@ ...@@ -49,14 +49,16 @@
* &struct drm_plane (possibly as part of a larger structure) and registers it * &struct drm_plane (possibly as part of a larger structure) and registers it
* with a call to drm_universal_plane_init(). * with a call to drm_universal_plane_init().
* *
* Cursor and overlay planes are optional. All drivers should provide one
* primary plane per CRTC to avoid surprising userspace too much. See enum
* drm_plane_type for a more in-depth discussion of these special uapi-relevant
* plane types. Special planes are associated with their CRTC by calling
* drm_crtc_init_with_planes().
*
* The type of a plane is exposed in the immutable "type" enumeration property, * The type of a plane is exposed in the immutable "type" enumeration property,
* which has one of the following values: "Overlay", "Primary", "Cursor". * which has one of the following values: "Overlay", "Primary", "Cursor" (see
* enum drm_plane_type). A plane can be compatible with multiple CRTCs, see
* &drm_plane.possible_crtcs.
*
* Legacy uAPI doesn't expose the primary and cursor planes directly. DRM core
* relies on the driver to set the primary and optionally the cursor plane used
* for legacy IOCTLs. This is done by calling drm_crtc_init_with_planes(). All
* drivers must provide one primary plane per CRTC to avoid surprising legacy
* userspace too much.
*/ */
static unsigned int drm_num_planes(struct drm_device *dev) static unsigned int drm_num_planes(struct drm_device *dev)
......
...@@ -978,44 +978,58 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, ...@@ -978,44 +978,58 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
EXPORT_SYMBOL(drm_gem_prime_import); EXPORT_SYMBOL(drm_gem_prime_import);
/** /**
* drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array * drm_prime_sg_to_page_array - convert an sg table into a page array
* @sgt: scatter-gather table to convert * @sgt: scatter-gather table to convert
* @pages: optional array of page pointers to store the page array in * @pages: array of page pointers to store the pages in
* @addrs: optional array to store the dma bus address of each page * @max_entries: size of the passed-in array
*
* Exports an sg table into an array of pages.
*
* This function is deprecated and strongly discouraged to be used.
* The page array is only useful for page faults and those can corrupt fields
* in the struct page if they are not handled by the exporting driver.
*/
int __deprecated drm_prime_sg_to_page_array(struct sg_table *sgt,
struct page **pages,
int max_entries)
{
struct sg_page_iter page_iter;
struct page **p = pages;
for_each_sgtable_page(sgt, &page_iter, 0) {
if (WARN_ON(p - pages >= max_entries))
return -1;
*p++ = sg_page_iter_page(&page_iter);
}
return 0;
}
EXPORT_SYMBOL(drm_prime_sg_to_page_array);
/**
* drm_prime_sg_to_dma_addr_array - convert an sg table into a dma addr array
* @sgt: scatter-gather table to convert
* @addrs: array to store the dma bus address of each page
* @max_entries: size of both the passed-in arrays * @max_entries: size of both the passed-in arrays
* *
* Exports an sg table into an array of pages and addresses. This is currently * Exports an sg table into an array of addresses.
* required by the TTM driver in order to do correct fault handling.
* *
* Drivers can use this in their &drm_driver.gem_prime_import_sg_table * Drivers should use this in their &drm_driver.gem_prime_import_sg_table
* implementation. * implementation.
*/ */
int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, int drm_prime_sg_to_dma_addr_array(struct sg_table *sgt, dma_addr_t *addrs,
dma_addr_t *addrs, int max_entries) int max_entries)
{ {
struct sg_dma_page_iter dma_iter; struct sg_dma_page_iter dma_iter;
struct sg_page_iter page_iter;
struct page **p = pages;
dma_addr_t *a = addrs; dma_addr_t *a = addrs;
if (pages) { for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
for_each_sgtable_page(sgt, &page_iter, 0) { if (WARN_ON(a - addrs >= max_entries))
if (WARN_ON(p - pages >= max_entries)) return -1;
return -1; *a++ = sg_page_iter_dma_address(&dma_iter);
*p++ = sg_page_iter_page(&page_iter);
}
}
if (addrs) {
for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
if (WARN_ON(a - addrs >= max_entries))
return -1;
*a++ = sg_page_iter_dma_address(&dma_iter);
}
} }
return 0; return 0;
} }
EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays); EXPORT_SYMBOL(drm_prime_sg_to_dma_addr_array);
/** /**
* drm_prime_gem_destroy - helper to clean up a PRIME-imported GEM object * drm_prime_gem_destroy - helper to clean up a PRIME-imported GEM object
......
...@@ -135,8 +135,7 @@ struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev, ...@@ -135,8 +135,7 @@ struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
goto fail; goto fail;
} }
ret = drm_prime_sg_to_page_addr_arrays(sgt, etnaviv_obj->pages, ret = drm_prime_sg_to_page_array(sgt, etnaviv_obj->pages, npages);
NULL, npages);
if (ret) if (ret)
goto fail; goto fail;
......
...@@ -279,11 +279,8 @@ int oaktrail_hdmi_i2c_init(struct pci_dev *dev) ...@@ -279,11 +279,8 @@ int oaktrail_hdmi_i2c_init(struct pci_dev *dev)
hdmi_dev = pci_get_drvdata(dev); hdmi_dev = pci_get_drvdata(dev);
i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL); i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL);
if (i2c_dev == NULL) { if (!i2c_dev)
DRM_ERROR("Can't allocate interface\n"); return -ENOMEM;
ret = -ENOMEM;
goto exit;
}
i2c_dev->adap = &oaktrail_hdmi_i2c_adapter; i2c_dev->adap = &oaktrail_hdmi_i2c_adapter;
i2c_dev->status = I2C_STAT_INIT; i2c_dev->status = I2C_STAT_INIT;
...@@ -300,16 +297,23 @@ int oaktrail_hdmi_i2c_init(struct pci_dev *dev) ...@@ -300,16 +297,23 @@ int oaktrail_hdmi_i2c_init(struct pci_dev *dev)
oaktrail_hdmi_i2c_adapter.name, hdmi_dev); oaktrail_hdmi_i2c_adapter.name, hdmi_dev);
if (ret) { if (ret) {
DRM_ERROR("Failed to request IRQ for I2C controller\n"); DRM_ERROR("Failed to request IRQ for I2C controller\n");
goto err; goto free_dev;
} }
/* Adapter registration */ /* Adapter registration */
ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter); ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter);
return ret; if (ret) {
DRM_ERROR("Failed to add I2C adapter\n");
goto free_irq;
}
err: return 0;
free_irq:
free_irq(dev->irq, hdmi_dev);
free_dev:
kfree(i2c_dev); kfree(i2c_dev);
exit:
return ret; return ret;
} }
......
...@@ -312,6 +312,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -312,6 +312,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
if (ret) if (ret)
goto out_err; goto out_err;
ret = -ENOMEM;
dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, 0); dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, 0);
if (!dev_priv->mmu) if (!dev_priv->mmu)
goto out_err; goto out_err;
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_ttm.o hibmc_drm_i2c.o hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_i2c.o
obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
...@@ -499,7 +499,7 @@ static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = { ...@@ -499,7 +499,7 @@ static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
int hibmc_de_init(struct hibmc_drm_private *priv) int hibmc_de_init(struct hibmc_drm_private *priv)
{ {
struct drm_device *dev = priv->dev; struct drm_device *dev = &priv->dev;
struct drm_crtc *crtc = &priv->crtc; struct drm_crtc *crtc = &priv->crtc;
struct drm_plane *plane = &priv->primary_plane; struct drm_plane *plane = &priv->primary_plane;
int ret; int ret;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_vram_helper.h> #include <drm/drm_gem_vram_helper.h>
#include <drm/drm_irq.h> #include <drm/drm_irq.h>
#include <drm/drm_managed.h> #include <drm/drm_managed.h>
...@@ -43,6 +44,12 @@ static irqreturn_t hibmc_drm_interrupt(int irq, void *arg) ...@@ -43,6 +44,12 @@ static irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
return drm_gem_vram_fill_create_dumb(file, dev, 0, 128, args);
}
static const struct drm_driver hibmc_driver = { static const struct drm_driver hibmc_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.fops = &hibmc_fops, .fops = &hibmc_fops,
...@@ -77,47 +84,48 @@ static const struct dev_pm_ops hibmc_pm_ops = { ...@@ -77,47 +84,48 @@ static const struct dev_pm_ops hibmc_pm_ops = {
hibmc_pm_resume) hibmc_pm_resume)
}; };
static const struct drm_mode_config_funcs hibmc_mode_funcs = {
.mode_valid = drm_vram_helper_mode_valid,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_gem_fb_create,
};
static int hibmc_kms_init(struct hibmc_drm_private *priv) static int hibmc_kms_init(struct hibmc_drm_private *priv)
{ {
struct drm_device *dev = &priv->dev;
int ret; int ret;
drm_mode_config_init(priv->dev); ret = drmm_mode_config_init(dev);
priv->mode_config_initialized = true; if (ret)
return ret;
priv->dev->mode_config.min_width = 0; dev->mode_config.min_width = 0;
priv->dev->mode_config.min_height = 0; dev->mode_config.min_height = 0;
priv->dev->mode_config.max_width = 1920; dev->mode_config.max_width = 1920;
priv->dev->mode_config.max_height = 1200; dev->mode_config.max_height = 1200;
priv->dev->mode_config.fb_base = priv->fb_base; dev->mode_config.fb_base = priv->fb_base;
priv->dev->mode_config.preferred_depth = 32; dev->mode_config.preferred_depth = 32;
priv->dev->mode_config.prefer_shadow = 1; dev->mode_config.prefer_shadow = 1;
priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs; dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
ret = hibmc_de_init(priv); ret = hibmc_de_init(priv);
if (ret) { if (ret) {
drm_err(priv->dev, "failed to init de: %d\n", ret); drm_err(dev, "failed to init de: %d\n", ret);
return ret; return ret;
} }
ret = hibmc_vdac_init(priv); ret = hibmc_vdac_init(priv);
if (ret) { if (ret) {
drm_err(priv->dev, "failed to init vdac: %d\n", ret); drm_err(dev, "failed to init vdac: %d\n", ret);
return ret; return ret;
} }
return 0; return 0;
} }
static void hibmc_kms_fini(struct hibmc_drm_private *priv)
{
if (priv->mode_config_initialized) {
drm_mode_config_cleanup(priv->dev);
priv->mode_config_initialized = false;
}
}
/* /*
* It can operate in one of three modes: 0, 1 or Sleep. * It can operate in one of three modes: 0, 1 or Sleep.
*/ */
...@@ -202,7 +210,7 @@ static void hibmc_hw_config(struct hibmc_drm_private *priv) ...@@ -202,7 +210,7 @@ static void hibmc_hw_config(struct hibmc_drm_private *priv)
static int hibmc_hw_map(struct hibmc_drm_private *priv) static int hibmc_hw_map(struct hibmc_drm_private *priv)
{ {
struct drm_device *dev = priv->dev; struct drm_device *dev = &priv->dev;
struct pci_dev *pdev = dev->pdev; struct pci_dev *pdev = dev->pdev;
resource_size_t addr, size, ioaddr, iosize; resource_size_t addr, size, ioaddr, iosize;
...@@ -242,40 +250,31 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv) ...@@ -242,40 +250,31 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv)
static int hibmc_unload(struct drm_device *dev) static int hibmc_unload(struct drm_device *dev)
{ {
struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
drm_atomic_helper_shutdown(dev); drm_atomic_helper_shutdown(dev);
if (dev->irq_enabled) if (dev->irq_enabled)
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
pci_disable_msi(dev->pdev); pci_disable_msi(dev->pdev);
hibmc_kms_fini(priv);
hibmc_mm_fini(priv);
dev->dev_private = NULL;
return 0; return 0;
} }
static int hibmc_load(struct drm_device *dev) static int hibmc_load(struct drm_device *dev)
{ {
struct hibmc_drm_private *priv; struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
int ret; int ret;
priv = drmm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
drm_err(dev, "no memory to allocate for hibmc_drm_private\n");
return -ENOMEM;
}
dev->dev_private = priv;
priv->dev = dev;
ret = hibmc_hw_init(priv); ret = hibmc_hw_init(priv);
if (ret) if (ret)
goto err; goto err;
ret = hibmc_mm_init(priv); ret = drmm_vram_helper_init(dev, pci_resource_start(dev->pdev, 0),
if (ret) priv->fb_size);
if (ret) {
drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
goto err; goto err;
}
ret = hibmc_kms_init(priv); ret = hibmc_kms_init(priv);
if (ret) if (ret)
...@@ -310,6 +309,7 @@ static int hibmc_load(struct drm_device *dev) ...@@ -310,6 +309,7 @@ static int hibmc_load(struct drm_device *dev)
static int hibmc_pci_probe(struct pci_dev *pdev, static int hibmc_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
struct hibmc_drm_private *priv;
struct drm_device *dev; struct drm_device *dev;
int ret; int ret;
...@@ -318,12 +318,14 @@ static int hibmc_pci_probe(struct pci_dev *pdev, ...@@ -318,12 +318,14 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
if (ret) if (ret)
return ret; return ret;
dev = drm_dev_alloc(&hibmc_driver, &pdev->dev); priv = devm_drm_dev_alloc(&pdev->dev, &hibmc_driver,
if (IS_ERR(dev)) { struct hibmc_drm_private, dev);
if (IS_ERR(priv)) {
DRM_ERROR("failed to allocate drm_device\n"); DRM_ERROR("failed to allocate drm_device\n");
return PTR_ERR(dev); return PTR_ERR(priv);
} }
dev = &priv->dev;
dev->pdev = pdev; dev->pdev = pdev;
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
...@@ -366,7 +368,6 @@ static void hibmc_pci_remove(struct pci_dev *pdev) ...@@ -366,7 +368,6 @@ static void hibmc_pci_remove(struct pci_dev *pdev)
drm_dev_unregister(dev); drm_dev_unregister(dev);
hibmc_unload(dev); hibmc_unload(dev);
drm_dev_put(dev);
} }
static const struct pci_device_id hibmc_pci_table[] = { static const struct pci_device_id hibmc_pci_table[] = {
......
...@@ -37,12 +37,11 @@ struct hibmc_drm_private { ...@@ -37,12 +37,11 @@ struct hibmc_drm_private {
resource_size_t fb_size; resource_size_t fb_size;
/* drm */ /* drm */
struct drm_device *dev; struct drm_device dev;
struct drm_plane primary_plane; struct drm_plane primary_plane;
struct drm_crtc crtc; struct drm_crtc crtc;
struct drm_encoder encoder; struct drm_encoder encoder;
struct hibmc_connector connector; struct hibmc_connector connector;
bool mode_config_initialized;
}; };
static inline struct hibmc_connector *to_hibmc_connector(struct drm_connector *connector) static inline struct hibmc_connector *to_hibmc_connector(struct drm_connector *connector)
...@@ -52,7 +51,7 @@ static inline struct hibmc_connector *to_hibmc_connector(struct drm_connector *c ...@@ -52,7 +51,7 @@ static inline struct hibmc_connector *to_hibmc_connector(struct drm_connector *c
static inline struct hibmc_drm_private *to_hibmc_drm_private(struct drm_device *dev) static inline struct hibmc_drm_private *to_hibmc_drm_private(struct drm_device *dev)
{ {
return dev->dev_private; return container_of(dev, struct hibmc_drm_private, dev);
} }
void hibmc_set_power_mode(struct hibmc_drm_private *priv, void hibmc_set_power_mode(struct hibmc_drm_private *priv,
...@@ -64,11 +63,6 @@ int hibmc_de_init(struct hibmc_drm_private *priv); ...@@ -64,11 +63,6 @@ int hibmc_de_init(struct hibmc_drm_private *priv);
int hibmc_vdac_init(struct hibmc_drm_private *priv); int hibmc_vdac_init(struct hibmc_drm_private *priv);
int hibmc_mm_init(struct hibmc_drm_private *hibmc); int hibmc_mm_init(struct hibmc_drm_private *hibmc);
void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args);
int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_connector *connector); int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_connector *connector);
extern const struct drm_mode_config_funcs hibmc_mode_funcs;
#endif #endif
...@@ -96,7 +96,7 @@ static const struct drm_encoder_funcs hibmc_encoder_funcs = { ...@@ -96,7 +96,7 @@ static const struct drm_encoder_funcs hibmc_encoder_funcs = {
int hibmc_vdac_init(struct hibmc_drm_private *priv) int hibmc_vdac_init(struct hibmc_drm_private *priv)
{ {
struct drm_device *dev = priv->dev; struct drm_device *dev = &priv->dev;
struct hibmc_connector *hibmc_connector = &priv->connector; struct hibmc_connector *hibmc_connector = &priv->connector;
struct drm_encoder *encoder = &priv->encoder; struct drm_encoder *encoder = &priv->encoder;
struct drm_connector *connector = &hibmc_connector->base; struct drm_connector *connector = &hibmc_connector->base;
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* Hisilicon Hibmc SoC drm driver
*
* Based on the bochs drm driver.
*
* Copyright (c) 2016 Huawei Limited.
*
* Author:
* Rongrong Zou <zourongrong@huawei.com>
* Rongrong Zou <zourongrong@gmail.com>
* Jianhua Li <lijianhua@huawei.com>
*/
#include <linux/pci.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_print.h>
#include "hibmc_drm_drv.h"
int hibmc_mm_init(struct hibmc_drm_private *hibmc)
{
struct drm_vram_mm *vmm;
int ret;
struct drm_device *dev = hibmc->dev;
vmm = drm_vram_helper_alloc_mm(dev,
pci_resource_start(dev->pdev, 0),
hibmc->fb_size);
if (IS_ERR(vmm)) {
ret = PTR_ERR(vmm);
drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
return ret;
}
return 0;
}
void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
{
if (!hibmc->dev->vram_mm)
return;
drm_vram_helper_release_mm(hibmc->dev);
}
int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
return drm_gem_vram_fill_create_dumb(file, dev, 0, 128, args);
}
const struct drm_mode_config_funcs hibmc_mode_funcs = {
.mode_valid = drm_vram_helper_mode_valid,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_gem_fb_create,
};
...@@ -17267,7 +17267,6 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, ...@@ -17267,7 +17267,6 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
} }
#define INTEL_CRTC_FUNCS \ #define INTEL_CRTC_FUNCS \
.gamma_set = drm_atomic_helper_legacy_gamma_set, \
.set_config = drm_atomic_helper_set_config, \ .set_config = drm_atomic_helper_set_config, \
.destroy = intel_crtc_destroy, \ .destroy = intel_crtc_destroy, \
.page_flip = drm_atomic_helper_page_flip, \ .page_flip = drm_atomic_helper_page_flip, \
......
...@@ -4,6 +4,7 @@ config DRM_INGENIC ...@@ -4,6 +4,7 @@ config DRM_INGENIC
depends on DRM depends on DRM
depends on CMA depends on CMA
depends on OF depends on OF
depends on COMMON_CLK
select DRM_BRIDGE select DRM_BRIDGE
select DRM_PANEL_BRIDGE select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER select DRM_KMS_HELPER
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_reserved_mem.h> #include <linux/of_reserved_mem.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
...@@ -190,15 +191,15 @@ static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv, ...@@ -190,15 +191,15 @@ static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv,
{ {
unsigned int vpe, vds, vde, vt, hpe, hds, hde, ht; unsigned int vpe, vds, vde, vt, hpe, hds, hde, ht;
vpe = mode->vsync_end - mode->vsync_start; vpe = mode->crtc_vsync_end - mode->crtc_vsync_start;
vds = mode->vtotal - mode->vsync_start; vds = mode->crtc_vtotal - mode->crtc_vsync_start;
vde = vds + mode->vdisplay; vde = vds + mode->crtc_vdisplay;
vt = vde + mode->vsync_start - mode->vdisplay; vt = vde + mode->crtc_vsync_start - mode->crtc_vdisplay;
hpe = mode->hsync_end - mode->hsync_start; hpe = mode->crtc_hsync_end - mode->crtc_hsync_start;
hds = mode->htotal - mode->hsync_start; hds = mode->crtc_htotal - mode->crtc_hsync_start;
hde = hds + mode->hdisplay; hde = hds + mode->crtc_hdisplay;
ht = hde + mode->hsync_start - mode->hdisplay; ht = hde + mode->crtc_hsync_start - mode->crtc_hdisplay;
regmap_write(priv->map, JZ_REG_LCD_VSYNC, regmap_write(priv->map, JZ_REG_LCD_VSYNC,
0 << JZ_LCD_VSYNC_VPS_OFFSET | 0 << JZ_LCD_VSYNC_VPS_OFFSET |
...@@ -333,7 +334,7 @@ static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -333,7 +334,7 @@ static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_pending_vblank_event *event = crtc_state->event; struct drm_pending_vblank_event *event = crtc_state->event;
if (drm_atomic_crtc_needs_modeset(crtc_state)) { if (drm_atomic_crtc_needs_modeset(crtc_state)) {
ingenic_drm_crtc_update_timings(priv, &crtc_state->mode); ingenic_drm_crtc_update_timings(priv, &crtc_state->adjusted_mode);
priv->update_clk_rate = true; priv->update_clk_rate = true;
} }
...@@ -589,7 +590,7 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, ...@@ -589,7 +590,7 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct drm_display_mode *mode = &crtc_state->adjusted_mode;
struct drm_connector *conn = conn_state->connector; struct drm_connector *conn = conn_state->connector;
struct drm_display_info *info = &conn->display_info; struct drm_display_info *info = &conn->display_info;
unsigned int cfg; unsigned int cfg, rgbcfg = 0;
priv->panel_is_sharp = info->bus_flags & DRM_BUS_FLAG_SHARP_SIGNALS; priv->panel_is_sharp = info->bus_flags & DRM_BUS_FLAG_SHARP_SIGNALS;
...@@ -626,6 +627,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, ...@@ -626,6 +627,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_RGB888_1X24:
cfg |= JZ_LCD_CFG_MODE_GENERIC_24BIT; cfg |= JZ_LCD_CFG_MODE_GENERIC_24BIT;
break; break;
case MEDIA_BUS_FMT_RGB888_3X8_DELTA:
rgbcfg = JZ_LCD_RGBC_EVEN_GBR | JZ_LCD_RGBC_ODD_RGB;
fallthrough;
case MEDIA_BUS_FMT_RGB888_3X8: case MEDIA_BUS_FMT_RGB888_3X8:
cfg |= JZ_LCD_CFG_MODE_8BIT_SERIAL; cfg |= JZ_LCD_CFG_MODE_8BIT_SERIAL;
break; break;
...@@ -636,6 +640,7 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, ...@@ -636,6 +640,7 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
} }
regmap_write(priv->map, JZ_REG_LCD_CFG, cfg); regmap_write(priv->map, JZ_REG_LCD_CFG, cfg);
regmap_write(priv->map, JZ_REG_LCD_RGBC, rgbcfg);
} }
static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder, static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder,
...@@ -643,6 +648,7 @@ static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder, ...@@ -643,6 +648,7 @@ static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
{ {
struct drm_display_info *info = &conn_state->connector->display_info; struct drm_display_info *info = &conn_state->connector->display_info;
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
if (info->num_bus_formats != 1) if (info->num_bus_formats != 1)
return -EINVAL; return -EINVAL;
...@@ -651,10 +657,23 @@ static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder, ...@@ -651,10 +657,23 @@ static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder,
return 0; return 0;
switch (*info->bus_formats) { switch (*info->bus_formats) {
case MEDIA_BUS_FMT_RGB888_3X8:
case MEDIA_BUS_FMT_RGB888_3X8_DELTA:
/*
* The LCD controller expects timing values in dot-clock ticks,
* which is 3x the timing values in pixels when using a 3x8-bit
* display; but it will count the display area size in pixels
* either way. Go figure.
*/
mode->crtc_clock = mode->clock * 3;
mode->crtc_hsync_start = mode->hsync_start * 3 - mode->hdisplay * 2;
mode->crtc_hsync_end = mode->hsync_end * 3 - mode->hdisplay * 2;
mode->crtc_hdisplay = mode->hdisplay;
mode->crtc_htotal = mode->htotal * 3 - mode->hdisplay * 2;
return 0;
case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_RGB565_1X16:
case MEDIA_BUS_FMT_RGB666_1X18: case MEDIA_BUS_FMT_RGB666_1X18:
case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_RGB888_3X8:
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;
...@@ -755,8 +774,6 @@ static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = { ...@@ -755,8 +774,6 @@ static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = {
.enable_vblank = ingenic_drm_enable_vblank, .enable_vblank = ingenic_drm_enable_vblank,
.disable_vblank = ingenic_drm_disable_vblank, .disable_vblank = ingenic_drm_disable_vblank,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
}; };
static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = { static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = {
...@@ -1167,6 +1184,22 @@ static int ingenic_drm_remove(struct platform_device *pdev) ...@@ -1167,6 +1184,22 @@ static int ingenic_drm_remove(struct platform_device *pdev)
return 0; return 0;
} }
static int __maybe_unused ingenic_drm_suspend(struct device *dev)
{
struct ingenic_drm *priv = dev_get_drvdata(dev);
return drm_mode_config_helper_suspend(&priv->drm);
}
static int __maybe_unused ingenic_drm_resume(struct device *dev)
{
struct ingenic_drm *priv = dev_get_drvdata(dev);
return drm_mode_config_helper_resume(&priv->drm);
}
static SIMPLE_DEV_PM_OPS(ingenic_drm_pm_ops, ingenic_drm_suspend, ingenic_drm_resume);
static const u32 jz4740_formats[] = { static const u32 jz4740_formats[] = {
DRM_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565, DRM_FORMAT_RGB565,
...@@ -1246,6 +1279,7 @@ MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); ...@@ -1246,6 +1279,7 @@ MODULE_DEVICE_TABLE(of, ingenic_drm_of_match);
static struct platform_driver ingenic_drm_driver = { static struct platform_driver ingenic_drm_driver = {
.driver = { .driver = {
.name = "ingenic-drm", .name = "ingenic-drm",
.pm = pm_ptr(&ingenic_drm_pm_ops),
.of_match_table = of_match_ptr(ingenic_drm_of_match), .of_match_table = of_match_ptr(ingenic_drm_of_match),
}, },
.probe = ingenic_drm_probe, .probe = ingenic_drm_probe,
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define JZ_REG_LCD_SA1 0x54 #define JZ_REG_LCD_SA1 0x54
#define JZ_REG_LCD_FID1 0x58 #define JZ_REG_LCD_FID1 0x58
#define JZ_REG_LCD_CMD1 0x5C #define JZ_REG_LCD_CMD1 0x5C
#define JZ_REG_LCD_RGBC 0x90
#define JZ_REG_LCD_OSDC 0x100 #define JZ_REG_LCD_OSDC 0x100
#define JZ_REG_LCD_OSDCTRL 0x104 #define JZ_REG_LCD_OSDCTRL 0x104
#define JZ_REG_LCD_OSDS 0x108 #define JZ_REG_LCD_OSDS 0x108
...@@ -138,6 +139,19 @@ ...@@ -138,6 +139,19 @@
#define JZ_LCD_STATE_SOF_IRQ BIT(4) #define JZ_LCD_STATE_SOF_IRQ BIT(4)
#define JZ_LCD_STATE_DISABLED BIT(0) #define JZ_LCD_STATE_DISABLED BIT(0)
#define JZ_LCD_RGBC_ODD_RGB (0x0 << 4)
#define JZ_LCD_RGBC_ODD_RBG (0x1 << 4)
#define JZ_LCD_RGBC_ODD_GRB (0x2 << 4)
#define JZ_LCD_RGBC_ODD_GBR (0x3 << 4)
#define JZ_LCD_RGBC_ODD_BRG (0x4 << 4)
#define JZ_LCD_RGBC_ODD_BGR (0x5 << 4)
#define JZ_LCD_RGBC_EVEN_RGB (0x0 << 0)
#define JZ_LCD_RGBC_EVEN_RBG (0x1 << 0)
#define JZ_LCD_RGBC_EVEN_GRB (0x2 << 0)
#define JZ_LCD_RGBC_EVEN_GBR (0x3 << 0)
#define JZ_LCD_RGBC_EVEN_BRG (0x4 << 0)
#define JZ_LCD_RGBC_EVEN_BGR (0x5 << 0)
#define JZ_LCD_OSDC_OSDEN BIT(0) #define JZ_LCD_OSDC_OSDEN BIT(0)
#define JZ_LCD_OSDC_F0EN BIT(3) #define JZ_LCD_OSDC_F0EN BIT(3)
#define JZ_LCD_OSDC_F1EN BIT(4) #define JZ_LCD_OSDC_F1EN BIT(4)
......
...@@ -556,7 +556,7 @@ MODULE_DEVICE_TABLE(of, kmb_of_match); ...@@ -556,7 +556,7 @@ MODULE_DEVICE_TABLE(of, kmb_of_match);
static int __maybe_unused kmb_pm_suspend(struct device *dev) static int __maybe_unused kmb_pm_suspend(struct device *dev)
{ {
struct drm_device *drm = dev_get_drvdata(dev); struct drm_device *drm = dev_get_drvdata(dev);
struct kmb_drm_private *kmb = drm ? to_kmb(drm) : NULL; struct kmb_drm_private *kmb = to_kmb(drm);
drm_kms_helper_poll_disable(drm); drm_kms_helper_poll_disable(drm);
......
...@@ -114,6 +114,9 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane, ...@@ -114,6 +114,9 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane,
kmb = to_kmb(plane->dev); kmb = to_kmb(plane->dev);
if (WARN_ON(plane_id >= KMB_MAX_PLANES))
return;
switch (plane_id) { switch (plane_id) {
case LAYER_0: case LAYER_0:
kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL1_ENABLE; kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL1_ENABLE;
......
...@@ -619,7 +619,6 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = { ...@@ -619,7 +619,6 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
.reset = mtk_drm_crtc_reset, .reset = mtk_drm_crtc_reset,
.atomic_duplicate_state = mtk_drm_crtc_duplicate_state, .atomic_duplicate_state = mtk_drm_crtc_duplicate_state,
.atomic_destroy_state = mtk_drm_crtc_destroy_state, .atomic_destroy_state = mtk_drm_crtc_destroy_state,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.enable_vblank = mtk_drm_crtc_enable_vblank, .enable_vblank = mtk_drm_crtc_enable_vblank,
.disable_vblank = mtk_drm_crtc_disable_vblank, .disable_vblank = mtk_drm_crtc_disable_vblank,
}; };
......
...@@ -260,7 +260,7 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) ...@@ -260,7 +260,7 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map)
return -ENOMEM; return -ENOMEM;
} }
drm_prime_sg_to_page_addr_arrays(sgt, mtk_gem->pages, NULL, npages); drm_prime_sg_to_page_array(sgt, mtk_gem->pages, npages);
mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP, mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL)); pgprot_writecombine(PAGE_KERNEL));
......
...@@ -1211,7 +1211,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, ...@@ -1211,7 +1211,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
goto fail; goto fail;
} }
ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages); ret = drm_prime_sg_to_page_array(sgt, msm_obj->pages, npages);
if (ret) { if (ret) {
msm_gem_unlock(obj); msm_gem_unlock(obj);
goto fail; goto fail;
......
...@@ -503,7 +503,6 @@ nv50_head_destroy(struct drm_crtc *crtc) ...@@ -503,7 +503,6 @@ nv50_head_destroy(struct drm_crtc *crtc)
static const struct drm_crtc_funcs static const struct drm_crtc_funcs
nv50_head_func = { nv50_head_func = {
.reset = nv50_head_reset, .reset = nv50_head_reset,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = nv50_head_destroy, .destroy = nv50_head_destroy,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
...@@ -518,7 +517,6 @@ nv50_head_func = { ...@@ -518,7 +517,6 @@ nv50_head_func = {
static const struct drm_crtc_funcs static const struct drm_crtc_funcs
nvd9_head_func = { nvd9_head_func = {
.reset = nv50_head_reset, .reset = nv50_head_reset,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = nv50_head_destroy, .destroy = nv50_head_destroy,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
......
...@@ -473,10 +473,10 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig) ...@@ -473,10 +473,10 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
switch (bo->mem.mem_type) { switch (bo->mem.mem_type) {
case TTM_PL_VRAM: case TTM_PL_VRAM:
drm->gem.vram_available -= bo->mem.size; drm->gem.vram_available -= bo->base.size;
break; break;
case TTM_PL_TT: case TTM_PL_TT:
drm->gem.gart_available -= bo->mem.size; drm->gem.gart_available -= bo->base.size;
break; break;
default: default:
break; break;
...@@ -504,10 +504,10 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) ...@@ -504,10 +504,10 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
if (!nvbo->bo.pin_count) { if (!nvbo->bo.pin_count) {
switch (bo->mem.mem_type) { switch (bo->mem.mem_type) {
case TTM_PL_VRAM: case TTM_PL_VRAM:
drm->gem.vram_available += bo->mem.size; drm->gem.vram_available += bo->base.size;
break; break;
case TTM_PL_TT: case TTM_PL_TT:
drm->gem.gart_available += bo->mem.size; drm->gem.gart_available += bo->base.size;
break; break;
default: default:
break; break;
...@@ -774,7 +774,10 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, ...@@ -774,7 +774,10 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
return ret; return ret;
} }
mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING); if (drm_drv_uses_atomic_modeset(drm->dev))
mutex_lock(&cli->mutex);
else
mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, ctx->interruptible); ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, ctx->interruptible);
if (ret == 0) { if (ret == 0) {
ret = drm->ttm.move(chan, bo, &bo->mem, new_reg); ret = drm->ttm.move(chan, bo, &bo->mem, new_reg);
...@@ -910,7 +913,7 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg, ...@@ -910,7 +913,7 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg,
return 0; return 0;
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) { if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) {
*new_tile = nv10_bo_set_tiling(dev, offset, new_reg->size, *new_tile = nv10_bo_set_tiling(dev, offset, bo->base.size,
nvbo->mode, nvbo->zeta); nvbo->mode, nvbo->zeta);
} }
...@@ -1232,9 +1235,8 @@ nouveau_ttm_tt_populate(struct ttm_bo_device *bdev, ...@@ -1232,9 +1235,8 @@ nouveau_ttm_tt_populate(struct ttm_bo_device *bdev,
return 0; return 0;
if (slave && ttm->sg) { if (slave && ttm->sg) {
/* make userspace faulting work */ drm_prime_sg_to_dma_addr_array(ttm->sg, ttm_dma->dma_address,
drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, ttm->num_pages);
ttm_dma->dma_address, ttm->num_pages);
return 0; return 0;
} }
......
...@@ -286,11 +286,11 @@ nouveau_check_bl_size(struct nouveau_drm *drm, struct nouveau_bo *nvbo, ...@@ -286,11 +286,11 @@ nouveau_check_bl_size(struct nouveau_drm *drm, struct nouveau_bo *nvbo,
bl_size = bw * bh * (1 << tile_mode) * gob_size; bl_size = bw * bh * (1 << tile_mode) * gob_size;
DRM_DEBUG_KMS("offset=%u stride=%u h=%u tile_mode=0x%02x bw=%u bh=%u gob_size=%u bl_size=%llu size=%lu\n", DRM_DEBUG_KMS("offset=%u stride=%u h=%u tile_mode=0x%02x bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n",
offset, stride, h, tile_mode, bw, bh, gob_size, bl_size, offset, stride, h, tile_mode, bw, bh, gob_size, bl_size,
nvbo->bo.mem.size); nvbo->bo.base.size);
if (bl_size + offset > nvbo->bo.mem.size) if (bl_size + offset > nvbo->bo.base.size)
return -ERANGE; return -ERANGE;
return 0; return 0;
...@@ -363,7 +363,7 @@ nouveau_framebuffer_new(struct drm_device *dev, ...@@ -363,7 +363,7 @@ nouveau_framebuffer_new(struct drm_device *dev,
} else { } else {
uint32_t size = mode_cmd->pitches[i] * height; uint32_t size = mode_cmd->pitches[i] * height;
if (size + mode_cmd->offsets[i] > nvbo->bo.mem.size) if (size + mode_cmd->offsets[i] > nvbo->bo.base.size)
return -ERANGE; return -ERANGE;
} }
} }
......
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
#include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_memory.h> #include <drm/ttm/ttm_memory.h>
#include <drm/ttm/ttm_module.h>
#include <drm/drm_audio_component.h> #include <drm/drm_audio_component.h>
......
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *obj) struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *obj)
{ {
struct nouveau_bo *nvbo = nouveau_gem_object(obj); struct nouveau_bo *nvbo = nouveau_gem_object(obj);
int npages = nvbo->bo.num_pages;
return drm_prime_pages_to_sg(obj->dev, nvbo->bo.ttm->pages, npages); return drm_prime_pages_to_sg(obj->dev, nvbo->bo.ttm->pages,
nvbo->bo.ttm->num_pages);
} }
struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
......
...@@ -84,7 +84,7 @@ nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, uint32_t page_flags) ...@@ -84,7 +84,7 @@ nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, uint32_t page_flags)
if (!nvbe) if (!nvbe)
return NULL; return NULL;
if (ttm_dma_tt_init(&nvbe->ttm, bo, page_flags, caching)) { if (ttm_sg_tt_init(&nvbe->ttm, bo, page_flags, caching)) {
kfree(nvbe); kfree(nvbe);
return NULL; return NULL;
} }
......
...@@ -80,7 +80,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) ...@@ -80,7 +80,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
struct nv10_fence_chan *fctx; struct nv10_fence_chan *fctx;
struct ttm_resource *reg = &priv->bo->bo.mem; struct ttm_resource *reg = &priv->bo->bo.mem;
u32 start = reg->start * PAGE_SIZE; u32 start = reg->start * PAGE_SIZE;
u32 limit = start + reg->size - 1; u32 limit = start + priv->bo->bo.base.size - 1;
int ret = 0; int ret = 0;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
......
...@@ -39,7 +39,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) ...@@ -39,7 +39,7 @@ nv50_fence_context_new(struct nouveau_channel *chan)
struct nv10_fence_chan *fctx; struct nv10_fence_chan *fctx;
struct ttm_resource *reg = &priv->bo->bo.mem; struct ttm_resource *reg = &priv->bo->bo.mem;
u32 start = reg->start * PAGE_SIZE; u32 start = reg->start * PAGE_SIZE;
u32 limit = start + reg->size - 1; u32 limit = start + priv->bo->bo.base.size - 1;
int ret; int ret;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
......
...@@ -5,13 +5,129 @@ config DRM_OMAP ...@@ -5,13 +5,129 @@ config DRM_OMAP
depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
select OMAP2_DSS select OMAP2_DSS
select DRM_KMS_HELPER select DRM_KMS_HELPER
select VIDEOMODE_HELPERS
select HDMI
default n default n
help help
DRM display driver for OMAP2/3/4 based boards. DRM display driver for OMAP2/3/4 based boards.
if DRM_OMAP if DRM_OMAP
source "drivers/gpu/drm/omapdrm/dss/Kconfig" config OMAP2_DSS_DEBUG
source "drivers/gpu/drm/omapdrm/displays/Kconfig" bool "Debug support"
default n
help
This enables printing of debug messages. Alternatively, debug messages
can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
appropriate flags in <debugfs>/dynamic_debug/control.
config OMAP2_DSS_DEBUGFS
bool "Debugfs filesystem support"
depends on DEBUG_FS
default n
help
This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
querying about clock configuration and register configuration of dss,
dispc, dsi, hdmi and rfbi.
config OMAP2_DSS_COLLECT_IRQ_STATS
bool "Collect DSS IRQ statistics"
depends on OMAP2_DSS_DEBUGFS
default n
help
Collect DSS IRQ statistics, printable via debugfs.
The statistics can be found from
<debugfs>/omapdss/dispc_irq for DISPC interrupts, and
<debugfs>/omapdss/dsi_irq for DSI interrupts.
config OMAP2_DSS_DPI
bool "DPI support"
default y
help
DPI Interface. This is the Parallel Display Interface.
config OMAP2_DSS_VENC
bool "VENC support"
default y
help
OMAP Video Encoder support for S-Video and composite TV-out.
config OMAP2_DSS_HDMI_COMMON
bool
config OMAP4_DSS_HDMI
bool "HDMI support for OMAP4"
default y
select OMAP2_DSS_HDMI_COMMON
help
HDMI support for OMAP4 based SoCs.
config OMAP4_DSS_HDMI_CEC
bool "Enable HDMI CEC support for OMAP4"
depends on OMAP4_DSS_HDMI
select CEC_CORE
default y
help
When selected the HDMI transmitter will support the CEC feature.
config OMAP5_DSS_HDMI
bool "HDMI support for OMAP5"
default n
select OMAP2_DSS_HDMI_COMMON
help
HDMI Interface for OMAP5 and similar cores. This adds the High
Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
specification.
config OMAP2_DSS_SDI
bool "SDI support"
default n
help
SDI (Serial Display Interface) support.
SDI is a high speed one-way display serial bus between the host
processor and a display.
config OMAP2_DSS_DSI
bool "DSI support"
default n
select DRM_MIPI_DSI
help
MIPI DSI (Display Serial Interface) support.
DSI is a high speed half-duplex serial interface between the host
processor and a peripheral, such as a display or a framebuffer chip.
See http://www.mipi.org/ for DSI specifications.
config OMAP2_DSS_MIN_FCK_PER_PCK
int "Minimum FCK/PCK ratio (for scaling)"
range 0 32
default 0
help
This can be used to adjust the minimum FCK/PCK ratio.
With this you can make sure that DISPC FCK is at least
n x PCK. Video plane scaling requires higher FCK than
normally.
If this is set to 0, there's no extra constraint on the
DISPC FCK. However, the FCK will at minimum be
2xPCK (if active matrix) or 3xPCK (if passive matrix).
Max FCK is 173MHz, so this doesn't work if your PCK
is very high.
config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
bool "Sleep 20ms after VENC reset"
default y
help
There is a 20ms sleep after VENC reset which seemed to fix the
reset. The reason for the bug is unclear, and it's also unclear
on what platforms this happens.
This option enables the sleep, and is enabled by default. You can
disable the sleep if it doesn't cause problems on your platform.
endif endif
...@@ -4,16 +4,12 @@ ...@@ -4,16 +4,12 @@
# Direct Rendering Infrastructure (DRI) # Direct Rendering Infrastructure (DRI)
# #
obj-y += dss/
obj-y += displays/
omapdrm-y := omap_drv.o \ omapdrm-y := omap_drv.o \
omap_irq.o \ omap_irq.o \
omap_debugfs.o \ omap_debugfs.o \
omap_crtc.o \ omap_crtc.o \
omap_plane.o \ omap_plane.o \
omap_encoder.o \ omap_encoder.o \
omap_connector.o \
omap_fb.o \ omap_fb.o \
omap_gem.o \ omap_gem.o \
omap_gem_dmabuf.o \ omap_gem_dmabuf.o \
...@@ -22,4 +18,17 @@ omapdrm-y := omap_drv.o \ ...@@ -22,4 +18,17 @@ omapdrm-y := omap_drv.o \
omapdrm-$(CONFIG_DRM_FBDEV_EMULATION) += omap_fbdev.o omapdrm-$(CONFIG_DRM_FBDEV_EMULATION) += omap_fbdev.o
obj-$(CONFIG_DRM_OMAP) += omapdrm.o omapdrm-y += dss/base.o dss/output.o dss/dss.o dss/dispc.o \
dss/dispc_coefs.o dss/pll.o dss/video-pll.o
omapdrm-$(CONFIG_OMAP2_DSS_DPI) += dss/dpi.o
omapdrm-$(CONFIG_OMAP2_DSS_VENC) += dss/venc.o
omapdrm-$(CONFIG_OMAP2_DSS_SDI) += dss/sdi.o
omapdrm-$(CONFIG_OMAP2_DSS_DSI) += dss/dsi.o
omapdrm-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += dss/hdmi_common.o dss/hdmi_wp.o \
dss/hdmi_pll.o dss/hdmi_phy.o
omapdrm-$(CONFIG_OMAP4_DSS_HDMI) += dss/hdmi4.o dss/hdmi4_core.o
omapdrm-$(CONFIG_OMAP4_DSS_HDMI_CEC) += dss/hdmi4_cec.o
omapdrm-$(CONFIG_OMAP5_DSS_HDMI) += dss/hdmi5.o dss/hdmi5_core.o
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
obj-$(CONFIG_DRM_OMAP) += omapdrm.o
# SPDX-License-Identifier: GPL-2.0-only
menu "OMAPDRM External Display Device Drivers"
config DRM_OMAP_PANEL_DSI_CM
tristate "Generic DSI Command Mode Panel"
depends on BACKLIGHT_CLASS_DEVICE
help
Driver for generic DSI command mode panels.
endmenu
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o
# SPDX-License-Identifier: GPL-2.0-only
config OMAP2_DSS_INIT
bool
config OMAP_DSS_BASE
tristate
menuconfig OMAP2_DSS
tristate "OMAP2+ Display Subsystem support"
select OMAP_DSS_BASE
select VIDEOMODE_HELPERS
select OMAP2_DSS_INIT
select HDMI
help
OMAP2+ Display Subsystem support.
if OMAP2_DSS
config OMAP2_DSS_DEBUG
bool "Debug support"
default n
help
This enables printing of debug messages. Alternatively, debug messages
can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
appropriate flags in <debugfs>/dynamic_debug/control.
config OMAP2_DSS_DEBUGFS
bool "Debugfs filesystem support"
depends on DEBUG_FS
default n
help
This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
querying about clock configuration and register configuration of dss,
dispc, dsi, hdmi and rfbi.
config OMAP2_DSS_COLLECT_IRQ_STATS
bool "Collect DSS IRQ statistics"
depends on OMAP2_DSS_DEBUGFS
default n
help
Collect DSS IRQ statistics, printable via debugfs.
The statistics can be found from
<debugfs>/omapdss/dispc_irq for DISPC interrupts, and
<debugfs>/omapdss/dsi_irq for DSI interrupts.
config OMAP2_DSS_DPI
bool "DPI support"
default y
help
DPI Interface. This is the Parallel Display Interface.
config OMAP2_DSS_VENC
bool "VENC support"
default y
help
OMAP Video Encoder support for S-Video and composite TV-out.
config OMAP2_DSS_HDMI_COMMON
bool
config OMAP4_DSS_HDMI
bool "HDMI support for OMAP4"
default y
select OMAP2_DSS_HDMI_COMMON
help
HDMI support for OMAP4 based SoCs.
config OMAP4_DSS_HDMI_CEC
bool "Enable HDMI CEC support for OMAP4"
depends on OMAP4_DSS_HDMI
select CEC_CORE
default y
help
When selected the HDMI transmitter will support the CEC feature.
config OMAP5_DSS_HDMI
bool "HDMI support for OMAP5"
default n
select OMAP2_DSS_HDMI_COMMON
help
HDMI Interface for OMAP5 and similar cores. This adds the High
Definition Multimedia Interface. See https://www.hdmi.org/ for HDMI
specification.
config OMAP2_DSS_SDI
bool "SDI support"
default n
help
SDI (Serial Display Interface) support.
SDI is a high speed one-way display serial bus between the host
processor and a display.
config OMAP2_DSS_DSI
bool "DSI support"
default n
help
MIPI DSI (Display Serial Interface) support.
DSI is a high speed half-duplex serial interface between the host
processor and a peripheral, such as a display or a framebuffer chip.
See https://www.mipi.org/ for DSI specifications.
config OMAP2_DSS_MIN_FCK_PER_PCK
int "Minimum FCK/PCK ratio (for scaling)"
range 0 32
default 0
help
This can be used to adjust the minimum FCK/PCK ratio.
With this you can make sure that DISPC FCK is at least
n x PCK. Video plane scaling requires higher FCK than
normally.
If this is set to 0, there's no extra constraint on the
DISPC FCK. However, the FCK will at minimum be
2xPCK (if active matrix) or 3xPCK (if passive matrix).
Max FCK is 173MHz, so this doesn't work if your PCK
is very high.
config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
bool "Sleep 20ms after VENC reset"
default y
help
There is a 20ms sleep after VENC reset which seemed to fix the
reset. The reason for the bug is unclear, and it's also unclear
on what platforms this happens.
This option enables the sleep, and is enabled by default. You can
disable the sleep if it doesn't cause problems on your platform.
endif
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
obj-$(CONFIG_OMAP_DSS_BASE) += omapdss-base.o
omapdss-base-y := base.o display.o output.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files
omapdss-y := dss.o dispc.o dispc_coefs.o \
pll.o video-pll.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
omapdss-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \
hdmi_phy.o
omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o
omapdss-$(CONFIG_OMAP4_DSS_HDMI_CEC) += hdmi4_cec.o
omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
...@@ -16,32 +16,10 @@ ...@@ -16,32 +16,10 @@
#include "dss.h" #include "dss.h"
#include "omapdss.h" #include "omapdss.h"
static struct dss_device *dss_device;
struct dss_device *omapdss_get_dss(void)
{
return dss_device;
}
EXPORT_SYMBOL(omapdss_get_dss);
void omapdss_set_dss(struct dss_device *dss)
{
dss_device = dss;
}
EXPORT_SYMBOL(omapdss_set_dss);
struct dispc_device *dispc_get_dispc(struct dss_device *dss) struct dispc_device *dispc_get_dispc(struct dss_device *dss)
{ {
return dss->dispc; return dss->dispc;
} }
EXPORT_SYMBOL(dispc_get_dispc);
const struct dispc_ops *dispc_get_ops(struct dss_device *dss)
{
return dss->dispc_ops;
}
EXPORT_SYMBOL(dispc_get_ops);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* OMAP DSS Devices Handling * OMAP DSS Devices Handling
...@@ -56,7 +34,6 @@ void omapdss_device_register(struct omap_dss_device *dssdev) ...@@ -56,7 +34,6 @@ void omapdss_device_register(struct omap_dss_device *dssdev)
list_add_tail(&dssdev->list, &omapdss_devices_list); list_add_tail(&dssdev->list, &omapdss_devices_list);
mutex_unlock(&omapdss_devices_lock); mutex_unlock(&omapdss_devices_lock);
} }
EXPORT_SYMBOL_GPL(omapdss_device_register);
void omapdss_device_unregister(struct omap_dss_device *dssdev) void omapdss_device_unregister(struct omap_dss_device *dssdev)
{ {
...@@ -64,7 +41,6 @@ void omapdss_device_unregister(struct omap_dss_device *dssdev) ...@@ -64,7 +41,6 @@ void omapdss_device_unregister(struct omap_dss_device *dssdev)
list_del(&dssdev->list); list_del(&dssdev->list);
mutex_unlock(&omapdss_devices_lock); mutex_unlock(&omapdss_devices_lock);
} }
EXPORT_SYMBOL_GPL(omapdss_device_unregister);
static bool omapdss_device_is_registered(struct device_node *node) static bool omapdss_device_is_registered(struct device_node *node)
{ {
...@@ -86,24 +62,16 @@ static bool omapdss_device_is_registered(struct device_node *node) ...@@ -86,24 +62,16 @@ static bool omapdss_device_is_registered(struct device_node *node)
struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev) struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
{ {
if (!try_module_get(dssdev->owner)) if (get_device(dssdev->dev) == NULL)
return NULL;
if (get_device(dssdev->dev) == NULL) {
module_put(dssdev->owner);
return NULL; return NULL;
}
return dssdev; return dssdev;
} }
EXPORT_SYMBOL(omapdss_device_get);
void omapdss_device_put(struct omap_dss_device *dssdev) void omapdss_device_put(struct omap_dss_device *dssdev)
{ {
put_device(dssdev->dev); put_device(dssdev->dev);
module_put(dssdev->owner);
} }
EXPORT_SYMBOL(omapdss_device_put);
struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node) struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node)
{ {
...@@ -149,7 +117,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) ...@@ -149,7 +117,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
goto done; goto done;
} }
if (dssdev->id && (dssdev->next || dssdev->bridge)) if (dssdev->id && dssdev->bridge)
goto done; goto done;
} }
...@@ -164,7 +132,6 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) ...@@ -164,7 +132,6 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
mutex_unlock(&omapdss_devices_lock); mutex_unlock(&omapdss_devices_lock);
return dssdev; return dssdev;
} }
EXPORT_SYMBOL(omapdss_device_next_output);
static bool omapdss_device_is_connected(struct omap_dss_device *dssdev) static bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
{ {
...@@ -175,8 +142,6 @@ int omapdss_device_connect(struct dss_device *dss, ...@@ -175,8 +142,6 @@ int omapdss_device_connect(struct dss_device *dss,
struct omap_dss_device *src, struct omap_dss_device *src,
struct omap_dss_device *dst) struct omap_dss_device *dst)
{ {
int ret;
dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n", dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
src ? dev_name(src->dev) : "NULL", src ? dev_name(src->dev) : "NULL",
dst ? dev_name(dst->dev) : "NULL"); dst ? dev_name(dst->dev) : "NULL");
...@@ -195,17 +160,8 @@ int omapdss_device_connect(struct dss_device *dss, ...@@ -195,17 +160,8 @@ int omapdss_device_connect(struct dss_device *dss,
dst->dss = dss; dst->dss = dss;
if (dst->ops && dst->ops->connect) {
ret = dst->ops->connect(src, dst);
if (ret < 0) {
dst->dss = NULL;
return ret;
}
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(omapdss_device_connect);
void omapdss_device_disconnect(struct omap_dss_device *src, void omapdss_device_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst) struct omap_dss_device *dst)
...@@ -222,43 +178,12 @@ void omapdss_device_disconnect(struct omap_dss_device *src, ...@@ -222,43 +178,12 @@ void omapdss_device_disconnect(struct omap_dss_device *src,
} }
if (!dst->id && !omapdss_device_is_connected(dst)) { if (!dst->id && !omapdss_device_is_connected(dst)) {
WARN_ON(!dst->display); WARN_ON(1);
return; return;
} }
WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
if (dst->ops && dst->ops->disconnect)
dst->ops->disconnect(src, dst);
dst->dss = NULL; dst->dss = NULL;
} }
EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
void omapdss_device_enable(struct omap_dss_device *dssdev)
{
if (!dssdev)
return;
if (dssdev->ops && dssdev->ops->enable)
dssdev->ops->enable(dssdev);
omapdss_device_enable(dssdev->next);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
}
EXPORT_SYMBOL_GPL(omapdss_device_enable);
void omapdss_device_disable(struct omap_dss_device *dssdev)
{
if (!dssdev)
return;
omapdss_device_disable(dssdev->next);
if (dssdev->ops && dssdev->ops->disable)
dssdev->ops->disable(dssdev);
}
EXPORT_SYMBOL_GPL(omapdss_device_disable);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Components Handling * Components Handling
...@@ -344,7 +269,6 @@ void omapdss_gather_components(struct device *dev) ...@@ -344,7 +269,6 @@ void omapdss_gather_components(struct device *dev)
for_each_available_child_of_node(dev->of_node, child) for_each_available_child_of_node(dev->of_node, child)
omapdss_walk_device(dev, child, true); omapdss_walk_device(dev, child, true);
} }
EXPORT_SYMBOL(omapdss_gather_components);
static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp) static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
{ {
...@@ -369,8 +293,3 @@ bool omapdss_stack_is_ready(void) ...@@ -369,8 +293,3 @@ bool omapdss_stack_is_ready(void)
return true; return true;
} }
EXPORT_SYMBOL(omapdss_stack_is_ready);
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
MODULE_DESCRIPTION("OMAP Display Subsystem Base");
MODULE_LICENSE("GPL v2");
...@@ -351,8 +351,6 @@ static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, ...@@ -351,8 +351,6 @@ static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc,
static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc,
enum omap_plane_id plane); enum omap_plane_id plane);
static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask);
static inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val) static inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val)
{ {
__raw_writel(val, dispc->base + idx); __raw_writel(val, dispc->base + idx);
...@@ -379,12 +377,12 @@ static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel, ...@@ -379,12 +377,12 @@ static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel,
REG_FLD_MOD(dispc, rfld->reg, val, rfld->high, rfld->low); REG_FLD_MOD(dispc, rfld->reg, val, rfld->high, rfld->low);
} }
static int dispc_get_num_ovls(struct dispc_device *dispc) int dispc_get_num_ovls(struct dispc_device *dispc)
{ {
return dispc->feat->num_ovls; return dispc->feat->num_ovls;
} }
static int dispc_get_num_mgrs(struct dispc_device *dispc) int dispc_get_num_mgrs(struct dispc_device *dispc)
{ {
return dispc->feat->num_mgrs; return dispc->feat->num_mgrs;
} }
...@@ -670,13 +668,13 @@ void dispc_runtime_put(struct dispc_device *dispc) ...@@ -670,13 +668,13 @@ void dispc_runtime_put(struct dispc_device *dispc)
WARN_ON(r < 0 && r != -ENOSYS); WARN_ON(r < 0 && r != -ENOSYS);
} }
static u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc, u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc,
enum omap_channel channel) enum omap_channel channel)
{ {
return mgr_desc[channel].vsync_irq; return mgr_desc[channel].vsync_irq;
} }
static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc, u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc,
enum omap_channel channel) enum omap_channel channel)
{ {
if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv) if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv)
...@@ -685,18 +683,18 @@ static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc, ...@@ -685,18 +683,18 @@ static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc,
return mgr_desc[channel].framedone_irq; return mgr_desc[channel].framedone_irq;
} }
static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc,
enum omap_channel channel) enum omap_channel channel)
{ {
return mgr_desc[channel].sync_lost_irq; return mgr_desc[channel].sync_lost_irq;
} }
static u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc)
{ {
return DISPC_IRQ_FRAMEDONEWB; return DISPC_IRQ_FRAMEDONEWB;
} }
static void dispc_mgr_enable(struct dispc_device *dispc, void dispc_mgr_enable(struct dispc_device *dispc,
enum omap_channel channel, bool enable) enum omap_channel channel, bool enable)
{ {
mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable); mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable);
...@@ -710,13 +708,13 @@ static bool dispc_mgr_is_enabled(struct dispc_device *dispc, ...@@ -710,13 +708,13 @@ static bool dispc_mgr_is_enabled(struct dispc_device *dispc,
return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE);
} }
static bool dispc_mgr_go_busy(struct dispc_device *dispc, bool dispc_mgr_go_busy(struct dispc_device *dispc,
enum omap_channel channel) enum omap_channel channel)
{ {
return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1; return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1;
} }
static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel)
{ {
WARN_ON(!dispc_mgr_is_enabled(dispc, channel)); WARN_ON(!dispc_mgr_is_enabled(dispc, channel));
WARN_ON(dispc_mgr_go_busy(dispc, channel)); WARN_ON(dispc_mgr_go_busy(dispc, channel));
...@@ -726,12 +724,12 @@ static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) ...@@ -726,12 +724,12 @@ static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel)
mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1); mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1);
} }
static bool dispc_wb_go_busy(struct dispc_device *dispc) bool dispc_wb_go_busy(struct dispc_device *dispc)
{ {
return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1;
} }
static void dispc_wb_go(struct dispc_device *dispc) void dispc_wb_go(struct dispc_device *dispc)
{ {
enum omap_plane_id plane = OMAP_DSS_WB; enum omap_plane_id plane = OMAP_DSS_WB;
bool enable, go; bool enable, go;
...@@ -877,50 +875,62 @@ static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc, ...@@ -877,50 +875,62 @@ static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc,
#undef CVAL #undef CVAL
} }
static void dispc_wb_write_color_conv_coef(struct dispc_device *dispc, /* YUV -> RGB, ITU-R BT.601, full range */
const struct csc_coef_rgb2yuv *ct) static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_full = {
{ 256, 0, 358, /* ry, rcb, rcr |1.000 0.000 1.402|*/
const enum omap_plane_id plane = OMAP_DSS_WB; 256, -88, -182, /* gy, gcb, gcr |1.000 -0.344 -0.714|*/
256, 452, 0, /* by, bcb, bcr |1.000 1.772 0.000|*/
#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) true, /* full range */
};
dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->yg, ct->yr)); /* YUV -> RGB, ITU-R BT.601, limited range */
dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->crr, ct->yb)); static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = {
dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->crb, ct->crg)); 298, 0, 409, /* ry, rcb, rcr |1.164 0.000 1.596|*/
dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->cbg, ct->cbr)); 298, -100, -208, /* gy, gcb, gcr |1.164 -0.392 -0.813|*/
dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->cbb)); 298, 516, 0, /* by, bcb, bcr |1.164 2.017 0.000|*/
false, /* limited range */
};
REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); /* YUV -> RGB, ITU-R BT.709, full range */
static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_full = {
256, 0, 402, /* ry, rcb, rcr |1.000 0.000 1.570|*/
256, -48, -120, /* gy, gcb, gcr |1.000 -0.187 -0.467|*/
256, 475, 0, /* by, bcb, bcr |1.000 1.856 0.000|*/
true, /* full range */
};
#undef CVAL /* YUV -> RGB, ITU-R BT.709, limited range */
} static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_lim = {
298, 0, 459, /* ry, rcb, rcr |1.164 0.000 1.793|*/
298, -55, -136, /* gy, gcb, gcr |1.164 -0.213 -0.533|*/
298, 541, 0, /* by, bcb, bcr |1.164 2.112 0.000|*/
false, /* limited range */
};
static void dispc_setup_color_conv_coef(struct dispc_device *dispc) static void dispc_ovl_set_csc(struct dispc_device *dispc,
enum omap_plane_id plane,
enum drm_color_encoding color_encoding,
enum drm_color_range color_range)
{ {
int i; const struct csc_coef_yuv2rgb *csc;
int num_ovl = dispc_get_num_ovls(dispc);
/* YUV -> RGB, ITU-R BT.601, limited range */
const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = {
298, 0, 409, /* ry, rcb, rcr */
298, -100, -208, /* gy, gcb, gcr */
298, 516, 0, /* by, bcb, bcr */
false, /* limited range */
};
/* RGB -> YUV, ITU-R BT.601, limited range */ switch (color_encoding) {
const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_lim = { default:
66, 129, 25, /* yr, yg, yb */ case DRM_COLOR_YCBCR_BT601:
-38, -74, 112, /* cbr, cbg, cbb */ if (color_range == DRM_COLOR_YCBCR_FULL_RANGE)
112, -94, -18, /* crr, crg, crb */ csc = &coefs_yuv2rgb_bt601_full;
false, /* limited range */ else
}; csc = &coefs_yuv2rgb_bt601_lim;
break;
for (i = 1; i < num_ovl; i++) case DRM_COLOR_YCBCR_BT709:
dispc_ovl_write_color_conv_coef(dispc, i, &coefs_yuv2rgb_bt601_lim); if (color_range == DRM_COLOR_YCBCR_FULL_RANGE)
csc = &coefs_yuv2rgb_bt709_full;
else
csc = &coefs_yuv2rgb_bt709_lim;
break;
}
if (dispc->feat->has_writeback) dispc_ovl_write_color_conv_coef(dispc, plane, csc);
dispc_wb_write_color_conv_coef(dispc, &coefs_rgb2yuv_bt601_lim);
} }
static void dispc_ovl_set_ba0(struct dispc_device *dispc, static void dispc_ovl_set_ba0(struct dispc_device *dispc,
...@@ -1285,7 +1295,7 @@ static bool dispc_ovl_color_mode_supported(struct dispc_device *dispc, ...@@ -1285,7 +1295,7 @@ static bool dispc_ovl_color_mode_supported(struct dispc_device *dispc,
return false; return false;
} }
static const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc, const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc,
enum omap_plane_id plane) enum omap_plane_id plane)
{ {
return dispc->feat->supported_color_modes[plane]; return dispc->feat->supported_color_modes[plane];
...@@ -2601,7 +2611,9 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc, ...@@ -2601,7 +2611,9 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
u8 pre_mult_alpha, u8 global_alpha, u8 pre_mult_alpha, u8 global_alpha,
enum omap_dss_rotation_type rotation_type, enum omap_dss_rotation_type rotation_type,
bool replication, const struct videomode *vm, bool replication, const struct videomode *vm,
bool mem_to_mem) bool mem_to_mem,
enum drm_color_encoding color_encoding,
enum drm_color_range color_range)
{ {
bool five_taps = true; bool five_taps = true;
bool fieldmode = false; bool fieldmode = false;
...@@ -2750,6 +2762,9 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc, ...@@ -2750,6 +2762,9 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
fieldmode, fourcc, rotation); fieldmode, fourcc, rotation);
dispc_ovl_set_output_size(dispc, plane, out_width, out_height); dispc_ovl_set_output_size(dispc, plane, out_width, out_height);
dispc_ovl_set_vid_color_conv(dispc, plane, cconv); dispc_ovl_set_vid_color_conv(dispc, plane, cconv);
if (plane != OMAP_DSS_WB)
dispc_ovl_set_csc(dispc, plane, color_encoding, color_range);
} }
dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type, dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type,
...@@ -2764,7 +2779,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc, ...@@ -2764,7 +2779,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc,
return 0; return 0;
} }
static int dispc_ovl_setup(struct dispc_device *dispc, int dispc_ovl_setup(struct dispc_device *dispc,
enum omap_plane_id plane, enum omap_plane_id plane,
const struct omap_overlay_info *oi, const struct omap_overlay_info *oi,
const struct videomode *vm, bool mem_to_mem, const struct videomode *vm, bool mem_to_mem,
...@@ -2786,12 +2801,13 @@ static int dispc_ovl_setup(struct dispc_device *dispc, ...@@ -2786,12 +2801,13 @@ static int dispc_ovl_setup(struct dispc_device *dispc,
oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
oi->out_width, oi->out_height, oi->fourcc, oi->rotation, oi->out_width, oi->out_height, oi->fourcc, oi->rotation,
oi->zorder, oi->pre_mult_alpha, oi->global_alpha, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
oi->rotation_type, replication, vm, mem_to_mem); oi->rotation_type, replication, vm, mem_to_mem,
oi->color_encoding, oi->color_range);
return r; return r;
} }
static int dispc_wb_setup(struct dispc_device *dispc, int dispc_wb_setup(struct dispc_device *dispc,
const struct omap_dss_writeback_info *wi, const struct omap_dss_writeback_info *wi,
bool mem_to_mem, const struct videomode *vm, bool mem_to_mem, const struct videomode *vm,
enum dss_writeback_channel channel_in) enum dss_writeback_channel channel_in)
...@@ -2819,7 +2835,8 @@ static int dispc_wb_setup(struct dispc_device *dispc, ...@@ -2819,7 +2835,8 @@ static int dispc_wb_setup(struct dispc_device *dispc,
wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
wi->height, wi->fourcc, wi->rotation, zorder, wi->height, wi->fourcc, wi->rotation, zorder,
wi->pre_mult_alpha, global_alpha, wi->rotation_type, wi->pre_mult_alpha, global_alpha, wi->rotation_type,
replication, vm, mem_to_mem); replication, vm, mem_to_mem, DRM_COLOR_YCBCR_BT601,
DRM_COLOR_YCBCR_LIMITED_RANGE);
if (r) if (r)
return r; return r;
...@@ -2874,12 +2891,12 @@ static int dispc_wb_setup(struct dispc_device *dispc, ...@@ -2874,12 +2891,12 @@ static int dispc_wb_setup(struct dispc_device *dispc,
return 0; return 0;
} }
static bool dispc_has_writeback(struct dispc_device *dispc) bool dispc_has_writeback(struct dispc_device *dispc)
{ {
return dispc->feat->has_writeback; return dispc->feat->has_writeback;
} }
static int dispc_ovl_enable(struct dispc_device *dispc, int dispc_ovl_enable(struct dispc_device *dispc,
enum omap_plane_id plane, bool enable) enum omap_plane_id plane, bool enable)
{ {
DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
...@@ -2970,7 +2987,7 @@ static void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc, ...@@ -2970,7 +2987,7 @@ static void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc,
REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19); REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19);
} }
static void dispc_mgr_setup(struct dispc_device *dispc, void dispc_mgr_setup(struct dispc_device *dispc,
enum omap_channel channel, enum omap_channel channel,
const struct omap_overlay_manager_info *info) const struct omap_overlay_manager_info *info)
{ {
...@@ -3049,7 +3066,7 @@ static void dispc_mgr_enable_stallmode(struct dispc_device *dispc, ...@@ -3049,7 +3066,7 @@ static void dispc_mgr_enable_stallmode(struct dispc_device *dispc,
mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable); mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable);
} }
static void dispc_mgr_set_lcd_config(struct dispc_device *dispc, void dispc_mgr_set_lcd_config(struct dispc_device *dispc,
enum omap_channel channel, enum omap_channel channel,
const struct dss_lcd_mgr_config *config) const struct dss_lcd_mgr_config *config)
{ {
...@@ -3098,7 +3115,7 @@ static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc, ...@@ -3098,7 +3115,7 @@ static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc,
return pclk <= dispc->feat->max_tv_pclk; return pclk <= dispc->feat->max_tv_pclk;
} }
static int dispc_mgr_check_timings(struct dispc_device *dispc, int dispc_mgr_check_timings(struct dispc_device *dispc,
enum omap_channel channel, enum omap_channel channel,
const struct videomode *vm) const struct videomode *vm)
{ {
...@@ -3191,7 +3208,7 @@ static int vm_flag_to_int(enum display_flags flags, enum display_flags high, ...@@ -3191,7 +3208,7 @@ static int vm_flag_to_int(enum display_flags flags, enum display_flags high,
} }
/* change name to mode? */ /* change name to mode? */
static void dispc_mgr_set_timings(struct dispc_device *dispc, void dispc_mgr_set_timings(struct dispc_device *dispc,
enum omap_channel channel, enum omap_channel channel,
const struct videomode *vm) const struct videomode *vm)
{ {
...@@ -3735,17 +3752,17 @@ int dispc_mgr_get_clock_div(struct dispc_device *dispc, ...@@ -3735,17 +3752,17 @@ int dispc_mgr_get_clock_div(struct dispc_device *dispc,
return 0; return 0;
} }
static u32 dispc_read_irqstatus(struct dispc_device *dispc) u32 dispc_read_irqstatus(struct dispc_device *dispc)
{ {
return dispc_read_reg(dispc, DISPC_IRQSTATUS); return dispc_read_reg(dispc, DISPC_IRQSTATUS);
} }
static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask) void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask)
{ {
dispc_write_reg(dispc, DISPC_IRQSTATUS, mask); dispc_write_reg(dispc, DISPC_IRQSTATUS, mask);
} }
static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask) void dispc_write_irqenable(struct dispc_device *dispc, u32 mask)
{ {
u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE); u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE);
...@@ -3769,7 +3786,7 @@ void dispc_disable_sidle(struct dispc_device *dispc) ...@@ -3769,7 +3786,7 @@ void dispc_disable_sidle(struct dispc_device *dispc)
REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
} }
static u32 dispc_mgr_gamma_size(struct dispc_device *dispc, u32 dispc_mgr_gamma_size(struct dispc_device *dispc,
enum omap_channel channel) enum omap_channel channel)
{ {
const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
...@@ -3824,7 +3841,7 @@ static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { ...@@ -3824,7 +3841,7 @@ static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
{ .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
}; };
static void dispc_mgr_set_gamma(struct dispc_device *dispc, void dispc_mgr_set_gamma(struct dispc_device *dispc,
enum omap_channel channel, enum omap_channel channel,
const struct drm_color_lut *lut, const struct drm_color_lut *lut,
unsigned int length) unsigned int length)
...@@ -3930,8 +3947,6 @@ static void _omap_dispc_initial_config(struct dispc_device *dispc) ...@@ -3930,8 +3947,6 @@ static void _omap_dispc_initial_config(struct dispc_device *dispc)
dispc->feat->has_gamma_table) dispc->feat->has_gamma_table)
REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9); REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9);
dispc_setup_color_conv_coef(dispc);
dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY); dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY);
dispc_init_fifos(dispc); dispc_init_fifos(dispc);
...@@ -4482,7 +4497,7 @@ static irqreturn_t dispc_irq_handler(int irq, void *arg) ...@@ -4482,7 +4497,7 @@ static irqreturn_t dispc_irq_handler(int irq, void *arg)
return dispc->user_handler(irq, dispc->user_data); return dispc->user_handler(irq, dispc->user_data);
} }
static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler, int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler,
void *dev_id) void *dev_id)
{ {
int r; int r;
...@@ -4506,7 +4521,7 @@ static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler, ...@@ -4506,7 +4521,7 @@ static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler,
return r; return r;
} }
static void dispc_free_irq(struct dispc_device *dispc, void *dev_id) void dispc_free_irq(struct dispc_device *dispc, void *dev_id)
{ {
devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc); devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc);
...@@ -4514,7 +4529,7 @@ static void dispc_free_irq(struct dispc_device *dispc, void *dev_id) ...@@ -4514,7 +4529,7 @@ static void dispc_free_irq(struct dispc_device *dispc, void *dev_id)
dispc->user_data = NULL; dispc->user_data = NULL;
} }
static u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc) u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc)
{ {
u32 limit = 0; u32 limit = 0;
...@@ -4684,47 +4699,6 @@ static void dispc_errata_i734_wa(struct dispc_device *dispc) ...@@ -4684,47 +4699,6 @@ static void dispc_errata_i734_wa(struct dispc_device *dispc)
REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4); REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4);
} }
static const struct dispc_ops dispc_ops = {
.read_irqstatus = dispc_read_irqstatus,
.clear_irqstatus = dispc_clear_irqstatus,
.write_irqenable = dispc_write_irqenable,
.request_irq = dispc_request_irq,
.free_irq = dispc_free_irq,
.runtime_get = dispc_runtime_get,
.runtime_put = dispc_runtime_put,
.get_num_ovls = dispc_get_num_ovls,
.get_num_mgrs = dispc_get_num_mgrs,
.get_memory_bandwidth_limit = dispc_get_memory_bandwidth_limit,
.mgr_enable = dispc_mgr_enable,
.mgr_is_enabled = dispc_mgr_is_enabled,
.mgr_get_vsync_irq = dispc_mgr_get_vsync_irq,
.mgr_get_framedone_irq = dispc_mgr_get_framedone_irq,
.mgr_get_sync_lost_irq = dispc_mgr_get_sync_lost_irq,
.mgr_go_busy = dispc_mgr_go_busy,
.mgr_go = dispc_mgr_go,
.mgr_set_lcd_config = dispc_mgr_set_lcd_config,
.mgr_check_timings = dispc_mgr_check_timings,
.mgr_set_timings = dispc_mgr_set_timings,
.mgr_setup = dispc_mgr_setup,
.mgr_gamma_size = dispc_mgr_gamma_size,
.mgr_set_gamma = dispc_mgr_set_gamma,
.ovl_enable = dispc_ovl_enable,
.ovl_setup = dispc_ovl_setup,
.ovl_get_color_modes = dispc_ovl_get_color_modes,
.wb_get_framedone_irq = dispc_wb_get_framedone_irq,
.wb_setup = dispc_wb_setup,
.has_writeback = dispc_has_writeback,
.wb_go_busy = dispc_wb_go_busy,
.wb_go = dispc_wb_go,
};
/* DISPC HW IP initialisation */ /* DISPC HW IP initialisation */
static const struct of_device_id dispc_of_match[] = { static const struct of_device_id dispc_of_match[] = {
{ .compatible = "ti,omap2-dispc", .data = &omap24xx_dispc_feats }, { .compatible = "ti,omap2-dispc", .data = &omap24xx_dispc_feats },
...@@ -4826,7 +4800,6 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) ...@@ -4826,7 +4800,6 @@ static int dispc_bind(struct device *dev, struct device *master, void *data)
dispc_runtime_put(dispc); dispc_runtime_put(dispc);
dss->dispc = dispc; dss->dispc = dispc;
dss->dispc_ops = &dispc_ops;
dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs,
dispc); dispc);
...@@ -4848,7 +4821,6 @@ static void dispc_unbind(struct device *dev, struct device *master, void *data) ...@@ -4848,7 +4821,6 @@ static void dispc_unbind(struct device *dev, struct device *master, void *data)
dss_debugfs_remove_file(dispc->debugfs); dss_debugfs_remove_file(dispc->debugfs);
dss->dispc = NULL; dss->dispc = NULL;
dss->dispc_ops = NULL;
pm_runtime_disable(dev); pm_runtime_disable(dev);
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
*/
#define DSS_SUBSYS_NAME "DISPLAY"
#include <linux/kernel.h>
#include <linux/of.h>
#include <drm/drm_connector.h>
#include <drm/drm_modes.h>
#include "omapdss.h"
static int disp_num_counter;
void omapdss_display_init(struct omap_dss_device *dssdev)
{
int id;
/*
* Note: this presumes that all displays either have an DT alias, or
* none has.
*/
id = of_alias_get_id(dssdev->dev->of_node, "display");
if (id < 0)
id = disp_num_counter++;
/* Use 'label' property for name, if it exists */
of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name);
if (dssdev->name == NULL)
dssdev->name = devm_kasprintf(dssdev->dev, GFP_KERNEL,
"display%u", id);
}
EXPORT_SYMBOL_GPL(omapdss_display_init);
int omapdss_display_get_modes(struct drm_connector *connector,
const struct videomode *vm)
{
struct drm_display_mode *mode;
mode = drm_mode_create(connector->dev);
if (!mode)
return 0;
drm_display_mode_from_videomode(vm, mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
return 1;
}
EXPORT_SYMBOL_GPL(omapdss_display_get_modes);
...@@ -641,7 +641,6 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) ...@@ -641,7 +641,6 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
out->type = OMAP_DISPLAY_TYPE_DPI; out->type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(dpi); out->dispc_channel = dpi_get_channel(dpi);
out->of_port = port_num; out->of_port = port_num;
out->owner = THIS_MODULE;
r = omapdss_device_init_output(out, &dpi->bridge); r = omapdss_device_init_output(out, &dpi->bridge);
if (r < 0) { if (r < 0) {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -707,7 +707,6 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) ...@@ -707,7 +707,6 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)
out->type = OMAP_DISPLAY_TYPE_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0"; out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->owner = THIS_MODULE;
out->of_port = 0; out->of_port = 0;
r = omapdss_device_init_output(out, &hdmi->bridge); r = omapdss_device_init_output(out, &hdmi->bridge);
......
...@@ -681,7 +681,6 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) ...@@ -681,7 +681,6 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi)
out->type = OMAP_DISPLAY_TYPE_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0"; out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->owner = THIS_MODULE;
out->of_port = 0; out->of_port = 0;
r = omapdss_device_init_output(out, &hdmi->bridge); r = omapdss_device_init_output(out, &hdmi->bridge);
......
...@@ -222,6 +222,9 @@ bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin, ...@@ -222,6 +222,9 @@ bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin,
n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max); n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
n_inc = 1; n_inc = 1;
if (n_start > n_stop)
return false;
if (hw->errata_i886) { if (hw->errata_i886) {
swap(n_start, n_stop); swap(n_start, n_stop);
n_inc = -1; n_inc = -1;
...@@ -239,6 +242,9 @@ bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin, ...@@ -239,6 +242,9 @@ bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin,
hw->m_max); hw->m_max);
m_inc = 1; m_inc = 1;
if (m_start > m_stop)
continue;
if (hw->errata_i886) { if (hw->errata_i886) {
swap(m_start, m_stop); swap(m_start, m_stop);
m_inc = -1; m_inc = -1;
......
...@@ -312,7 +312,6 @@ static int sdi_init_output(struct sdi_device *sdi) ...@@ -312,7 +312,6 @@ static int sdi_init_output(struct sdi_device *sdi)
out->dispc_channel = OMAP_DSS_CHANNEL_LCD; out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
/* We have SDI only on OMAP3, where it's on port 1 */ /* We have SDI only on OMAP3, where it's on port 1 */
out->of_port = 1; out->of_port = 1;
out->owner = THIS_MODULE;
out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */ out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */
| DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE; | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册