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

More drm-misc stuff for 4.12:

- drm_platform removal from Laurent
- more dw-hdmi bridge driver updates (Laurent, Kieran, Neil)
- more header cleanup and documentation
- more drm_debugs_remove_files removal (Noralf)
- minor qxl updates (Gerd)
- edp crc support in helper + analogix_dp (Tomeu) for more igt
  testing!
- old/new iterator roll-out (Maarten)
- new bridge drivers: lvds (Laurent), megachips-something (Peter
  Senna)

* tag 'drm-misc-next-2017-03-12' of git://anongit.freedesktop.org/git/drm-misc: (51 commits)
  drm: bridge: dw-hdmi: Move the driver to a separate directory.
  drm: bridge: dw-hdmi: Switch to regmap for register access
  drm: bridge: dw-hdmi: Remove device type from platform data
  drm: bridge: dw-hdmi: Add support for custom PHY configuration
  drm: bridge: dw-hdmi: Create PHY operations
  drm: bridge: dw-hdmi: Fix the PHY power up sequence
  drm: bridge: dw-hdmi: Fix the PHY power down sequence
  drm: bridge: dw-hdmi: Enable CSC even for DVI
  drm: bridge: dw-hdmi: Move CSC configuration out of PHY code
  drm: bridge: dw-hdmi: Remove unused functions
  drm: Extract drm_file.h
  drm: Remove DRM_MINOR_CNT
  drm: rename drm_fops.c to drm_file.c
  drm/doc: document fallback behaviour for atomic events
  drm: Remove drmP.h include from drm_kms_helper_common.c
  drm: Extract drm_pci.h
  drm: Move drm_lock_data out of drmP.h
  drm: Extract drm_prime.h
  drm/doc: Add todo about connector_list_iter
  drm/qxl: Remove qxl_debugfs_remove_files()
  ...
This commit is contained in:
Dave Airlie 2017-03-15 11:32:01 +10:00
commit 9c233760a6
81 changed files with 2445 additions and 1189 deletions

View File

@ -0,0 +1,64 @@
Parallel to LVDS Encoder
------------------------
This binding supports the parallel to LVDS encoders that don't require any
configuration.
LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple
incompatible data link layers have been used over time to transmit image data
to LVDS panels. This binding targets devices compatible with the following
specifications only.
[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February
1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA)
[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National
Semiconductor
[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video
Electronics Standards Association (VESA)
Those devices have been marketed under the FPD-Link and FlatLink brand names
among others.
Required properties:
- compatible: Must be "lvds-encoder"
Required nodes:
This device has two video ports. Their connections are modeled using the OF
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
- Video port 0 for parallel input
- Video port 1 for LVDS output
Example
-------
lvds-encoder {
compatible = "lvds-encoder";
#address-cells = <1>;
#size-cells = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds_enc_in: endpoint {
remote-endpoint = <&display_out_rgb>;
};
};
port@1 {
reg = <1>;
lvds_enc_out: endpoint {
remote-endpoint = <&lvds_panel_in>;
};
};
};
};

View File

@ -0,0 +1,94 @@
Drivers for the second video output of the GE B850v3:
STDP4028-ge-b850v3-fw bridges (LVDS-DP)
STDP2690-ge-b850v3-fw bridges (DP-DP++)
The video processing pipeline on the second output on the GE B850v3:
Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
Each bridge has a dedicated flash containing firmware for supporting the custom
design. The result is that, in this design, neither the STDP4028 nor the
STDP2690 behave as the stock bridges would. The compatible strings include the
suffix "-ge-b850v3-fw" to make it clear that the driver is for the bridges with
the firmware specific for the GE B850v3.
The hardware do not provide control over the video processing pipeline, as the
two bridges behaves as a single one. The only interfaces exposed by the
hardware are EDID, HPD, and interrupts.
stdp4028-ge-b850v3-fw required properties:
- compatible : "megachips,stdp4028-ge-b850v3-fw"
- reg : I2C bus address
- interrupt-parent : phandle of the interrupt controller that services
interrupts to the device
- interrupts : one interrupt should be described here, as in
<0 IRQ_TYPE_LEVEL_HIGH>
- ports : One input port(reg = <0>) and one output port(reg = <1>)
stdp2690-ge-b850v3-fw required properties:
compatible : "megachips,stdp2690-ge-b850v3-fw"
- reg : I2C bus address
- ports : One input port(reg = <0>) and one output port(reg = <1>)
Example:
&mux2_i2c2 {
status = "okay";
clock-frequency = <100000>;
stdp4028@73 {
compatible = "megachips,stdp4028-ge-b850v3-fw";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x73>;
interrupt-parent = <&gpio2>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
stdp4028_in: endpoint {
remote-endpoint = <&lvds0_out>;
};
};
port@1 {
reg = <1>;
stdp4028_out: endpoint {
remote-endpoint = <&stdp2690_in>;
};
};
};
};
stdp2690@72 {
compatible = "megachips,stdp2690-ge-b850v3-fw";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x72>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
stdp2690_in: endpoint {
remote-endpoint = <&stdp4028_out>;
};
};
port@1 {
reg = <1>;
stdp2690_out: endpoint {
/* Connector for external display */
};
};
};
};
};

View File

@ -178,6 +178,7 @@ maxim Maxim Integrated Products
mcube mCube mcube mCube
meas Measurement Specialties meas Measurement Specialties
mediatek MediaTek Inc. mediatek MediaTek Inc.
megachips MegaChips
melexis Melexis N.V. melexis Melexis N.V.
melfas MELFAS Inc. melfas MELFAS Inc.
memsic MEMSIC Inc. memsic MEMSIC Inc.

View File

@ -240,9 +240,6 @@ drivers.
.. kernel-doc:: drivers/gpu/drm/drm_pci.c .. kernel-doc:: drivers/gpu/drm/drm_pci.c
:export: :export:
.. kernel-doc:: drivers/gpu/drm/drm_platform.c
:export:
Open/Close, File Operations and IOCTLs Open/Close, File Operations and IOCTLs
====================================== ======================================
@ -298,10 +295,10 @@ over.
File Operations File Operations
--------------- ---------------
.. kernel-doc:: drivers/gpu/drm/drm_fops.c .. kernel-doc:: drivers/gpu/drm/drm_file.c
:doc: file operations :doc: file operations
.. kernel-doc:: drivers/gpu/drm/drm_fops.c .. kernel-doc:: drivers/gpu/drm/drm_file.c
:export: :export:
IOCTLs IOCTLs

View File

@ -449,6 +449,9 @@ PRIME Helper Functions
PRIME Function References PRIME Function References
------------------------- -------------------------
.. kernel-doc:: include/drm/drm_prime.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_prime.c .. kernel-doc:: drivers/gpu/drm/drm_prime.c
:export: :export:

View File

@ -153,6 +153,19 @@ following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and
Contact: Daniel Vetter Contact: Daniel Vetter
Switch to drm_connector_list_iter for any connector_list walking
----------------------------------------------------------------
Connectors can be hotplugged, and we now have a special list of helpers to walk
the connector_list in a race-free fashion, without incurring deadlocks on
mutexes and other fun stuff.
Unfortunately most drivers are not converted yet. At least all those supporting
DP MST hotplug should be converted, since for those drivers the difference
matters. See drm_for_each_connector_iter() vs. drm_for_each_connector().
Contact: Daniel Vetter
Core refactorings Core refactorings
================= =================

View File

@ -8123,6 +8123,14 @@ L: linux-wireless@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/wireless/mediatek/mt7601u/ F: drivers/net/wireless/mediatek/mt7601u/
MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
M: Peter Senna Tschudin <peter.senna@collabora.com>
M: Martin Donnelly <martin.donnelly@ge.com>
M: Martyn Welch <martyn.welch@collabora.co.uk>
S: Maintained
F: drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
F: Documentation/devicetree/bindings/video/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
MEGARAID SCSI/SAS DRIVERS MEGARAID SCSI/SAS DRIVERS
M: Kashyap Desai <kashyap.desai@broadcom.com> M: Kashyap Desai <kashyap.desai@broadcom.com>
M: Sumit Saxena <sumit.saxena@broadcom.com> M: Sumit Saxena <sumit.saxena@broadcom.com>

View File

@ -4,10 +4,10 @@
drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_context.o drm_dma.o \ drm_context.o drm_dma.o \
drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_drv.o \ drm_lock.o drm_memory.o drm_drv.o \
drm_scatter.o drm_pci.o \ drm_scatter.o drm_pci.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \ drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
drm_info.o drm_encoder_slave.o \ drm_info.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o drm_prime.o \ drm_trace_points.o drm_global.o drm_prime.o \

View File

@ -137,10 +137,9 @@ static int armada_drm_bind(struct device *dev)
return ret; return ret;
} }
priv->drm.platformdev = to_platform_device(dev);
priv->drm.dev_private = priv; priv->drm.dev_private = priv;
platform_set_drvdata(priv->drm.platformdev, &priv->drm); dev_set_drvdata(dev, &priv->drm);
INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);
INIT_KFIFO(priv->fb_unref); INIT_KFIFO(priv->fb_unref);

View File

@ -24,29 +24,25 @@ config DRM_DUMB_VGA_DAC
help help
Support for RGB to VGA DAC based bridges Support for RGB to VGA DAC based bridges
config DRM_DW_HDMI config DRM_LVDS_ENCODER
tristate tristate "Transparent parallel to LVDS encoder support"
depends on OF
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_PANEL
config DRM_DW_HDMI_AHB_AUDIO
tristate "Synopsis Designware AHB Audio interface"
depends on DRM_DW_HDMI && SND
select SND_PCM
select SND_PCM_ELD
select SND_PCM_IEC958
help help
Support the AHB Audio interface which is part of the Synopsis Support for transparent parallel to LVDS encoders that don't require
Designware HDMI block. This is used in conjunction with any configuration.
the i.MX6 HDMI driver.
config DRM_DW_HDMI_I2S_AUDIO config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
tristate "Synopsis Designware I2S Audio interface" tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"
depends on SND_SOC depends on OF
depends on DRM_DW_HDMI select DRM_KMS_HELPER
select SND_SOC_HDMI_CODEC select DRM_PANEL
help ---help---
Support the I2S Audio interface which is part of the Synopsis This is a driver for the display bridges of
Designware HDMI block. GE B850v3 that convert dual channel LVDS
to DP++. This is used with the i.MX6 imx-ldb
driver. You are likely to say N here.
config DRM_NXP_PTN3460 config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge" tristate "NXP PTN3460 DP/LVDS bridge"
@ -101,4 +97,6 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig"
source "drivers/gpu/drm/bridge/adv7511/Kconfig" source "drivers/gpu/drm/bridge/adv7511/Kconfig"
source "drivers/gpu/drm/bridge/synopsys/Kconfig"
endmenu endmenu

View File

@ -2,9 +2,8 @@ ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
@ -13,3 +12,4 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
obj-y += synopsys/

View File

@ -1488,6 +1488,28 @@ int analogix_dp_resume(struct device *dev)
EXPORT_SYMBOL_GPL(analogix_dp_resume); EXPORT_SYMBOL_GPL(analogix_dp_resume);
#endif #endif
int analogix_dp_start_crc(struct drm_connector *connector)
{
struct analogix_dp_device *dp = to_dp(connector);
if (!connector->state->crtc) {
DRM_ERROR("Connector %s doesn't currently have a CRTC.\n",
connector->name);
return -EINVAL;
}
return drm_dp_start_crc(&dp->aux, connector->state->crtc);
}
EXPORT_SYMBOL_GPL(analogix_dp_start_crc);
int analogix_dp_stop_crc(struct drm_connector *connector)
{
struct analogix_dp_device *dp = to_dp(connector);
return drm_dp_stop_crc(&dp->aux);
}
EXPORT_SYMBOL_GPL(analogix_dp_stop_crc);
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Analogix DP Core Driver"); MODULE_DESCRIPTION("Analogix DP Core Driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -237,6 +237,7 @@ static int dumb_vga_remove(struct platform_device *pdev)
static const struct of_device_id dumb_vga_match[] = { static const struct of_device_id dumb_vga_match[] = {
{ .compatible = "dumb-vga-dac" }, { .compatible = "dumb-vga-dac" },
{ .compatible = "adi,adv7123" },
{ .compatible = "ti,ths8135" }, { .compatible = "ti,ths8135" },
{}, {},
}; };

