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",
|
- adi,input-justification: The input bit justification ("left", "evenly",
|
||||||
"right").
|
"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:
|
The following properties are required for ADV7533:
|
||||||
|
|
||||||
- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
|
- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
|
||||||
be one of 1, 2, 3 or 4.
|
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:
|
Optional properties:
|
||||||
|
|
||||||
|
@ -1,52 +1,33 @@
|
|||||||
DesignWare HDMI bridge bindings
|
Synopsys DesignWare HDMI TX Encoder
|
||||||
|
===================================
|
||||||
|
|
||||||
Required properties:
|
This document defines device tree properties for the Synopsys DesignWare HDMI
|
||||||
- compatible: platform specific such as:
|
TX Encoder (DWC HDMI TX). It doesn't constitue a device tree binding
|
||||||
* "snps,dw-hdmi-tx"
|
specification by itself but is meant to be referenced by platform-specific
|
||||||
* "fsl,imx6q-hdmi"
|
device tree bindings.
|
||||||
* "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
|
|
||||||
|
|
||||||
Optional properties
|
When referenced from platform device tree bindings the properties defined in
|
||||||
- reg-io-width: the width of the reg:1,4, default set to 1 if not present
|
this document are defined as follows. The platform device tree bindings are
|
||||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing,
|
responsible for defining whether each property is required or optional.
|
||||||
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"
|
|
||||||
|
|
||||||
Example:
|
- reg: Memory mapped base address and length of the DWC HDMI TX registers.
|
||||||
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>;
|
|
||||||
|
|
||||||
port@0 {
|
- reg-io-width: Width of the registers specified by the reg property. The
|
||||||
reg = <0>;
|
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 {
|
- interrupts: Reference to the DWC HDMI TX interrupt.
|
||||||
remote-endpoint = <&ipu1_di0_hdmi>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
port@1 {
|
- clocks: References to all the clocks specified in the clock-names property
|
||||||
reg = <1>;
|
as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt.
|
||||||
|
|
||||||
hdmi_mux_1: endpoint {
|
- clock-names: The DWC HDMI TX uses the following clocks.
|
||||||
remote-endpoint = <&ipu1_di1_hdmi>;
|
|
||||||
};
|
- "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:
|
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:
|
- compatible : Shall be one of "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
|
||||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
- 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 {
|
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:
|
Required properties:
|
||||||
- compatible: "rockchip,rk3288-dw-hdmi";
|
|
||||||
- reg: Physical base address and length of the controller's registers.
|
- compatible: Shall contain "rockchip,rk3288-dw-hdmi".
|
||||||
- clocks: phandle to hdmi iahb and isfr clocks.
|
- reg: See dw_hdmi.txt.
|
||||||
- clock-names: should be "iahb" "isfr"
|
- reg-io-width: See dw_hdmi.txt. Shall be 4.
|
||||||
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
|
|
||||||
- interrupts: HDMI interrupt number
|
- interrupts: HDMI interrupt number
|
||||||
- ports: contain a port node with endpoint definitions as defined in
|
- clocks: See dw_hdmi.txt.
|
||||||
Documentation/devicetree/bindings/media/video-interfaces.txt. For
|
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||||
vopb,set the reg = <0> and set the reg = <1> for vopl.
|
- ports: See dw_hdmi.txt. The DWC HDMI shall have a single port numbered 0
|
||||||
- reg-io-width: the width of the reg:1,4, the value should be 4 on
|
corresponding to the video input of the controller. The port shall have two
|
||||||
rk3288 platform
|
endpoints, numbered 0 and 1, connected respectively to the vopb and vopl.
|
||||||
|
- rockchip,grf: Shall reference the GRF to mux vopl/vopb.
|
||||||
|
|
||||||
Optional properties
|
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:
|
Example:
|
||||||
|
|
||||||
hdmi: hdmi@ff980000 {
|
hdmi: hdmi@ff980000 {
|
||||||
compatible = "rockchip,rk3288-dw-hdmi";
|
compatible = "rockchip,rk3288-dw-hdmi";
|
||||||
reg = <0xff980000 0x20000>;
|
reg = <0xff980000 0x20000>;
|
||||||
|
@ -470,3 +470,9 @@ DRM MM Range Allocator Function References
|
|||||||
|
|
||||||
.. kernel-doc:: include/drm/drm_mm.h
|
.. kernel-doc:: include/drm/drm_mm.h
|
||||||
:internal:
|
: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
|
config DRM_VM
|
||||||
bool
|
bool
|
||||||
depends on DRM
|
depends on DRM && MMU
|
||||||
|
|
||||||
source "drivers/gpu/drm/i2c/Kconfig"
|
source "drivers/gpu/drm/i2c/Kconfig"
|
||||||
|
|
||||||
@ -267,7 +267,7 @@ source "drivers/gpu/drm/meson/Kconfig"
|
|||||||
|
|
||||||
menuconfig DRM_LEGACY
|
menuconfig DRM_LEGACY
|
||||||
bool "Enable legacy drivers (DANGEROUS)"
|
bool "Enable legacy drivers (DANGEROUS)"
|
||||||
depends on DRM
|
depends on DRM && MMU
|
||||||
select DRM_VM
|
select DRM_VM
|
||||||
help
|
help
|
||||||
Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
|
Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
config DRM_ARMADA
|
config DRM_ARMADA
|
||||||
tristate "DRM support for Marvell Armada SoCs"
|
tristate "DRM support for Marvell Armada SoCs"
|
||||||
depends on DRM && HAVE_CLK && ARM
|
depends on DRM && HAVE_CLK && ARM && MMU
|
||||||
select DRM_KMS_HELPER
|
select DRM_KMS_HELPER
|
||||||
help
|
help
|
||||||
Support the "LCD" controllers found on the Marvell Armada 510
|
Support the "LCD" controllers found on the Marvell Armada 510
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <linux/hdmi.h>
|
#include <linux/hdmi.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
#include <drm/drm_crtc_helper.h>
|
#include <drm/drm_crtc_helper.h>
|
||||||
#include <drm/drm_mipi_dsi.h>
|
#include <drm/drm_mipi_dsi.h>
|
||||||
@ -317,6 +318,8 @@ struct adv7511 {
|
|||||||
bool edid_read;
|
bool edid_read;
|
||||||
|
|
||||||
wait_queue_head_t wq;
|
wait_queue_head_t wq;
|
||||||
|
struct work_struct hpd_work;
|
||||||
|
|
||||||
struct drm_bridge bridge;
|
struct drm_bridge bridge;
|
||||||
struct drm_connector connector;
|
struct drm_connector connector;
|
||||||
|
|
||||||
@ -329,6 +332,9 @@ struct adv7511 {
|
|||||||
|
|
||||||
struct gpio_desc *gpio_pd;
|
struct gpio_desc *gpio_pd;
|
||||||
|
|
||||||
|
struct regulator_bulk_data *supplies;
|
||||||
|
unsigned int num_supplies;
|
||||||
|
|
||||||
/* ADV7533 DSI RX related params */
|
/* ADV7533 DSI RX related params */
|
||||||
struct device_node *host_node;
|
struct device_node *host_node;
|
||||||
struct mipi_dsi_device *dsi;
|
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;
|
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;
|
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.
|
* Still, let's be safe and stick to the documentation.
|
||||||
*/
|
*/
|
||||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
|
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),
|
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
|
||||||
ADV7511_INT1_DDC_ERROR);
|
ADV7511_INT1_DDC_ERROR);
|
||||||
}
|
}
|
||||||
@ -354,6 +354,11 @@ static void adv7511_power_on(struct adv7511 *adv7511)
|
|||||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
|
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
|
||||||
ADV7511_REG_POWER2_HPD_SRC_MASK,
|
ADV7511_REG_POWER2_HPD_SRC_MASK,
|
||||||
ADV7511_REG_POWER2_HPD_SRC_NONE);
|
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.
|
* 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)
|
if (adv7511->type == ADV7533)
|
||||||
adv7533_dsi_power_on(adv7511);
|
adv7533_dsi_power_on(adv7511);
|
||||||
|
|
||||||
adv7511->powered = true;
|
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 */
|
/* TODO: setup additional power down modes */
|
||||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
||||||
ADV7511_POWER_POWER_DOWN,
|
ADV7511_POWER_POWER_DOWN,
|
||||||
ADV7511_POWER_POWER_DOWN);
|
ADV7511_POWER_POWER_DOWN);
|
||||||
regcache_mark_dirty(adv7511->regmap);
|
regcache_mark_dirty(adv7511->regmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adv7511_power_off(struct adv7511 *adv7511)
|
||||||
|
{
|
||||||
|
__adv7511_power_off(adv7511);
|
||||||
if (adv7511->type == ADV7533)
|
if (adv7511->type == ADV7533)
|
||||||
adv7533_dsi_power_off(adv7511);
|
adv7533_dsi_power_off(adv7511);
|
||||||
|
|
||||||
adv7511->powered = false;
|
adv7511->powered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,6 +409,27 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
|
|||||||
return false;
|
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)
|
static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
|
||||||
{
|
{
|
||||||
unsigned int irq0, irq1;
|
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);
|
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
|
||||||
|
|
||||||
if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
|
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) {
|
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
|
||||||
adv7511->edid_read = true;
|
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 */
|
/* Reading the EDID only works if the device is powered */
|
||||||
if (!adv7511->powered) {
|
if (!adv7511->powered) {
|
||||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
unsigned int edid_i2c_addr =
|
||||||
ADV7511_POWER_POWER_DOWN, 0);
|
(adv7511->i2c_main->addr << 1) + 4;
|
||||||
if (adv7511->i2c_main->irq) {
|
|
||||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
|
__adv7511_power_on(adv7511);
|
||||||
ADV7511_INT0_EDID_READY);
|
|
||||||
regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
|
/* Reset the EDID_I2C_ADDR register as it might be cleared */
|
||||||
ADV7511_INT1_DDC_ERROR);
|
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
|
||||||
}
|
edid_i2c_addr);
|
||||||
adv7511->current_edid_segment = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
|
edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
|
||||||
|
|
||||||
if (!adv7511->powered)
|
if (!adv7511->powered)
|
||||||
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
|
__adv7511_power_off(adv7511);
|
||||||
ADV7511_POWER_POWER_DOWN,
|
|
||||||
ADV7511_POWER_POWER_DOWN);
|
|
||||||
|
|
||||||
kfree(adv7511->edid);
|
kfree(adv7511->edid);
|
||||||
adv7511->edid = edid;
|
adv7511->edid = edid;
|
||||||
@ -825,6 +850,10 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
|
|||||||
if (adv->type == ADV7533)
|
if (adv->type == ADV7533)
|
||||||
ret = adv7533_attach_dsi(adv);
|
ret = adv7533_attach_dsi(adv);
|
||||||
|
|
||||||
|
if (adv->i2c_main->irq)
|
||||||
|
regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0),
|
||||||
|
ADV7511_INT0_HPD);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,6 +868,58 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = {
|
|||||||
* Probe & remove
|
* 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,
|
static int adv7511_parse_dt(struct device_node *np,
|
||||||
struct adv7511_link_config *config)
|
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)
|
if (!adv7511)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
adv7511->i2c_main = i2c;
|
||||||
adv7511->powered = false;
|
adv7511->powered = false;
|
||||||
adv7511->status = connector_status_disconnected;
|
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)
|
if (ret)
|
||||||
return 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
|
* The power down GPIO is optional. If present, toggle it from active to
|
||||||
* inactive to wake up the encoder.
|
* inactive to wake up the encoder.
|
||||||
*/
|
*/
|
||||||
adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
|
adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
|
||||||
if (IS_ERR(adv7511->gpio_pd))
|
if (IS_ERR(adv7511->gpio_pd)) {
|
||||||
return PTR_ERR(adv7511->gpio_pd);
|
ret = PTR_ERR(adv7511->gpio_pd);
|
||||||
|
goto uninit_regulators;
|
||||||
|
}
|
||||||
|
|
||||||
if (adv7511->gpio_pd) {
|
if (adv7511->gpio_pd) {
|
||||||
mdelay(5);
|
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);
|
adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
|
||||||
if (IS_ERR(adv7511->regmap))
|
if (IS_ERR(adv7511->regmap)) {
|
||||||
return PTR_ERR(adv7511->regmap);
|
ret = PTR_ERR(adv7511->regmap);
|
||||||
|
goto uninit_regulators;
|
||||||
|
}
|
||||||
|
|
||||||
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
|
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto uninit_regulators;
|
||||||
dev_dbg(dev, "Rev. %d\n", val);
|
dev_dbg(dev, "Rev. %d\n", val);
|
||||||
|
|
||||||
if (adv7511->type == ADV7511)
|
if (adv7511->type == ADV7511)
|
||||||
@ -985,7 +1077,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
|||||||
else
|
else
|
||||||
ret = adv7533_patch_registers(adv7511);
|
ret = adv7533_patch_registers(adv7511);
|
||||||
if (ret)
|
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_EDID_I2C_ADDR, edid_i2c_addr);
|
||||||
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_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_packet_disable(adv7511, 0xffff);
|
||||||
|
|
||||||
adv7511->i2c_main = i2c;
|
|
||||||
adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
|
adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
|
||||||
if (!adv7511->i2c_edid)
|
if (!adv7511->i2c_edid) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto uninit_regulators;
|
||||||
|
}
|
||||||
|
|
||||||
if (adv7511->type == ADV7533) {
|
if (adv7511->type == ADV7533) {
|
||||||
ret = adv7533_init_cec(adv7511);
|
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;
|
goto err_i2c_unregister_edid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
|
||||||
|
|
||||||
if (i2c->irq) {
|
if (i2c->irq) {
|
||||||
init_waitqueue_head(&adv7511->wq);
|
init_waitqueue_head(&adv7511->wq);
|
||||||
|
|
||||||
@ -1045,6 +1140,8 @@ err_unregister_cec:
|
|||||||
adv7533_uninit_cec(adv7511);
|
adv7533_uninit_cec(adv7511);
|
||||||
err_i2c_unregister_edid:
|
err_i2c_unregister_edid:
|
||||||
i2c_unregister_device(adv7511->i2c_edid);
|
i2c_unregister_device(adv7511->i2c_edid);
|
||||||
|
uninit_regulators:
|
||||||
|
adv7511_uninit_regulators(adv7511);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1058,6 +1155,8 @@ static int adv7511_remove(struct i2c_client *i2c)
|
|||||||
adv7533_uninit_cec(adv7511);
|
adv7533_uninit_cec(adv7511);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adv7511_uninit_regulators(adv7511);
|
||||||
|
|
||||||
drm_bridge_remove(&adv7511->bridge);
|
drm_bridge_remove(&adv7511->bridge);
|
||||||
|
|
||||||
adv7511_audio_exit(adv7511);
|
adv7511_audio_exit(adv7511);
|
||||||
|
@ -113,13 +113,20 @@ struct dw_hdmi_i2c {
|
|||||||
bool is_regaddr;
|
bool is_regaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dw_hdmi_phy_data {
|
||||||
|
enum dw_hdmi_phy_type type;
|
||||||
|
const char *name;
|
||||||
|
bool has_svsret;
|
||||||
|
};
|
||||||
|
|
||||||
struct dw_hdmi {
|
struct dw_hdmi {
|
||||||
struct drm_connector connector;
|
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;
|
struct platform_device *audio;
|
||||||
enum dw_hdmi_devtype dev_type;
|
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct clk *isfr_clk;
|
struct clk *isfr_clk;
|
||||||
struct clk *iahb_clk;
|
struct clk *iahb_clk;
|
||||||
@ -133,7 +140,9 @@ 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;
|
||||||
bool phy_enabled;
|
bool phy_enabled;
|
||||||
|
|
||||||
struct drm_display_mode previous_mode;
|
struct drm_display_mode previous_mode;
|
||||||
|
|
||||||
struct i2c_adapter *ddc;
|
struct i2c_adapter *ddc;
|
||||||
@ -868,7 +877,7 @@ 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,
|
static void 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);
|
||||||
@ -882,13 +891,6 @@ static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
|||||||
hdmi_phy_wait_i2c_done(hdmi, 1000);
|
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)
|
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
|
||||||
{
|
{
|
||||||
hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
|
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);
|
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_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
|
||||||
HDMI_PHY_CONF0_SPARECTRL_OFFSET,
|
HDMI_PHY_CONF0_SVSRET_OFFSET,
|
||||||
HDMI_PHY_CONF0_SPARECTRL_MASK);
|
HDMI_PHY_CONF0_SVSRET_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
|
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);
|
HDMI_PHY_CONF0_SELDIPIF_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
|
||||||
unsigned char res, int cscon)
|
|
||||||
{
|
{
|
||||||
unsigned res_idx;
|
|
||||||
u8 val, msec;
|
u8 val, msec;
|
||||||
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
|
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;
|
||||||
|
|
||||||
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 */
|
/* 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 (hdmi->hdmi_data.video_mode.mpixelclock <=
|
||||||
@ -1004,9 +986,13 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
|||||||
/* gen2 pddq */
|
/* gen2 pddq */
|
||||||
dw_hdmi_phy_gen2_pddq(hdmi, 1);
|
dw_hdmi_phy_gen2_pddq(hdmi, 1);
|
||||||
|
|
||||||
/* PHY reset */
|
/* Leave low power consumption mode by asserting SVSRET. */
|
||||||
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
|
if (hdmi->phy->has_svsret)
|
||||||
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
|
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);
|
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_I2CM_SLAVE_ADDR);
|
||||||
hdmi_phy_test_clear(hdmi, 0);
|
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[0].cpce,
|
||||||
hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
|
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, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
|
||||||
hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10);
|
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, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
|
||||||
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
|
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 */
|
/* Override and disable clock termination. */
|
||||||
hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
|
hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
|
||||||
hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */
|
HDMI_3D_TX_PHY_CKCALCTRL);
|
||||||
|
|
||||||
/* REMOVE CLK TERM */
|
|
||||||
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
|
|
||||||
|
|
||||||
dw_hdmi_phy_enable_powerdown(hdmi, false);
|
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_txpwron(hdmi, 1);
|
||||||
dw_hdmi_phy_gen2_pddq(hdmi, 0);
|
dw_hdmi_phy_gen2_pddq(hdmi, 0);
|
||||||
|
|
||||||
if (hdmi->dev_type == RK3288_HDMI)
|
/* Wait for PHY PLL lock */
|
||||||
dw_hdmi_phy_enable_spare(hdmi, 1);
|
|
||||||
|
|
||||||
/*Wait for PHY PLL lock */
|
|
||||||
msec = 5;
|
msec = 5;
|
||||||
do {
|
do {
|
||||||
val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
|
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);
|
dw_hdmi_phy_enable_powerdown(hdmi, true);
|
||||||
|
|
||||||
/* Enable CSC */
|
/* Enable CSC */
|
||||||
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
|
ret = hdmi_phy_configure(hdmi, cscon);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1351,19 +1339,38 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
|
|||||||
/* Workaround to clear the overflow condition */
|
/* Workaround to clear the overflow condition */
|
||||||
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
|
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
|
||||||
{
|
{
|
||||||
int count;
|
unsigned int count;
|
||||||
|
unsigned int i;
|
||||||
u8 val;
|
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 */
|
/* TMDS software reset */
|
||||||
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
|
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
|
||||||
|
|
||||||
val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
|
val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
|
||||||
if (hdmi->dev_type == IMX6DL_HDMI) {
|
for (i = 0; i < count; i++)
|
||||||
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (count = 0; count < 4; count++)
|
|
||||||
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
|
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);
|
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
|
static enum drm_connector_status
|
||||||
dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
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,
|
.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 = {
|
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
|
||||||
|
.attach = dw_hdmi_bridge_attach,
|
||||||
.enable = dw_hdmi_bridge_enable,
|
.enable = dw_hdmi_bridge_enable,
|
||||||
.disable = dw_hdmi_bridge_disable,
|
.disable = dw_hdmi_bridge_disable,
|
||||||
.mode_set = dw_hdmi_bridge_mode_set,
|
.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) {
|
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
|
||||||
dev_dbg(hdmi->dev, "EVENT=%s\n",
|
dev_dbg(hdmi->dev, "EVENT=%s\n",
|
||||||
phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
|
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);
|
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;
|
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;
|
unsigned int i;
|
||||||
struct drm_bridge *bridge;
|
u8 phy_type;
|
||||||
int ret;
|
|
||||||
|
|
||||||
bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
|
phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
|
||||||
if (!bridge) {
|
|
||||||
DRM_ERROR("Failed to allocate drm bridge\n");
|
for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
|
||||||
return -ENOMEM;
|
if (dw_hdmi_phys[i].type == phy_type) {
|
||||||
|
hdmi->phy = &dw_hdmi_phys[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi->bridge = bridge;
|
if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
|
||||||
bridge->driver_private = hdmi;
|
dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
|
||||||
bridge->funcs = &dw_hdmi_bridge_funcs;
|
else
|
||||||
ret = drm_bridge_attach(encoder, bridge, NULL);
|
dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
|
||||||
if (ret) {
|
phy_type);
|
||||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
return -ENODEV;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dw_hdmi_bind(struct device *dev, struct device *master,
|
static struct dw_hdmi *
|
||||||
void *data, struct drm_encoder *encoder,
|
__dw_hdmi_probe(struct platform_device *pdev,
|
||||||
struct resource *iores, int irq,
|
const struct dw_hdmi_plat_data *plat_data)
|
||||||
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 device_node *np = dev->of_node;
|
||||||
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;
|
||||||
|
int irq;
|
||||||
int ret;
|
int ret;
|
||||||
u32 val = 1;
|
u32 val = 1;
|
||||||
|
u8 prod_id0;
|
||||||
|
u8 prod_id1;
|
||||||
u8 config0;
|
u8 config0;
|
||||||
u8 config1;
|
u8 config3;
|
||||||
|
|
||||||
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
|
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
|
||||||
if (!hdmi)
|
if (!hdmi)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
hdmi->connector.interlace_allowed = 1;
|
|
||||||
|
|
||||||
hdmi->plat_data = plat_data;
|
hdmi->plat_data = plat_data;
|
||||||
hdmi->dev = dev;
|
hdmi->dev = dev;
|
||||||
hdmi->dev_type = plat_data->dev_type;
|
hdmi->dev_type = plat_data->dev_type;
|
||||||
hdmi->sample_rate = 48000;
|
hdmi->sample_rate = 48000;
|
||||||
hdmi->encoder = encoder;
|
|
||||||
hdmi->disabled = true;
|
hdmi->disabled = true;
|
||||||
hdmi->rxsense = true;
|
hdmi->rxsense = true;
|
||||||
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(dev, "reg-io-width must be 1 or 4\n");
|
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);
|
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);
|
of_node_put(ddc_node);
|
||||||
if (!hdmi->ddc) {
|
if (!hdmi->ddc) {
|
||||||
dev_dbg(hdmi->dev, "failed to read ddc node\n");
|
dev_dbg(hdmi->dev, "failed to read ddc node\n");
|
||||||
return -EPROBE_DEFER;
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
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);
|
||||||
hdmi->regs = devm_ioremap_resource(dev, iores);
|
hdmi->regs = devm_ioremap_resource(dev, iores);
|
||||||
if (IS_ERR(hdmi->regs)) {
|
if (IS_ERR(hdmi->regs)) {
|
||||||
ret = PTR_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 */
|
/* Product and revision IDs */
|
||||||
dev_info(dev,
|
hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
|
||||||
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
|
| (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
|
||||||
hdmi_readb(hdmi, HDMI_DESIGN_ID),
|
prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0);
|
||||||
hdmi_readb(hdmi, HDMI_REVISION_ID),
|
prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1);
|
||||||
hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
|
|
||||||
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);
|
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,
|
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
|
||||||
dw_hdmi_irq, IRQF_SHARED,
|
dw_hdmi_irq, IRQF_SHARED,
|
||||||
dev_name(dev), hdmi);
|
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_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
|
||||||
HDMI_IH_PHY_STAT0);
|
HDMI_IH_PHY_STAT0);
|
||||||
|
|
||||||
ret = dw_hdmi_fb_registered(hdmi);
|
hdmi->bridge.driver_private = hdmi;
|
||||||
if (ret)
|
hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
|
||||||
goto err_iahb;
|
hdmi->bridge.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
ret = dw_hdmi_register(drm, hdmi);
|
ret = dw_hdmi_fb_registered(hdmi);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_iahb;
|
goto err_iahb;
|
||||||
|
|
||||||
@ -2012,9 +2075,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
|||||||
pdevinfo.id = PLATFORM_DEVID_AUTO;
|
pdevinfo.id = PLATFORM_DEVID_AUTO;
|
||||||
|
|
||||||
config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
|
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;
|
struct dw_hdmi_audio_data audio;
|
||||||
|
|
||||||
audio.phys = iores->start;
|
audio.phys = iores->start;
|
||||||
@ -2046,9 +2109,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
|||||||
if (hdmi->i2c)
|
if (hdmi->i2c)
|
||||||
dw_hdmi_i2c_init(hdmi);
|
dw_hdmi_i2c_init(hdmi);
|
||||||
|
|
||||||
dev_set_drvdata(dev, hdmi);
|
platform_set_drvdata(pdev, hdmi);
|
||||||
|
|
||||||
return 0;
|
return hdmi;
|
||||||
|
|
||||||
err_iahb:
|
err_iahb:
|
||||||
if (hdmi->i2c) {
|
if (hdmi->i2c) {
|
||||||
@ -2062,14 +2125,11 @@ err_isfr:
|
|||||||
err_res:
|
err_res:
|
||||||
i2c_put_adapter(hdmi->ddc);
|
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))
|
if (hdmi->audio && !IS_ERR(hdmi->audio))
|
||||||
platform_device_unregister(hdmi->audio);
|
platform_device_unregister(hdmi->audio);
|
||||||
|
|
||||||
@ -2084,6 +2144,70 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
|
|||||||
else
|
else
|
||||||
i2c_put_adapter(hdmi->ddc);
|
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);
|
EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
|
||||||
|
|
||||||
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
|
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
|
||||||
|
@ -545,12 +545,24 @@
|
|||||||
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
|
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
|
||||||
|
|
||||||
enum {
|
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 */
|
/* CONFIG0_ID field values */
|
||||||
HDMI_CONFIG0_I2S = 0x10,
|
HDMI_CONFIG0_I2S = 0x10,
|
||||||
|
|
||||||
/* CONFIG1_ID field values */
|
/* CONFIG1_ID field values */
|
||||||
HDMI_CONFIG1_AHB = 0x01,
|
HDMI_CONFIG1_AHB = 0x01,
|
||||||
|
|
||||||
|
/* CONFIG3_ID field values */
|
||||||
|
HDMI_CONFIG3_AHBAUDDMA = 0x02,
|
||||||
|
HDMI_CONFIG3_GPAUD = 0x01,
|
||||||
|
|
||||||
/* IH_FC_INT2 field values */
|
/* IH_FC_INT2 field values */
|
||||||
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
|
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
|
||||||
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
|
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
|
||||||
@ -847,8 +859,8 @@ enum {
|
|||||||
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
|
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
|
||||||
HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
|
HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
|
||||||
HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
|
HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
|
||||||
HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
|
HDMI_PHY_CONF0_SVSRET_MASK = 0x20,
|
||||||
HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
|
HDMI_PHY_CONF0_SVSRET_OFFSET = 5,
|
||||||
HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
|
HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
|
||||||
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
|
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
|
||||||
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
|
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
|
||||||
@ -977,8 +989,7 @@ enum {
|
|||||||
HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
|
HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
|
||||||
|
|
||||||
/* MC_PHYRSTZ field values */
|
/* MC_PHYRSTZ field values */
|
||||||
HDMI_MC_PHYRSTZ_ASSERT = 0x0,
|
HDMI_MC_PHYRSTZ_PHYRSTZ = 0x01,
|
||||||
HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
|
|
||||||
|
|
||||||
/* MC_HEACPHY_RST field values */
|
/* MC_HEACPHY_RST field values */
|
||||||
HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
|
HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
|
||||||
@ -1073,4 +1084,70 @@ enum {
|
|||||||
HDMI_I2CM_CTLINT_ARB_MASK = 0x4,
|
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__ */
|
#endif /* __DW_HDMI_H__ */
|
||||||
|
@ -2708,6 +2708,44 @@ backoff:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
|
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
|
* drm_atomic_helper_page_flip - execute a legacy page flip
|
||||||
* @crtc: DRM crtc
|
* @crtc: DRM crtc
|
||||||
@ -2715,7 +2753,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
|
|||||||
* @event: optional DRM event to signal upon completion
|
* @event: optional DRM event to signal upon completion
|
||||||
* @flags: flip flags for non-vblank sync'ed updates
|
* @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
|
* 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
|
* 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:
|
||||||
* Returns 0 on success, negative errno numbers on failure.
|
* 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,
|
int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
||||||
struct drm_framebuffer *fb,
|
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_plane *plane = crtc->primary;
|
||||||
struct drm_atomic_state *state;
|
struct drm_atomic_state *state;
|
||||||
struct drm_plane_state *plane_state;
|
|
||||||
struct drm_crtc_state *crtc_state;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
|
if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
|
||||||
@ -2743,35 +2783,14 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
|
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
ret = page_flip_common(state, crtc, fb, event);
|
||||||
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);
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto fail;
|
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);
|
ret = drm_atomic_nonblocking_commit(state);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (ret == -EDEADLK)
|
if (ret == -EDEADLK)
|
||||||
goto backoff;
|
goto backoff;
|
||||||
@ -2794,6 +2813,78 @@ backoff:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_atomic_helper_page_flip);
|
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
|
* drm_atomic_helper_connector_dpms() - connector dpms helper implementation
|
||||||
* @connector: affected connector
|
* @connector: affected connector
|
||||||
|
@ -67,6 +67,14 @@ static void drm_cache_flush_clflush(struct page *pages[],
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
void
|
||||||
drm_clflush_pages(struct page *pages[], unsigned long num_pages)
|
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);
|
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
|
void
|
||||||
drm_clflush_sg(struct sg_table *st)
|
drm_clflush_sg(struct sg_table *st)
|
||||||
{
|
{
|
||||||
@ -125,6 +140,14 @@ drm_clflush_sg(struct sg_table *st)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_clflush_sg);
|
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
|
void
|
||||||
drm_clflush_virt_range(void *addr, unsigned long length)
|
drm_clflush_virt_range(void *addr, unsigned long length)
|
||||||
{
|
{
|
||||||
|
@ -473,8 +473,7 @@ drm_fbdev_cma_create(struct drm_fb_helper *helper,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_cma_destroy:
|
err_cma_destroy:
|
||||||
drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
|
drm_framebuffer_remove(&fbdev_cma->fb->fb);
|
||||||
drm_fb_cma_destroy(&fbdev_cma->fb->fb);
|
|
||||||
err_fb_info_destroy:
|
err_fb_info_destroy:
|
||||||
drm_fb_helper_release_fbi(helper);
|
drm_fb_helper_release_fbi(helper);
|
||||||
err_gem_free_object:
|
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_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev);
|
||||||
drm_fb_helper_release_fbi(&fbdev_cma->fb_helper);
|
drm_fb_helper_release_fbi(&fbdev_cma->fb_helper);
|
||||||
|
|
||||||
if (fbdev_cma->fb) {
|
if (fbdev_cma->fb)
|
||||||
drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
|
drm_framebuffer_remove(&fbdev_cma->fb->fb);
|
||||||
drm_fb_cma_destroy(&fbdev_cma->fb->fb);
|
|
||||||
}
|
|
||||||
|
|
||||||
drm_fb_helper_fini(&fbdev_cma->fb_helper);
|
drm_fb_helper_fini(&fbdev_cma->fb_helper);
|
||||||
kfree(fbdev_cma);
|
kfree(fbdev_cma);
|
||||||
|
@ -3,6 +3,7 @@ config DRM_ETNAVIV
|
|||||||
tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
|
tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
|
||||||
depends on DRM
|
depends on DRM
|
||||||
depends on ARCH_MXC || ARCH_DOVE
|
depends on ARCH_MXC || ARCH_DOVE
|
||||||
|
depends on MMU
|
||||||
select SHMEM
|
select SHMEM
|
||||||
select TMPFS
|
select TMPFS
|
||||||
select IOMMU_API
|
select IOMMU_API
|
||||||
|
@ -467,7 +467,7 @@ err:
|
|||||||
clk_disable_unprepare(ctx->clks[i]);
|
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,
|
.enable = decon_enable,
|
||||||
.disable = decon_disable,
|
.disable = decon_disable,
|
||||||
.enable_vblank = decon_enable_vblank,
|
.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)
|
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_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);
|
drm_crtc_cleanup(crtc);
|
||||||
kfree(exynos_crtc);
|
kfree(exynos_crtc);
|
||||||
@ -134,7 +131,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
|||||||
void *ctx)
|
void *ctx)
|
||||||
{
|
{
|
||||||
struct exynos_drm_crtc *exynos_crtc;
|
struct exynos_drm_crtc *exynos_crtc;
|
||||||
struct exynos_drm_private *private = drm_dev->dev_private;
|
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -149,8 +145,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
|
|||||||
|
|
||||||
crtc = &exynos_crtc->base;
|
crtc = &exynos_crtc->base;
|
||||||
|
|
||||||
private->crtc[pipe] = crtc;
|
|
||||||
|
|
||||||
ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
|
ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
|
||||||
&exynos_crtc_funcs, NULL);
|
&exynos_crtc_funcs, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -211,12 +211,6 @@ struct drm_exynos_file_private {
|
|||||||
struct exynos_drm_private {
|
struct exynos_drm_private {
|
||||||
struct drm_fb_helper *fb_helper;
|
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;
|
struct device *dma_dev;
|
||||||
void *mapping;
|
void *mapping;
|
||||||
|
|
||||||
@ -231,9 +225,9 @@ struct exynos_drm_private {
|
|||||||
static inline struct exynos_drm_crtc *
|
static inline struct exynos_drm_crtc *
|
||||||
exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
|
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)
|
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)
|
static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct kirin_drm_private *priv = dev->dev_private;
|
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||||
struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
|
struct ade_crtc *acrtc = to_ade_crtc(crtc);
|
||||||
struct ade_hw_ctx *ctx = acrtc->ctx;
|
struct ade_hw_ctx *ctx = acrtc->ctx;
|
||||||
void __iomem *base = ctx->base;
|
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)
|
static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct kirin_drm_private *priv = dev->dev_private;
|
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||||
struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
|
struct ade_crtc *acrtc = to_ade_crtc(crtc);
|
||||||
struct ade_hw_ctx *ctx = acrtc->ctx;
|
struct ade_hw_ctx *ctx = acrtc->ctx;
|
||||||
void __iomem *base = ctx->base;
|
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,
|
static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
|
||||||
struct drm_plane *plane)
|
struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
struct kirin_drm_private *priv = dev->dev_private;
|
|
||||||
struct device_node *port;
|
struct device_node *port;
|
||||||
int ret;
|
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);
|
drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
|
||||||
priv->crtc[drm_crtc_index(crtc)] = crtc;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ struct kirin_dc_ops {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct kirin_drm_private {
|
struct kirin_drm_private {
|
||||||
struct drm_crtc *crtc[MAX_CRTC];
|
|
||||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||||
struct drm_fbdev_cma *fbdev;
|
struct drm_fbdev_cma *fbdev;
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include <drm/drm_legacy.h> /* for struct drm_dma_handle */
|
#include <drm/drm_legacy.h> /* for struct drm_dma_handle */
|
||||||
#include <drm/drm_gem.h>
|
#include <drm/drm_gem.h>
|
||||||
#include <drm/drm_auth.h>
|
#include <drm/drm_auth.h>
|
||||||
|
#include <drm/drm_cache.h>
|
||||||
|
|
||||||
#include "i915_params.h"
|
#include "i915_params.h"
|
||||||
#include "i915_reg.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_device *drm = data;
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
struct imx_hdmi *hdmi;
|
struct imx_hdmi *hdmi;
|
||||||
struct resource *iores;
|
|
||||||
int irq;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!pdev->dev.of_node)
|
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;
|
hdmi->dev = &pdev->dev;
|
||||||
encoder = &hdmi->encoder;
|
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);
|
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||||
/*
|
/*
|
||||||
* If we failed to find the CRTC(s) which this encoder is
|
* 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_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
|
||||||
DRM_MODE_ENCODER_TMDS, NULL);
|
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(),
|
* 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,
|
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
return dw_hdmi_unbind(dev, master, data);
|
return dw_hdmi_unbind(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops dw_hdmi_imx_ops = {
|
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)
|
int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct mtk_drm_private *priv = drm->dev_private;
|
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
|
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
||||||
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
|
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
|
||||||
|
|
||||||
mtk_ddp_comp_enable_vblank(ovl, &mtk_crtc->base);
|
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)
|
void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct mtk_drm_private *priv = drm->dev_private;
|
struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
|
||||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
|
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
||||||
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
|
struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
|
||||||
|
|
||||||
mtk_ddp_comp_disable_vblank(ovl);
|
mtk_ddp_comp_disable_vblank(ovl);
|
||||||
@ -588,7 +588,6 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
|
|||||||
goto unprepare;
|
goto unprepare;
|
||||||
drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
|
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);
|
drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE);
|
||||||
priv->crtc[pipe] = &mtk_crtc->base;
|
|
||||||
priv->num_pipes++;
|
priv->num_pipes++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -32,7 +32,6 @@ struct mtk_drm_private {
|
|||||||
struct drm_device *drm;
|
struct drm_device *drm;
|
||||||
struct device *dma_dev;
|
struct device *dma_dev;
|
||||||
|
|
||||||
struct drm_crtc *crtc[MAX_CRTC];
|
|
||||||
unsigned int num_pipes;
|
unsigned int num_pipes;
|
||||||
|
|
||||||
struct device_node *mutex_node;
|
struct device_node *mutex_node;
|
||||||
|
@ -4,6 +4,7 @@ config DRM_MSM
|
|||||||
depends on DRM
|
depends on DRM
|
||||||
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
|
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
|
||||||
depends on OF && COMMON_CLK
|
depends on OF && COMMON_CLK
|
||||||
|
depends on MMU
|
||||||
select REGULATOR
|
select REGULATOR
|
||||||
select DRM_KMS_HELPER
|
select DRM_KMS_HELPER
|
||||||
select DRM_PANEL
|
select DRM_PANEL
|
||||||
|
@ -174,10 +174,8 @@ fail_unlock:
|
|||||||
fail:
|
fail:
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (fb) {
|
if (fb)
|
||||||
drm_framebuffer_unregister_private(fb);
|
|
||||||
drm_framebuffer_remove(fb);
|
drm_framebuffer_remove(fb);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -247,7 +245,6 @@ void msm_fbdev_free(struct drm_device *dev)
|
|||||||
/* this will free the backing object */
|
/* this will free the backing object */
|
||||||
if (fbdev->fb) {
|
if (fbdev->fb) {
|
||||||
msm_gem_put_vaddr(fbdev->bo);
|
msm_gem_put_vaddr(fbdev->bo);
|
||||||
drm_framebuffer_unregister_private(fbdev->fb);
|
|
||||||
drm_framebuffer_remove(fbdev->fb);
|
drm_framebuffer_remove(fbdev->fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,27 +58,30 @@ int
|
|||||||
nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
|
nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
struct nouveau_crtc *nv_crtc;
|
||||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
|
||||||
if (nv_crtc->index == pipe) {
|
crtc = drm_crtc_from_index(dev, pipe);
|
||||||
nvif_notify_get(&nv_crtc->vblank);
|
if (!crtc)
|
||||||
return 0;
|
return -EINVAL;
|
||||||
}
|
|
||||||
}
|
nv_crtc = nouveau_crtc(crtc);
|
||||||
return -EINVAL;
|
nvif_notify_get(&nv_crtc->vblank);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
|
nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
struct nouveau_crtc *nv_crtc;
|
||||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
|
||||||
if (nv_crtc->index == pipe) {
|
crtc = drm_crtc_from_index(dev, pipe);
|
||||||
nvif_notify_put(&nv_crtc->vblank);
|
if (!crtc)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
nv_crtc = nouveau_crtc(crtc);
|
||||||
|
nvif_notify_put(&nv_crtc->vblank);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -225,10 +225,8 @@ fail:
|
|||||||
|
|
||||||
drm_fb_helper_release_fbi(helper);
|
drm_fb_helper_release_fbi(helper);
|
||||||
|
|
||||||
if (fb) {
|
if (fb)
|
||||||
drm_framebuffer_unregister_private(fb);
|
|
||||||
drm_framebuffer_remove(fb);
|
drm_framebuffer_remove(fb);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -314,10 +312,8 @@ void omap_fbdev_free(struct drm_device *dev)
|
|||||||
omap_gem_put_paddr(fbdev->bo);
|
omap_gem_put_paddr(fbdev->bo);
|
||||||
|
|
||||||
/* this will free the backing object */
|
/* this will free the backing object */
|
||||||
if (fbdev->fb) {
|
if (fbdev->fb)
|
||||||
drm_framebuffer_unregister_private(fbdev->fb);
|
|
||||||
drm_framebuffer_remove(fbdev->fb);
|
drm_framebuffer_remove(fbdev->fb);
|
||||||
}
|
|
||||||
|
|
||||||
kfree(fbdev);
|
kfree(fbdev);
|
||||||
|
|
||||||
|
@ -84,8 +84,18 @@ int
|
|||||||
qxl_debugfs_init(struct drm_minor *minor)
|
qxl_debugfs_init(struct drm_minor *minor)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_DEBUG_FS)
|
#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,
|
drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES,
|
||||||
minor->debugfs_root, minor);
|
minor->debugfs_root, minor);
|
||||||
|
|
||||||
|
r = qxl_ttm_debugfs_init(dev);
|
||||||
|
if (r) {
|
||||||
|
DRM_ERROR("Failed to init TTM debugfs\n");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
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);
|
dev->mode_config.suggested_x_property, 0);
|
||||||
drm_object_attach_property(&connector->base,
|
drm_object_attach_property(&connector->base,
|
||||||
dev->mode_config.suggested_y_property, 0);
|
dev->mode_config.suggested_y_property, 0);
|
||||||
drm_connector_register(connector);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,20 +62,83 @@ static struct pci_driver qxl_pci_driver;
|
|||||||
static int
|
static int
|
||||||
qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
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) {
|
if (pdev->revision < 4) {
|
||||||
DRM_ERROR("qxl too old, doesn't support client_monitors_config,"
|
DRM_ERROR("qxl too old, doesn't support client_monitors_config,"
|
||||||
" use xf86-video-qxl in user mode");
|
" use xf86-video-qxl in user mode");
|
||||||
return -EINVAL; /* TODO: ENODEV ? */
|
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
|
static void
|
||||||
qxl_pci_remove(struct pci_dev *pdev)
|
qxl_pci_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = pci_get_drvdata(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 = {
|
static const struct file_operations qxl_fops = {
|
||||||
@ -230,8 +293,6 @@ static struct pci_driver qxl_pci_driver = {
|
|||||||
static struct drm_driver qxl_driver = {
|
static struct drm_driver qxl_driver = {
|
||||||
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
|
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
|
||||||
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||||
.load = qxl_driver_load,
|
|
||||||
.unload = qxl_driver_unload,
|
|
||||||
.get_vblank_counter = qxl_noop_get_vblank_counter,
|
.get_vblank_counter = qxl_noop_get_vblank_counter,
|
||||||
.enable_vblank = qxl_noop_enable_vblank,
|
.enable_vblank = qxl_noop_enable_vblank,
|
||||||
.disable_vblank = qxl_noop_disable_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 const struct drm_ioctl_desc qxl_ioctls[];
|
||||||
extern int qxl_max_ioctl;
|
extern int qxl_max_ioctl;
|
||||||
|
|
||||||
int qxl_driver_load(struct drm_device *dev, unsigned long flags);
|
int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev,
|
||||||
void qxl_driver_unload(struct drm_device *dev);
|
struct pci_dev *pdev, unsigned long flags);
|
||||||
|
void qxl_device_fini(struct qxl_device *qdev);
|
||||||
|
|
||||||
int qxl_modeset_init(struct qxl_device *qdev);
|
int qxl_modeset_init(struct qxl_device *qdev);
|
||||||
void qxl_modeset_fini(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);
|
int qxl_debugfs_init(struct drm_minor *minor);
|
||||||
void qxl_debugfs_takedown(struct drm_minor *minor);
|
void qxl_debugfs_takedown(struct drm_minor *minor);
|
||||||
|
int qxl_ttm_debugfs_init(struct qxl_device *qdev);
|
||||||
|
|
||||||
/* qxl_prime.c */
|
/* qxl_prime.c */
|
||||||
int qxl_gem_prime_pin(struct drm_gem_object *obj);
|
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);
|
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 drm_device *ddev,
|
||||||
struct pci_dev *pdev,
|
struct pci_dev *pdev,
|
||||||
unsigned long flags)
|
unsigned long flags)
|
||||||
@ -263,7 +263,7 @@ static int qxl_device_init(struct qxl_device *qdev,
|
|||||||
return 0;
|
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])
|
if (qdev->current_release_bo[0])
|
||||||
qxl_bo_unref(&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;
|
qdev->mode_info.num_modes = 0;
|
||||||
qxl_debugfs_remove_files(qdev);
|
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 "qxl_object.h"
|
||||||
|
|
||||||
#include <linux/delay.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)
|
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));
|
((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
|
||||||
DRM_INFO("qxl: %uM of Surface memory size\n",
|
DRM_INFO("qxl: %uM of Surface memory size\n",
|
||||||
(unsigned)qdev->surfaceram_size / (1024 * 1024));
|
(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +467,7 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if defined(CONFIG_DEBUG_FS)
|
||||||
static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
|
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_device *drm = data;
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
struct rockchip_hdmi *hdmi;
|
struct rockchip_hdmi *hdmi;
|
||||||
struct resource *iores;
|
|
||||||
int irq;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!pdev->dev.of_node)
|
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;
|
hdmi->dev = &pdev->dev;
|
||||||
encoder = &hdmi->encoder;
|
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);
|
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||||
/*
|
/*
|
||||||
* If we failed to find the CRTC(s) which this encoder is
|
* 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_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
|
||||||
DRM_MODE_ENCODER_TMDS, NULL);
|
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(),
|
* 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,
|
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
return dw_hdmi_unbind(dev, master, data);
|
return dw_hdmi_unbind(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops dw_hdmi_rockchip_ops = {
|
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))
|
if (drm_mm_scan_add_block(&scan, &e->node))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
list_for_each_entry(e, &evict_list, link) {
|
list_for_each_entry(e, &evict_list, link) {
|
||||||
if (!drm_mm_scan_remove_block(&scan, &e->node)) {
|
if (!drm_mm_scan_remove_block(&scan, &e->node)) {
|
||||||
pr_err("Node %lld not marked for eviction!\n",
|
if (!err) {
|
||||||
e->node.start);
|
pr_err("Node %lld not marked for eviction!\n",
|
||||||
list_del(&e->link);
|
e->node.start);
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (err)
|
||||||
|
return false;
|
||||||
|
|
||||||
list_for_each_entry(e, &evict_list, link)
|
list_for_each_entry(e, &evict_list, link)
|
||||||
drm_mm_remove_node(&e->node);
|
drm_mm_remove_node(&e->node);
|
||||||
|
@ -804,23 +804,10 @@ static const struct file_operations tegra_drm_fops = {
|
|||||||
.llseek = noop_llseek,
|
.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,
|
static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
|
||||||
unsigned int pipe)
|
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);
|
struct tegra_dc *dc = to_tegra_dc(crtc);
|
||||||
|
|
||||||
if (!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)
|
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);
|
struct tegra_dc *dc = to_tegra_dc(crtc);
|
||||||
|
|
||||||
if (!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)
|
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);
|
struct tegra_dc *dc = to_tegra_dc(crtc);
|
||||||
|
|
||||||
if (crtc)
|
if (crtc)
|
||||||
|
@ -271,8 +271,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
destroy:
|
destroy:
|
||||||
drm_framebuffer_unregister_private(fb);
|
drm_framebuffer_remove(fb);
|
||||||
tegra_fb_destroy(fb);
|
|
||||||
release:
|
release:
|
||||||
drm_fb_helper_release_fbi(helper);
|
drm_fb_helper_release_fbi(helper);
|
||||||
return err;
|
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_unregister_fbi(&fbdev->base);
|
||||||
drm_fb_helper_release_fbi(&fbdev->base);
|
drm_fb_helper_release_fbi(&fbdev->base);
|
||||||
|
|
||||||
if (fbdev->fb) {
|
if (fbdev->fb)
|
||||||
drm_framebuffer_unregister_private(&fbdev->fb->base);
|
|
||||||
drm_framebuffer_remove(&fbdev->fb->base);
|
drm_framebuffer_remove(&fbdev->fb->base);
|
||||||
}
|
|
||||||
|
|
||||||
drm_fb_helper_fini(&fbdev->base);
|
drm_fb_helper_fini(&fbdev->base);
|
||||||
tegra_fbdev_free(fbdev);
|
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)
|
const struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
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;
|
u32 val;
|
||||||
int fifo_lines;
|
int fifo_lines;
|
||||||
int vblank_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,
|
int *max_error, struct timeval *vblank_time,
|
||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
|
||||||
struct drm_crtc *crtc = &vc4_crtc->base;
|
|
||||||
struct drm_crtc_state *state = crtc->state;
|
struct drm_crtc_state *state = crtc->state;
|
||||||
|
|
||||||
/* Helper routine in DRM core does all the work: */
|
/* 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)
|
int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
|
||||||
{
|
{
|
||||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||||
|
|
||||||
CRTC_WRITE(PV_INTEN, PV_INT_VFP_START);
|
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)
|
void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id)
|
||||||
{
|
{
|
||||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||||
struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
|
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||||
|
|
||||||
CRTC_WRITE(PV_INTEN, 0);
|
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 platform_device *pdev = to_platform_device(dev);
|
||||||
struct drm_device *drm = dev_get_drvdata(master);
|
struct drm_device *drm = dev_get_drvdata(master);
|
||||||
struct vc4_dev *vc4 = to_vc4_dev(drm);
|
|
||||||
struct vc4_crtc *vc4_crtc;
|
struct vc4_crtc *vc4_crtc;
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
|
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);
|
&vc4_crtc_funcs, NULL);
|
||||||
drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
|
drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
|
||||||
primary_plane->crtc = crtc;
|
primary_plane->crtc = crtc;
|
||||||
vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc;
|
|
||||||
vc4_crtc->channel = vc4_crtc->data->hvs_channel;
|
vc4_crtc->channel = vc4_crtc->data->hvs_channel;
|
||||||
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
|
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_hdmi *hdmi;
|
||||||
struct vc4_hvs *hvs;
|
struct vc4_hvs *hvs;
|
||||||
struct vc4_crtc *crtc[3];
|
|
||||||
struct vc4_v3d *v3d;
|
struct vc4_v3d *v3d;
|
||||||
struct vc4_dpi *dpi;
|
struct vc4_dpi *dpi;
|
||||||
struct vc4_vec *vec;
|
struct vc4_vec *vec;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <drm/drmP.h>
|
#include <drm/drmP.h>
|
||||||
#include <drm/drm_gem.h>
|
#include <drm/drm_gem.h>
|
||||||
|
#include <drm/drm_cache.h>
|
||||||
|
|
||||||
#include <uapi/drm/vgem_drm.h>
|
#include <uapi/drm/vgem_drm.h>
|
||||||
|
|
||||||
|
@ -27,6 +27,16 @@ enum dw_hdmi_devtype {
|
|||||||
RK3288_HDMI,
|
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 {
|
struct dw_hdmi_mpll_config {
|
||||||
unsigned long mpixelclock;
|
unsigned long mpixelclock;
|
||||||
struct {
|
struct {
|
||||||
@ -56,10 +66,11 @@ struct dw_hdmi_plat_data {
|
|||||||
struct drm_display_mode *mode);
|
struct drm_display_mode *mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
|
int dw_hdmi_probe(struct platform_device *pdev,
|
||||||
int dw_hdmi_bind(struct device *dev, struct device *master,
|
const struct dw_hdmi_plat_data *plat_data);
|
||||||
void *data, struct drm_encoder *encoder,
|
void dw_hdmi_remove(struct platform_device *pdev);
|
||||||
struct resource *iores, int irq,
|
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);
|
const struct dw_hdmi_plat_data *plat_data);
|
||||||
|
|
||||||
void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
|
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,
|
int drm_invalid_op(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv);
|
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
|
* These are exported to drivers so that they can implement fencing using
|
||||||
* DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
|
* 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_framebuffer *fb,
|
||||||
struct drm_pending_vblank_event *event,
|
struct drm_pending_vblank_event *event,
|
||||||
uint32_t flags);
|
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 drm_atomic_helper_connector_dpms(struct drm_connector *connector,
|
||||||
int mode);
|
int mode);
|
||||||
struct drm_encoder *
|
struct drm_encoder *
|
||||||
|
@ -33,7 +33,11 @@
|
|||||||
#ifndef _DRM_CACHE_H_
|
#ifndef _DRM_CACHE_H_
|
||||||
#define _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_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)
|
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 *ctm;
|
||||||
struct drm_property_blob *gamma_lut;
|
struct drm_property_blob *gamma_lut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @target_vblank:
|
||||||
|
*
|
||||||
|
* Target vertical blank period when a page flip
|
||||||
|
* should take effect.
|
||||||
|
*/
|
||||||
|
|
||||||
|
u32 target_vblank;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @event:
|
* @event:
|
||||||
*
|
*
|
||||||
|
@ -41,10 +41,17 @@ extern "C" {
|
|||||||
/* 8 bpp Red */
|
/* 8 bpp Red */
|
||||||
#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
|
#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 */
|
/* 16 bpp RG */
|
||||||
#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
|
#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 */
|
#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 */
|
/* 8 bpp RGB */
|
||||||
#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
|
#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 */
|
#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