forked from Minki/linux
Merge tag 'drm-misc-next-2017-01-23' of git://anongit.freedesktop.org/git/drm-misc into drm-next
- cleanups&fixes for dw-hdmi bride driver (Laurent) - updates for adv bridge driver (John Stultz) for nexus - drm_crtc_from_index helper rollout (Shawn Guo) - removing drm_framebuffer_unregister_private from drivers&core - target_vblank (Andrey Grodzovsky) - misc tiny stuff * tag 'drm-misc-next-2017-01-23' of git://anongit.freedesktop.org/git/drm-misc: (49 commits) drm: qxl: Open code teardown function for qxl drm: qxl: Open code probing sequence for qxl drm/bridge: adv7511: Re-write the i2c address before EDID probing drm/bridge: adv7511: Reuse __adv7511_power_on/off() when probing EDID drm/bridge: adv7511: Rework adv7511_power_on/off() so they can be reused internally drm/bridge: adv7511: Enable HPD interrupts to support hotplug and improve monitor detection drm/bridge: adv7511: Switch to using drm_kms_helper_hotplug_event() drm/bridge: adv7511: Use work_struct to defer hotplug handing to out of irq context drm: vc4: use crtc helper drm_crtc_from_index() drm: tegra: use crtc helper drm_crtc_from_index() drm: nouveau: use crtc helper drm_crtc_from_index() drm: mediatek: use crtc helper drm_crtc_from_index() drm: kirin: use crtc helper drm_crtc_from_index() drm: exynos: use crtc helper drm_crtc_from_index() dt-bindings: display: dw-hdmi: Clean up DT bindings documentation drm: bridge: dw-hdmi: Assert SVSRET before resetting the PHY drm: bridge: dw-hdmi: Fix the name of the PHY reset macros drm: bridge: dw-hdmi: Define and use macros for PHY register addresses drm: bridge: dw-hdmi: Detect PHY type at runtime drm: bridge: dw-hdmi: Handle overflow workaround based on device version ...
This commit is contained in:
commit
3875623c56
@ -38,10 +38,22 @@ The following input format properties are required except in "rgb 1x" and
|
||||
- adi,input-justification: The input bit justification ("left", "evenly",
|
||||
"right").
|
||||
|
||||
- avdd-supply: A 1.8V supply that powers up the AVDD pin on the chip.
|
||||
- dvdd-supply: A 1.8V supply that powers up the DVDD pin on the chip.
|
||||
- pvdd-supply: A 1.8V supply that powers up the PVDD pin on the chip.
|
||||
- dvdd-3v-supply: A 3.3V supply that powers up the pin called DVDD_3V
|
||||
on the chip.
|
||||
- bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is
|
||||
needed only for ADV7511.
|
||||
|
||||
The following properties are required for ADV7533:
|
||||
|
||||
- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
|
||||
be one of 1, 2, 3 or 4.
|
||||
- a2vdd-supply: 1.8V supply that powers up the A2VDD pin on the chip.
|
||||
- v3p3-supply: A 3.3V supply that powers up the V3P3 pin on the chip.
|
||||
- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
|
||||
either 1.2V or 1.8V.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
@ -1,52 +1,33 @@
|
||||
DesignWare HDMI bridge bindings
|
||||
Synopsys DesignWare HDMI TX Encoder
|
||||
===================================
|
||||
|
||||
Required properties:
|
||||
- compatible: platform specific such as:
|
||||
* "snps,dw-hdmi-tx"
|
||||
* "fsl,imx6q-hdmi"
|
||||
* "fsl,imx6dl-hdmi"
|
||||
* "rockchip,rk3288-dw-hdmi"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The HDMI interrupt number
|
||||
- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
|
||||
as described in Documentation/devicetree/bindings/clock/clock-bindings.txt,
|
||||
the clocks are soc specific, the clock-names should be "iahb", "isfr"
|
||||
-port@[X]: SoC specific port nodes with endpoint definitions as defined
|
||||
in Documentation/devicetree/bindings/media/video-interfaces.txt,
|
||||
please refer to the SoC specific binding document:
|
||||
* Documentation/devicetree/bindings/display/imx/hdmi.txt
|
||||
* Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
|
||||
This document defines device tree properties for the Synopsys DesignWare HDMI
|
||||
TX Encoder (DWC HDMI TX). It doesn't constitue a device tree binding
|
||||
specification by itself but is meant to be referenced by platform-specific
|
||||
device tree bindings.
|
||||
|
||||
Optional properties
|
||||
- reg-io-width: the width of the reg:1,4, default set to 1 if not present
|
||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing,
|
||||
if the property is omitted, a functionally reduced I2C bus
|
||||
controller on DW HDMI is probed
|
||||
- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
|
||||
When referenced from platform device tree bindings the properties defined in
|
||||
this document are defined as follows. The platform device tree bindings are
|
||||
responsible for defining whether each property is required or optional.
|
||||
|
||||
Example:
|
||||
hdmi: hdmi@0120000 {
|
||||
compatible = "fsl,imx6q-hdmi";
|
||||
reg = <0x00120000 0x9000>;
|
||||
interrupts = <0 115 0x04>;
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks 123>, <&clks 124>;
|
||||
clock-names = "iahb", "isfr";
|
||||
ddc-i2c-bus = <&i2c2>;
|
||||
- reg: Memory mapped base address and length of the DWC HDMI TX registers.
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
- reg-io-width: Width of the registers specified by the reg property. The
|
||||
value is expressed in bytes and must be equal to 1 or 4 if specified. The
|
||||
register width defaults to 1 if the property is not present.
|
||||
|
||||
hdmi_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_hdmi>;
|
||||
};
|
||||
};
|
||||
- interrupts: Reference to the DWC HDMI TX interrupt.
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
- clocks: References to all the clocks specified in the clock-names property
|
||||
as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt.
|
||||
|
||||
hdmi_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
- clock-names: The DWC HDMI TX uses the following clocks.
|
||||
|
||||
- "iahb" is the bus clock for either AHB and APB (mandatory).
|
||||
- "isfr" is the internal register configuration clock (mandatory).
|
||||
- "cec" is the HDMI CEC controller main clock (optional).
|
||||
|
||||
- ports: The connectivity of the DWC HDMI TX with the rest of the system is
|
||||
expressed in using ports as specified in the device graph bindings defined
|
||||
in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
|
||||
is platform-specific.
|
||||
|
@ -1,29 +1,36 @@
|
||||
Device-Tree bindings for HDMI Transmitter
|
||||
Freescale i.MX6 DWC HDMI TX Encoder
|
||||
===================================
|
||||
|
||||
HDMI Transmitter
|
||||
================
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with accompanying PHY IP.
|
||||
|
||||
Required properties:
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
- compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
|
||||
- gpr : should be <&gpr>.
|
||||
The phandle points to the iomuxc-gpr region containing the HDMI
|
||||
multiplexer control register.
|
||||
- clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
|
||||
in Documentation/devicetree/bindings/clock/clock-bindings.txt and
|
||||
Documentation/devicetree/bindings/clock/imx6q-clock.txt.
|
||||
- port@[0-4]: Up to four port nodes with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt,
|
||||
corresponding to the four inputs to the HDMI multiplexer.
|
||||
|
||||
Optional properties:
|
||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||
- compatible : Shall be one of "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
|
||||
- reg: See dw_hdmi.txt.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: See dw_hdmi.txt.
|
||||
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||
- ports: See dw_hdmi.txt. The DWC HDMI shall have between one and four ports,
|
||||
numbered 0 to 3, corresponding to the four inputs of the HDMI multiplexer.
|
||||
Each port shall have a single endpoint.
|
||||
- gpr : Shall contain a phandle to the iomuxc-gpr region containing the HDMI
|
||||
multiplexer control register.
|
||||
|
||||
example:
|
||||
Optional properties
|
||||
|
||||
- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master
|
||||
or the functionally-reduced I2C master contained in the DWC HDMI. When
|
||||
connected to a system I2C master this property contains a phandle to that
|
||||
I2C master controller.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
gpr: iomuxc-gpr@020e0000 {
|
||||
/* ... */
|
||||
|
@ -1,24 +1,39 @@
|
||||
Rockchip specific extensions to the Synopsys Designware HDMI
|
||||
================================
|
||||
Rockchip DWC HDMI TX Encoder
|
||||
============================
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
- compatible: "rockchip,rk3288-dw-hdmi";
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- clocks: phandle to hdmi iahb and isfr clocks.
|
||||
- clock-names: should be "iahb" "isfr"
|
||||
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
|
||||
|
||||
- compatible: Shall contain "rockchip,rk3288-dw-hdmi".
|
||||
- reg: See dw_hdmi.txt.
|
||||
- reg-io-width: See dw_hdmi.txt. Shall be 4.
|
||||
- interrupts: HDMI interrupt number
|
||||
- ports: contain a port node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. For
|
||||
vopb,set the reg = <0> and set the reg = <1> for vopl.
|
||||
- reg-io-width: the width of the reg:1,4, the value should be 4 on
|
||||
rk3288 platform
|
||||
- clocks: See dw_hdmi.txt.
|
||||
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||
- ports: See dw_hdmi.txt. The DWC HDMI shall have a single port numbered 0
|
||||
corresponding to the video input of the controller. The port shall have two
|
||||
endpoints, numbered 0 and 1, connected respectively to the vopb and vopl.
|
||||
- rockchip,grf: Shall reference the GRF to mux vopl/vopb.
|
||||
|
||||
Optional properties
|
||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||
- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
|
||||
|
||||
- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master
|
||||
or the functionally-reduced I2C master contained in the DWC HDMI. When
|
||||
connected to a system I2C master this property contains a phandle to that
|
||||
I2C master controller.
|
||||
- clock-names: See dw_hdmi.txt. The "cec" clock is optional.
|
||||
- clock-names: May contain "cec" as defined in dw_hdmi.txt.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
hdmi: hdmi@ff980000 {
|
||||
compatible = "rockchip,rk3288-dw-hdmi";
|
||||
reg = <0xff980000 0x20000>;
|
||||
|
@ -470,3 +470,9 @@ DRM MM Range Allocator Function References
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mm.h
|
||||
:internal:
|
||||
|
||||
DRM Cache Handling
|
||||
==================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_cache.c
|
||||
:export:
|
||||
|
@ -138,7 +138,7 @@ config DRM_KMS_CMA_HELPER
|
||||
|
||||
config DRM_VM
|
||||
bool
|
||||
depends on DRM
|
||||
depends on DRM && MMU
|
||||
|
||||
source "drivers/gpu/drm/i2c/Kconfig"
|
||||
|
||||
@ -267,7 +267,7 @@ source "drivers/gpu/drm/meson/Kconfig"
|
||||
|
||||
menuconfig DRM_LEGACY
|
||||
bool "Enable legacy drivers (DANGEROUS)"
|
||||
depends on DRM
|
||||
depends on DRM && MMU
|
||||
select DRM_VM
|
||||
help
|
||||
Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
|
||||
|
@ -1,6 +1,6 @@
|
||||
config DRM_ARMADA
|
||||
tristate "DRM support for Marvell Armada SoCs"
|
||||
depends on DRM && HAVE_CLK && ARM
|
||||
depends on DRM && HAVE_CLK && ARM && MMU
|
||||
select DRM_KMS_HELPER
|
||||
help
|
||||
Support the "LCD" controllers found on the Marvell Armada 510
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
@ -317,6 +318,8 @@ struct adv7511 {
|
||||
bool edid_read;
|
||||
|
||||
wait_queue_head_t wq;
|
||||
struct work_struct hpd_work;
|
||||
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector connector;
|
||||
|
||||
@ -329,6 +332,9 @@ struct adv7511 {
|
||||
|
||||
struct gpio_desc *gpio_pd;
|
||||
|
||||
struct regulator_bulk_data *supplies;
|
||||
unsigned int num_supplies;
|
||||
|
||||
/* ADV7533 DSI RX related params */
|
||||
struct device_node *host_node;
|
||||
struct mipi_dsi_device *dsi;
|
||||
|
@ -325,7 +325,7 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
|
||||
adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
|
||||
}
|
||||
|
||||
static void adv7511_power_on(struct adv7511 *adv7511)
|
||||
static void __adv7511_power_on(struct adv7511 *adv7511)
|
||||
{
|
||||
adv7511->current_edid_segment = -1;
|
||||
|
||||
@ -338,7 +338,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
|
||||
* Still, let's be safe and stick to the documentation.
|
||||
*/
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
|
||||
ADV7511_INT0_EDID_READY);
|
||||
ADV7511_INT0_EDID_READY | ADV7511_INT0_HPD);
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
|
||||
ADV7511_INT1_DDC_ERROR);
|
||||
}
|
||||
@ -354,6 +354,11 @@ static void adv7511_power_on(struct adv7511 *adv7511)
|
||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
|
||||
ADV7511_REG_POWER2_HPD_SRC_MASK,
|
||||
ADV7511_REG_POWER2_HPD_SRC_NONE);
|
||||
}
|
||||
|
||||
static void adv7511_power_on(struct adv7511 *adv7511)
|
||||
{
|
||||
__adv7511_power_on(adv7511);
|
||||
|
||||
/*
|
||||
* Most of the registers are reset during power down or when HPD is low.
|
||||
@ -362,21 +367,23 @@ static void adv7511_power_on(struct adv7511 *adv7511)
|
||||
|
||||
if (adv7511->type == ADV7533)
|
||||
adv7533_dsi_power_on(adv7511);
|
||||
|
||||
adv7511->powered = true;
|
||||
}
|
||||
|
||||
static void adv7511_power_off(struct adv7511 *adv7511)
|
||||
static void __adv7511_power_off(struct adv7511 *adv7511)
|
||||
{
|
||||
/* TODO: setup additional power down modes */
|
||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
||||
ADV7511_POWER_POWER_DOWN,
|
||||
ADV7511_POWER_POWER_DOWN);
|
||||
regcache_mark_dirty(adv7511->regmap);
|
||||
}
|
||||
|
||||
static void adv7511_power_off(struct adv7511 *adv7511)
|
||||
{
|
||||
__adv7511_power_off(adv7511);
|
||||
if (adv7511->type == ADV7533)
|
||||
adv7533_dsi_power_off(adv7511);
|
||||
|
||||
adv7511->powered = false;
|
||||
}
|
||||
|
||||
@ -402,6 +409,27 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void adv7511_hpd_work(struct work_struct *work)
|
||||
{
|
||||
struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
|
||||
enum drm_connector_status status;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
|
||||
if (ret < 0)
|
||||
status = connector_status_disconnected;
|
||||
else if (val & ADV7511_STATUS_HPD)
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = connector_status_disconnected;
|
||||
|
||||
if (adv7511->connector.status != status) {
|
||||
adv7511->connector.status = status;
|
||||
drm_kms_helper_hotplug_event(adv7511->connector.dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
|
||||
{
|
||||
unsigned int irq0, irq1;
|
||||
@ -419,7 +447,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
|
||||
|
||||
if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
|
||||
drm_helper_hpd_irq_event(adv7511->connector.dev);
|
||||
schedule_work(&adv7511->hpd_work);
|
||||
|
||||
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
|
||||
adv7511->edid_read = true;
|
||||
@ -546,23 +574,20 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
|
||||
|
||||
/* Reading the EDID only works if the device is powered */
|
||||
if (!adv7511->powered) {
|
||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
||||
ADV7511_POWER_POWER_DOWN, 0);
|
||||
if (adv7511->i2c_main->irq) {
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
|
||||
ADV7511_INT0_EDID_READY);
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
|
||||
ADV7511_INT1_DDC_ERROR);
|
||||
}
|
||||
adv7511->current_edid_segment = -1;
|
||||
unsigned int edid_i2c_addr =
|
||||
(adv7511->i2c_main->addr << 1) + 4;
|
||||
|
||||
__adv7511_power_on(adv7511);
|
||||
|
||||
/* Reset the EDID_I2C_ADDR register as it might be cleared */
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
|
||||
edid_i2c_addr);
|
||||
}
|
||||
|
||||
edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
|
||||
|
||||
if (!adv7511->powered)
|
||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
||||
ADV7511_POWER_POWER_DOWN,
|
||||
ADV7511_POWER_POWER_DOWN);
|
||||
__adv7511_power_off(adv7511);
|
||||
|
||||
kfree(adv7511->edid);
|
||||
adv7511->edid = edid;
|
||||
@ -825,6 +850,10 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
|
||||
if (adv->type == ADV7533)
|
||||
ret = adv7533_attach_dsi(adv);
|
||||
|
||||
if (adv->i2c_main->irq)
|
||||
regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0),
|
||||
ADV7511_INT0_HPD);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -839,6 +868,58 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = {
|
||||
* Probe & remove
|
||||
*/
|
||||
|
||||
static const char * const adv7511_supply_names[] = {
|
||||
"avdd",
|
||||
"dvdd",
|
||||
"pvdd",
|
||||
"bgvdd",
|
||||
"dvdd-3v",
|
||||
};
|
||||
|
||||
static const char * const adv7533_supply_names[] = {
|
||||
"avdd",
|
||||
"dvdd",
|
||||
"pvdd",
|
||||
"a2vdd",
|
||||
"v3p3",
|
||||
"v1p2",
|
||||
};
|
||||
|
||||
static int adv7511_init_regulators(struct adv7511 *adv)
|
||||
{
|
||||
struct device *dev = &adv->i2c_main->dev;
|
||||
const char * const *supply_names;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (adv->type == ADV7511) {
|
||||
supply_names = adv7511_supply_names;
|
||||
adv->num_supplies = ARRAY_SIZE(adv7511_supply_names);
|
||||
} else {
|
||||
supply_names = adv7533_supply_names;
|
||||
adv->num_supplies = ARRAY_SIZE(adv7533_supply_names);
|
||||
}
|
||||
|
||||
adv->supplies = devm_kcalloc(dev, adv->num_supplies,
|
||||
sizeof(*adv->supplies), GFP_KERNEL);
|
||||
if (!adv->supplies)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < adv->num_supplies; i++)
|
||||
adv->supplies[i].supply = supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, adv->num_supplies, adv->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regulator_bulk_enable(adv->num_supplies, adv->supplies);
|
||||
}
|
||||
|
||||
static void adv7511_uninit_regulators(struct adv7511 *adv)
|
||||
{
|
||||
regulator_bulk_disable(adv->num_supplies, adv->supplies);
|
||||
}
|
||||
|
||||
static int adv7511_parse_dt(struct device_node *np,
|
||||
struct adv7511_link_config *config)
|
||||
{
|
||||
@ -939,6 +1020,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
if (!adv7511)
|
||||
return -ENOMEM;
|
||||
|
||||
adv7511->i2c_main = i2c;
|
||||
adv7511->powered = false;
|
||||
adv7511->status = connector_status_disconnected;
|
||||
|
||||
@ -956,13 +1038,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adv7511_init_regulators(adv7511);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The power down GPIO is optional. If present, toggle it from active to
|
||||
* inactive to wake up the encoder.
|
||||
*/
|
||||
adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(adv7511->gpio_pd))
|
||||
return PTR_ERR(adv7511->gpio_pd);
|
||||
if (IS_ERR(adv7511->gpio_pd)) {
|
||||
ret = PTR_ERR(adv7511->gpio_pd);
|
||||
goto uninit_regulators;
|
||||
}
|
||||
|
||||
if (adv7511->gpio_pd) {
|
||||
mdelay(5);
|
||||
@ -970,12 +1060,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
}
|
||||
|
||||
adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
|
||||
if (IS_ERR(adv7511->regmap))
|
||||
return PTR_ERR(adv7511->regmap);
|
||||
if (IS_ERR(adv7511->regmap)) {
|
||||
ret = PTR_ERR(adv7511->regmap);
|
||||
goto uninit_regulators;
|
||||
}
|
||||
|
||||
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto uninit_regulators;
|
||||
dev_dbg(dev, "Rev. %d\n", val);
|
||||
|
||||
if (adv7511->type == ADV7511)
|
||||
@ -985,7 +1077,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
else
|
||||
ret = adv7533_patch_registers(adv7511);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto uninit_regulators;
|
||||
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
|
||||
@ -995,10 +1087,11 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
|
||||
adv7511_packet_disable(adv7511, 0xffff);
|
||||
|
||||
adv7511->i2c_main = i2c;
|
||||
adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
|
||||
if (!adv7511->i2c_edid)
|
||||
return -ENOMEM;
|
||||
if (!adv7511->i2c_edid) {
|
||||
ret = -ENOMEM;
|
||||
goto uninit_regulators;
|
||||
}
|
||||
|
||||
if (adv7511->type == ADV7533) {
|
||||
ret = adv7533_init_cec(adv7511);
|
||||
@ -1006,6 +1099,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
goto err_i2c_unregister_edid;
|
||||
}
|
||||
|
||||
INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
|
||||
|
||||
if (i2c->irq) {
|
||||
init_waitqueue_head(&adv7511->wq);
|
||||
|
||||
@ -1045,6 +1140,8 @@ err_unregister_cec:
|
||||
adv7533_uninit_cec(adv7511);
|
||||
err_i2c_unregister_edid:
|
||||
i2c_unregister_device(adv7511->i2c_edid);
|
||||
uninit_regulators:
|
||||
adv7511_uninit_regulators(adv7511);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1058,6 +1155,8 @@ static int adv7511_remove(struct i2c_client *i2c)
|
||||
adv7533_uninit_cec(adv7511);
|
||||
}
|
||||
|
||||
adv7511_uninit_regulators(adv7511);
|
||||
|
||||
drm_bridge_remove(&adv7511->bridge);
|
||||
|
||||
adv7511_audio_exit(adv7511);
|
||||
|
@ -113,13 +113,20 @@ struct dw_hdmi_i2c {
|
||||
bool is_regaddr;
|
||||
};
|
||||
|
||||
struct dw_hdmi_phy_data {
|
||||
enum dw_hdmi_phy_type type;
|
||||
const char *name;
|
||||
bool has_svsret;
|
||||
};
|
||||
|
||||
struct dw_hdmi {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_bridge bridge;
|
||||
|
||||
enum dw_hdmi_devtype dev_type;
|
||||
unsigned int version;
|
||||
|
||||
struct platform_device *audio;
|
||||
enum dw_hdmi_devtype dev_type;
|
||||
struct device *dev;
|
||||
struct clk *isfr_clk;
|
||||
struct clk *iahb_clk;
|
||||
@ -133,7 +140,9 @@ struct dw_hdmi {
|
||||
u8 edid[HDMI_EDID_LEN];
|
||||
bool cable_plugin;
|
||||
|
||||
const struct dw_hdmi_phy_data *phy;
|
||||
bool phy_enabled;
|
||||
|
||||
struct drm_display_mode previous_mode;
|
||||
|
||||
struct i2c_adapter *ddc;
|
||||
@ -868,7 +877,7 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
||||
static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
||||
unsigned char addr)
|
||||
{
|
||||
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
|
||||
@ -882,13 +891,6 @@ static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
||||
hdmi_phy_wait_i2c_done(hdmi, 1000);
|
||||
}
|
||||
|
||||
static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
||||
unsigned char addr)
|
||||
{
|
||||
__hdmi_phy_i2c_write(hdmi, data, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
|
||||
{
|
||||
hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
|
||||
@ -903,11 +905,11 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
|
||||
HDMI_PHY_CONF0_ENTMDS_MASK);
|
||||
}
|
||||
|
||||
static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
|
||||
static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
|
||||
{
|
||||
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
|
||||
HDMI_PHY_CONF0_SPARECTRL_OFFSET,
|
||||
HDMI_PHY_CONF0_SPARECTRL_MASK);
|
||||
HDMI_PHY_CONF0_SVSRET_OFFSET,
|
||||
HDMI_PHY_CONF0_SVSRET_MASK);
|
||||
}
|
||||
|
||||
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
|
||||
@ -938,34 +940,14 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
|
||||
HDMI_PHY_CONF0_SELDIPIF_MASK);
|
||||
}
|
||||
|
||||
static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
||||
unsigned char res, int cscon)
|
||||
static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
|
||||
{
|
||||
unsigned res_idx;
|
||||
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_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
||||
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
|
||||
|
||||
if (prep)
|
||||
return -EINVAL;
|
||||
|
||||
switch (res) {
|
||||
case 0: /* color resolution 0 is 8 bit colour depth */
|
||||
case 8:
|
||||
res_idx = DW_HDMI_RES_8;
|
||||
break;
|
||||
case 10:
|
||||
res_idx = DW_HDMI_RES_10;
|
||||
break;
|
||||
case 12:
|
||||
res_idx = DW_HDMI_RES_12;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* PLL/MPLL Cfg - always match on final entry */
|
||||
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
|
||||
if (hdmi->hdmi_data.video_mode.mpixelclock <=
|
||||
@ -1004,9 +986,13 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
||||
/* gen2 pddq */
|
||||
dw_hdmi_phy_gen2_pddq(hdmi, 1);
|
||||
|
||||
/* PHY reset */
|
||||
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
|
||||
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
|
||||
/* Leave low power consumption mode by asserting SVSRET. */
|
||||
if (hdmi->phy->has_svsret)
|
||||
dw_hdmi_phy_enable_svsret(hdmi, 1);
|
||||
|
||||
/* PHY reset. The reset signal is active high on Gen2 PHYs. */
|
||||
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
|
||||
hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
|
||||
|
||||
@ -1015,21 +1001,26 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
||||
HDMI_PHY_I2CM_SLAVE_ADDR);
|
||||
hdmi_phy_test_clear(hdmi, 0);
|
||||
|
||||
hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06);
|
||||
hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
|
||||
hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
|
||||
HDMI_3D_TX_PHY_CPCE_CTRL);
|
||||
hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
|
||||
HDMI_3D_TX_PHY_GMPCTRL);
|
||||
hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
|
||||
HDMI_3D_TX_PHY_CURRCTRL);
|
||||
|
||||
/* CURRCTRL */
|
||||
hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10);
|
||||
hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
|
||||
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, 0x0000, 0x13); /* PLLPHBYCTRL */
|
||||
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
|
||||
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);
|
||||
|
||||
hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19); /* TXTERM */
|
||||
hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
|
||||
hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */
|
||||
|
||||
/* REMOVE CLK TERM */
|
||||
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
|
||||
/* 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);
|
||||
|
||||
@ -1041,10 +1032,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
||||
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
|
||||
dw_hdmi_phy_gen2_pddq(hdmi, 0);
|
||||
|
||||
if (hdmi->dev_type == RK3288_HDMI)
|
||||
dw_hdmi_phy_enable_spare(hdmi, 1);
|
||||
|
||||
/*Wait for PHY PLL lock */
|
||||
/* Wait for PHY PLL lock */
|
||||
msec = 5;
|
||||
do {
|
||||
val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
|
||||
@ -1079,7 +1067,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
|
||||
dw_hdmi_phy_enable_powerdown(hdmi, true);
|
||||
|
||||
/* Enable CSC */
|
||||
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
|
||||
ret = hdmi_phy_configure(hdmi, cscon);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -1351,19 +1339,38 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
|
||||
/* Workaround to clear the overflow condition */
|
||||
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
|
||||
{
|
||||
int count;
|
||||
unsigned int count;
|
||||
unsigned int i;
|
||||
u8 val;
|
||||
|
||||
/*
|
||||
* Under some circumstances the Frame Composer arithmetic unit can miss
|
||||
* an FC register write due to being busy processing the previous one.
|
||||
* The issue can be worked around by issuing a TMDS software reset and
|
||||
* then write one of the FC registers several times.
|
||||
*
|
||||
* The number of iterations matters and depends on the HDMI TX revision
|
||||
* (and possibly on the platform). So far only i.MX6Q (v1.30a) and
|
||||
* i.MX6DL (v1.31a) have been identified as needing the workaround, with
|
||||
* 4 and 1 iterations respectively.
|
||||
*/
|
||||
|
||||
switch (hdmi->version) {
|
||||
case 0x130a:
|
||||
count = 4;
|
||||
break;
|
||||
case 0x131a:
|
||||
count = 1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* TMDS software reset */
|
||||
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
|
||||
|
||||
val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
|
||||
if (hdmi->dev_type == IMX6DL_HDMI) {
|
||||
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
|
||||
return;
|
||||
}
|
||||
|
||||
for (count = 0; count < 4; count++)
|
||||
for (i = 0; i < count; i++)
|
||||
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
|
||||
}
|
||||
|
||||
@ -1586,42 +1593,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
|
||||
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
struct drm_display_mode *orig_mode,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
|
||||
/* Store the display mode for plugin/DKMS poweron events */
|
||||
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
|
||||
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
hdmi->disabled = true;
|
||||
dw_hdmi_update_power(hdmi);
|
||||
dw_hdmi_update_phy_mask(hdmi);
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
hdmi->disabled = false;
|
||||
dw_hdmi_update_power(hdmi);
|
||||
dw_hdmi_update_phy_mask(hdmi);
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@ -1714,7 +1685,63 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
|
||||
.best_encoder = drm_atomic_helper_best_encoder,
|
||||
};
|
||||
|
||||
static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
|
||||
connector->interlace_allowed = 1;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
|
||||
|
||||
drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
|
||||
drm_mode_connector_attach_encoder(connector, encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
struct drm_display_mode *orig_mode,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
|
||||
/* Store the display mode for plugin/DKMS poweron events */
|
||||
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
|
||||
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
hdmi->disabled = true;
|
||||
dw_hdmi_update_power(hdmi);
|
||||
dw_hdmi_update_phy_mask(hdmi);
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
|
||||
mutex_lock(&hdmi->mutex);
|
||||
hdmi->disabled = false;
|
||||
dw_hdmi_update_power(hdmi);
|
||||
dw_hdmi_update_phy_mask(hdmi);
|
||||
mutex_unlock(&hdmi->mutex);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
|
||||
.attach = dw_hdmi_bridge_attach,
|
||||
.enable = dw_hdmi_bridge_enable,
|
||||
.disable = dw_hdmi_bridge_disable,
|
||||
.mode_set = dw_hdmi_bridge_mode_set,
|
||||
@ -1816,7 +1843,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
|
||||
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
|
||||
dev_dbg(hdmi->dev, "EVENT=%s\n",
|
||||
phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
|
||||
drm_helper_hpd_irq_event(hdmi->bridge->dev);
|
||||
if (hdmi->bridge.dev)
|
||||
drm_helper_hpd_irq_event(hdmi->bridge.dev);
|
||||
}
|
||||
|
||||
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
|
||||
@ -1826,67 +1854,80 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
|
||||
static const struct dw_hdmi_phy_data dw_hdmi_phys[] = {
|
||||
{
|
||||
.type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
|
||||
.name = "DWC HDMI TX PHY",
|
||||
}, {
|
||||
.type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
|
||||
.name = "DWC MHL PHY + HEAC PHY",
|
||||
.has_svsret = true,
|
||||
}, {
|
||||
.type = DW_HDMI_PHY_DWC_MHL_PHY,
|
||||
.name = "DWC MHL PHY",
|
||||
.has_svsret = true,
|
||||
}, {
|
||||
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
|
||||
.name = "DWC HDMI 3D TX PHY + HEAC PHY",
|
||||
}, {
|
||||
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
|
||||
.name = "DWC HDMI 3D TX PHY",
|
||||
}, {
|
||||
.type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
|
||||
.name = "DWC HDMI 2.0 TX PHY",
|
||||
.has_svsret = true,
|
||||
}
|
||||
};
|
||||
|
||||
static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
|
||||
{
|
||||
struct drm_encoder *encoder = hdmi->encoder;
|
||||
struct drm_bridge *bridge;
|
||||
int ret;
|
||||
unsigned int i;
|
||||
u8 phy_type;
|
||||
|
||||
bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge) {
|
||||
DRM_ERROR("Failed to allocate drm bridge\n");
|
||||
return -ENOMEM;
|
||||
phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
|
||||
if (dw_hdmi_phys[i].type == phy_type) {
|
||||
hdmi->phy = &dw_hdmi_phys[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
hdmi->bridge = bridge;
|
||||
bridge->driver_private = hdmi;
|
||||
bridge->funcs = &dw_hdmi_bridge_funcs;
|
||||
ret = drm_bridge_attach(encoder, bridge, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
|
||||
dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
|
||||
else
|
||||
dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
|
||||
phy_type);
|
||||
|
||||
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
drm_connector_helper_add(&hdmi->connector,
|
||||
&dw_hdmi_connector_helper_funcs);
|
||||
|
||||
drm_connector_init(drm, &hdmi->connector,
|
||||
&dw_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
|
||||
drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
|
||||
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
void *data, struct drm_encoder *encoder,
|
||||
struct resource *iores, int irq,
|
||||
const struct dw_hdmi_plat_data *plat_data)
|
||||
static struct dw_hdmi *
|
||||
__dw_hdmi_probe(struct platform_device *pdev,
|
||||
const struct dw_hdmi_plat_data *plat_data)
|
||||
{
|
||||
struct drm_device *drm = data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_device_info pdevinfo;
|
||||
struct device_node *ddc_node;
|
||||
struct dw_hdmi *hdmi;
|
||||
struct resource *iores;
|
||||
int irq;
|
||||
int ret;
|
||||
u32 val = 1;
|
||||
u8 prod_id0;
|
||||
u8 prod_id1;
|
||||
u8 config0;
|
||||
u8 config1;
|
||||
u8 config3;
|
||||
|
||||
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
hdmi->connector.interlace_allowed = 1;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hdmi->plat_data = plat_data;
|
||||
hdmi->dev = dev;
|
||||
hdmi->dev_type = plat_data->dev_type;
|
||||
hdmi->sample_rate = 48000;
|
||||
hdmi->encoder = encoder;
|
||||
hdmi->disabled = true;
|
||||
hdmi->rxsense = true;
|
||||
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
|
||||
@ -1908,7 +1949,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "reg-io-width must be 1 or 4\n");
|
||||
return -EINVAL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
|
||||
@ -1917,13 +1958,14 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
of_node_put(ddc_node);
|
||||
if (!hdmi->ddc) {
|
||||
dev_dbg(hdmi->dev, "failed to read ddc node\n");
|
||||
return -EPROBE_DEFER;
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
} else {
|
||||
dev_dbg(hdmi->dev, "no ddc property found\n");
|
||||
}
|
||||
|
||||
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);
|
||||
@ -1957,15 +1999,36 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
}
|
||||
|
||||
/* Product and revision IDs */
|
||||
dev_info(dev,
|
||||
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
|
||||
hdmi_readb(hdmi, HDMI_DESIGN_ID),
|
||||
hdmi_readb(hdmi, HDMI_REVISION_ID),
|
||||
hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
|
||||
hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
|
||||
hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
|
||||
| (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
|
||||
prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0);
|
||||
prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1);
|
||||
|
||||
if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX ||
|
||||
(prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) {
|
||||
dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n",
|
||||
hdmi->version, prod_id0, prod_id1);
|
||||
ret = -ENODEV;
|
||||
goto err_iahb;
|
||||
}
|
||||
|
||||
ret = dw_hdmi_detect_phy(hdmi);
|
||||
if (ret < 0)
|
||||
goto err_iahb;
|
||||
|
||||
dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
|
||||
hdmi->version >> 12, hdmi->version & 0xfff,
|
||||
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
|
||||
hdmi->phy->name);
|
||||
|
||||
initialize_hdmi_ih_mutes(hdmi);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto err_iahb;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
|
||||
dw_hdmi_irq, IRQF_SHARED,
|
||||
dev_name(dev), hdmi);
|
||||
@ -1995,11 +2058,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
|
||||
HDMI_IH_PHY_STAT0);
|
||||
|
||||
ret = dw_hdmi_fb_registered(hdmi);
|
||||
if (ret)
|
||||
goto err_iahb;
|
||||
hdmi->bridge.driver_private = hdmi;
|
||||
hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
|
||||
hdmi->bridge.of_node = pdev->dev.of_node;
|
||||
|
||||
ret = dw_hdmi_register(drm, hdmi);
|
||||
ret = dw_hdmi_fb_registered(hdmi);
|
||||
if (ret)
|
||||
goto err_iahb;
|
||||
|
||||
@ -2012,9 +2075,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
pdevinfo.id = PLATFORM_DEVID_AUTO;
|
||||
|
||||
config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
|
||||
config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
|
||||
config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
|
||||
|
||||
if (config1 & HDMI_CONFIG1_AHB) {
|
||||
if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
|
||||
struct dw_hdmi_audio_data audio;
|
||||
|
||||
audio.phys = iores->start;
|
||||
@ -2046,9 +2109,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
if (hdmi->i2c)
|
||||
dw_hdmi_i2c_init(hdmi);
|
||||
|
||||
dev_set_drvdata(dev, hdmi);
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
return 0;
|
||||
return hdmi;
|
||||
|
||||
err_iahb:
|
||||
if (hdmi->i2c) {
|
||||
@ -2062,14 +2125,11 @@ err_isfr:
|
||||
err_res:
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_bind);
|
||||
|
||||
void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
|
||||
static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
|
||||
{
|
||||
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
if (hdmi->audio && !IS_ERR(hdmi->audio))
|
||||
platform_device_unregister(hdmi->audio);
|
||||
|
||||
@ -2084,6 +2144,70 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
|
||||
else
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Probe/remove API, used from platforms based on the DRM bridge API.
|
||||
*/
|
||||
int dw_hdmi_probe(struct platform_device *pdev,
|
||||
const struct dw_hdmi_plat_data *plat_data)
|
||||
{
|
||||
struct dw_hdmi *hdmi;
|
||||
int ret;
|
||||
|
||||
hdmi = __dw_hdmi_probe(pdev, plat_data);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
|
||||
ret = drm_bridge_add(&hdmi->bridge);
|
||||
if (ret < 0) {
|
||||
__dw_hdmi_remove(hdmi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_probe);
|
||||
|
||||
void dw_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&hdmi->bridge);
|
||||
|
||||
__dw_hdmi_remove(hdmi);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_remove);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Bind/unbind API, used from platforms based on the component framework.
|
||||
*/
|
||||
int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
|
||||
const struct dw_hdmi_plat_data *plat_data)
|
||||
{
|
||||
struct dw_hdmi *hdmi;
|
||||
int ret;
|
||||
|
||||
hdmi = __dw_hdmi_probe(pdev, plat_data);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
|
||||
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
|
||||
if (ret) {
|
||||
dw_hdmi_remove(pdev);
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_bind);
|
||||
|
||||
void dw_hdmi_unbind(struct device *dev)
|
||||
{
|
||||
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
__dw_hdmi_remove(hdmi);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
|
||||
|
||||
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
|
||||
|
@ -545,12 +545,24 @@
|
||||
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
|
||||
|
||||
enum {
|
||||
/* PRODUCT_ID0 field values */
|
||||
HDMI_PRODUCT_ID0_HDMI_TX = 0xa0,
|
||||
|
||||
/* PRODUCT_ID1 field values */
|
||||
HDMI_PRODUCT_ID1_HDCP = 0xc0,
|
||||
HDMI_PRODUCT_ID1_HDMI_RX = 0x02,
|
||||
HDMI_PRODUCT_ID1_HDMI_TX = 0x01,
|
||||
|
||||
/* CONFIG0_ID field values */
|
||||
HDMI_CONFIG0_I2S = 0x10,
|
||||
|
||||
/* CONFIG1_ID field values */
|
||||
HDMI_CONFIG1_AHB = 0x01,
|
||||
|
||||
/* CONFIG3_ID field values */
|
||||
HDMI_CONFIG3_AHBAUDDMA = 0x02,
|
||||
HDMI_CONFIG3_GPAUD = 0x01,
|
||||
|
||||
/* IH_FC_INT2 field values */
|
||||
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
|
||||
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
|
||||
@ -847,8 +859,8 @@ enum {
|
||||
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
|
||||
HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
|
||||
HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
|
||||
HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
|
||||
HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
|
||||
HDMI_PHY_CONF0_SVSRET_MASK = 0x20,
|
||||
HDMI_PHY_CONF0_SVSRET_OFFSET = 5,
|
||||
HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
|
||||
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
|
||||
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
|
||||
@ -977,8 +989,7 @@ enum {
|
||||
HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
|
||||
|
||||
/* MC_PHYRSTZ field values */
|
||||
HDMI_MC_PHYRSTZ_ASSERT = 0x0,
|
||||
HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
|
||||
HDMI_MC_PHYRSTZ_PHYRSTZ = 0x01,
|
||||
|
||||
/* MC_HEACPHY_RST field values */
|
||||
HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
|
||||
@ -1073,4 +1084,70 @@ enum {
|
||||
HDMI_I2CM_CTLINT_ARB_MASK = 0x4,
|
||||
};
|
||||
|
||||
/*
|
||||
* HDMI 3D TX PHY registers
|
||||
*/
|
||||
#define HDMI_3D_TX_PHY_PWRCTRL 0x00
|
||||
#define HDMI_3D_TX_PHY_SERDIVCTRL 0x01
|
||||
#define HDMI_3D_TX_PHY_SERCKCTRL 0x02
|
||||
#define HDMI_3D_TX_PHY_SERCKKILLCTRL 0x03
|
||||
#define HDMI_3D_TX_PHY_TXRESCTRL 0x04
|
||||
#define HDMI_3D_TX_PHY_CKCALCTRL 0x05
|
||||
#define HDMI_3D_TX_PHY_CPCE_CTRL 0x06
|
||||
#define HDMI_3D_TX_PHY_TXCLKMEASCTRL 0x07
|
||||
#define HDMI_3D_TX_PHY_TXMEASCTRL 0x08
|
||||
#define HDMI_3D_TX_PHY_CKSYMTXCTRL 0x09
|
||||
#define HDMI_3D_TX_PHY_CMPSEQCTRL 0x0a
|
||||
#define HDMI_3D_TX_PHY_CMPPWRCTRL 0x0b
|
||||
#define HDMI_3D_TX_PHY_CMPMODECTRL 0x0c
|
||||
#define HDMI_3D_TX_PHY_MEASCTRL 0x0d
|
||||
#define HDMI_3D_TX_PHY_VLEVCTRL 0x0e
|
||||
#define HDMI_3D_TX_PHY_D2ACTRL 0x0f
|
||||
#define HDMI_3D_TX_PHY_CURRCTRL 0x10
|
||||
#define HDMI_3D_TX_PHY_DRVANACTRL 0x11
|
||||
#define HDMI_3D_TX_PHY_PLLMEASCTRL 0x12
|
||||
#define HDMI_3D_TX_PHY_PLLPHBYCTRL 0x13
|
||||
#define HDMI_3D_TX_PHY_GRP_CTRL 0x14
|
||||
#define HDMI_3D_TX_PHY_GMPCTRL 0x15
|
||||
#define HDMI_3D_TX_PHY_MPLLMEASCTRL 0x16
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL 0x17
|
||||
#define HDMI_3D_TX_PHY_SCRPB_STATUS 0x18
|
||||
#define HDMI_3D_TX_PHY_TXTERM 0x19
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL 0x1a
|
||||
#define HDMI_3D_TX_PHY_PATTERNGEN 0x1b
|
||||
#define HDMI_3D_TX_PHY_SDCAP_MODE 0x1c
|
||||
#define HDMI_3D_TX_PHY_SCOPEMODE 0x1d
|
||||
#define HDMI_3D_TX_PHY_DIGTXMODE 0x1e
|
||||
#define HDMI_3D_TX_PHY_STR_STATUS 0x1f
|
||||
#define HDMI_3D_TX_PHY_SCOPECNT0 0x20
|
||||
#define HDMI_3D_TX_PHY_SCOPECNT1 0x21
|
||||
#define HDMI_3D_TX_PHY_SCOPECNT2 0x22
|
||||
#define HDMI_3D_TX_PHY_SCOPECNTCLK 0x23
|
||||
#define HDMI_3D_TX_PHY_SCOPESAMPLE 0x24
|
||||
#define HDMI_3D_TX_PHY_SCOPECNTMSB01 0x25
|
||||
#define HDMI_3D_TX_PHY_SCOPECNTMSB2CK 0x26
|
||||
|
||||
/* HDMI_3D_TX_PHY_CKCALCTRL values */
|
||||
#define HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE BIT(15)
|
||||
|
||||
/* HDMI_3D_TX_PHY_MSM_CTRL values */
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL_MPLL_PH_SEL_CK BIT(13)
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_CLK_REF_MPLL (0 << 1)
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_OFF (1 << 1)
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_PCLK (2 << 1)
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK (3 << 1)
|
||||
#define HDMI_3D_TX_PHY_MSM_CTRL_SCOPE_CK_SEL BIT(0)
|
||||
|
||||
/* HDMI_3D_TX_PHY_PTRPT_ENBL values */
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_OVERRIDE BIT(15)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT2 BIT(8)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT1 BIT(7)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT0 BIT(6)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_CK_REF_ENB BIT(5)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_RCAL_ENB BIT(4)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_CLK_ALIGN_ENB BIT(3)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_READY BIT(2)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_CKO_WORD_ENB BIT(1)
|
||||
#define HDMI_3D_TX_PHY_PTRPT_ENBL_REFCLK_ENB BIT(0)
|
||||
|
||||
#endif /* __DW_HDMI_H__ */
|
||||
|
@ -2708,6 +2708,44 @@ backoff:
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
|
||||
|
||||
static int page_flip_common(
|
||||
struct drm_atomic_state *state,
|
||||
struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event)
|
||||
{
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int ret = 0;
|
||||
|
||||
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
|
||||
crtc_state->event = event;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state, plane);
|
||||
if (IS_ERR(plane_state))
|
||||
return PTR_ERR(plane_state);
|
||||
|
||||
|
||||
ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
drm_atomic_set_fb_for_plane(plane_state, fb);
|
||||
|
||||
/* Make sure we don't accidentally do a full modeset. */
|
||||
state->allow_modeset = false;
|
||||
if (!crtc_state->active) {
|
||||
DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
|
||||
crtc->base.id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_page_flip - execute a legacy page flip
|
||||
* @crtc: DRM crtc
|
||||
@ -2715,7 +2753,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
|
||||
* @event: optional DRM event to signal upon completion
|
||||
* @flags: flip flags for non-vblank sync'ed updates
|
||||
*
|
||||
* Provides a default page flip implementation using the atomic driver interface.
|
||||
* Provides a default &drm_crtc_funcs.page_flip implementation
|
||||
* using the atomic driver interface.
|
||||
*
|
||||
* Note that for now so called async page flips (i.e. updates which are not
|
||||
* synchronized to vblank) are not supported, since the atomic interfaces have
|
||||
@ -2723,6 +2762,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
|
||||
*
|
||||
* Returns:
|
||||
* Returns 0 on success, negative errno numbers on failure.
|
||||
*
|
||||
* See also:
|
||||
* drm_atomic_helper_page_flip_target()
|
||||
*/
|
||||
int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
@ -2731,8 +2773,6 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
||||
{
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int ret = 0;
|
||||
|
||||
if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
|
||||
@ -2743,35 +2783,14 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
||||
return -ENOMEM;
|
||||
|
||||
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
|
||||
|
||||
retry:
|
||||
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
||||
if (IS_ERR(crtc_state)) {
|
||||
ret = PTR_ERR(crtc_state);
|
||||
goto fail;
|
||||
}
|
||||
crtc_state->event = event;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state, plane);
|
||||
if (IS_ERR(plane_state)) {
|
||||
ret = PTR_ERR(plane_state);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
|
||||
ret = page_flip_common(state, crtc, fb, event);
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
drm_atomic_set_fb_for_plane(plane_state, fb);
|
||||
|
||||
/* Make sure we don't accidentally do a full modeset. */
|
||||
state->allow_modeset = false;
|
||||
if (!crtc_state->active) {
|
||||
DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
|
||||
crtc->base.id);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = drm_atomic_nonblocking_commit(state);
|
||||
|
||||
fail:
|
||||
if (ret == -EDEADLK)
|
||||
goto backoff;
|
||||
@ -2794,6 +2813,78 @@ backoff:
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_page_flip);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_page_flip_target - do page flip on target vblank period.
|
||||
* @crtc: DRM crtc
|
||||
* @fb: DRM framebuffer
|
||||
* @event: optional DRM event to signal upon completion
|
||||
* @flags: flip flags for non-vblank sync'ed updates
|
||||
* @target: specifying the target vblank period when the flip to take effect
|
||||
*
|
||||
* Provides a default &drm_crtc_funcs.page_flip_target implementation.
|
||||
* Similar to drm_atomic_helper_page_flip() with extra parameter to specify
|
||||
* target vblank period to flip.
|
||||
*
|
||||
* Returns:
|
||||
* Returns 0 on success, negative errno numbers on failure.
|
||||
*/
|
||||
int drm_atomic_helper_page_flip_target(
|
||||
struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t flags,
|
||||
uint32_t target)
|
||||
{
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int ret = 0;
|
||||
|
||||
if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
|
||||
return -EINVAL;
|
||||
|
||||
state = drm_atomic_state_alloc(plane->dev);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
|
||||
|
||||
retry:
|
||||
ret = page_flip_common(state, crtc, fb, event);
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
|
||||
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
|
||||
if (WARN_ON(!crtc_state)) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
crtc_state->target_vblank = target;
|
||||
|
||||
ret = drm_atomic_nonblocking_commit(state);
|
||||
|
||||
fail:
|
||||
if (ret == -EDEADLK)
|
||||
goto backoff;
|
||||
|
||||
drm_atomic_state_put(state);
|
||||
return ret;
|
||||
|
||||
backoff:
|
||||
drm_atomic_state_clear(state);
|
||||
drm_atomic_legacy_backoff(state);
|
||||
|
||||
/*
|
||||
* Someone might have exchanged the framebuffer while we dropped locks
|
||||
* in the backoff code. We need to fix up the fb refcount tracking the
|
||||
* core does for us.
|
||||
*/
|
||||
plane->old_fb = plane->fb;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_connector_dpms() - connector dpms helper implementation
|
||||
* @connector: affected connector
|
||||
|
@ -67,6 +67,14 @@ static void drm_cache_flush_clflush(struct page *pages[],
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* drm_clflush_pages - Flush dcache lines of a set of pages.
|
||||
* @pages: List of pages to be flushed.
|
||||
* @num_pages: Number of pages in the array.
|
||||
*
|
||||
* Flush every data cache line entry that points to an address belonging
|
||||
* to a page in the array.
|
||||
*/
|
||||
void
|
||||
drm_clflush_pages(struct page *pages[], unsigned long num_pages)
|
||||
{
|
||||
@ -101,6 +109,13 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_clflush_pages);
|
||||
|
||||
/**
|
||||
* drm_clflush_sg - Flush dcache lines pointing to a scather-gather.
|
||||
* @st: struct sg_table.
|
||||
*
|
||||
* Flush every data cache line entry that points to an address in the
|
||||
* sg.
|
||||
*/
|
||||
void
|
||||
drm_clflush_sg(struct sg_table *st)
|
||||
{
|
||||
@ -125,6 +140,14 @@ drm_clflush_sg(struct sg_table *st)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_clflush_sg);
|
||||
|
||||
/**
|
||||
* drm_clflush_virt_range - Flush dcache lines of a region
|
||||
* @addr: Initial kernel memory address.
|
||||
* @length: Region size.
|
||||
*
|
||||
* Flush every data cache line entry that points to an address in the
|
||||
* region requested.
|
||||
*/
|
||||
void
|
||||
drm_clflush_virt_range(void *addr, unsigned long length)
|
||||
{
|
||||
|
@ -473,8 +473,7 @@ drm_fbdev_cma_create(struct drm_fb_helper *helper,
|
||||
return 0;
|
||||
|
||||
err_cma_destroy:
|
||||
drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
|
||||
drm_fb_cma_destroy(&fbdev_cma->fb->fb);
|
||||
drm_framebuffer_remove(&fbdev_cma->fb->fb);
|
||||
err_fb_info_destroy:
|
||||
drm_fb_helper_release_fbi(helper);
|
||||
err_gem_free_object:
|
||||
@ -574,10 +573,8 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
|
||||
drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev);
|
||||
drm_fb_helper_release_fbi(&fbdev_cma->fb_helper);
|
||||
|
||||
if (fbdev_cma->fb) {
|
||||
drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
|
||||
drm_fb_cma_destroy(&fbdev_cma->fb->fb);
|
||||
}
|
||||
if (fbdev_cma->fb)
|
||||
drm_framebuffer_remove(&fbdev_cma->fb->fb);
|
||||
|
||||
drm_fb_helper_fini(&fbdev_cma->fb_helper);
|
||||
kfree(fbdev_cma);
|
||||
|
@ -3,6 +3,7 @@ config DRM_ETNAVIV
|
||||
tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
|
||||
depends on DRM
|
||||
depends on ARCH_MXC || ARCH_DOVE
|
||||
depends on MMU
|
||||
select SHMEM
|
||||
select TMPFS
|
||||
select IOMMU_API
|
||||
|
@ -467,7 +467,7 @@ err:
|
||||
clk_disable_unprepare(ctx->clks[i]);
|
||||
}
|
||||
|
||||
static struct exynos_drm_crtc_ops decon_crtc_ops = {
|
||||
static const struct exynos_drm_crtc_ops decon_crtc_ops = {
|
||||
.enable = decon_enable,
|
||||
.disable = decon_disable,
|
||||
.enable_vblank = decon_enable_vblank,
|
||||
|
@ -109,9 +109,6 @@ static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
|
||||
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
struct exynos_drm_private *private = crtc->dev->dev_private;
|
||||
|
||||
private->crtc[exynos_crtc->pipe] = NULL;
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
kfree(exynos_crtc);
|
||||
@ -134,7 +131,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
||||
void *ctx)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc;
|
||||
struct exynos_drm_private *private = drm_dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
int ret;
|
||||
|
||||
@ -149,8 +145,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
||||
|
||||
crtc = &exynos_crtc->base;
|
||||
|
||||
private->crtc[pipe] = crtc;
|
||||
|
||||
ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
|
||||
&exynos_crtc_funcs, NULL);
|
||||
if (ret < 0)
|
||||
|
@ -211,12 +211,6 @@ struct drm_exynos_file_private {
|
||||
struct exynos_drm_private {
|
||||
struct drm_fb_helper *fb_helper;
|
||||
|
||||
/*
|
||||
* created crtc object would be contained at this array and
|
||||
* this array is used to be aware of which crtc did it request vblank.
|
||||
*/
|
||||
struct drm_crtc *crtc[MAX_CRTC];
|
||||
|
||||
struct device *dma_dev;
|
||||
void *mapping;
|
||||
|
||||
@ -231,9 +225,9 @@ struct exynos_drm_private {
|
||||
static inline struct exynos_drm_crtc *
|
||||
exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct exynos_drm_private *private = dev->dev_private;
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
|
||||
return to_exynos_crtc(private->crtc[pipe]);
|
||||
return to_exynos_crtc(crtc);
|
||||
}
|
||||
|
||||
static inline struct device *to_dma_dev(struct drm_device *dev)
|
||||
|
@ -304,8 +304,8 @@ static void ade_set_medianoc_qos(struct ade_crtc *acrtc)
|
||||
|
||||
static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct kirin_drm_private *priv = dev->dev_private;
|
||||
struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
struct ade_crtc *acrtc = to_ade_crtc(crtc);
|
||||
struct ade_hw_ctx *ctx = acrtc->ctx;
|
||||
void __iomem *base = ctx->base;
|
||||
|
||||
@ -320,8 +320,8 @@ static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
|
||||
static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct kirin_drm_private *priv = dev->dev_private;
|
||||
struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
struct ade_crtc *acrtc = to_ade_crtc(crtc);
|
||||
struct ade_hw_ctx *ctx = acrtc->ctx;
|
||||
void __iomem *base = ctx->base;
|
||||
|
||||
@ -575,7 +575,6 @@ static const struct drm_crtc_funcs ade_crtc_funcs = {
|
||||
static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
struct drm_plane *plane)
|
||||
{
|
||||
struct kirin_drm_private *priv = dev->dev_private;
|
||||
struct device_node *port;
|
||||
int ret;
|
||||
|
||||
@ -599,7 +598,6 @@ static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
}
|
||||
|
||||
drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
|
||||
priv->crtc[drm_crtc_index(crtc)] = crtc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ struct kirin_dc_ops {
|
||||
};
|
||||
|
||||
struct kirin_drm_private {
|
||||
struct drm_crtc *crtc[MAX_CRTC];
|
||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||
struct drm_fbdev_cma *fbdev;
|
||||
#endif
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include <drm/drm_legacy.h> /* for struct drm_dma_handle */
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_auth.h>
|
||||
#include <drm/drm_cache.h>
|
||||
|
||||
#include "i915_params.h"
|
||||
#include "i915_reg.h"
|
||||
|
@ -207,8 +207,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
struct drm_device *drm = data;
|
||||
struct drm_encoder *encoder;
|
||||
struct imx_hdmi *hdmi;
|
||||
struct resource *iores;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
@ -223,14 +221,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENXIO;
|
||||
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
@ -249,7 +239,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
|
||||
ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
|
||||
ret = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
|
||||
/*
|
||||
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
||||
@ -264,7 +254,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
return dw_hdmi_unbind(dev, master, data);
|
||||
return dw_hdmi_unbind(dev);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_imx_ops = {
|
||||
|
@ -170,8 +170,8 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
|
||||
int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||
{
|
||||
struct mtk_drm_private *priv = drm->dev_private;
|
||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
||||
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
|
||||
|
||||
mtk_ddp_comp_enable_vblank(ovl, &mtk_crtc->base);
|
||||
@ -181,8 +181,8 @@ int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||
|
||||
void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||
{
|
||||
struct mtk_drm_private *priv = drm->dev_private;
|
||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
||||
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
|
||||
|
||||
mtk_ddp_comp_disable_vblank(ovl);
|
||||
@ -588,7 +588,6 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
|
||||
goto unprepare;
|
||||
drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
|
||||
drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE);
|
||||
priv->crtc[pipe] = &mtk_crtc->base;
|
||||
priv->num_pipes++;
|
||||
|
||||
return 0;
|
||||
|
@ -32,7 +32,6 @@ struct mtk_drm_private {
|
||||
struct drm_device *drm;
|
||||
struct device *dma_dev;
|
||||
|
||||
struct drm_crtc *crtc[MAX_CRTC];
|
||||
unsigned int num_pipes;
|
||||
|
||||
struct device_node *mutex_node;
|
||||
|
@ -4,6 +4,7 @@ config DRM_MSM
|
||||
depends on DRM
|
||||
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
|
||||
depends on OF && COMMON_CLK
|
||||
depends on MMU
|
||||
select REGULATOR
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
|
@ -174,10 +174,8 @@ fail_unlock:
|
||||
fail:
|
||||
|
||||
if (ret) {
|
||||
if (fb) {
|
||||
drm_framebuffer_unregister_private(fb);
|
||||
if (fb)
|
||||
drm_framebuffer_remove(fb);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -247,7 +245,6 @@ void msm_fbdev_free(struct drm_device *dev)
|
||||
/* this will free the backing object */
|
||||
if (fbdev->fb) {
|
||||
msm_gem_put_vaddr(fbdev->bo);
|
||||
drm_framebuffer_unregister_private(fbdev->fb);
|
||||
drm_framebuffer_remove(fbdev->fb);
|
||||
}
|
||||
|
||||
|
@ -58,27 +58,30 @@ int
|
||||
nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||
if (nv_crtc->index == pipe) {
|
||||
nvif_notify_get(&nv_crtc->vblank);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
struct nouveau_crtc *nv_crtc;
|
||||
|
||||
crtc = drm_crtc_from_index(dev, pipe);
|
||||
if (!crtc)
|
||||
return -EINVAL;
|
||||
|
||||
nv_crtc = nouveau_crtc(crtc);
|
||||
nvif_notify_get(&nv_crtc->vblank);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||
if (nv_crtc->index == pipe) {
|
||||
nvif_notify_put(&nv_crtc->vblank);
|
||||
return;
|
||||
}
|
||||
}
|
||||
struct nouveau_crtc *nv_crtc;
|
||||
|
||||
crtc = drm_crtc_from_index(dev, pipe);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
nv_crtc = nouveau_crtc(crtc);
|
||||
nvif_notify_put(&nv_crtc->vblank);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -225,10 +225,8 @@ fail:
|
||||
|
||||
drm_fb_helper_release_fbi(helper);
|
||||
|
||||
if (fb) {
|
||||
drm_framebuffer_unregister_private(fb);
|
||||
if (fb)
|
||||
drm_framebuffer_remove(fb);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -314,10 +312,8 @@ void omap_fbdev_free(struct drm_device *dev)
|
||||
omap_gem_put_paddr(fbdev->bo);
|
||||
|
||||
/* this will free the backing object */
|
||||
if (fbdev->fb) {
|
||||
drm_framebuffer_unregister_private(fbdev->fb);
|
||||
if (fbdev->fb)
|
||||
drm_framebuffer_remove(fbdev->fb);
|
||||
}
|
||||
|
||||
kfree(fbdev);
|
||||
|
||||
|
@ -84,8 +84,18 @@ int
|
||||
qxl_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
int r;
|
||||
struct qxl_device *dev =
|
||||
(struct qxl_device *) minor->dev->dev_private;
|
||||
|
||||
drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES,
|
||||
minor->debugfs_root, minor);
|
||||
|
||||
r = qxl_ttm_debugfs_init(dev);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to init TTM debugfs\n");
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1077,7 +1077,6 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
|
||||
dev->mode_config.suggested_x_property, 0);
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.suggested_y_property, 0);
|
||||
drm_connector_register(connector);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -62,20 +62,83 @@ static struct pci_driver qxl_pci_driver;
|
||||
static int
|
||||
qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct drm_device *drm;
|
||||
struct qxl_device *qdev;
|
||||
int ret;
|
||||
|
||||
if (pdev->revision < 4) {
|
||||
DRM_ERROR("qxl too old, doesn't support client_monitors_config,"
|
||||
" use xf86-video-qxl in user mode");
|
||||
return -EINVAL; /* TODO: ENODEV ? */
|
||||
}
|
||||
return drm_get_pci_dev(pdev, ent, &qxl_driver);
|
||||
|
||||
drm = drm_dev_alloc(&qxl_driver, &pdev->dev);
|
||||
if (IS_ERR(drm))
|
||||
return -ENOMEM;
|
||||
|
||||
qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
|
||||
if (!qdev) {
|
||||
ret = -ENOMEM;
|
||||
goto free_drm_device;
|
||||
}
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
goto free_drm_device;
|
||||
|
||||
drm->pdev = pdev;
|
||||
pci_set_drvdata(pdev, drm);
|
||||
drm->dev_private = qdev;
|
||||
|
||||
ret = qxl_device_init(qdev, drm, pdev, ent->driver_data);
|
||||
if (ret)
|
||||
goto disable_pci;
|
||||
|
||||
ret = drm_vblank_init(drm, 1);
|
||||
if (ret)
|
||||
goto unload;
|
||||
|
||||
ret = qxl_modeset_init(qdev);
|
||||
if (ret)
|
||||
goto vblank_cleanup;
|
||||
|
||||
drm_kms_helper_poll_init(qdev->ddev);
|
||||
|
||||
/* Complete initialization. */
|
||||
ret = drm_dev_register(drm, ent->driver_data);
|
||||
if (ret)
|
||||
goto modeset_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
modeset_cleanup:
|
||||
qxl_modeset_fini(qdev);
|
||||
vblank_cleanup:
|
||||
drm_vblank_cleanup(drm);
|
||||
unload:
|
||||
qxl_device_fini(qdev);
|
||||
disable_pci:
|
||||
pci_disable_device(pdev);
|
||||
free_drm_device:
|
||||
kfree(qdev);
|
||||
kfree(drm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
qxl_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
|
||||
drm_put_dev(dev);
|
||||
drm_dev_unregister(dev);
|
||||
|
||||
qxl_modeset_fini(qdev);
|
||||
qxl_device_fini(qdev);
|
||||
|
||||
dev->dev_private = NULL;
|
||||
kfree(qdev);
|
||||
drm_dev_unref(dev);
|
||||
}
|
||||
|
||||
static const struct file_operations qxl_fops = {
|
||||
@ -230,8 +293,6 @@ static struct pci_driver qxl_pci_driver = {
|
||||
static struct drm_driver qxl_driver = {
|
||||
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
|
||||
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||
.load = qxl_driver_load,
|
||||
.unload = qxl_driver_unload,
|
||||
.get_vblank_counter = qxl_noop_get_vblank_counter,
|
||||
.enable_vblank = qxl_noop_enable_vblank,
|
||||
.disable_vblank = qxl_noop_disable_vblank,
|
||||
|
@ -336,8 +336,9 @@ __printf(2,3) void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...);
|
||||
extern const struct drm_ioctl_desc qxl_ioctls[];
|
||||
extern int qxl_max_ioctl;
|
||||
|
||||
int qxl_driver_load(struct drm_device *dev, unsigned long flags);
|
||||
void qxl_driver_unload(struct drm_device *dev);
|
||||
int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev,
|
||||
struct pci_dev *pdev, unsigned long flags);
|
||||
void qxl_device_fini(struct qxl_device *qdev);
|
||||
|
||||
int qxl_modeset_init(struct qxl_device *qdev);
|
||||
void qxl_modeset_fini(struct qxl_device *qdev);
|
||||
@ -531,6 +532,7 @@ int qxl_garbage_collect(struct qxl_device *qdev);
|
||||
|
||||
int qxl_debugfs_init(struct drm_minor *minor);
|
||||
void qxl_debugfs_takedown(struct drm_minor *minor);
|
||||
int qxl_ttm_debugfs_init(struct qxl_device *qdev);
|
||||
|
||||
/* qxl_prime.c */
|
||||
int qxl_gem_prime_pin(struct drm_gem_object *obj);
|
||||
|
@ -115,7 +115,7 @@ static void qxl_gc_work(struct work_struct *work)
|
||||
qxl_garbage_collect(qdev);
|
||||
}
|
||||
|
||||
static int qxl_device_init(struct qxl_device *qdev,
|
||||
int qxl_device_init(struct qxl_device *qdev,
|
||||
struct drm_device *ddev,
|
||||
struct pci_dev *pdev,
|
||||
unsigned long flags)
|
||||
@ -263,7 +263,7 @@ static int qxl_device_init(struct qxl_device *qdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qxl_device_fini(struct qxl_device *qdev)
|
||||
void qxl_device_fini(struct qxl_device *qdev)
|
||||
{
|
||||
if (qdev->current_release_bo[0])
|
||||
qxl_bo_unref(&qdev->current_release_bo[0]);
|
||||
@ -284,55 +284,3 @@ static void qxl_device_fini(struct qxl_device *qdev)
|
||||
qdev->mode_info.num_modes = 0;
|
||||
qxl_debugfs_remove_files(qdev);
|
||||
}
|
||||
|
||||
void qxl_driver_unload(struct drm_device *dev)
|
||||
{
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
|
||||
if (qdev == NULL)
|
||||
return;
|
||||
|
||||
drm_vblank_cleanup(dev);
|
||||
|
||||
qxl_modeset_fini(qdev);
|
||||
qxl_device_fini(qdev);
|
||||
|
||||
kfree(qdev);
|
||||
dev->dev_private = NULL;
|
||||
}
|
||||
|
||||
int qxl_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
struct qxl_device *qdev;
|
||||
int r;
|
||||
|
||||
qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
|
||||
if (qdev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->dev_private = qdev;
|
||||
|
||||
r = qxl_device_init(qdev, dev, dev->pdev, flags);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = drm_vblank_init(dev, 1);
|
||||
if (r)
|
||||
goto unload;
|
||||
|
||||
r = qxl_modeset_init(qdev);
|
||||
if (r)
|
||||
goto unload;
|
||||
|
||||
drm_kms_helper_poll_init(qdev->ddev);
|
||||
|
||||
return 0;
|
||||
unload:
|
||||
qxl_driver_unload(dev);
|
||||
|
||||
out:
|
||||
kfree(qdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "qxl_object.h"
|
||||
|
||||
#include <linux/delay.h>
|
||||
static int qxl_ttm_debugfs_init(struct qxl_device *qdev);
|
||||
|
||||
static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
|
||||
{
|
||||
@ -436,11 +435,6 @@ int qxl_ttm_init(struct qxl_device *qdev)
|
||||
((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
|
||||
DRM_INFO("qxl: %uM of Surface memory size\n",
|
||||
(unsigned)qdev->surfaceram_size / (1024 * 1024));
|
||||
r = qxl_ttm_debugfs_init(qdev);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to init debugfs\n");
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -473,7 +467,7 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qxl_ttm_debugfs_init(struct qxl_device *qdev)
|
||||
int qxl_ttm_debugfs_init(struct qxl_device *qdev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
|
||||
|
@ -257,8 +257,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
struct drm_device *drm = data;
|
||||
struct drm_encoder *encoder;
|
||||
struct rockchip_hdmi *hdmi;
|
||||
struct resource *iores;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
@ -273,14 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENXIO;
|
||||
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
@ -301,7 +291,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
|
||||
ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
|
||||
ret = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
|
||||
/*
|
||||
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
||||
@ -316,7 +306,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
return dw_hdmi_unbind(dev, master, data);
|
||||
return dw_hdmi_unbind(dev);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_rockchip_ops = {
|
||||
|
@ -1274,13 +1274,19 @@ static bool evict_everything(struct drm_mm *mm,
|
||||
if (drm_mm_scan_add_block(&scan, &e->node))
|
||||
break;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
list_for_each_entry(e, &evict_list, link) {
|
||||
if (!drm_mm_scan_remove_block(&scan, &e->node)) {
|
||||
pr_err("Node %lld not marked for eviction!\n",
|
||||
e->node.start);
|
||||
list_del(&e->link);
|
||||
if (!err) {
|
||||
pr_err("Node %lld not marked for eviction!\n",
|
||||
e->node.start);
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
list_for_each_entry(e, &evict_list, link)
|
||||
drm_mm_remove_node(&e->node);
|
||||
|
@ -804,23 +804,10 @@ static const struct file_operations tegra_drm_fops = {
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
|
||||
unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
|
||||
if (pipe == drm_crtc_index(crtc))
|
||||
return crtc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
|
||||
unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||
struct tegra_dc *dc = to_tegra_dc(crtc);
|
||||
|
||||
if (!crtc)
|
||||
@ -831,7 +818,7 @@ static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
|
||||
|
||||
static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||
struct tegra_dc *dc = to_tegra_dc(crtc);
|
||||
|
||||
if (!crtc)
|
||||
@ -844,7 +831,7 @@ static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||
|
||||
static void tegra_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||
struct tegra_dc *dc = to_tegra_dc(crtc);
|
||||
|
||||
if (crtc)
|
||||
|
@ -271,8 +271,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
|
||||
return 0;
|
||||
|
||||
destroy:
|
||||
drm_framebuffer_unregister_private(fb);
|
||||
tegra_fb_destroy(fb);
|
||||
drm_framebuffer_remove(fb);
|
||||
release:
|
||||
drm_fb_helper_release_fbi(helper);
|
||||
return err;
|
||||
@ -342,10 +341,8 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
|
||||
drm_fb_helper_unregister_fbi(&fbdev->base);
|
||||
drm_fb_helper_release_fbi(&fbdev->base);
|
||||
|
||||
if (fbdev->fb) {
|
||||
drm_framebuffer_unregister_private(&fbdev->fb->base);
|
||||
if (fbdev->fb)
|
||||
drm_framebuffer_remove(&fbdev->fb->base);
|
||||
}
|
||||
|
||||
drm_fb_helper_fini(&fbdev->base);
|
||||
tegra_fbdev_free(fbdev);
|
||||
|
@ -156,7 +156,8 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
u32 val;
|
||||
int fifo_lines;
|
||||
int vblank_lines;
|
||||
@ -272,9 +273,7 @@ int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
|
||||
int *max_error, struct timeval *vblank_time,
|
||||
unsigned flags)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
||||
struct drm_crtc *crtc = &vc4_crtc->base;
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||
struct drm_crtc_state *state = crtc->state;
|
||||
|
||||
/* Helper routine in DRM core does all the work: */
|
||||
@ -652,8 +651,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
|
||||
int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
|
||||
CRTC_WRITE(PV_INTEN, PV_INT_VFP_START);
|
||||
|
||||
@ -662,8 +661,8 @@ int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
|
||||
|
||||
void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
|
||||
CRTC_WRITE(PV_INTEN, 0);
|
||||
}
|
||||
@ -937,7 +936,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm = dev_get_drvdata(master);
|
||||
struct vc4_dev *vc4 = to_vc4_dev(drm);
|
||||
struct vc4_crtc *vc4_crtc;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
|
||||
@ -975,7 +973,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
|
||||
&vc4_crtc_funcs, NULL);
|
||||
drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
|
||||
primary_plane->crtc = crtc;
|
||||
vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc;
|
||||
vc4_crtc->channel = vc4_crtc->data->hvs_channel;
|
||||
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
|
||||
|
||||
|
@ -16,7 +16,6 @@ struct vc4_dev {
|
||||
|
||||
struct vc4_hdmi *hdmi;
|
||||
struct vc4_hvs *hvs;
|
||||
struct vc4_crtc *crtc[3];
|
||||
struct vc4_v3d *v3d;
|
||||
struct vc4_dpi *dpi;
|
||||
struct vc4_vec *vec;
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_cache.h>
|
||||
|
||||
#include <uapi/drm/vgem_drm.h>
|
||||
|
||||
|
@ -27,6 +27,16 @@ enum dw_hdmi_devtype {
|
||||
RK3288_HDMI,
|
||||
};
|
||||
|
||||
enum dw_hdmi_phy_type {
|
||||
DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
|
||||
DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
|
||||
DW_HDMI_PHY_DWC_MHL_PHY = 0xc2,
|
||||
DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC = 0xe2,
|
||||
DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY = 0xf2,
|
||||
DW_HDMI_PHY_DWC_HDMI20_TX_PHY = 0xf3,
|
||||
DW_HDMI_PHY_VENDOR_PHY = 0xfe,
|
||||
};
|
||||
|
||||
struct dw_hdmi_mpll_config {
|
||||
unsigned long mpixelclock;
|
||||
struct {
|
||||
@ -56,10 +66,11 @@ struct dw_hdmi_plat_data {
|
||||
struct drm_display_mode *mode);
|
||||
};
|
||||
|
||||
void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
|
||||
int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
void *data, struct drm_encoder *encoder,
|
||||
struct resource *iores, int irq,
|
||||
int dw_hdmi_probe(struct platform_device *pdev,
|
||||
const struct dw_hdmi_plat_data *plat_data);
|
||||
void dw_hdmi_remove(struct platform_device *pdev);
|
||||
void dw_hdmi_unbind(struct device *dev);
|
||||
int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
|
||||
const struct dw_hdmi_plat_data *plat_data);
|
||||
|
||||
void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
|
||||
|
@ -731,11 +731,6 @@ int drm_noop(struct drm_device *dev, void *data,
|
||||
int drm_invalid_op(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* Cache management (drm_cache.c) */
|
||||
void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
|
||||
void drm_clflush_sg(struct sg_table *st);
|
||||
void drm_clflush_virt_range(void *addr, unsigned long length);
|
||||
|
||||
/*
|
||||
* These are exported to drivers so that they can implement fencing using
|
||||
* DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
|
||||
|
@ -121,6 +121,12 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t flags);
|
||||
int drm_atomic_helper_page_flip_target(
|
||||
struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t flags,
|
||||
uint32_t target);
|
||||
int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
|
||||
int mode);
|
||||
struct drm_encoder *
|
||||
|
@ -33,7 +33,11 @@
|
||||
#ifndef _DRM_CACHE_H_
|
||||
#define _DRM_CACHE_H_
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
|
||||
void drm_clflush_sg(struct sg_table *st);
|
||||
void drm_clflush_virt_range(void *addr, unsigned long length);
|
||||
|
||||
static inline bool drm_arch_can_wc_memory(void)
|
||||
{
|
||||
|
@ -148,6 +148,15 @@ struct drm_crtc_state {
|
||||
struct drm_property_blob *ctm;
|
||||
struct drm_property_blob *gamma_lut;
|
||||
|
||||
/**
|
||||
* @target_vblank:
|
||||
*
|
||||
* Target vertical blank period when a page flip
|
||||
* should take effect.
|
||||
*/
|
||||
|
||||
u32 target_vblank;
|
||||
|
||||
/**
|
||||
* @event:
|
||||
*
|
||||
|
@ -41,10 +41,17 @@ extern "C" {
|
||||
/* 8 bpp Red */
|
||||
#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
|
||||
|
||||
/* 16 bpp Red */
|
||||
#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
|
||||
|
||||
/* 16 bpp RG */
|
||||
#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
|
||||
#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
|
||||
|
||||
/* 32 bpp RG */
|
||||
#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
|
||||
#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
|
||||
|
||||
/* 8 bpp RGB */
|
||||
#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
|
||||
#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
|
||||
|
Loading…
Reference in New Issue
Block a user