View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
#include <linux/of_graph.h>
struct lvds_encoder {
struct device *dev;
struct drm_bridge bridge;
struct drm_connector connector;
struct drm_panel *panel;
};
static inline struct lvds_encoder *
drm_bridge_to_lvds_encoder(struct drm_bridge *bridge)
{
return container_of(bridge, struct lvds_encoder, bridge);
}
static inline struct lvds_encoder *
drm_connector_to_lvds_encoder(struct drm_connector *connector)
{
return container_of(connector, struct lvds_encoder, connector);
}
static int lvds_connector_get_modes(struct drm_connector *connector)
{
struct lvds_encoder *lvds = drm_connector_to_lvds_encoder(connector);
return drm_panel_get_modes(lvds->panel);
}
static const struct drm_connector_helper_funcs lvds_connector_helper_funcs = {
.get_modes = lvds_connector_get_modes,
};
static const struct drm_connector_funcs lvds_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int lvds_encoder_attach(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge);
struct drm_connector *connector = &lvds->connector;
int ret;
if (!bridge->encoder) {
DRM_ERROR("Missing encoder\n");
return -ENODEV;
}
drm_connector_helper_add(connector, &lvds_connector_helper_funcs);
ret = drm_connector_init(bridge->dev, connector, &lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
if (ret) {
DRM_ERROR("Failed to initialize connector\n");
return ret;
}
drm_mode_connector_attach_encoder(&lvds->connector, bridge->encoder);
ret = drm_panel_attach(lvds->panel, &lvds->connector);
if (ret < 0)
return ret;
return 0;
}
static void lvds_encoder_detach(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge);
drm_panel_detach(lvds->panel);
}
static void lvds_encoder_pre_enable(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge);
drm_panel_prepare(lvds->panel);
}
static void lvds_encoder_enable(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge);
drm_panel_enable(lvds->panel);
}
static void lvds_encoder_disable(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge);
drm_panel_disable(lvds->panel);
}
static void lvds_encoder_post_disable(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge);
drm_panel_unprepare(lvds->panel);
}
static const struct drm_bridge_funcs lvds_encoder_bridge_funcs = {
.attach = lvds_encoder_attach,
.detach = lvds_encoder_detach,
.pre_enable = lvds_encoder_pre_enable,
.enable = lvds_encoder_enable,
.disable = lvds_encoder_disable,
.post_disable = lvds_encoder_post_disable,
};
static int lvds_encoder_probe(struct platform_device *pdev)
{
struct lvds_encoder *lvds;
struct device_node *port;
struct device_node *endpoint;
struct device_node *panel;
lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
if (!lvds)
return -ENOMEM;
lvds->dev = &pdev->dev;
platform_set_drvdata(pdev, lvds);
lvds->bridge.funcs = &lvds_encoder_bridge_funcs;
lvds->bridge.of_node = pdev->dev.of_node;
/* Locate the panel DT node. */
port = of_graph_get_port_by_id(pdev->dev.of_node, 1);
if (!port) {
dev_dbg(&pdev->dev, "port 1 not found\n");
return -ENXIO;
}
endpoint = of_get_child_by_name(port, "endpoint");
of_node_put(port);
if (!endpoint) {
dev_dbg(&pdev->dev, "no endpoint for port 1\n");
return -ENXIO;
}
panel = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (!panel) {
dev_dbg(&pdev->dev, "no remote endpoint for port 1\n");
return -ENXIO;
}
lvds->panel = of_drm_find_panel(panel);
of_node_put(panel);
if (!lvds->panel) {
dev_dbg(&pdev->dev, "panel not found, deferring probe\n");
return -EPROBE_DEFER;
}
/* Register the bridge. */
return drm_bridge_add(&lvds->bridge);
}
static int lvds_encoder_remove(struct platform_device *pdev)
{
struct lvds_encoder *encoder = platform_get_drvdata(pdev);
drm_bridge_remove(&encoder->bridge);
return 0;
}
static const struct of_device_id lvds_encoder_match[] = {
{ .compatible = "lvds-encoder" },
{ .compatible = "thine,thc63lvdm83d" },
{},
};
MODULE_DEVICE_TABLE(of, lvds_encoder_match);
static struct platform_driver lvds_encoder_driver = {
.probe = lvds_encoder_probe,
.remove = lvds_encoder_remove,
.driver = {
.name = "lvds-encoder",
.of_match_table = lvds_encoder_match,
},
};
module_platform_driver(lvds_encoder_driver);
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
MODULE_DESCRIPTION("Transparent parallel to LVDS encoder");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,428 @@
/*
* Driver for MegaChips STDP4028 with GE B850v3 firmware (LVDS-DP)
* Driver for MegaChips STDP2690 with GE B850v3 firmware (DP-DP++)
* Copyright (c) 2017, Collabora Ltd.
* Copyright (c) 2017, General Electric Company
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* This driver creates a drm_bridge and a drm_connector for the LVDS to DP++
* display bridge of the GE B850v3. There are two physical bridges on the video
* signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The
* physical bridges are automatically configured by the input video signal, and
* the driver has no access to the video processing pipeline. The driver is
* only needed to read EDID from the STDP2690 and to handle HPD events from the
* STDP4028. The driver communicates with both bridges over i2c. The video
* signal pipeline is as follows:
*
* Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
*
*/
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drmP.h>
#define EDID_EXT_BLOCK_CNT 0x7E
#define STDP4028_IRQ_OUT_CONF_REG 0x02
#define STDP4028_DPTX_IRQ_EN_REG 0x3C
#define STDP4028_DPTX_IRQ_STS_REG 0x3D
#define STDP4028_DPTX_STS_REG 0x3E
#define STDP4028_DPTX_DP_IRQ_EN 0x1000
#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400
#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000
#define STDP4028_DPTX_IRQ_CONFIG \
(STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN)
#define STDP4028_DPTX_HOTPLUG_STS 0x0200
#define STDP4028_DPTX_LINK_STS 0x1000
#define STDP4028_CON_STATE_CONNECTED \
(STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS)
#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400
#define STDP4028_DPTX_LINK_CH_STS 0x2000
#define STDP4028_DPTX_IRQ_CLEAR \
(STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS)
static DEFINE_MUTEX(ge_b850v3_lvds_dev_mutex);
struct ge_b850v3_lvds {
struct drm_connector connector;
struct drm_bridge bridge;
struct i2c_client *stdp4028_i2c;
struct i2c_client *stdp2690_i2c;
struct edid *edid;
};
static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr;
static u8 *stdp2690_get_edid(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
unsigned char start = 0x00;
unsigned int total_size;
u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL);
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &start,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.len = EDID_LENGTH,
.buf = block,
}
};
if (!block)
return NULL;
if (i2c_transfer(adapter, msgs, 2) != 2) {
DRM_ERROR("Unable to read EDID.\n");
goto err;
}
if (!drm_edid_block_valid(block, 0, false, NULL)) {
DRM_ERROR("Invalid EDID data\n");
goto err;
}
total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH;
if (total_size > EDID_LENGTH) {
kfree(block);
block = kmalloc(total_size, GFP_KERNEL);
if (!block)
return NULL;
/* Yes, read the entire buffer, and do not skip the first
* EDID_LENGTH bytes.
*/
start = 0x00;
msgs[1].len = total_size;
msgs[1].buf = block;
if (i2c_transfer(adapter, msgs, 2) != 2) {
DRM_ERROR("Unable to read EDID extension blocks.\n");
goto err;
}
if (!drm_edid_block_valid(block, 1, false, NULL)) {
DRM_ERROR("Invalid EDID data\n");
goto err;
}
}
return block;
err:
kfree(block);
return NULL;
}
static int ge_b850v3_lvds_get_modes(struct drm_connector *connector)
{
struct i2c_client *client;
int num_modes = 0;
client = ge_b850v3_lvds_ptr->stdp2690_i2c;
kfree(ge_b850v3_lvds_ptr->edid);
ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client);
if (ge_b850v3_lvds_ptr->edid) {
drm_mode_connector_update_edid_property(connector,
ge_b850v3_lvds_ptr->edid);
num_modes = drm_add_edid_modes(connector,
ge_b850v3_lvds_ptr->edid);
}
return num_modes;
}
static enum drm_mode_status ge_b850v3_lvds_mode_valid(
struct drm_connector *connector, struct drm_display_mode *mode)
{
return MODE_OK;
}
static const struct
drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = {
.get_modes = ge_b850v3_lvds_get_modes,
.mode_valid = ge_b850v3_lvds_mode_valid,
};
static enum drm_connector_status ge_b850v3_lvds_detect(
struct drm_connector *connector, bool force)
{
struct i2c_client *stdp4028_i2c =
ge_b850v3_lvds_ptr->stdp4028_i2c;
s32 link_state;
link_state = i2c_smbus_read_word_data(stdp4028_i2c,
STDP4028_DPTX_STS_REG);
if (link_state == STDP4028_CON_STATE_CONNECTED)
return connector_status_connected;
if (link_state == 0)
return connector_status_disconnected;
return connector_status_unknown;
}
static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ge_b850v3_lvds_detect,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
{
struct i2c_client *stdp4028_i2c
= ge_b850v3_lvds_ptr->stdp4028_i2c;
i2c_smbus_write_word_data(stdp4028_i2c,
STDP4028_DPTX_IRQ_STS_REG,
STDP4028_DPTX_IRQ_CLEAR);
if (ge_b850v3_lvds_ptr->connector.dev)
drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->connector.dev);
return IRQ_HANDLED;
}
static int ge_b850v3_lvds_attach(struct drm_bridge *bridge)
{
struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector;
struct i2c_client *stdp4028_i2c
= ge_b850v3_lvds_ptr->stdp4028_i2c;
int ret;
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
return -ENODEV;
}
connector->polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(connector,
&ge_b850v3_lvds_connector_helper_funcs);
ret = drm_connector_init(bridge->dev, connector,
&ge_b850v3_lvds_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
return ret;
}
ret = drm_mode_connector_attach_encoder(connector, bridge->encoder);
if (ret)
return ret;
/* Configures the bridge to re-enable interrupts after each ack. */
i2c_smbus_write_word_data(stdp4028_i2c,
STDP4028_IRQ_OUT_CONF_REG,
STDP4028_DPTX_DP_IRQ_EN);
/* Enable interrupts */
i2c_smbus_write_word_data(stdp4028_i2c,
STDP4028_DPTX_IRQ_EN_REG,
STDP4028_DPTX_IRQ_CONFIG);
return 0;
}
static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = {
.attach = ge_b850v3_lvds_attach,
};
static int ge_b850v3_lvds_init(struct device *dev)
{
mutex_lock(&ge_b850v3_lvds_dev_mutex);
if (ge_b850v3_lvds_ptr)
goto success;
ge_b850v3_lvds_ptr = devm_kzalloc(dev,
sizeof(*ge_b850v3_lvds_ptr),
GFP_KERNEL);
if (!ge_b850v3_lvds_ptr) {
mutex_unlock(&ge_b850v3_lvds_dev_mutex);
return -ENOMEM;
}
ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs;
ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node;
drm_bridge_add(&ge_b850v3_lvds_ptr->bridge);
success:
mutex_unlock(&ge_b850v3_lvds_dev_mutex);
return 0;
}
static void ge_b850v3_lvds_remove(void)
{
mutex_lock(&ge_b850v3_lvds_dev_mutex);
/*
* This check is to avoid both the drivers
* removing the bridge in their remove() function
*/
if (!ge_b850v3_lvds_ptr)
goto out;
drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
kfree(ge_b850v3_lvds_ptr->edid);
ge_b850v3_lvds_ptr = NULL;
out:
mutex_unlock(&ge_b850v3_lvds_dev_mutex);
}
static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
const struct i2c_device_id *id)
{
struct device *dev = &stdp4028_i2c->dev;
ge_b850v3_lvds_init(dev);
ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c;
i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr);
/* Clear pending interrupts since power up. */
i2c_smbus_write_word_data(stdp4028_i2c,
STDP4028_DPTX_IRQ_STS_REG,
STDP4028_DPTX_IRQ_CLEAR);
if (!stdp4028_i2c->irq)
return 0;
return devm_request_threaded_irq(&stdp4028_i2c->dev,
stdp4028_i2c->irq, NULL,
ge_b850v3_lvds_irq_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
}
static int stdp4028_ge_b850v3_fw_remove(struct i2c_client *stdp4028_i2c)
{
ge_b850v3_lvds_remove();
return 0;
}
static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = {
{"stdp4028_ge_fw", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table);
static const struct of_device_id stdp4028_ge_b850v3_fw_match[] = {
{ .compatible = "megachips,stdp4028-ge-b850v3-fw" },
{},
};
MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match);
static struct i2c_driver stdp4028_ge_b850v3_fw_driver = {
.id_table = stdp4028_ge_b850v3_fw_i2c_table,
.probe = stdp4028_ge_b850v3_fw_probe,
.remove = stdp4028_ge_b850v3_fw_remove,
.driver = {
.name = "stdp4028-ge-b850v3-fw",
.of_match_table = stdp4028_ge_b850v3_fw_match,
},
};
static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c,
const struct i2c_device_id *id)
{
struct device *dev = &stdp2690_i2c->dev;
ge_b850v3_lvds_init(dev);
ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c;
i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr);
return 0;
}
static int stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c)
{
ge_b850v3_lvds_remove();
return 0;
}
static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = {
{"stdp2690_ge_fw", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table);
static const struct of_device_id stdp2690_ge_b850v3_fw_match[] = {
{ .compatible = "megachips,stdp2690-ge-b850v3-fw" },
{},
};
MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match);
static struct i2c_driver stdp2690_ge_b850v3_fw_driver = {
.id_table = stdp2690_ge_b850v3_fw_i2c_table,
.probe = stdp2690_ge_b850v3_fw_probe,
.remove = stdp2690_ge_b850v3_fw_remove,
.driver = {
.name = "stdp2690-ge-b850v3-fw",
.of_match_table = stdp2690_ge_b850v3_fw_match,
},
};
static int __init stdpxxxx_ge_b850v3_init(void)
{
int ret;
ret = i2c_add_driver(&stdp4028_ge_b850v3_fw_driver);
if (ret)
return ret;
return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
}
module_init(stdpxxxx_ge_b850v3_init);
static void __exit stdpxxxx_ge_b850v3_exit(void)
{
i2c_del_driver(&stdp2690_ge_b850v3_fw_driver);
i2c_del_driver(&stdp4028_ge_b850v3_fw_driver);
}
module_exit(stdpxxxx_ge_b850v3_exit);
MODULE_AUTHOR("Peter Senna Tschudin <peter.senna@collabora.com>");
MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk>");
MODULE_DESCRIPTION("GE LVDS to DP++ display bridge)");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,23 @@
config DRM_DW_HDMI
tristate
select DRM_KMS_HELPER
config DRM_DW_HDMI_AHB_AUDIO
tristate "Synopsys Designware AHB Audio interface"
depends on DRM_DW_HDMI && SND
select SND_PCM
select SND_PCM_ELD
select SND_PCM_IEC958
help
Support the AHB Audio interface which is part of the Synopsys
Designware HDMI block. This is used in conjunction with
the i.MX6 HDMI driver.
config DRM_DW_HDMI_I2S_AUDIO
tristate "Synopsys Designware I2S Audio interface"
depends on SND_SOC
depends on DRM_DW_HDMI
select SND_SOC_HDMI_CODEC
help
Support the I2S Audio interface which is part of the Synopsys
Designware HDMI block.

View File

@ -0,0 +1,5 @@
#ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o

View File

@ -19,6 +19,7 @@
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
@ -116,14 +117,17 @@ struct dw_hdmi_i2c {
struct dw_hdmi_phy_data { struct dw_hdmi_phy_data {
enum dw_hdmi_phy_type type; enum dw_hdmi_phy_type type;
const char *name; const char *name;
unsigned int gen;
bool has_svsret; bool has_svsret;
int (*configure)(struct dw_hdmi *hdmi,
const struct dw_hdmi_plat_data *pdata,
unsigned long mpixelclock);
}; };
struct dw_hdmi { struct dw_hdmi {
struct drm_connector connector; struct drm_connector connector;
struct drm_bridge bridge; struct drm_bridge bridge;
enum dw_hdmi_devtype dev_type;
unsigned int version; unsigned int version;
struct platform_device *audio; struct platform_device *audio;
@ -140,8 +144,12 @@ struct dw_hdmi {
u8 edid[HDMI_EDID_LEN]; u8 edid[HDMI_EDID_LEN];
bool cable_plugin; bool cable_plugin;
const struct dw_hdmi_phy_data *phy; struct {
bool phy_enabled; const struct dw_hdmi_phy_ops *ops;
const char *name;
void *data;
bool enabled;
} phy;
struct drm_display_mode previous_mode; struct drm_display_mode previous_mode;
@ -164,8 +172,8 @@ struct dw_hdmi {
unsigned int audio_n; unsigned int audio_n;
bool audio_enable; bool audio_enable;
void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); unsigned int reg_shift;
u8 (*read)(struct dw_hdmi *hdmi, int offset); struct regmap *regm;
}; };
#define HDMI_IH_PHY_STAT0_RX_SENSE \ #define HDMI_IH_PHY_STAT0_RX_SENSE \
@ -176,42 +184,23 @@ struct dw_hdmi {
(HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \ (HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \
HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3)
static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
{
writel(val, hdmi->regs + (offset << 2));
}
static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
{
return readl(hdmi->regs + (offset << 2));
}
static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
}
static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
return readb(hdmi->regs + offset);
}
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{ {
hdmi->write(hdmi, val, offset); regmap_write(hdmi->regm, offset << hdmi->reg_shift, val);
} }
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{ {
return hdmi->read(hdmi, offset); unsigned int val = 0;
regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val);
return val;
} }
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{ {
u8 val = hdmi_readb(hdmi, reg) & ~mask; regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
val |= data & mask;
hdmi_writeb(hdmi, val, reg);
} }
static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
@ -830,6 +819,10 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
HDMI_VP_CONF); HDMI_VP_CONF);
} }
/* -----------------------------------------------------------------------------
* Synopsys PHY Handling
*/
static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi, static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit) unsigned char bit)
{ {
@ -837,32 +830,6 @@ static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
} }
static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec) static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{ {
u32 val; u32 val;
@ -877,8 +844,8 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
return true; return true;
} }
static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr) unsigned char addr)
{ {
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
@ -890,6 +857,7 @@ static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
HDMI_PHY_I2CM_OPERATION_ADDR); HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000); hdmi_phy_wait_i2c_done(hdmi, 1000);
} }
EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable) static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{ {
@ -940,54 +908,142 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK); HDMI_PHY_CONF0_SELDIPIF_MASK);
} }
static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
{
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
unsigned int i;
u16 val;
if (phy->gen == 1) {
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_enable_powerdown(hdmi, true);
return;
}
dw_hdmi_phy_gen2_txpwron(hdmi, 0);
/*
* Wait for TX_PHY_LOCK to be deasserted to indicate that the PHY went
* to low power mode.
*/
for (i = 0; i < 5; ++i) {
val = hdmi_readb(hdmi, HDMI_PHY_STAT0);
if (!(val & HDMI_PHY_TX_PHY_LOCK))
break;
usleep_range(1000, 2000);
}
if (val & HDMI_PHY_TX_PHY_LOCK)
dev_warn(hdmi->dev, "PHY failed to power down\n");
else
dev_dbg(hdmi->dev, "PHY powered down in %u iterations\n", i);
dw_hdmi_phy_gen2_pddq(hdmi, 1);
}
static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
{
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
unsigned int i;
u8 val;
if (phy->gen == 1) {
dw_hdmi_phy_enable_powerdown(hdmi, false);
/* Toggle TMDS enable. */
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_enable_tmds(hdmi, 1);
return 0;
}
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
/* Wait for PHY PLL lock */
for (i = 0; i < 5; ++i) {
val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
if (val)
break;
usleep_range(1000, 2000);
}
if (!val) {
dev_err(hdmi->dev, "PHY PLL failed to lock\n");
return -ETIMEDOUT;
}
dev_dbg(hdmi->dev, "PHY PLL locked %u iterations\n", i);
return 0;
}
/*
* PHY configuration function for the DWC HDMI 3D TX PHY. Based on the available
* information the DWC MHL PHY has the same register layout and is thus also
* supported by this function.
*/
static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
const struct dw_hdmi_plat_data *pdata,
unsigned long mpixelclock)
{ {
u8 val, msec;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
/* PLL/MPLL Cfg - always match on final entry */ /* PLL/MPLL Cfg - always match on final entry */
for (; mpll_config->mpixelclock != ~0UL; mpll_config++) for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
if (hdmi->hdmi_data.video_mode.mpixelclock <= if (mpixelclock <= mpll_config->mpixelclock)
mpll_config->mpixelclock)
break; break;
for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
if (hdmi->hdmi_data.video_mode.mpixelclock <= if (mpixelclock <= curr_ctrl->mpixelclock)
curr_ctrl->mpixelclock)
break; break;
for (; phy_config->mpixelclock != ~0UL; phy_config++) for (; phy_config->mpixelclock != ~0UL; phy_config++)
if (hdmi->hdmi_data.video_mode.mpixelclock <= if (mpixelclock <= phy_config->mpixelclock)
phy_config->mpixelclock)
break; break;
if (mpll_config->mpixelclock == ~0UL || if (mpll_config->mpixelclock == ~0UL ||
curr_ctrl->mpixelclock == ~0UL || curr_ctrl->mpixelclock == ~0UL ||
phy_config->mpixelclock == ~0UL) { phy_config->mpixelclock == ~0UL)
dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL; return -EINVAL;
}
/* Enable csc path */ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
if (cscon) HDMI_3D_TX_PHY_CPCE_CTRL);
val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH; dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
else HDMI_3D_TX_PHY_GMPCTRL);
val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS; dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
HDMI_3D_TX_PHY_CURRCTRL);
hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL); dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
HDMI_3D_TX_PHY_MSM_CTRL);
/* gen2 tx power off */ dw_hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
dw_hdmi_phy_gen2_txpwron(hdmi, 0); dw_hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
HDMI_3D_TX_PHY_CKSYMTXCTRL);
dw_hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
HDMI_3D_TX_PHY_VLEVCTRL);
/* gen2 pddq */ /* Override and disable clock termination. */
dw_hdmi_phy_gen2_pddq(hdmi, 1); dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
HDMI_3D_TX_PHY_CKCALCTRL);
return 0;
}
static int hdmi_phy_configure(struct dw_hdmi *hdmi)
{
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
int ret;
dw_hdmi_phy_power_off(hdmi);
/* Leave low power consumption mode by asserting SVSRET. */ /* Leave low power consumption mode by asserting SVSRET. */
if (hdmi->phy->has_svsret) if (phy->has_svsret)
dw_hdmi_phy_enable_svsret(hdmi, 1); dw_hdmi_phy_enable_svsret(hdmi, 1);
/* PHY reset. The reset signal is active high on Gen2 PHYs. */ /* PHY reset. The reset signal is active high on Gen2 PHYs. */
@ -1001,81 +1057,60 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
HDMI_PHY_I2CM_SLAVE_ADDR); HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0); hdmi_phy_test_clear(hdmi, 0);
hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, /* Write to the PHY as configured by the platform */
HDMI_3D_TX_PHY_CPCE_CTRL); if (pdata->configure_phy)
hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, ret = pdata->configure_phy(hdmi, pdata, mpixelclock);
HDMI_3D_TX_PHY_GMPCTRL); else
hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], ret = phy->configure(hdmi, pdata, mpixelclock);
HDMI_3D_TX_PHY_CURRCTRL); if (ret) {
dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
mpixelclock);
return ret;
}
hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); return dw_hdmi_phy_power_on(hdmi);
hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
HDMI_3D_TX_PHY_MSM_CTRL);
hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
HDMI_3D_TX_PHY_CKSYMTXCTRL);
hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
HDMI_3D_TX_PHY_VLEVCTRL);
/* Override and disable clock termination. */
hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
HDMI_3D_TX_PHY_CKCALCTRL);
dw_hdmi_phy_enable_powerdown(hdmi, false);
/* toggle TMDS enable */
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_enable_tmds(hdmi, 1);
/* gen2 tx power on */
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
/* Wait for PHY PLL lock */
msec = 5;
do {
val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
if (!val)
break;
if (msec == 0) {
dev_err(hdmi->dev, "PHY PLL not locked\n");
return -ETIMEDOUT;
}
udelay(1000);
msec--;
} while (1);
return 0;
} }
static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
struct drm_display_mode *mode)
{ {
int i, ret; int i, ret;
bool cscon;
/*check csc whether needed activated in HDMI mode */
cscon = hdmi->sink_is_hdmi && is_color_space_conversion(hdmi);
/* HDMI Phy spec says to do the phy initialization sequence twice */ /* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
dw_hdmi_phy_sel_data_en_pol(hdmi, 1); dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
dw_hdmi_phy_sel_interface_control(hdmi, 0); dw_hdmi_phy_sel_interface_control(hdmi, 0);
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_enable_powerdown(hdmi, true);
/* Enable CSC */ ret = hdmi_phy_configure(hdmi);
ret = hdmi_phy_configure(hdmi, cscon);
if (ret) if (ret)
return ret; return ret;
} }
hdmi->phy_enabled = true;
return 0; return 0;
} }
static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
{
dw_hdmi_phy_power_off(hdmi);
}
static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
void *data)
{
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
.init = dw_hdmi_phy_init,
.disable = dw_hdmi_phy_disable,
.read_hpd = dw_hdmi_phy_read_hpd,
};
/* -----------------------------------------------------------------------------
* HDMI TX Setup
*/
static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{ {
u8 de; u8 de;
@ -1290,17 +1325,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
} }
static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
{
if (!hdmi->phy_enabled)
return;
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_enable_powerdown(hdmi, true);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.4 */ /* HDMI Initialization Step B.4 */
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{ {
@ -1329,6 +1353,14 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
} }
/* Enable color space conversion if needed */
if (is_color_space_conversion(hdmi))
hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
HDMI_MC_FLOWCTRL);
else
hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
HDMI_MC_FLOWCTRL);
} }
static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
@ -1425,9 +1457,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode); hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */ /* HDMI Initializateion Step B.2 */
ret = dw_hdmi_phy_init(hdmi); ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode);
if (ret) if (ret)
return ret; return ret;
hdmi->phy.enabled = true;
/* HDMI Initialization Step B.3 */ /* HDMI Initialization Step B.3 */
dw_hdmi_enable_video_path(hdmi); dw_hdmi_enable_video_path(hdmi);
@ -1542,7 +1575,11 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{ {
dw_hdmi_phy_disable(hdmi); if (hdmi->phy.enabled) {
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
hdmi->phy.enabled = false;
}
hdmi->bridge_is_on = false; hdmi->bridge_is_on = false;
} }
@ -1605,8 +1642,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
dw_hdmi_update_phy_mask(hdmi); dw_hdmi_update_phy_mask(hdmi);
mutex_unlock(&hdmi->mutex); mutex_unlock(&hdmi->mutex);
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
connector_status_connected : connector_status_disconnected;
} }
static int dw_hdmi_connector_get_modes(struct drm_connector *connector) static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
@ -1858,24 +1894,37 @@ static const struct dw_hdmi_phy_data dw_hdmi_phys[] = {
{ {
.type = DW_HDMI_PHY_DWC_HDMI_TX_PHY, .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
.name = "DWC HDMI TX PHY", .name = "DWC HDMI TX PHY",
.gen = 1,
}, { }, {
.type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC, .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
.name = "DWC MHL PHY + HEAC PHY", .name = "DWC MHL PHY + HEAC PHY",
.gen = 2,
.has_svsret = true, .has_svsret = true,
.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, { }, {
.type = DW_HDMI_PHY_DWC_MHL_PHY, .type = DW_HDMI_PHY_DWC_MHL_PHY,
.name = "DWC MHL PHY", .name = "DWC MHL PHY",
.gen = 2,
.has_svsret = true, .has_svsret = true,
.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, { }, {
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC, .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
.name = "DWC HDMI 3D TX PHY + HEAC PHY", .name = "DWC HDMI 3D TX PHY + HEAC PHY",
.gen = 2,
.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, { }, {
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY, .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
.name = "DWC HDMI 3D TX PHY", .name = "DWC HDMI 3D TX PHY",
.gen = 2,
.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, { }, {
.type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY, .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
.name = "DWC HDMI 2.0 TX PHY", .name = "DWC HDMI 2.0 TX PHY",
.gen = 2,
.has_svsret = true, .has_svsret = true,
}, {
.type = DW_HDMI_PHY_VENDOR_PHY,
.name = "Vendor PHY",
} }
}; };
@ -1886,22 +1935,56 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID); phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
if (phy_type == DW_HDMI_PHY_VENDOR_PHY) {
/* Vendor PHYs require support from the glue layer. */
if (!hdmi->plat_data->phy_ops || !hdmi->plat_data->phy_name) {
dev_err(hdmi->dev,
"Vendor HDMI PHY not supported by glue layer\n");
return -ENODEV;
}
hdmi->phy.ops = hdmi->plat_data->phy_ops;
hdmi->phy.data = hdmi->plat_data->phy_data;
hdmi->phy.name = hdmi->plat_data->phy_name;
return 0;
}
/* Synopsys PHYs are handled internally. */
for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) { for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
if (dw_hdmi_phys[i].type == phy_type) { if (dw_hdmi_phys[i].type == phy_type) {
hdmi->phy = &dw_hdmi_phys[i]; hdmi->phy.ops = &dw_hdmi_synopsys_phy_ops;
hdmi->phy.name = dw_hdmi_phys[i].name;
hdmi->phy.data = (void *)&dw_hdmi_phys[i];
if (!dw_hdmi_phys[i].configure &&
!hdmi->plat_data->configure_phy) {
dev_err(hdmi->dev, "%s requires platform support\n",
hdmi->phy.name);
return -ENODEV;
}
return 0; return 0;
} }
} }
if (phy_type == DW_HDMI_PHY_VENDOR_PHY) dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", phy_type);
dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
else
dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
phy_type);
return -ENODEV; return -ENODEV;
} }
static const struct regmap_config hdmi_regmap_8bit_config = {
.reg_bits = 32,
.val_bits = 8,
.reg_stride = 1,
.max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR,
};
static const struct regmap_config hdmi_regmap_32bit_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2,
};
static struct dw_hdmi * static struct dw_hdmi *
__dw_hdmi_probe(struct platform_device *pdev, __dw_hdmi_probe(struct platform_device *pdev,
const struct dw_hdmi_plat_data *plat_data) const struct dw_hdmi_plat_data *plat_data)
@ -1911,7 +1994,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
struct platform_device_info pdevinfo; struct platform_device_info pdevinfo;
struct device_node *ddc_node; struct device_node *ddc_node;
struct dw_hdmi *hdmi; struct dw_hdmi *hdmi;
struct resource *iores; struct resource *iores = NULL;
int irq; int irq;
int ret; int ret;
u32 val = 1; u32 val = 1;
@ -1926,7 +2009,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
hdmi->plat_data = plat_data; hdmi->plat_data = plat_data;
hdmi->dev = dev; hdmi->dev = dev;
hdmi->dev_type = plat_data->dev_type;
hdmi->sample_rate = 48000; hdmi->sample_rate = 48000;
hdmi->disabled = true; hdmi->disabled = true;
hdmi->rxsense = true; hdmi->rxsense = true;
@ -1936,22 +2018,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
mutex_init(&hdmi->audio_mutex); mutex_init(&hdmi->audio_mutex);
spin_lock_init(&hdmi->audio_lock); spin_lock_init(&hdmi->audio_lock);
of_property_read_u32(np, "reg-io-width", &val);
switch (val) {
case 4:
hdmi->write = dw_hdmi_writel;
hdmi->read = dw_hdmi_readl;
break;
case 1:
hdmi->write = dw_hdmi_writeb;
hdmi->read = dw_hdmi_readb;
break;
default:
dev_err(dev, "reg-io-width must be 1 or 4\n");
return ERR_PTR(-EINVAL);
}
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) { if (ddc_node) {
hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
@ -1965,11 +2031,38 @@ __dw_hdmi_probe(struct platform_device *pdev,
dev_dbg(hdmi->dev, "no ddc property found\n"); dev_dbg(hdmi->dev, "no ddc property found\n");
} }
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!plat_data->regm) {
hdmi->regs = devm_ioremap_resource(dev, iores); const struct regmap_config *reg_config;
if (IS_ERR(hdmi->regs)) {
ret = PTR_ERR(hdmi->regs); of_property_read_u32(np, "reg-io-width", &val);
goto err_res; switch (val) {
case 4:
reg_config = &hdmi_regmap_32bit_config;
hdmi->reg_shift = 2;
break;
case 1:
reg_config = &hdmi_regmap_8bit_config;
break;
default:
dev_err(dev, "reg-io-width must be 1 or 4\n");
return ERR_PTR(-EINVAL);
}
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs)) {
ret = PTR_ERR(hdmi->regs);
goto err_res;
}
hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config);
if (IS_ERR(hdmi->regm)) {
dev_err(dev, "Failed to configure regmap\n");
ret = PTR_ERR(hdmi->regm);
goto err_res;
}
} else {
hdmi->regm = plat_data->regm;
} }
hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
@ -2019,7 +2112,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n", dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
hdmi->version >> 12, hdmi->version & 0xfff, hdmi->version >> 12, hdmi->version & 0xfff,
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without", prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
hdmi->phy->name); hdmi->phy.name);
initialize_hdmi_ih_mutes(hdmi); initialize_hdmi_ih_mutes(hdmi);
@ -2079,7 +2172,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID); config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
if (config3 & HDMI_CONFIG3_AHBAUDDMA) { if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) {
struct dw_hdmi_audio_data audio; struct dw_hdmi_audio_data audio;
audio.phys = iores->start; audio.phys = iores->start;

View File

@ -1374,8 +1374,8 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
return 0; return 0;
if (conn_state->crtc) { if (conn_state->crtc) {
crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state, crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
conn_state->crtc); conn_state->crtc);
crtc_state->connector_mask &= crtc_state->connector_mask &=
~(1 << drm_connector_index(conn_state->connector)); ~(1 << drm_connector_index(conn_state->connector));
@ -1492,7 +1492,7 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
{ {
struct drm_plane *plane; struct drm_plane *plane;
WARN_ON(!drm_atomic_get_existing_crtc_state(state, crtc)); WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc));
drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) {
struct drm_plane_state *plane_state = struct drm_plane_state *plane_state =

File diff suppressed because it is too large Load Diff

View File

@ -377,27 +377,26 @@ int drm_atomic_normalize_zpos(struct drm_device *dev,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state; struct drm_crtc_state *old_crtc_state, *new_crtc_state;
struct drm_plane *plane; struct drm_plane *plane;
struct drm_plane_state *plane_state; struct drm_plane_state *old_plane_state, *new_plane_state;
int i, ret = 0; int i, ret = 0;
for_each_plane_in_state(state, plane, plane_state, i) { for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
crtc = plane_state->crtc; crtc = new_plane_state->crtc;
if (!crtc) if (!crtc)
continue; continue;
if (plane->state->zpos != plane_state->zpos) { if (old_plane_state->zpos != new_plane_state->zpos) {
crtc_state = new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
drm_atomic_get_existing_crtc_state(state, crtc); new_crtc_state->zpos_changed = true;
crtc_state->zpos_changed = true;
} }
} }
for_each_crtc_in_state(state, crtc, crtc_state, i) { for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (crtc_state->plane_mask != crtc->state->plane_mask || if (old_crtc_state->plane_mask != new_crtc_state->plane_mask ||
crtc_state->zpos_changed) { new_crtc_state->zpos_changed) {
ret = drm_atomic_helper_crtc_normalize_zpos(crtc, ret = drm_atomic_helper_crtc_normalize_zpos(crtc,
crtc_state); new_crtc_state);
if (ret) if (ret)
return ret; return ret;
} }

View File

@ -242,14 +242,9 @@ static void drm_debugfs_remove_all_files(struct drm_minor *minor)
*/ */
int drm_debugfs_cleanup(struct drm_minor *minor) int drm_debugfs_cleanup(struct drm_minor *minor)
{ {
struct drm_device *dev = minor->dev;
if (!minor->debugfs_root) if (!minor->debugfs_root)
return 0; return 0;
if (dev->driver->debugfs_cleanup)
dev->driver->debugfs_cleanup(minor);
drm_debugfs_remove_all_files(minor); drm_debugfs_remove_all_files(minor);
debugfs_remove_recursive(minor->debugfs_root); debugfs_remove_recursive(minor->debugfs_root);

View File

@ -981,6 +981,78 @@ static const struct i2c_lock_operations drm_dp_i2c_lock_ops = {
.unlock_bus = unlock_bus, .unlock_bus = unlock_bus,
}; };
static int drm_dp_aux_get_crc(struct drm_dp_aux *aux, u8 *crc)
{
u8 buf, count;
int ret;
ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf);
if (ret < 0)
return ret;
WARN_ON(!(buf & DP_TEST_SINK_START));
ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK_MISC, &buf);
if (ret < 0)
return ret;
count = buf & DP_TEST_COUNT_MASK;
if (count == aux->crc_count)
return -EAGAIN; /* No CRC yet */
aux->crc_count = count;
/*
* At DP_TEST_CRC_R_CR, there's 6 bytes containing CRC data, 2 bytes
* per component (RGB or CrYCb).
*/
ret = drm_dp_dpcd_read(aux, DP_TEST_CRC_R_CR, crc, 6);
if (ret < 0)
return ret;
return 0;
}
static void drm_dp_aux_crc_work(struct work_struct *work)
{
struct drm_dp_aux *aux = container_of(work, struct drm_dp_aux,
crc_work);
struct drm_crtc *crtc;
u8 crc_bytes[6];
uint32_t crcs[3];
int ret;
if (WARN_ON(!aux->crtc))
return;
crtc = aux->crtc;
while (crtc->crc.opened) {
drm_crtc_wait_one_vblank(crtc);
if (!crtc->crc.opened)
break;
ret = drm_dp_aux_get_crc(aux, crc_bytes);
if (ret == -EAGAIN) {
usleep_range(1000, 2000);
ret = drm_dp_aux_get_crc(aux, crc_bytes);
}
if (ret == -EAGAIN) {
DRM_DEBUG_KMS("Get CRC failed after retrying: %d\n",
ret);
continue;
} else if (ret) {
DRM_DEBUG_KMS("Failed to get a CRC: %d\n", ret);
continue;
}
crcs[0] = crc_bytes[0] | crc_bytes[1] << 8;
crcs[1] = crc_bytes[2] | crc_bytes[3] << 8;
crcs[2] = crc_bytes[4] | crc_bytes[5] << 8;
drm_crtc_add_crc_entry(crtc, false, 0, crcs);
}
}
/** /**
* drm_dp_aux_init() - minimally initialise an aux channel * drm_dp_aux_init() - minimally initialise an aux channel
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
@ -993,6 +1065,7 @@ static const struct i2c_lock_operations drm_dp_i2c_lock_ops = {
void drm_dp_aux_init(struct drm_dp_aux *aux) void drm_dp_aux_init(struct drm_dp_aux *aux)
{ {
mutex_init(&aux->hw_mutex); mutex_init(&aux->hw_mutex);
INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work);
aux->ddc.algo = &drm_dp_i2c_algo; aux->ddc.algo = &drm_dp_i2c_algo;
aux->ddc.algo_data = aux; aux->ddc.algo_data = aux;
@ -1081,3 +1154,57 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE])
EXPORT_SYMBOL(drm_dp_psr_setup_time); EXPORT_SYMBOL(drm_dp_psr_setup_time);
#undef PSR_SETUP_TIME #undef PSR_SETUP_TIME
/**
* drm_dp_start_crc() - start capture of frame CRCs
* @aux: DisplayPort AUX channel
* @crtc: CRTC displaying the frames whose CRCs are to be captured
*
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc)
{
u8 buf;
int ret;
ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf);
if (ret < 0)
return ret;
ret = drm_dp_dpcd_writeb(aux, DP_TEST_SINK, buf | DP_TEST_SINK_START);
if (ret < 0)
return ret;
aux->crc_count = 0;
aux->crtc = crtc;
schedule_work(&aux->crc_work);
return 0;
}
EXPORT_SYMBOL(drm_dp_start_crc);
/**
* drm_dp_stop_crc() - stop capture of frame CRCs
* @aux: DisplayPort AUX channel
*
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_stop_crc(struct drm_dp_aux *aux)
{
u8 buf;
int ret;
ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf);
if (ret < 0)
return ret;
ret = drm_dp_dpcd_writeb(aux, DP_TEST_SINK, buf & ~DP_TEST_SINK_START);
if (ret < 0)
return ret;
flush_work(&aux->crc_work);
aux->crtc = NULL;
return 0;
}
EXPORT_SYMBOL(drm_dp_stop_crc);

View File

@ -1,7 +1,4 @@
/* /*
* \file drm_fops.c
* File operations for DRM
*
* \author Rickard E. (Rik) Faith <faith@valinux.com> * \author Rickard E. (Rik) Faith <faith@valinux.com>
* \author Daryll Strauss <daryll@valinux.com> * \author Daryll Strauss <daryll@valinux.com>
* \author Gareth Hughes <gareth@valinux.com> * \author Gareth Hughes <gareth@valinux.com>
@ -34,10 +31,13 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <drm/drmP.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <drm/drm_file.h>
#include <drm/drmP.h>
#include "drm_legacy.h" #include "drm_legacy.h"
#include "drm_internal.h" #include "drm_internal.h"
#include "drm_crtc_internal.h" #include "drm_crtc_internal.h"

View File

@ -24,7 +24,7 @@
#define DRM_IF_MAJOR 1 #define DRM_IF_MAJOR 1
#define DRM_IF_MINOR 4 #define DRM_IF_MINOR 4
/* drm_fops.c */ /* drm_file.c */
extern struct mutex drm_global_mutex; extern struct mutex drm_global_mutex;
void drm_lastclose(struct drm_device *dev); void drm_lastclose(struct drm_device *dev);

View File

@ -25,8 +25,7 @@
* *
*/ */
#include <drm/drmP.h> #include <linux/module.h>
#include <drm/drm_fb_helper.h>
#include "drm_crtc_helper_internal.h" #include "drm_crtc_helper_internal.h"

View File

@ -26,6 +26,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/export.h> #include <linux/export.h>
#include <drm/drm_pci.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include "drm_internal.h" #include "drm_internal.h"
#include "drm_legacy.h" #include "drm_legacy.h"
@ -36,6 +37,9 @@
* @size: size of block to allocate * @size: size of block to allocate
* @align: alignment of block * @align: alignment of block
* *
* FIXME: This is a needless abstraction of the Linux dma-api and should be
* removed.
*
* Return: A handle to the allocated memory block on success or NULL on * Return: A handle to the allocated memory block on success or NULL on
* failure. * failure.
*/ */
@ -104,6 +108,9 @@ void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
* drm_pci_free - Free a PCI consistent memory block * drm_pci_free - Free a PCI consistent memory block
* @dev: DRM device * @dev: DRM device
* @dmah: handle to memory block * @dmah: handle to memory block
*
* FIXME: This is a needless abstraction of the Linux dma-api and should be
* removed.
*/ */
void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
{ {

View File

@ -469,7 +469,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
* Drivers may optionally implement the ->atomic_disable callback, so * Drivers may optionally implement the ->atomic_disable callback, so
* special-case that here. * special-case that here.
*/ */
if (drm_atomic_plane_disabling(plane, plane_state) && if (drm_atomic_plane_disabling(plane_state, plane->state) &&
plane_funcs->atomic_disable) plane_funcs->atomic_disable)
plane_funcs->atomic_disable(plane, plane_state); plane_funcs->atomic_disable(plane, plane_state);
else else

View File

@ -1,87 +0,0 @@
/*
* Derived from drm_pci.c
*
* Copyright 2003 José Fonseca.
* Copyright 2003 Leif Delgass.
* Copyright (c) 2009, Code Aurora Forum.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/export.h>
#include <drm/drmP.h>
/*
* Register.
*
* \param platdev - Platform device struture
* \return zero on success or a negative number on failure.
*
* Attempt to gets inter module "drm" information. If we are first
* then register the character device and inter module information.
* Try and register, if we fail to register, backout previous work.
*/
static int drm_get_platform_dev(struct platform_device *platdev,
struct drm_driver *driver)
{
struct drm_device *dev;
int ret;
DRM_DEBUG("\n");
dev = drm_dev_alloc(driver, &platdev->dev);
if (IS_ERR(dev))
return PTR_ERR(dev);
dev->platformdev = platdev;
ret = drm_dev_register(dev, 0);
if (ret)
goto err_free;
return 0;
err_free:
drm_dev_unref(dev);
return ret;
}
/**
* drm_platform_init - Register a platform device with the DRM subsystem
* @driver: DRM device driver
* @platform_device: platform device to register
*
* Registers the specified DRM device driver and platform device with the DRM
* subsystem, initializing a drm_device structure and calling the driver's
* .load() function.
*
* NOTE: This function is deprecated, please use drm_dev_alloc() and
* drm_dev_register() instead and remove your &drm_driver.load callback.
*
* Return: 0 on success or a negative error code on failure.
*/
int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device)
{
DRM_DEBUG("\n");
return drm_get_platform_dev(platform_device, driver);
}
EXPORT_SYMBOL(drm_platform_init);

View File

@ -29,8 +29,9 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <drm/drmP.h> #include <drm/drm_prime.h>
#include <drm/drm_gem.h> #include <drm/drm_gem.h>
#include <drm/drmP.h>
#include "drm_internal.h" #include "drm_internal.h"

View File

@ -86,8 +86,8 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
int ret; int ret;
pipe = container_of(plane, struct drm_simple_display_pipe, plane); pipe = container_of(plane, struct drm_simple_display_pipe, plane);
crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
&pipe->crtc); &pipe->crtc);
if (crtc_state->enable != !!plane_state->crtc) if (crtc_state->enable != !!plane_state->crtc)
return -EINVAL; /* plane must match crtc enable state */ return -EINVAL; /* plane must match crtc enable state */

View File

@ -101,7 +101,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
struct exynos_dp_device *dp = to_dp(plat_data); struct exynos_dp_device *dp = to_dp(plat_data);
int ret; int ret;
drm_connector_register(connector);
dp->connector = connector; dp->connector = connector;
/* Pre-empt DP connector creation if there's a bridge */ /* Pre-empt DP connector creation if there's a bridge */

View File

@ -114,7 +114,6 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder)
} }
drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs); drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs);
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
return 0; return 0;

View File

@ -39,118 +39,6 @@
static struct device *exynos_drm_get_dma_device(void); static struct device *exynos_drm_get_dma_device(void);
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{
struct exynos_drm_private *private;
struct drm_encoder *encoder;
unsigned int clone_mask;
int cnt, ret;
private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
if (!private)
return -ENOMEM;
init_waitqueue_head(&private->wait);
spin_lock_init(&private->lock);
dev_set_drvdata(dev->dev, dev);
dev->dev_private = (void *)private;
/* the first real CRTC device is used for all dma mapping operations */
private->dma_dev = exynos_drm_get_dma_device();
if (!private->dma_dev) {
DRM_ERROR("no device found for DMA mapping operations.\n");
ret = -ENODEV;
goto err_free_private;
}
DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
dev_name(private->dma_dev));
/* create common IOMMU mapping for all devices attached to Exynos DRM */
ret = drm_create_iommu_mapping(dev);
if (ret < 0) {
DRM_ERROR("failed to create iommu mapping.\n");
goto err_free_private;
}
drm_mode_config_init(dev);
exynos_drm_mode_config_init(dev);
/* setup possible_clones. */
cnt = 0;
clone_mask = 0;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
clone_mask |= (1 << (cnt++));
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
encoder->possible_clones = clone_mask;
platform_set_drvdata(dev->platformdev, dev);
/* Try to bind all sub drivers. */
ret = component_bind_all(dev->dev, dev);
if (ret)
goto err_mode_config_cleanup;
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret)
goto err_unbind_all;
/* Probe non kms sub drivers and virtual display driver. */
ret = exynos_drm_device_subdrv_probe(dev);
if (ret)
goto err_cleanup_vblank;
drm_mode_config_reset(dev);
/*
* enable drm irq mode.
* - with irq_enabled = true, we can use the vblank feature.
*
* P.S. note that we wouldn't use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler.
*/
dev->irq_enabled = true;
/* init kms poll for handling hpd */
drm_kms_helper_poll_init(dev);
/* force connectors detection */
drm_helper_hpd_irq_event(dev);
return 0;
err_cleanup_vblank:
drm_vblank_cleanup(dev);
err_unbind_all:
component_unbind_all(dev->dev, dev);
err_mode_config_cleanup:
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
err_free_private:
kfree(private);
return ret;
}
static void exynos_drm_unload(struct drm_device *dev)
{
exynos_drm_device_subdrv_remove(dev);
exynos_drm_fbdev_fini(dev);
drm_kms_helper_poll_fini(dev);
drm_vblank_cleanup(dev);
component_unbind_all(dev->dev, dev);
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
kfree(dev->dev_private);
dev->dev_private = NULL;
}
int exynos_atomic_check(struct drm_device *dev, int exynos_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
@ -256,8 +144,6 @@ static const struct file_operations exynos_drm_driver_fops = {
static struct drm_driver exynos_drm_driver = { static struct drm_driver exynos_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
| DRIVER_ATOMIC | DRIVER_RENDER, | DRIVER_ATOMIC | DRIVER_RENDER,
.load = exynos_drm_load,
.unload = exynos_drm_unload,
.open = exynos_drm_open, .open = exynos_drm_open,
.preclose = exynos_drm_preclose, .preclose = exynos_drm_preclose,
.lastclose = exynos_drm_lastclose, .lastclose = exynos_drm_lastclose,
@ -432,12 +318,135 @@ static struct component_match *exynos_drm_match_add(struct device *dev)
static int exynos_drm_bind(struct device *dev) static int exynos_drm_bind(struct device *dev)
{ {
return drm_platform_init(&exynos_drm_driver, to_platform_device(dev)); struct exynos_drm_private *private;
struct drm_encoder *encoder;
struct drm_device *drm;
unsigned int clone_mask;
int cnt, ret;
drm = drm_dev_alloc(&exynos_drm_driver, dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
if (!private) {
ret = -ENOMEM;
goto err_free_drm;
}
init_waitqueue_head(&private->wait);
spin_lock_init(&private->lock);
dev_set_drvdata(dev, drm);
drm->dev_private = (void *)private;
/* the first real CRTC device is used for all dma mapping operations */
private->dma_dev = exynos_drm_get_dma_device();
if (!private->dma_dev) {
DRM_ERROR("no device found for DMA mapping operations.\n");
ret = -ENODEV;
goto err_free_private;
}
DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
dev_name(private->dma_dev));
/* create common IOMMU mapping for all devices attached to Exynos DRM */
ret = drm_create_iommu_mapping(drm);
if (ret < 0) {
DRM_ERROR("failed to create iommu mapping.\n");
goto err_free_private;
}
drm_mode_config_init(drm);
exynos_drm_mode_config_init(drm);
/* setup possible_clones. */
cnt = 0;
clone_mask = 0;
list_for_each_entry(encoder, &drm->mode_config.encoder_list, head)
clone_mask |= (1 << (cnt++));
list_for_each_entry(encoder, &drm->mode_config.encoder_list, head)
encoder->possible_clones = clone_mask;
/* Try to bind all sub drivers. */
ret = component_bind_all(drm->dev, drm);
if (ret)
goto err_mode_config_cleanup;
ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret)
goto err_unbind_all;
/* Probe non kms sub drivers and virtual display driver. */
ret = exynos_drm_device_subdrv_probe(drm);
if (ret)
goto err_cleanup_vblank;
drm_mode_config_reset(drm);
/*
* enable drm irq mode.
* - with irq_enabled = true, we can use the vblank feature.
*
* P.S. note that we wouldn't use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler.
*/
drm->irq_enabled = true;
/* init kms poll for handling hpd */
drm_kms_helper_poll_init(drm);
/* force connectors detection */
drm_helper_hpd_irq_event(drm);
/* register the DRM device */
ret = drm_dev_register(drm, 0);
if (ret < 0)
goto err_cleanup_fbdev;
return 0;
err_cleanup_fbdev:
exynos_drm_fbdev_fini(drm);
drm_kms_helper_poll_fini(drm);
exynos_drm_device_subdrv_remove(drm);
err_cleanup_vblank:
drm_vblank_cleanup(drm);
err_unbind_all:
component_unbind_all(drm->dev, drm);
err_mode_config_cleanup:
drm_mode_config_cleanup(drm);
drm_release_iommu_mapping(drm);
err_free_private:
kfree(private);
err_free_drm:
drm_dev_unref(drm);
return ret;
} }
static void exynos_drm_unbind(struct device *dev) static void exynos_drm_unbind(struct device *dev)
{ {
drm_put_dev(dev_get_drvdata(dev)); struct drm_device *drm = dev_get_drvdata(dev);
drm_dev_unregister(drm);
exynos_drm_device_subdrv_remove(drm);
exynos_drm_fbdev_fini(drm);
drm_kms_helper_poll_fini(drm);
component_unbind_all(drm->dev, drm);
drm_mode_config_cleanup(drm);
drm_release_iommu_mapping(drm);
kfree(drm->dev_private);
drm->dev_private = NULL;
drm_dev_unref(drm);
} }
static const struct component_master_ops exynos_drm_ops = { static const struct component_master_ops exynos_drm_ops = {

View File

@ -1587,7 +1587,6 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
} }
drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
return 0; return 0;

View File

@ -119,7 +119,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
struct exynos_drm_gem *exynos_gem; struct exynos_drm_gem *exynos_gem;
struct drm_device *dev = helper->dev; struct drm_device *dev = helper->dev;
struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct platform_device *pdev = dev->platformdev;
unsigned long size; unsigned long size;
int ret; int ret;
@ -142,7 +141,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
* memory area. * memory area.
*/ */
if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) { if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) {
dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); dev_warn(dev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n");
exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG,
size); size);
} }

View File

@ -359,7 +359,6 @@ static int vidi_create_connector(struct drm_encoder *encoder)
} }
drm_connector_helper_add(connector, &vidi_connector_helper_funcs); drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
return 0; return 0;

View File

@ -920,7 +920,6 @@ static int hdmi_create_connector(struct drm_encoder *encoder)
} }
drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
if (hdata->bridge) { if (hdata->bridge) {

View File

@ -175,7 +175,6 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
.mpll_cfg = imx_mpll_cfg, .mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr, .cur_ctr = imx_cur_ctr,
.phy_config = imx_phy_config, .phy_config = imx_phy_config,
.dev_type = IMX6Q_HDMI,
.mode_valid = imx6q_hdmi_mode_valid, .mode_valid = imx6q_hdmi_mode_valid,
}; };
@ -183,7 +182,6 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
.mpll_cfg = imx_mpll_cfg, .mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr, .cur_ctr = imx_cur_ctr,
.phy_config = imx_phy_config, .phy_config = imx_phy_config,
.dev_type = IMX6DL_HDMI,
.mode_valid = imx6dl_hdmi_mode_valid, .mode_valid = imx6dl_hdmi_mode_valid,
}; };

View File

@ -434,7 +434,7 @@ fail:
struct msm_kms *mdp4_kms_init(struct drm_device *dev) struct msm_kms *mdp4_kms_init(struct drm_device *dev)
{ {
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = to_platform_device(dev->dev);
struct mdp4_platform_config *config = mdp4_get_config(pdev); struct mdp4_platform_config *config = mdp4_get_config(pdev);
struct mdp4_kms *mdp4_kms; struct mdp4_kms *mdp4_kms;
struct msm_kms *kms = NULL; struct msm_kms *kms = NULL;

View File

@ -505,7 +505,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
uint32_t major, uint32_t minor) uint32_t major, uint32_t minor)
{ {
struct drm_device *dev = mdp5_kms->dev; struct drm_device *dev = mdp5_kms->dev;
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = to_platform_device(dev->dev);
struct mdp5_cfg_handler *cfg_handler; struct mdp5_cfg_handler *cfg_handler;
struct mdp5_cfg_platform *pconfig; struct mdp5_cfg_platform *pconfig;
int i, ret = 0; int i, ret = 0;

View File

@ -160,7 +160,7 @@ void msm_mdss_destroy(struct drm_device *dev)
int msm_mdss_init(struct drm_device *dev) int msm_mdss_init(struct drm_device *dev)
{ {
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = to_platform_device(dev->dev);
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
struct msm_mdss *mdss; struct msm_mdss *mdss;
int ret; int ret;

View File

@ -164,20 +164,5 @@ int msm_debugfs_init(struct drm_minor *minor)
return ret; return ret;
} }
void msm_debugfs_cleanup(struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct msm_drm_private *priv = dev->dev_private;
if (!priv)
return;
if (priv->kms->funcs->debugfs_cleanup)
priv->kms->funcs->debugfs_cleanup(priv->kms, minor);
msm_rd_debugfs_cleanup(minor);
msm_perf_debugfs_cleanup(minor);
}
#endif #endif

View File

@ -20,7 +20,6 @@
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
int msm_debugfs_init(struct drm_minor *minor); int msm_debugfs_init(struct drm_minor *minor);
void msm_debugfs_cleanup(struct drm_minor *minor);
#endif #endif
#endif /* __MSM_DEBUGFS_H__ */ #endif /* __MSM_DEBUGFS_H__ */

View File

@ -241,6 +241,9 @@ static int msm_drm_uninit(struct device *dev)
drm_dev_unregister(ddev); drm_dev_unregister(ddev);
msm_perf_debugfs_cleanup(priv);
msm_rd_debugfs_cleanup(priv);
#ifdef CONFIG_DRM_FBDEV_EMULATION #ifdef CONFIG_DRM_FBDEV_EMULATION
if (fbdev && priv->fbdev) if (fbdev && priv->fbdev)
msm_fbdev_free(ddev); msm_fbdev_free(ddev);
@ -383,7 +386,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
} }
platform_set_drvdata(pdev, ddev); platform_set_drvdata(pdev, ddev);
ddev->platformdev = pdev;
priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) { if (!priv) {
@ -836,7 +838,6 @@ static struct drm_driver msm_driver = {
.gem_prime_mmap = msm_gem_prime_mmap, .gem_prime_mmap = msm_gem_prime_mmap,
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
.debugfs_init = msm_debugfs_init, .debugfs_init = msm_debugfs_init,
.debugfs_cleanup = msm_debugfs_cleanup,
#endif #endif
.ioctls = msm_ioctls, .ioctls = msm_ioctls,
.num_ioctls = DRM_MSM_NUM_IOCTLS, .num_ioctls = DRM_MSM_NUM_IOCTLS,

View File

@ -304,10 +304,10 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
int msm_debugfs_late_init(struct drm_device *dev); int msm_debugfs_late_init(struct drm_device *dev);
int msm_rd_debugfs_init(struct drm_minor *minor); int msm_rd_debugfs_init(struct drm_minor *minor);
void msm_rd_debugfs_cleanup(struct drm_minor *minor); void msm_rd_debugfs_cleanup(struct msm_drm_private *priv);
void msm_rd_dump_submit(struct msm_gem_submit *submit); void msm_rd_dump_submit(struct msm_gem_submit *submit);
int msm_perf_debugfs_init(struct drm_minor *minor); int msm_perf_debugfs_init(struct drm_minor *minor);
void msm_perf_debugfs_cleanup(struct drm_minor *minor); void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);
#else #else
static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; } static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }
static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {} static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {}

View File

@ -64,7 +64,6 @@ struct msm_kms_funcs {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
/* debugfs: */ /* debugfs: */
int (*debugfs_init)(struct msm_kms *kms, struct drm_minor *minor); int (*debugfs_init)(struct msm_kms *kms, struct drm_minor *minor);
void (*debugfs_cleanup)(struct msm_kms *kms, struct drm_minor *minor);
#endif #endif
}; };

View File

@ -231,13 +231,12 @@ int msm_perf_debugfs_init(struct drm_minor *minor)
return 0; return 0;
fail: fail:
msm_perf_debugfs_cleanup(minor); msm_perf_debugfs_cleanup(priv);
return -1; return -1;
} }
void msm_perf_debugfs_cleanup(struct drm_minor *minor) void msm_perf_debugfs_cleanup(struct msm_drm_private *priv)
{ {
struct msm_drm_private *priv = minor->dev->dev_private;
struct msm_perf_state *perf = priv->perf; struct msm_perf_state *perf = priv->perf;
if (!perf) if (!perf)

View File

@ -245,13 +245,12 @@ int msm_rd_debugfs_init(struct drm_minor *minor)
return 0; return 0;
fail: fail:
msm_rd_debugfs_cleanup(minor); msm_rd_debugfs_cleanup(priv);
return -1; return -1;
} }
void msm_rd_debugfs_cleanup(struct drm_minor *minor) void msm_rd_debugfs_cleanup(struct msm_drm_private *priv)
{ {
struct msm_drm_private *priv = minor->dev->dev_private;
struct msm_rd_state *rd = priv->rd; struct msm_rd_state *rd = priv->rd;
if (!rd) if (!rd)

View File

@ -108,7 +108,7 @@ nouveau_name(struct drm_device *dev)
if (dev->pdev) if (dev->pdev)
return nouveau_pci_name(dev->pdev); return nouveau_pci_name(dev->pdev);
else else
return nouveau_platform_name(dev->platformdev); return nouveau_platform_name(to_platform_device(dev->dev));
} }
static void static void
@ -1095,7 +1095,6 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,
goto err_free; goto err_free;
} }
drm->platformdev = pdev;
platform_set_drvdata(pdev, drm); platform_set_drvdata(pdev, drm);
return drm; return drm;

View File

@ -129,16 +129,3 @@ int qxl_debugfs_add_files(struct qxl_device *qdev,
#endif #endif
return 0; return 0;
} }
void qxl_debugfs_remove_files(struct qxl_device *qdev)
{
#if defined(CONFIG_DEBUG_FS)
unsigned i;
for (i = 0; i < qdev->debugfs_count; i++) {
drm_debugfs_remove_files(qdev->debugfs[i].files,
qdev->debugfs[i].num_files,
qdev->ddev.primary);
}
#endif
}

View File

@ -81,6 +81,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
qdev->rom->client_monitors_config_crc); qdev->rom->client_monitors_config_crc);
return MONITORS_CONFIG_BAD_CRC; return MONITORS_CONFIG_BAD_CRC;
} }
if (!num_monitors) {
DRM_DEBUG_KMS("no client monitors configured\n");
return status;
}
if (num_monitors > qdev->monitors_config->max_allowed) { if (num_monitors > qdev->monitors_config->max_allowed) {
DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n", DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
qdev->monitors_config->max_allowed, num_monitors); qdev->monitors_config->max_allowed, num_monitors);
@ -157,19 +161,23 @@ static void qxl_update_offset_props(struct qxl_device *qdev)
void qxl_display_read_client_monitors_config(struct qxl_device *qdev) void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
{ {
struct drm_device *dev = &qdev->ddev; struct drm_device *dev = &qdev->ddev;
int status; int status, retries;
status = qxl_display_copy_rom_client_monitors_config(qdev); for (retries = 0; retries < 10; retries++) {
while (status == MONITORS_CONFIG_BAD_CRC) {
qxl_io_log(qdev, "failed crc check for client_monitors_config,"
" retrying\n");
status = qxl_display_copy_rom_client_monitors_config(qdev); status = qxl_display_copy_rom_client_monitors_config(qdev);
if (status != MONITORS_CONFIG_BAD_CRC)
break;
udelay(5);
}
if (status == MONITORS_CONFIG_BAD_CRC) {
qxl_io_log(qdev, "config: bad crc\n");
DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
return;
} }
if (status == MONITORS_CONFIG_UNCHANGED) { if (status == MONITORS_CONFIG_UNCHANGED) {
qxl_io_log(qdev, "config unchanged\n"); qxl_io_log(qdev, "config: unchanged\n");
DRM_DEBUG("ignoring unchanged client monitors config"); DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
return; return;
} }
@ -194,9 +202,17 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector,
struct drm_display_mode *mode = NULL; struct drm_display_mode *mode = NULL;
struct qxl_head *head; struct qxl_head *head;
if (!qdev->monitors_config)
return 0;
if (h >= qdev->monitors_config->max_allowed)
return 0;
if (!qdev->client_monitors_config) if (!qdev->client_monitors_config)
return 0; return 0;
if (h >= qdev->client_monitors_config->count)
return 0;
head = &qdev->client_monitors_config->heads[h]; head = &qdev->client_monitors_config->heads[h];
DRM_DEBUG_KMS("head %d is %dx%d\n", h, head->width, head->height);
mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false, mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false,
false); false);
@ -903,19 +919,13 @@ static void qxl_enc_mode_set(struct drm_encoder *encoder,
static int qxl_conn_get_modes(struct drm_connector *connector) static int qxl_conn_get_modes(struct drm_connector *connector)
{ {
int ret = 0;
struct qxl_device *qdev = connector->dev->dev_private;
unsigned pwidth = 1024; unsigned pwidth = 1024;
unsigned pheight = 768; unsigned pheight = 768;
int ret = 0;
DRM_DEBUG_KMS("monitors_config=%p\n", qdev->monitors_config); ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
/* TODO: what should we do here? only show the configured modes for the if (ret < 0)
* device, or allow the full list, or both? */ return ret;
if (qdev->monitors_config && qdev->monitors_config->count) {
ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
if (ret < 0)
return ret;
}
ret += qxl_add_common_modes(connector, pwidth, pheight); ret += qxl_add_common_modes(connector, pwidth, pheight);
return ret; return ret;
} }
@ -1188,6 +1198,7 @@ int qxl_modeset_init(struct qxl_device *qdev)
qdev_output_init(&qdev->ddev, i); qdev_output_init(&qdev->ddev, i);
} }
qxl_display_read_client_monitors_config(qdev);
qdev->mode_info.mode_config_initialized = true; qdev->mode_info.mode_config_initialized = true;
drm_mode_config_reset(&qdev->ddev); drm_mode_config_reset(&qdev->ddev);

View File

@ -160,8 +160,6 @@ struct qxl_mman {
}; };
struct qxl_mode_info { struct qxl_mode_info {
int num_modes;
struct qxl_mode *modes;
bool mode_config_initialized; bool mode_config_initialized;
/* pointer to fbdev info structure */ /* pointer to fbdev info structure */
@ -232,7 +230,6 @@ int qxl_debugfs_add_files(struct qxl_device *rdev,
struct drm_info_list *files, struct drm_info_list *files,
unsigned nfiles); unsigned nfiles);
int qxl_debugfs_fence_init(struct qxl_device *rdev); int qxl_debugfs_fence_init(struct qxl_device *rdev);
void qxl_debugfs_remove_files(struct qxl_device *qdev);
struct qxl_device; struct qxl_device;

View File

@ -368,9 +368,11 @@ static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = {
int qxl_fbdev_init(struct qxl_device *qdev) int qxl_fbdev_init(struct qxl_device *qdev)
{ {
int ret = 0;
#ifdef CONFIG_DRM_FBDEV_EMULATION
struct qxl_fbdev *qfbdev; struct qxl_fbdev *qfbdev;
int bpp_sel = 32; /* TODO: parameter from somewhere? */ int bpp_sel = 32; /* TODO: parameter from somewhere? */
int ret;
qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL); qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);
if (!qfbdev) if (!qfbdev)
@ -403,6 +405,8 @@ fini:
drm_fb_helper_fini(&qfbdev->helper); drm_fb_helper_fini(&qfbdev->helper);
free: free:
kfree(qfbdev); kfree(qfbdev);
#endif
return ret; return ret;
} }
@ -418,6 +422,9 @@ void qxl_fbdev_fini(struct qxl_device *qdev)
void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state) void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
{ {
if (!qdev->mode_info.qfbdev)
return;
drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state); drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);
} }

View File

@ -31,19 +31,9 @@
int qxl_log_level; int qxl_log_level;
static void qxl_dump_mode(struct qxl_device *qdev, void *p)
{
struct qxl_mode *m = p;
DRM_DEBUG_KMS("%d: %dx%d %d bits, stride %d, %dmm x %dmm, orientation %d\n",
m->id, m->x_res, m->y_res, m->bits, m->stride, m->x_mili,
m->y_mili, m->orientation);
}
static bool qxl_check_device(struct qxl_device *qdev) static bool qxl_check_device(struct qxl_device *qdev)
{ {
struct qxl_rom *rom = qdev->rom; struct qxl_rom *rom = qdev->rom;
int mode_offset;
int i;
if (rom->magic != 0x4f525851) { if (rom->magic != 0x4f525851) {
DRM_ERROR("bad rom signature %x\n", rom->magic); DRM_ERROR("bad rom signature %x\n", rom->magic);
@ -53,8 +43,6 @@ static bool qxl_check_device(struct qxl_device *qdev)
DRM_INFO("Device Version %d.%d\n", rom->id, rom->update_id); DRM_INFO("Device Version %d.%d\n", rom->id, rom->update_id);
DRM_INFO("Compression level %d log level %d\n", rom->compression_level, DRM_INFO("Compression level %d log level %d\n", rom->compression_level,
rom->log_level); rom->log_level);
DRM_INFO("Currently using mode #%d, list at 0x%x\n",
rom->mode, rom->modes_offset);
DRM_INFO("%d io pages at offset 0x%x\n", DRM_INFO("%d io pages at offset 0x%x\n",
rom->num_io_pages, rom->pages_offset); rom->num_io_pages, rom->pages_offset);
DRM_INFO("%d byte draw area at offset 0x%x\n", DRM_INFO("%d byte draw area at offset 0x%x\n",
@ -62,14 +50,6 @@ static bool qxl_check_device(struct qxl_device *qdev)
qdev->vram_size = rom->surface0_area_size; qdev->vram_size = rom->surface0_area_size;
DRM_INFO("RAM header offset: 0x%x\n", rom->ram_header_offset); DRM_INFO("RAM header offset: 0x%x\n", rom->ram_header_offset);
mode_offset = rom->modes_offset / 4;
qdev->mode_info.num_modes = ((u32 *)rom)[mode_offset];
DRM_INFO("rom modes offset 0x%x for %d modes\n", rom->modes_offset,
qdev->mode_info.num_modes);
qdev->mode_info.modes = (void *)((uint32_t *)rom + mode_offset + 1);
for (i = 0; i < qdev->mode_info.num_modes; i++)
qxl_dump_mode(qdev, qdev->mode_info.modes + i);
return true; return true;
} }
@ -282,7 +262,4 @@ void qxl_device_fini(struct qxl_device *qdev)
iounmap(qdev->ram_header); iounmap(qdev->ram_header);
iounmap(qdev->rom); iounmap(qdev->rom);
qdev->rom = NULL; qdev->rom = NULL;
qdev->mode_info.modes = NULL;
qdev->mode_info.num_modes = 0;
qxl_debugfs_remove_files(qdev);
} }

View File

@ -237,7 +237,6 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
.mpll_cfg = rockchip_mpll_cfg, .mpll_cfg = rockchip_mpll_cfg,
.cur_ctr = rockchip_cur_ctr, .cur_ctr = rockchip_cur_ctr,
.phy_config = rockchip_phy_config, .phy_config = rockchip_phy_config,
.dev_type = RK3288_HDMI,
}; };
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {

View File

@ -19,6 +19,9 @@
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_flip_work.h> #include <drm/drm_flip_work.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#ifdef CONFIG_DRM_ANALOGIX_DP
#include <drm/bridge/analogix_dp.h>
#endif
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
@ -1111,6 +1114,53 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc,
kfree(s); kfree(s);
} }
#ifdef CONFIG_DRM_ANALOGIX_DP
static struct drm_connector *vop_get_edp_connector(struct vop *vop)
{
struct drm_crtc *crtc = &vop->crtc;
struct drm_connector *connector;
mutex_lock(&crtc->dev->mode_config.mutex);
drm_for_each_connector(connector, crtc->dev)
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
mutex_unlock(&crtc->dev->mode_config.mutex);
return connector;
}
mutex_unlock(&crtc->dev->mode_config.mutex);
return NULL;
}
static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
const char *source_name, size_t *values_cnt)
{
struct vop *vop = to_vop(crtc);
struct drm_connector *connector;
int ret;
connector = vop_get_edp_connector(vop);
if (!connector)
return -EINVAL;
*values_cnt = 3;
if (source_name && strcmp(source_name, "auto") == 0)
ret = analogix_dp_start_crc(connector);
else if (!source_name)
ret = analogix_dp_stop_crc(connector);
else
ret = -EINVAL;
return ret;
}
#else
static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
const char *source_name, size_t *values_cnt)
{
return -ENODEV;
}
#endif
static const struct drm_crtc_funcs vop_crtc_funcs = { static const struct drm_crtc_funcs vop_crtc_funcs = {
.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,
@ -1120,6 +1170,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {
.atomic_destroy_state = vop_crtc_destroy_state, .atomic_destroy_state = vop_crtc_destroy_state,
.enable_vblank = vop_crtc_enable_vblank, .enable_vblank = vop_crtc_enable_vblank,
.disable_vblank = vop_crtc_disable_vblank, .disable_vblank = vop_crtc_disable_vblank,
.set_crc_source = vop_crtc_set_crc_source,
}; };
static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)

View File

@ -711,13 +711,10 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
return ret; return ret;
drm_connector_helper_add(connector, &connector_helper_funcs); drm_connector_helper_add(connector, &connector_helper_funcs);
ret = drm_connector_register(connector);
if (ret < 0)
goto err_cleanup;
ret = shmob_drm_backlight_init(&sdev->connector); ret = shmob_drm_backlight_init(&sdev->connector);
if (ret < 0) if (ret < 0)
goto err_sysfs; goto err_cleanup;
ret = drm_mode_connector_attach_encoder(connector, encoder); ret = drm_mode_connector_attach_encoder(connector, encoder);
if (ret < 0) if (ret < 0)
@ -731,8 +728,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
err_backlight: err_backlight:
shmob_drm_backlight_exit(&sdev->connector); shmob_drm_backlight_exit(&sdev->connector);
err_sysfs:
drm_connector_unregister(connector);
err_cleanup: err_cleanup:
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
return ret; return ret;

View File

@ -103,100 +103,6 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
* DRM operations * DRM operations
*/ */
static void shmob_drm_unload(struct drm_device *dev)
{
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
drm_vblank_cleanup(dev);
drm_irq_uninstall(dev);
dev->dev_private = NULL;
}
static int shmob_drm_load(struct drm_device *dev, unsigned long flags)
{
struct shmob_drm_platform_data *pdata = dev->dev->platform_data;
struct platform_device *pdev = dev->platformdev;
struct shmob_drm_device *sdev;
struct resource *res;
unsigned int i;
int ret;
if (pdata == NULL) {
dev_err(dev->dev, "no platform data\n");
return -EINVAL;
}
sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
if (sdev == NULL) {
dev_err(dev->dev, "failed to allocate private data\n");
return -ENOMEM;
}
sdev->dev = &pdev->dev;
sdev->pdata = pdata;
spin_lock_init(&sdev->irq_lock);
sdev->ddev = dev;
dev->dev_private = sdev;
/* I/O resources and clocks */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "failed to get memory resource\n");
return -EINVAL;
}
sdev->mmio = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (sdev->mmio == NULL) {
dev_err(&pdev->dev, "failed to remap memory resource\n");
return -ENOMEM;
}
ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
if (ret < 0)
return ret;
ret = shmob_drm_init_interface(sdev);
if (ret < 0)
return ret;
ret = shmob_drm_modeset_init(sdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize mode setting\n");
return ret;
}
for (i = 0; i < 4; ++i) {
ret = shmob_drm_plane_create(sdev, i);
if (ret < 0) {
dev_err(&pdev->dev, "failed to create plane %u\n", i);
goto done;
}
}
ret = drm_vblank_init(dev, 1);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize vblank\n");
goto done;
}
ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
if (ret < 0) {
dev_err(&pdev->dev, "failed to install IRQ handler\n");
goto done;
}
platform_set_drvdata(pdev, sdev);
done:
if (ret)
shmob_drm_unload(dev);
return ret;
}
static irqreturn_t shmob_drm_irq(int irq, void *arg) static irqreturn_t shmob_drm_irq(int irq, void *arg)
{ {
struct drm_device *dev = arg; struct drm_device *dev = arg;
@ -236,8 +142,6 @@ static const struct file_operations shmob_drm_fops = {
static struct drm_driver shmob_drm_driver = { static struct drm_driver shmob_drm_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
| DRIVER_PRIME, | DRIVER_PRIME,
.load = shmob_drm_load,
.unload = shmob_drm_unload,
.irq_handler = shmob_drm_irq, .irq_handler = shmob_drm_irq,
.gem_free_object_unlocked = drm_gem_cma_free_object, .gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops, .gem_vm_ops = &drm_gem_cma_vm_ops,
@ -297,20 +201,118 @@ static const struct dev_pm_ops shmob_drm_pm_ops = {
* Platform driver * Platform driver
*/ */
static int shmob_drm_probe(struct platform_device *pdev)
{
return drm_platform_init(&shmob_drm_driver, pdev);
}
static int shmob_drm_remove(struct platform_device *pdev) static int shmob_drm_remove(struct platform_device *pdev)
{ {
struct shmob_drm_device *sdev = platform_get_drvdata(pdev); struct shmob_drm_device *sdev = platform_get_drvdata(pdev);
struct drm_device *ddev = sdev->ddev;
drm_put_dev(sdev->ddev); drm_dev_unregister(ddev);
drm_kms_helper_poll_fini(ddev);
drm_mode_config_cleanup(ddev);
drm_irq_uninstall(ddev);
drm_dev_unref(ddev);
return 0; return 0;
} }
static int shmob_drm_probe(struct platform_device *pdev)
{
struct shmob_drm_platform_data *pdata = pdev->dev.platform_data;
struct shmob_drm_device *sdev;
struct drm_device *ddev;
struct resource *res;
unsigned int i;
int ret;
if (pdata == NULL) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
/*
* Allocate and initialize the driver private data, I/O resources and
* clocks.
*/
sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
if (sdev == NULL)
return -ENOMEM;
sdev->dev = &pdev->dev;
sdev->pdata = pdata;
spin_lock_init(&sdev->irq_lock);
platform_set_drvdata(pdev, sdev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sdev->mmio = devm_ioremap_resource(&pdev->dev, res);
if (sdev->mmio == NULL)
return -ENOMEM;
ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
if (ret < 0)
return ret;
ret = shmob_drm_init_interface(sdev);
if (ret < 0)
return ret;
/* Allocate and initialize the DRM device. */
ddev = drm_dev_alloc(&shmob_drm_driver, &pdev->dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
sdev->ddev = ddev;
ddev->dev_private = sdev;
ret = shmob_drm_modeset_init(sdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize mode setting\n");
goto err_free_drm_dev;
}
for (i = 0; i < 4; ++i) {
ret = shmob_drm_plane_create(sdev, i);
if (ret < 0) {
dev_err(&pdev->dev, "failed to create plane %u\n", i);
goto err_modeset_cleanup;
}
}
ret = drm_vblank_init(ddev, 1);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize vblank\n");
goto err_modeset_cleanup;
}
ret = drm_irq_install(ddev, platform_get_irq(pdev, 0));
if (ret < 0) {
dev_err(&pdev->dev, "failed to install IRQ handler\n");
goto err_vblank_cleanup;
}
/*
* Register the DRM device with the core and the connectors with
* sysfs.
*/
ret = drm_dev_register(ddev, 0);
if (ret < 0)
goto err_irq_uninstall;
return 0;
err_irq_uninstall:
drm_irq_uninstall(ddev);
err_vblank_cleanup:
drm_vblank_cleanup(ddev);
err_modeset_cleanup:
drm_kms_helper_poll_fini(ddev);
drm_mode_config_cleanup(ddev);
err_free_drm_dev:
drm_dev_unref(ddev);
return ret;
}
static struct platform_driver shmob_drm_platform_driver = { static struct platform_driver shmob_drm_platform_driver = {
.probe = shmob_drm_probe, .probe = shmob_drm_probe,
.remove = shmob_drm_remove, .remove = shmob_drm_remove,

View File

@ -263,8 +263,6 @@ static int sti_bind(struct device *dev)
if (IS_ERR(ddev)) if (IS_ERR(ddev))
return PTR_ERR(ddev); return PTR_ERR(ddev);
ddev->platformdev = to_platform_device(dev);
ret = sti_init(ddev); ret = sti_init(ddev);
if (ret) if (ret)
goto err_drm_dev_unref; goto err_drm_dev_unref;

View File

@ -245,7 +245,6 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
if (IS_ERR(ddev)) if (IS_ERR(ddev))
return PTR_ERR(ddev); return PTR_ERR(ddev);
ddev->platformdev = pdev;
ddev->dev_private = priv; ddev->dev_private = priv;
platform_set_drvdata(pdev, ddev); platform_set_drvdata(pdev, ddev);
drm_mode_config_init(ddev); drm_mode_config_init(ddev);

View File

@ -178,9 +178,7 @@ struct virtio_gpu_device {
struct virtio_gpu_queue ctrlq; struct virtio_gpu_queue ctrlq;
struct virtio_gpu_queue cursorq; struct virtio_gpu_queue cursorq;
struct list_head free_vbufs; struct kmem_cache *vbufs;
spinlock_t free_vbufs_lock;
void *vbufs;
bool vqs_ready; bool vqs_ready;
struct idr resource_idr; struct idr resource_idr;

View File

@ -74,51 +74,19 @@ void virtio_gpu_cursor_ack(struct virtqueue *vq)
int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev) int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev)
{ {
struct virtio_gpu_vbuffer *vbuf; vgdev->vbufs = kmem_cache_create("virtio-gpu-vbufs",
int i, size, count = 16; VBUFFER_SIZE,
void *ptr; __alignof__(struct virtio_gpu_vbuffer),
0, NULL);
INIT_LIST_HEAD(&vgdev->free_vbufs);
spin_lock_init(&vgdev->free_vbufs_lock);
count += virtqueue_get_vring_size(vgdev->ctrlq.vq);
count += virtqueue_get_vring_size(vgdev->cursorq.vq);
size = count * VBUFFER_SIZE;
DRM_INFO("virtio vbuffers: %d bufs, %zdB each, %dkB total.\n",
count, VBUFFER_SIZE, size / 1024);
vgdev->vbufs = kzalloc(size, GFP_KERNEL);
if (!vgdev->vbufs) if (!vgdev->vbufs)
return -ENOMEM; return -ENOMEM;
for (i = 0, ptr = vgdev->vbufs;
i < count;
i++, ptr += VBUFFER_SIZE) {
vbuf = ptr;
list_add(&vbuf->list, &vgdev->free_vbufs);
}
return 0; return 0;
} }
void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev) void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev)
{ {
struct virtio_gpu_vbuffer *vbuf; kmem_cache_destroy(vgdev->vbufs);
int i, count = 0; vgdev->vbufs = NULL;
count += virtqueue_get_vring_size(vgdev->ctrlq.vq);
count += virtqueue_get_vring_size(vgdev->cursorq.vq);
spin_lock(&vgdev->free_vbufs_lock);
for (i = 0; i < count; i++) {
if (WARN_ON(list_empty(&vgdev->free_vbufs))) {
spin_unlock(&vgdev->free_vbufs_lock);
return;
}
vbuf = list_first_entry(&vgdev->free_vbufs,
struct virtio_gpu_vbuffer, list);
list_del(&vbuf->list);
}
spin_unlock(&vgdev->free_vbufs_lock);
kfree(vgdev->vbufs);
} }
static struct virtio_gpu_vbuffer* static struct virtio_gpu_vbuffer*
@ -128,12 +96,9 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
{ {
struct virtio_gpu_vbuffer *vbuf; struct virtio_gpu_vbuffer *vbuf;
spin_lock(&vgdev->free_vbufs_lock); vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL);
BUG_ON(list_empty(&vgdev->free_vbufs)); if (IS_ERR(vbuf))
vbuf = list_first_entry(&vgdev->free_vbufs, return ERR_CAST(vbuf);
struct virtio_gpu_vbuffer, list);
list_del(&vbuf->list);
spin_unlock(&vgdev->free_vbufs_lock);
memset(vbuf, 0, VBUFFER_SIZE); memset(vbuf, 0, VBUFFER_SIZE);
BUG_ON(size > MAX_INLINE_CMD_SIZE); BUG_ON(size > MAX_INLINE_CMD_SIZE);
@ -208,9 +173,7 @@ static void free_vbuf(struct virtio_gpu_device *vgdev,
if (vbuf->resp_size > MAX_INLINE_RESP_SIZE) if (vbuf->resp_size > MAX_INLINE_RESP_SIZE)
kfree(vbuf->resp_buf); kfree(vbuf->resp_buf);
kfree(vbuf->data_buf); kfree(vbuf->data_buf);
spin_lock(&vgdev->free_vbufs_lock); kmem_cache_free(vgdev->vbufs, vbuf);
list_add(&vbuf->list, &vgdev->free_vbufs);
spin_unlock(&vgdev->free_vbufs_lock);
} }
static void reclaim_vbufs(struct virtqueue *vq, struct list_head *reclaim_list) static void reclaim_vbufs(struct virtqueue *vq, struct list_head *reclaim_list)

View File

@ -49,4 +49,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
struct analogix_dp_plat_data *plat_data); struct analogix_dp_plat_data *plat_data);
void analogix_dp_unbind(struct device *dev, struct device *master, void *data); void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
int analogix_dp_start_crc(struct drm_connector *connector);
int analogix_dp_stop_crc(struct drm_connector *connector);
#endif /* _ANALOGIX_DP_H_ */ #endif /* _ANALOGIX_DP_H_ */

View File

@ -21,12 +21,6 @@ enum {
DW_HDMI_RES_MAX, DW_HDMI_RES_MAX,
}; };
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
RK3288_HDMI,
};
enum dw_hdmi_phy_type { enum dw_hdmi_phy_type {
DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00, DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2, DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
@ -57,13 +51,30 @@ struct dw_hdmi_phy_config {
u16 vlev_ctr; /* voltage level control */ u16 vlev_ctr; /* voltage level control */
}; };
struct dw_hdmi_phy_ops {
int (*init)(struct dw_hdmi *hdmi, void *data,
struct drm_display_mode *mode);
void (*disable)(struct dw_hdmi *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data);
};
struct dw_hdmi_plat_data { struct dw_hdmi_plat_data {
enum dw_hdmi_devtype dev_type; struct regmap *regm;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
/* Vendor PHY support */
const struct dw_hdmi_phy_ops *phy_ops;
const char *phy_name;
void *phy_data;
/* Synopsys PHY support */
const struct dw_hdmi_mpll_config *mpll_cfg; const struct dw_hdmi_mpll_config *mpll_cfg;
const struct dw_hdmi_curr_ctrl *cur_ctr; const struct dw_hdmi_curr_ctrl *cur_ctr;
const struct dw_hdmi_phy_config *phy_config; const struct dw_hdmi_phy_config *phy_config;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector, int (*configure_phy)(struct dw_hdmi *hdmi,
struct drm_display_mode *mode); const struct dw_hdmi_plat_data *pdata,
unsigned long mpixelclock);
}; };
int dw_hdmi_probe(struct platform_device *pdev, int dw_hdmi_probe(struct platform_device *pdev,
@ -77,4 +88,8 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
/* PHY configuration */
void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr);
#endif /* __IMX_HDMI_H__ */ #endif /* __IMX_HDMI_H__ */

View File

@ -47,17 +47,16 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/rbtree.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/dma-fence.h> #include <linux/dma-fence.h>
#include <linux/module.h>
#include <asm/mman.h> #include <asm/mman.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
@ -75,26 +74,30 @@
#include <drm/drm_mm.h> #include <drm/drm_mm.h>
#include <drm/drm_os_linux.h> #include <drm/drm_os_linux.h>
#include <drm/drm_sarea.h> #include <drm/drm_sarea.h>
#include <drm/drm_vma_manager.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_prime.h>
#include <drm/drm_pci.h>
#include <drm/drm_file.h>
struct module; struct module;
struct drm_file;
struct drm_device; struct drm_device;
struct drm_agp_head; struct drm_agp_head;
struct drm_local_map; struct drm_local_map;
struct drm_device_dma; struct drm_device_dma;
struct drm_dma_handle;
struct drm_gem_object; struct drm_gem_object;
struct drm_master; struct drm_master;
struct drm_vblank_crtc; struct drm_vblank_crtc;
struct drm_vma_offset_manager;
struct device_node; struct device_node;
struct videomode; struct videomode;
struct reservation_object; struct reservation_object;
struct dma_buf_attachment; struct dma_buf_attachment;
struct pci_dev;
struct pci_controller;
/* /*
* The following categories are defined: * The following categories are defined:
* *
@ -357,97 +360,6 @@ struct drm_ioctl_desc {
.name = #ioctl \ .name = #ioctl \
} }
/* Event queued up for userspace to read */
struct drm_pending_event {
struct completion *completion;
void (*completion_release)(struct completion *completion);
struct drm_event *event;
struct dma_fence *fence;
struct list_head link;
struct list_head pending_link;
struct drm_file *file_priv;
pid_t pid; /* pid of requester, no guarantee it's valid by the time
we deliver the event, for tracing only */
};
struct drm_prime_file_private {
struct mutex lock;
struct rb_root dmabufs;
struct rb_root handles;
};
/** File private data */
struct drm_file {
unsigned authenticated :1;
/* true when the client has asked us to expose stereo 3D mode flags */
unsigned stereo_allowed :1;
/*
* true if client understands CRTC primary planes and cursor planes
* in the plane list
*/
unsigned universal_planes:1;
/* true if client understands atomic properties */
unsigned atomic:1;
/*
* This client is the creator of @master.
* Protected by struct drm_device::master_mutex.
*/
unsigned is_master:1;
struct pid *pid;
drm_magic_t magic;
struct list_head lhead;
struct drm_minor *minor;
unsigned long lock_count;
/** Mapping of mm object handles to object pointers. */
struct idr object_idr;
/** Lock for synchronization of access to object_idr. */
spinlock_t table_lock;
struct file *filp;
void *driver_priv;
struct drm_master *master; /* master this node is currently associated with
N.B. not always dev->master */
/**
* fbs - List of framebuffers associated with this file.
*
* Protected by fbs_lock. Note that the fbs list holds a reference on
* the fb object to prevent it from untimely disappearing.
*/
struct list_head fbs;
struct mutex fbs_lock;
/** User-created blob properties; this retains a reference on the
* property. */
struct list_head blobs;
wait_queue_head_t event_wait;
struct list_head pending_event_list;
struct list_head event_list;
int event_space;
struct mutex event_read_lock;
struct drm_prime_file_private prime;
};
/**
* Lock data.
*/
struct drm_lock_data {
struct drm_hw_lock *hw_lock; /**< Hardware lock */
/** Private of lock holder's file (NULL=kernel) */
struct drm_file *file_priv;
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
spinlock_t spinlock;
uint32_t kernel_waiters;
uint32_t user_waiters;
int idle_has_lock;
};
/* Flags and return codes for get_vblank_timestamp() driver function. */ /* Flags and return codes for get_vblank_timestamp() driver function. */
#define DRM_CALLED_FROM_VBLIRQ 1 #define DRM_CALLED_FROM_VBLIRQ 1
#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
@ -458,13 +370,6 @@ struct drm_lock_data {
#define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1)
#define DRM_SCANOUTPOS_ACCURATE (1 << 2) #define DRM_SCANOUTPOS_ACCURATE (1 << 2)
enum drm_minor_type {
DRM_MINOR_PRIMARY,
DRM_MINOR_CONTROL,
DRM_MINOR_RENDER,
DRM_MINOR_CNT,
};
/** /**
* Info file list entry. This structure represents a debugfs or proc file to * Info file list entry. This structure represents a debugfs or proc file to
* be created by the drm core * be created by the drm core
@ -486,21 +391,6 @@ struct drm_info_node {
struct dentry *dent; struct dentry *dent;
}; };
/**
* DRM minor structure. This structure represents a drm minor number.
*/
struct drm_minor {
int index; /**< Minor device number */
int type; /**< Control or render */
struct device *kdev; /**< Linux device */
struct drm_device *dev;
struct dentry *debugfs_root;
struct list_head debugfs_list;
struct mutex debugfs_lock; /* Protects debugfs_list. */
};
/** /**
* DRM device structure. This structure represent a complete card that * DRM device structure. This structure represent a complete card that
* may contain multiple heads. * may contain multiple heads.
@ -611,7 +501,6 @@ struct drm_device {
struct pci_controller *hose; struct pci_controller *hose;
#endif #endif
struct platform_device *platformdev; /**< Platform device struture */
struct virtio_device *virtdev; struct virtio_device *virtdev;
struct drm_sg_mem *sg; /**< Scatter gather memory */ struct drm_sg_mem *sg; /**< Scatter gather memory */
@ -675,21 +564,6 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)
return ret; return ret;
} }
static inline bool drm_is_render_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_RENDER;
}
static inline bool drm_is_control_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_CONTROL;
}
static inline bool drm_is_primary_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_PRIMARY;
}
/******************************************************************/ /******************************************************************/
/** \name Internal function definitions */ /** \name Internal function definitions */
/*@{*/ /*@{*/
@ -707,25 +581,6 @@ extern long drm_compat_ioctl(struct file *filp,
#endif #endif
extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags);
/* File Operations (drm_fops.c) */
int drm_open(struct inode *inode, struct file *filp);
ssize_t drm_read(struct file *filp, char __user *buffer,
size_t count, loff_t *offset);
int drm_release(struct inode *inode, struct file *filp);
unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
int drm_event_reserve_init_locked(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e);
int drm_event_reserve_init(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e);
void drm_event_cancel_free(struct drm_device *dev,
struct drm_pending_event *p);
void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e);
void drm_send_event(struct drm_device *dev, struct drm_pending_event *e);
/* Misc. IOCTL support (drm_ioctl.c) */ /* Misc. IOCTL support (drm_ioctl.c) */
int drm_noop(struct drm_device *dev, void *data, int drm_noop(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
@ -759,70 +614,12 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
} }
#endif #endif
struct dma_buf_export_info;
extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *obj,
int flags);
extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
struct drm_file *file_priv, uint32_t handle, uint32_t flags,
int *prime_fd);
extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf);
extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
struct drm_file *file_priv, int prime_fd, uint32_t *handle);
struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
struct dma_buf_export_info *exp_info);
extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
dma_addr_t *addrs, int max_pages);
extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages);
extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size,
size_t align);
extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah);
/* sysfs support (drm_sysfs.c) */ /* sysfs support (drm_sysfs.c) */
extern void drm_sysfs_hotplug_event(struct drm_device *dev); extern void drm_sysfs_hotplug_event(struct drm_device *dev);
/*@}*/ /*@}*/
extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
#ifdef CONFIG_PCI
extern int drm_get_pci_dev(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver);
extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master);
#else
static inline int drm_get_pci_dev(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver)
{
return -ENOSYS;
}
static inline int drm_pci_set_busid(struct drm_device *dev,
struct drm_master *master)
{
return -ENOSYS;
}
#endif
#define DRM_PCIE_SPEED_25 1
#define DRM_PCIE_SPEED_50 2
#define DRM_PCIE_SPEED_80 4
extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask);
extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw);
/* platform section */
extern int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device);
/* returns true if currently okay to sleep */ /* returns true if currently okay to sleep */
static __inline__ bool drm_can_sleep(void) static __inline__ bool drm_can_sleep(void)
{ {

View File

@ -277,6 +277,9 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
* *
* This function returns the crtc state for the given crtc, or NULL * This function returns the crtc state for the given crtc, or NULL
* if the crtc is not part of the global atomic state. * if the crtc is not part of the global atomic state.
*
* This function is deprecated, @drm_atomic_get_old_crtc_state or
* @drm_atomic_get_new_crtc_state should be used instead.
*/ */
static inline struct drm_crtc_state * static inline struct drm_crtc_state *
drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state, drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
@ -285,6 +288,35 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
return state->crtcs[drm_crtc_index(crtc)].state; return state->crtcs[drm_crtc_index(crtc)].state;
} }
/**
* drm_atomic_get_old_crtc_state - get old crtc state, if it exists
* @state: global atomic state object
* @crtc: crtc to grab
*
* This function returns the old crtc state for the given crtc, or
* NULL if the crtc is not part of the global atomic state.
*/
static inline struct drm_crtc_state *
drm_atomic_get_old_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
return state->crtcs[drm_crtc_index(crtc)].old_state;
}
/**
* drm_atomic_get_new_crtc_state - get new crtc state, if it exists
* @state: global atomic state object
* @crtc: crtc to grab
*
* This function returns the new crtc state for the given crtc, or
* NULL if the crtc is not part of the global atomic state.
*/
static inline struct drm_crtc_state *
drm_atomic_get_new_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
return state->crtcs[drm_crtc_index(crtc)].new_state;
}
/** /**
* drm_atomic_get_existing_plane_state - get plane state, if it exists * drm_atomic_get_existing_plane_state - get plane state, if it exists
* @state: global atomic state object * @state: global atomic state object
@ -292,6 +324,9 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
* *
* This function returns the plane state for the given plane, or NULL * This function returns the plane state for the given plane, or NULL
* if the plane is not part of the global atomic state. * if the plane is not part of the global atomic state.
*
* This function is deprecated, @drm_atomic_get_old_plane_state or
* @drm_atomic_get_new_plane_state should be used instead.
*/ */
static inline struct drm_plane_state * static inline struct drm_plane_state *
drm_atomic_get_existing_plane_state(struct drm_atomic_state *state, drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
@ -300,6 +335,36 @@ drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
return state->planes[drm_plane_index(plane)].state; return state->planes[drm_plane_index(plane)].state;
} }
/**
* drm_atomic_get_old_plane_state - get plane state, if it exists
* @state: global atomic state object
* @plane: plane to grab
*
* This function returns the old plane state for the given plane, or
* NULL if the plane is not part of the global atomic state.
*/
static inline struct drm_plane_state *
drm_atomic_get_old_plane_state(struct drm_atomic_state *state,
struct drm_plane *plane)
{
return state->planes[drm_plane_index(plane)].old_state;
}
/**
* drm_atomic_get_new_plane_state - get plane state, if it exists
* @state: global atomic state object
* @plane: plane to grab
*
* This function returns the new plane state for the given plane, or
* NULL if the plane is not part of the global atomic state.
*/
static inline struct drm_plane_state *
drm_atomic_get_new_plane_state(struct drm_atomic_state *state,
struct drm_plane *plane)
{
return state->planes[drm_plane_index(plane)].new_state;
}
/** /**
* drm_atomic_get_existing_connector_state - get connector state, if it exists * drm_atomic_get_existing_connector_state - get connector state, if it exists
* @state: global atomic state object * @state: global atomic state object
@ -307,6 +372,9 @@ drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
* *
* This function returns the connector state for the given connector, * This function returns the connector state for the given connector,
* or NULL if the connector is not part of the global atomic state. * or NULL if the connector is not part of the global atomic state.
*
* This function is deprecated, @drm_atomic_get_old_connector_state or
* @drm_atomic_get_new_connector_state should be used instead.
*/ */
static inline struct drm_connector_state * static inline struct drm_connector_state *
drm_atomic_get_existing_connector_state(struct drm_atomic_state *state, drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
@ -320,6 +388,46 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
return state->connectors[index].state; return state->connectors[index].state;
} }
/**
* drm_atomic_get_old_connector_state - get connector state, if it exists
* @state: global atomic state object
* @connector: connector to grab
*
* This function returns the old connector state for the given connector,
* or NULL if the connector is not part of the global atomic state.
*/
static inline struct drm_connector_state *
drm_atomic_get_old_connector_state(struct drm_atomic_state *state,
struct drm_connector *connector)
{
int index = drm_connector_index(connector);
if (index >= state->num_connector)
return NULL;
return state->connectors[index].old_state;
}
/**
* drm_atomic_get_new_connector_state - get connector state, if it exists
* @state: global atomic state object
* @connector: connector to grab
*
* This function returns the new connector state for the given connector,
* or NULL if the connector is not part of the global atomic state.
*/
static inline struct drm_connector_state *
drm_atomic_get_new_connector_state(struct drm_atomic_state *state,
struct drm_connector *connector)
{
int index = drm_connector_index(connector);
if (index >= state->num_connector)
return NULL;
return state->connectors[index].new_state;
}
/** /**
* __drm_atomic_get_current_plane_state - get current plane state * __drm_atomic_get_current_plane_state - get current plane state
* @state: global atomic state object * @state: global atomic state object

View File

@ -220,10 +220,10 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
__drm_atomic_get_current_plane_state((crtc_state)->state, \ __drm_atomic_get_current_plane_state((crtc_state)->state, \
plane))) plane)))
/* /**
* drm_atomic_plane_disabling - check whether a plane is being disabled * drm_atomic_plane_disabling - check whether a plane is being disabled
* @plane: plane object * @old_plane_state: old atomic plane state
* @old_state: previous atomic state * @new_plane_state: new atomic plane state
* *
* Checks the atomic state of a plane to determine whether it's being disabled * Checks the atomic state of a plane to determine whether it's being disabled
* or not. This also WARNs if it detects an invalid state (both CRTC and FB * or not. This also WARNs if it detects an invalid state (both CRTC and FB
@ -233,28 +233,18 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
* True if the plane is being disabled, false otherwise. * True if the plane is being disabled, false otherwise.
*/ */
static inline bool static inline bool
drm_atomic_plane_disabling(struct drm_plane *plane, drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state,
struct drm_plane_state *old_state) struct drm_plane_state *new_plane_state)
{ {
/* /*
* When disabling a plane, CRTC and FB should always be NULL together. * When disabling a plane, CRTC and FB should always be NULL together.
* Anything else should be considered a bug in the atomic core, so we * Anything else should be considered a bug in the atomic core, so we
* gently warn about it. * gently warn about it.
*/ */
WARN_ON((plane->state->crtc == NULL && plane->state->fb != NULL) || WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) ||
(plane->state->crtc != NULL && plane->state->fb == NULL)); (new_plane_state->crtc != NULL && new_plane_state->fb == NULL));
/* return old_plane_state->crtc && !new_plane_state->crtc;
* When using the transitional helpers, old_state may be NULL. If so,
* we know nothing about the current state and have to assume that it
* might be enabled.
*
* When using the atomic helpers, old_state won't be NULL. Therefore
* this check assumes that either the driver will have reconstructed
* the correct state in ->reset() or that the driver will have taken
* appropriate measures to disable all planes.
*/
return (!old_state || old_state->crtc) && !plane->state->crtc;
} }
#endif /* DRM_ATOMIC_HELPER_H_ */ #endif /* DRM_ATOMIC_HELPER_H_ */

View File

@ -28,6 +28,23 @@
#ifndef _DRM_AUTH_H_ #ifndef _DRM_AUTH_H_
#define _DRM_AUTH_H_ #define _DRM_AUTH_H_
/*
* Legacy DRI1 locking data structure. Only here instead of in drm_legacy.h for
* include ordering reasons.
*
* DO NOT USE.
*/
struct drm_lock_data {
struct drm_hw_lock *hw_lock;
struct drm_file *file_priv;
wait_queue_head_t lock_queue;
unsigned long lock_time;
spinlock_t spinlock;
uint32_t kernel_waiters;
uint32_t user_waiters;
int idle_has_lock;
};
/** /**
* struct drm_master - drm master structure * struct drm_master - drm master structure
* *

View File

@ -204,6 +204,12 @@ struct drm_crtc_state {
* drm_crtc_arm_vblank_event(). See the documentation of that function * drm_crtc_arm_vblank_event(). See the documentation of that function
* for a detailed discussion of the constraints it needs to be used * for a detailed discussion of the constraints it needs to be used
* safely. * safely.
*
* If the device can't notify of flip completion in a race-free way
* at all, then the event should be armed just after the page flip is
* committed. In the worst case the driver will send the event to
* userspace one frame too late. This doesn't allow for a real atomic
* update, but it should avoid tearing.
*/ */
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
@ -776,6 +782,7 @@ struct drm_crtc {
* Debugfs directory for this CRTC. * Debugfs directory for this CRTC.
*/ */
struct dentry *debugfs_entry; struct dentry *debugfs_entry;
#endif
/** /**
* @crc: * @crc:
@ -783,7 +790,6 @@ struct drm_crtc {
* Configuration settings of CRC capture. * Configuration settings of CRC capture.
*/ */
struct drm_crtc_crc crc; struct drm_crtc_crc crc;
#endif
/** /**
* @fence_context: * @fence_context:

View File

@ -789,7 +789,10 @@ struct drm_dp_aux_msg {
* @name: user-visible name of this AUX channel and the I2C-over-AUX adapter * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter
* @ddc: I2C adapter that can be used for I2C-over-AUX communication * @ddc: I2C adapter that can be used for I2C-over-AUX communication
* @dev: pointer to struct device that is the parent for this AUX channel * @dev: pointer to struct device that is the parent for this AUX channel
* @crtc: backpointer to the crtc that is currently using this AUX channel
* @hw_mutex: internal mutex used for locking transfers * @hw_mutex: internal mutex used for locking transfers
* @crc_work: worker that captures CRCs for each frame
* @crc_count: counter of captured frame CRCs
* @transfer: transfers a message representing a single AUX transaction * @transfer: transfers a message representing a single AUX transaction
* *
* The .dev field should be set to a pointer to the device that implements * The .dev field should be set to a pointer to the device that implements
@ -825,7 +828,10 @@ struct drm_dp_aux {
const char *name; const char *name;
struct i2c_adapter ddc; struct i2c_adapter ddc;
struct device *dev; struct device *dev;
struct drm_crtc *crtc;
struct mutex hw_mutex; struct mutex hw_mutex;
struct work_struct crc_work;
u8 crc_count;
ssize_t (*transfer)(struct drm_dp_aux *aux, ssize_t (*transfer)(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg); struct drm_dp_aux_msg *msg);
/** /**
@ -904,4 +910,7 @@ void drm_dp_aux_init(struct drm_dp_aux *aux);
int drm_dp_aux_register(struct drm_dp_aux *aux); int drm_dp_aux_register(struct drm_dp_aux *aux);
void drm_dp_aux_unregister(struct drm_dp_aux *aux); void drm_dp_aux_unregister(struct drm_dp_aux *aux);
int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc);
int drm_dp_stop_crc(struct drm_dp_aux *aux);
#endif /* _DRM_DP_HELPER_H_ */ #endif /* _DRM_DP_HELPER_H_ */

View File

@ -302,7 +302,6 @@ struct drm_driver {
void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv); void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
int (*debugfs_init)(struct drm_minor *minor); int (*debugfs_init)(struct drm_minor *minor);
void (*debugfs_cleanup)(struct drm_minor *minor);
/** /**
* @gem_free_object: deconstructor for drm_gem_objects * @gem_free_object: deconstructor for drm_gem_objects

172
include/drm/drm_file.h Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* Copyright (c) 2009-2010, Code Aurora Forum.
* All rights reserved.
*
* Author: Rickard E. (Rik) Faith <faith@valinux.com>
* Author: Gareth Hughes <gareth@valinux.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DRM_FILE_H_
#define _DRM_FILE_H_
#include <linux/types.h>
#include <linux/completion.h>
#include <uapi/drm/drm.h>
#include <drm/drm_prime.h>
struct dma_fence;
struct drm_file;
struct drm_device;
/*
* FIXME: Not sure we want to have drm_minor here in the end, but to avoid
* header include loops we need it here for now.
*/
enum drm_minor_type {
DRM_MINOR_PRIMARY,
DRM_MINOR_CONTROL,
DRM_MINOR_RENDER,
};
/**
* DRM minor structure. This structure represents a drm minor number.
*/
struct drm_minor {
int index; /**< Minor device number */
int type; /**< Control or render */
struct device *kdev; /**< Linux device */
struct drm_device *dev;
struct dentry *debugfs_root;
struct list_head debugfs_list;
struct mutex debugfs_lock; /* Protects debugfs_list. */
};
/* Event queued up for userspace to read */
struct drm_pending_event {
struct completion *completion;
void (*completion_release)(struct completion *completion);
struct drm_event *event;
struct dma_fence *fence;
struct list_head link;
struct list_head pending_link;
struct drm_file *file_priv;
pid_t pid; /* pid of requester, no guarantee it's valid by the time
we deliver the event, for tracing only */
};
/** File private data */
struct drm_file {
unsigned authenticated :1;
/* true when the client has asked us to expose stereo 3D mode flags */
unsigned stereo_allowed :1;
/*
* true if client understands CRTC primary planes and cursor planes
* in the plane list
*/
unsigned universal_planes:1;
/* true if client understands atomic properties */
unsigned atomic:1;
/*
* This client is the creator of @master.
* Protected by struct drm_device::master_mutex.
*/
unsigned is_master:1;
struct pid *pid;
drm_magic_t magic;
struct list_head lhead;
struct drm_minor *minor;
unsigned long lock_count;
/** Mapping of mm object handles to object pointers. */
struct idr object_idr;
/** Lock for synchronization of access to object_idr. */
spinlock_t table_lock;
struct file *filp;
void *driver_priv;
struct drm_master *master; /* master this node is currently associated with
N.B. not always dev->master */
/**
* fbs - List of framebuffers associated with this file.
*
* Protected by fbs_lock. Note that the fbs list holds a reference on
* the fb object to prevent it from untimely disappearing.
*/
struct list_head fbs;
struct mutex fbs_lock;
/** User-created blob properties; this retains a reference on the
* property. */
struct list_head blobs;
wait_queue_head_t event_wait;
struct list_head pending_event_list;
struct list_head event_list;
int event_space;
struct mutex event_read_lock;
struct drm_prime_file_private prime;
};
static inline bool drm_is_render_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_RENDER;
}
static inline bool drm_is_control_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_CONTROL;
}
static inline bool drm_is_primary_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_PRIMARY;
}
int drm_open(struct inode *inode, struct file *filp);
ssize_t drm_read(struct file *filp, char __user *buffer,
size_t count, loff_t *offset);
int drm_release(struct inode *inode, struct file *filp);
unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
int drm_event_reserve_init_locked(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e);
int drm_event_reserve_init(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e);
void drm_event_cancel_free(struct drm_device *dev,
struct drm_pending_event *p);
void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e);
void drm_send_event(struct drm_device *dev, struct drm_pending_event *e);
#endif /* _DRM_FILE_H_ */

View File

@ -34,6 +34,10 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <linux/kref.h>
#include <drm/drm_vma_manager.h>
/** /**
* struct drm_gem_object - GEM buffer object * struct drm_gem_object - GEM buffer object
* *

75
include/drm/drm_pci.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Internal Header for the Direct Rendering Manager
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* Copyright (c) 2009-2010, Code Aurora Forum.
* All rights reserved.
*
* Author: Rickard E. (Rik) Faith <faith@valinux.com>
* Author: Gareth Hughes <gareth@valinux.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DRM_PCI_H_
#define _DRM_PCI_H_
#include <linux/pci.h>
struct drm_dma_handle;
struct drm_device;
struct drm_driver;
struct drm_master;
extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size,
size_t align);
extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah);
extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
#ifdef CONFIG_PCI
extern int drm_get_pci_dev(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver);
extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master);
#else
static inline int drm_get_pci_dev(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver)
{
return -ENOSYS;
}
static inline int drm_pci_set_busid(struct drm_device *dev,
struct drm_master *master)
{
return -ENOSYS;
}
#endif
#define DRM_PCIE_SPEED_25 1
#define DRM_PCIE_SPEED_50 2
#define DRM_PCIE_SPEED_80 4
extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask);
extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw);
#endif /* _DRM_PCI_H_ */

80
include/drm/drm_prime.h Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright © 2012 Red Hat
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* Copyright (c) 2009-2010, Code Aurora Forum.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Dave Airlie <airlied@redhat.com>
* Rob Clark <rob.clark@linaro.org>
*
*/
#ifndef __DRM_PRIME_H__
#define __DRM_PRIME_H__
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/scatterlist.h>
/**
* struct drm_prime_file_private - per-file tracking for PRIME
*
* This just contains the internal &struct dma_buf and handle caches for each
* &struct drm_file used by the PRIME core code.
*/
struct drm_prime_file_private {
/* private: */
struct mutex lock;
struct rb_root dmabufs;
struct rb_root handles;
};
struct dma_buf_export_info;
struct dma_buf;
struct drm_device;
struct drm_gem_object;
struct drm_file;
extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *obj,
int flags);
extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
struct drm_file *file_priv, uint32_t handle, uint32_t flags,
int *prime_fd);
extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf);
extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
struct drm_file *file_priv, int prime_fd, uint32_t *handle);
struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
struct dma_buf_export_info *exp_info);
extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
dma_addr_t *addrs, int max_pages);
extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages);
extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
#endif /* __DRM_PRIME_H__ */

View File

@ -25,7 +25,6 @@
#include <drm/drm_mm.h> #include <drm/drm_mm.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>